美文网首页
经典卷积神经网络——LeNet

经典卷积神经网络——LeNet

作者: 小黄不头秃 | 来源:发表于2022-09-06 00:06 被阅读0次

    (一)LeNet神经网络

    这个网络是远古时期的网络了,出自美国八十年代。当时为了解决的是支票或者邮件编码的识别问题。也就是MNIST手写数字识别的起源来源。

    我们可以看看它具体的网络结构:

    • 第一层:卷积核的形状(1,6,5,5),六个(5,5)的卷积核
    • 第二层:池化层,窗口的形状是(6,2,2),设置stride = 2.输出大小为:(6,14,14)
    • 第三层:卷积层,卷积核的形状为(6,16,5,5).
    • 第四层:池化层,窗口大小为(16,2,2),设置stride = 2.输出大小为(16,5,5)
    • 第五层:全连接层,120个节点
    • 第六层:全连接层,84个节点
    • 第七层:输出层,10个分类

    (一)LeNet神经网络

    这里的输入由于数据集的问题,原本的(32 * 32)被裁减成了(28 * 28)所以在第一个卷积层通过padding给补上了。 网络结构和原本的LeNet还是有小小的差别。

    import torch
    from torch import nn
    from torchvision import transforms
    import torchvision
    from torch.utils import data
    from d2l import torch as d2l
    import numpy as np
    import matplotlib.pyplot as plt
    
    class Reshape(nn.Module):
        def forward(self,x):
            return x.view((-1,1,28,28))
    
    net  = torch.nn.Sequential(
        Reshape(), # (-1,1,28,28)
        nn.Conv2d(in_channels=1,out_channels=6,kernel_size=5,padding=2), # (-1,6,28,28)
        nn.Sigmoid(),
        nn.AvgPool2d(kernel_size=2,stride=2), # (-1,6,14,14)
        nn.Conv2d(in_channels=6,out_channels=16,kernel_size=5), # (-1,16,10,10)
        nn.Sigmoid(),
        nn.AvgPool2d(kernel_size=2,stride=2), # (-1,16,5,5)
        nn.Flatten(),
        nn.Linear(in_features=16*5*5,out_features=120), # (-1,120)
        nn.Sigmoid(),
        nn.Linear(120,84),# (-1,84)
        nn.Sigmoid(),
        nn.Linear(in_features=84,out_features=10)# (-1,10)
    )
    
    print(net)
    
    x = torch.randn(4*28*28,dtype=torch.float32).reshape(4,1,28,28)
    
    for layer in net:
        x = layer(x)
        print(layer.__class__.__name__,"output shape = ", x.shape)
    
    # 超参数设置
    batch_size = 128
    learning_rate = 0.3
    epochs = 20
    
    # 现在使用mnist数据集测试一下结果
    def load_data_fashion_mnist(batch_size, resize=None):
        """下载或者加载Fashion-MNIST数据集"""
        trans = transforms.ToTensor()
        mnist_train = torchvision.datasets.FashionMNIST(
            root="../data/",
            train=True,
            transform=trans,
            download=False # 要是没下载过就选择true
        )
        mnist_test = torchvision.datasets.FashionMNIST(
            root="../data/",
            train=False,
            transform=trans,
            download=False # 要是没下载过就选择true
        )
        return (data.DataLoader(mnist_train,batch_size=batch_size,shuffle=True,num_workers=0),
                data.DataLoader(mnist_test,batch_size=batch_size,shuffle=True,num_workers=0))
    
    # 加载数据
    train_iter, test_iter = load_data_fashion_mnist(batch_size)
    
    # 简化版评估模型准确率
    def evalue_acc(net,data_iter,device=None):
        if isinstance(net, nn.Module):
            net.eval()
            if not device:
                device = next(iter(net.parameters())).device
        # 正确的预测数量,总预测的数量
        acc_list = np.array([])
        with torch.no_grad():
            for X, y in data_iter:
                if isinstance(X, list):
                    # Bert微调所需
                    X = [x.to(device) for x in X]
                else:
                    X = X.to(device)
                y_hat = net(X)
                y = y.to(device)
                if len(y_hat.shape) > 1 and y_hat.shape[1] >1:
                    y_hat = y_hat.argmax(axis=1)
                cmp = y_hat.type(y.dtype) == y
                acc = torch.tensor(cmp).sum().item()/len(y)
                acc_list = np.append(acc_list,acc)
        return acc_list.mean()
    
    # print(evalue_acc(net,train_iter,device=None))
    
    %matplotlib inline
    
    # 简化版的训练函数
    def train(net,train_iter,test_iter,epochs,lr,device):
        """使用GPU训练模型"""
        def init_weights(m):
            if type(m) == nn.Linear or type(m) == nn.Conv2d:
                nn.init.xavier_uniform_(m.weight)
        net.apply(init_weights)
    
        print("Network traning on",device)
        net.to(device)
    
        # 优化器和损失函数
        optimizer = torch.optim.SGD(net.parameters(),lr)
        loss = nn.CrossEntropyLoss()
    
        #画图用的变量
        loss_history = np.array([])
        train_acc = np.array([])
        test_acc = np.array([])
    
        plt.ion()
        for epoch in range(epochs):
            l_epoch = np.array([])
            for x, y in train_iter:
                if isinstance(net,torch.nn.Module):
                    net.train() # 开启训练模式
                x = x.to(device)
                y = y.to(device)
                l = loss(net(x),y)
                optimizer.zero_grad()
                l.backward()
                optimizer.step()
                l_epoch = np.append(l_epoch,l.detach().mean().to("cpu"))
                
            print(f"epoch:{epoch}, train_loss:{l_epoch.mean()}")
            loss_history = np.append(loss_history,l_epoch.mean())
            train_acc = np.append(train_acc,evalue_acc(net,train_iter))
            test_acc = np.append(test_acc,evalue_acc(net,test_iter))
    
            # 画图
            plt.clf()  #清除上一幅图像
            plt.plot(np.arange(epoch+1),loss_history,'b',label="train_loss")
            plt.plot(np.arange(epoch+1),train_acc,':g',label="train_acc")
            plt.plot(np.arange(epoch+1),test_acc,':m',label="test_acc")
            plt.xlabel("epoch")
            plt.legend()
            plt.pause(0.01)  # 暂停0.01秒
        print(f"train_acc:{train_acc[-1]},test_acc:{test_acc[-1]}")
    
        plt.ioff()
    
    train(net,train_iter,test_iter,epochs,lr=learning_rate,device=d2l.try_gpu())
    
    train_acc:0.8572205934612651, test_acc:0.8443433544303798

    下面的是书本上的代码写法,比我写的要精炼的多。

    # 书本上的版本
    def evaluate_accuracy_gpu(net, data_iter, device=None): #@save
        """使用GPU计算模型在数据集上的精度"""
        if isinstance(net, nn.Module):
            net.eval()  # 设置为评估模式
            if not device:
                device = next(iter(net.parameters())).device
        # 正确预测的数量,总预测的数量
        metric = d2l.Accumulator(2)
        with torch.no_grad():
            for X, y in data_iter:
                if isinstance(X, list):
                    # BERT微调所需的(之后将介绍)
                    X = [x.to(device) for x in X]
                else:
                    X = X.to(device)
                y = y.to(device)
                metric.add(d2l.accuracy(net(X), y), y.numel())
        return metric[0] / metric[1]
    
    #@save 书上的版本
    def train_ch6(net, train_iter, test_iter, num_epochs, lr, device):
        """用GPU训练模型(在第六章定义)"""
        def init_weights(m):
            if type(m) == nn.Linear or type(m) == nn.Conv2d:
                nn.init.xavier_uniform_(m.weight)
        net.apply(init_weights)
        print('training on', device)
        net.to(device)
        optimizer = torch.optim.SGD(net.parameters(), lr=lr)
        loss = nn.CrossEntropyLoss()
        animator = d2l.Animator(xlabel='epoch', xlim=[1, num_epochs],
                                legend=['train loss', 'train acc', 'test acc'])
        timer, num_batches = d2l.Timer(), len(train_iter)
        for epoch in range(num_epochs):
            # 训练损失之和,训练准确率之和,样本数
            metric = d2l.Accumulator(3)
            net.train()
            for i, (X, y) in enumerate(train_iter):
                timer.start()
                optimizer.zero_grad()
                X, y = X.to(device), y.to(device)
                y_hat = net(X)
                l = loss(y_hat, y)
                l.backward()
                optimizer.step()
                with torch.no_grad():
                    metric.add(l * X.shape[0], d2l.accuracy(y_hat, y), X.shape[0])
                timer.stop()
                train_l = metric[0] / metric[2]
                train_acc = metric[1] / metric[2]
                if (i + 1) % (num_batches // 5) == 0 or i == num_batches - 1:
                    animator.add(epoch + (i + 1) / num_batches,
                                 (train_l, train_acc, None))
            test_acc = evaluate_accuracy_gpu(net, test_iter)
            animator.add(epoch + 1, (None, None, test_acc))
        print(f'loss {train_l:.3f}, train acc {train_acc:.3f}, '
              f'test acc {test_acc:.3f}')
        print(f'{metric[2] * num_epochs / timer.sum():.1f} examples/sec '
              f'on {str(device)}')
    

    相关文章

      网友评论

          本文标题:经典卷积神经网络——LeNet

          本文链接:https://www.haomeiwen.com/subject/qnqjnrtx.html