Pytorch CIFAR10图像分类 LeNet5篇

Posted Real&Love

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Pytorch CIFAR10图像分类 LeNet5篇相关的知识,希望对你有一定的参考价值。

Pytorch CIFAR10图像分类 LeNet5篇


这里贴一下汇总篇: 汇总篇

4.定义网络(LeNet5)

手写字体识别模型LeNet5诞生于1994年,是最早的卷积神经网络之一。LeNet5通过巧妙的设计,利用卷积、参数共享、池化等操作提取特征,避免了大量的计算成本,最后再使用全连接神经网络进行分类识别,这个网络也是最近大量神经网络架构的起点。

LeNet-5 一些性质:

  • 如果输入层不算神经网络的层数,那么 LeNet-5 是一个 7 层的网络。(有些地方也可能把 卷积和池化 当作一个 layer)(LeNet-5 名字中的“5”也可以理解为整个网络中含可训练参数的层数为 5。)

  • LeNet-5 大约有 60,000 个参数。

  • 随着网络越来越深,图像的高度和宽度在缩小,与此同时,图像的 channel 数量一直在增加。

  • 现在常用的 LeNet-5 结构和 Yann LeCun 教授在 1998 年论文中提出的结构在某些地方有区别,比如激活函数的使用,现在一般使用 ReLU 作为激活函数,输出层一般选择 softmax。

首先我们还是得判断是否可以利用GPU,因为GPU的速度可能会比我们用CPU的速度快20-50倍左右,特别是对卷积神经网络来说,更是提升特别明显。

device = 'cuda' if torch.cuda.is_available() else 'cpu'
#定义网络
class LeNet5(nn.Module):# nn.Module是所有神经网络的基类,我们自己定义任何神经网络,都要继承nn.Module
    def __init__(self):
        super(LeNet5,self).__init__()
        self.conv1 = nn.Sequential(
            # 卷积层1,3通道输入,6个卷积核,核大小5*5
            # 经过该层图像大小变为32-5+1,28*28
            nn.Conv2d(in_channels=3,out_channels=6,kernel_size=5,stride=1, padding=0),
            #激活函数
            nn.ReLU(),
            # 经2*2最大池化,图像变为14*14
            nn.MaxPool2d(kernel_size=2,stride=2,padding=0),
        )
        self.conv2 = nn.Sequential(
            # 卷积层2,6输入通道,16个卷积核,核大小5*5
            # 经过该层图像变为14-5+1,10*10
            nn.Conv2d(in_channels=6,out_channels=16,kernel_size=5,stride=1, padding=0),
            nn.ReLU(),
            # 经2*2最大池化,图像变为5*5
            nn.MaxPool2d(kernel_size=2,stride=2,padding=0),
        )
        self.fc = nn.Sequential(
            # 接着三个全连接层
            nn.Linear(16*5*5,120),
            nn.ReLU(),
            nn.Linear(120,84),
            nn.ReLU(),
            nn.Linear(84,10),
        )
        
        # 定义前向传播过程,输入为
    def forward(self,x):
        x = self.conv1(x)
        x = self.conv2(x)
        # nn.Linear()的输入输出都是维度为一的值,所以要把多维度的tensor展平成一维
            
        x = x.view(x.size()[0],-1)
        x = self.fc(x)
        return x
            
net = LeNet5().cuda()
summary(net,(3,32,32))
----------------------------------------------------------------
     Layer (type)               Output Shape         Param #
================================================================
         Conv2d-1            [-1, 6, 28, 28]             456
           ReLU-2            [-1, 6, 28, 28]               0
      MaxPool2d-3            [-1, 6, 14, 14]               0
         Conv2d-4           [-1, 16, 10, 10]           2,416
           ReLU-5           [-1, 16, 10, 10]               0
      MaxPool2d-6             [-1, 16, 5, 5]               0
         Linear-7                  [-1, 120]          48,120
           ReLU-8                  [-1, 120]               0
         Linear-9                   [-1, 84]          10,164
          ReLU-10                   [-1, 84]               0
        Linear-11                   [-1, 10]             850
================================================================
Total params: 62,006
Trainable params: 62,006
Non-trainable params: 0
----------------------------------------------------------------
Input size (MB): 0.01
Forward/backward pass size (MB): 0.11
Params size (MB): 0.24
Estimated Total Size (MB): 0.36
----------------------------------------------------------------

首先从我们summary可以看到,我们定义的模型的参数大概是62 thousands,我们输入的是(batch,3,32,32)的张量,并且这里也能看到每一层后我们的图像输出大小的变化,最后输出10个参数,再通过softmax函数就可以得到我们每个类别的概率了。

我们也可以打印出我们的模型观察一下

LeNet5(
  (conv1): Sequential(
    (0): Conv2d(3, 6, kernel_size=(5, 5), stride=(1, 1))
    (1): ReLU()
    (2): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  )
  (conv2): Sequential(
    (0): Conv2d(6, 16, kernel_size=(5, 5), stride=(1, 1))
    (1): ReLU()
    (2): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  )
  (fc): Sequential(
    (0): Linear(in_features=400, out_features=120, bias=True)
    (1): ReLU()
    (2): Linear(in_features=120, out_features=84, bias=True)
    (3): ReLU()
    (4): Linear(in_features=84, out_features=10, bias=True)
  )
)

如果你的电脑有多个GPU,这段代码可以利用GPU进行并行计算,加快运算速度

net =LeNet5().to(device)
if device == 'cuda':
    net = nn.DataParallel(net)
    # 当计算图不会改变的时候(每次输入形状相同,模型不改变)的情况下可以提高性能,反之则降低性能
    torch.backends.cudnn.benchmark = True

5. 定义损失函数和优化器

pytorch将深度学习中常用的优化方法全部封装在torch.optim之中,所有的优化方法都是继承基类optim.Optimizier
损失函数是封装在神经网络工具箱nn中的,包含很多损失函数

这里我使用的是SGD + momentum算法,并且我们损失函数定义为交叉熵函数,除此之外学习策略定义为动态更新学习率,如果5次迭代后,训练的损失并没有下降,那么我们便会更改学习率,会变为原来的0.5倍,最小降低到0.00001

如果想更加了解优化器和学习率策略的话,可以参考以下资料

这里决定迭代20次

import torch.optim as optim
optimizer = optim.SGD(net.parameters(), lr=1e-1, momentum=0.9, weight_decay=5e-4)
criterion = nn.CrossEntropyLoss()
scheduler = optim.lr_scheduler.ReduceLROnPlateau(optimizer, 'min', factor=0.5 ,patience = 5,min_lr = 0.000001) # 动态更新学习率
# scheduler = optim.lr_scheduler.MultiStepLR(optimizer, milestones=[75, 150], gamma=0.5)
import time
epoch = 20

6. 训练

首先定义模型保存的位置

import os
if not os.path.exists('./model'):
    os.makedirs('./model')
else:
    print('文件已存在')
save_path = './model/LeNet5.pth'

我定义了一个train函数,在train函数中进行一个训练,并保存我们训练后的模型

from utils import trainfrom utils import plot_historyAcc, Loss, Lr = train(net, trainloader, testloader, epoch, optimizer, criterion, scheduler, save_path, verbose = True)
Epoch [  1/ 20]  Train Loss:1.918313  Train Acc:28.19% Test Loss:1.647650  Test Acc:39.23%  Learning Rate:0.100000	Time 00:29Epoch [  2/ 20]  Train Loss:1.574629  Train Acc:42.00% Test Loss:1.521759  Test Acc:44.59%  Learning Rate:0.100000	Time 00:21Epoch [  3/ 20]  Train Loss:1.476749  Train Acc:46.23% Test Loss:1.438898  Test Acc:48.56%  Learning Rate:0.100000	Time 00:21Epoch [  4/ 20]  Train Loss:1.415963  Train Acc:49.10% Test Loss:1.378597  Test Acc:50.25%  Learning Rate:0.100000	Time 00:21Epoch [  5/ 20]  Train Loss:1.384430  Train Acc:50.69% Test Loss:1.350369  Test Acc:51.81%  Learning Rate:0.100000	Time 00:20Epoch [  6/ 20]  Train Loss:1.331118  Train Acc:52.49% Test Loss:1.384710  Test Acc:49.62%  Learning Rate:0.100000	Time 00:20Epoch [  7/ 20]  Train Loss:1.323763  Train Acc:53.08% Test Loss:1.348911  Test Acc:52.59%  Learning Rate:0.100000	Time 00:21Epoch [  8/ 20]  Train Loss:1.291410  Train Acc:54.19% Test Loss:1.273263  Test Acc:55.00%  Learning Rate:0.100000	Time 00:20Epoch [  9/ 20]  Train Loss:1.261590  Train Acc:55.36% Test Loss:1.295092  Test Acc:54.50%  Learning Rate:0.100000	Time 00:20Epoch [ 10/ 20]  Train Loss:1.239585  Train Acc:56.45% Test Loss:1.349028  Test Acc:52.57%  Learning Rate:0.100000	Time 00:21Epoch [ 11/ 20]  Train Loss:1.225227  Train Acc:56.81% Test Loss:1.293521  Test Acc:53.87%  Learning Rate:0.100000	Time 00:22Epoch [ 12/ 20]  Train Loss:1.221355  Train Acc:56.86% Test Loss:1.255155  Test Acc:56.13%  Learning Rate:0.100000	Time 00:21Epoch [ 13/ 20]  Train Loss:1.207748  Train Acc:57.59% Test Loss:1.238375  Test Acc:57.10%  Learning Rate:0.100000	Time 00:21Epoch [ 14/ 20]  Train Loss:1.195587  Train Acc:58.01% Test Loss:1.185524  Test Acc:58.56%  Learning Rate:0.100000	Time 00:20Epoch [ 15/ 20]  Train Loss:1.183456  Train Acc:58.50% Test Loss:1.192770  Test Acc:58.04%  Learning Rate:0.100000	Time 00:21Epoch [ 16/ 20]  Train Loss:1.168697  Train Acc:59.13% Test Loss:1.272912  Test Acc:55.85%  Learning Rate:0.100000	Time 00:20Epoch [ 17/ 20]  Train Loss:1.167685  Train Acc:59.23% Test Loss:1.195087  Test Acc:58.33%  Learning Rate:0.100000	Time 00:20Epoch [ 18/ 20]  Train Loss:1.162324  Train Acc:59.37% Test Loss:1.242964  Test Acc:56.62%  Learning Rate:0.100000	Time 00:21Epoch [ 19/ 20]  Train Loss:1.154494  Train Acc:59.72% Test Loss:1.274993  Test Acc:54.90%  Learning Rate:0.100000	Time 00:21Epoch [ 20/ 20]  Train Loss:1.163650  Train Acc:59.45% Test Loss:1.182077  Test Acc:59.00%  Learning Rate:0.100000	Time 00:20

接着可以分别打印,损失函数曲线,准确率曲线和学习率曲线

plot_history(epoch ,Acc, Loss, Lr)

损失函数曲线

准确率曲线

学习率曲线

7.测试

查看准确率

correct = 0   # 定义预测正确的图片数,初始化为0
total = 0     # 总共参与测试的图片数,也初始化为0
# testloader = torch.utils.data.DataLoader(testset, batch_size=32,shuffle=True, num_workers=2)
for data in testloader:  # 循环每一个batch
    images, labels = data
    images = images.to(device)
    labels = labels.to(device)
    net.eval()  # 把模型转为test模式
    if hasattr(torch.cuda, 'empty_cache'):
        torch.cuda.empty_cache()
    outputs = net(images)  # 输入网络进行测试
    
    # outputs.data是一个4x10张量,将每一行的最大的那一列的值和序号各自组成一个一维张量返回,第一个是值的张量,第二个是序号的张量。
    _, predicted = torch.max(outputs.data, 1)
    total += labels.size(0)          # 更新测试图片的数量
    correct += (predicted == labels).sum() # 更新正确分类的图

以上是关于Pytorch CIFAR10图像分类 LeNet5篇的主要内容,如果未能解决你的问题,请参考以下文章

LeNet模型对CIFAR-10数据集分类pytorch

Pytorch CIFAR10 图像分类篇 汇总

Keras CIFAR-10分类 LeNet-5篇

Pytorch CIFAR10 图像分类篇 汇总

我用 PyTorch 复现了 LeNet-5 神经网络(CIFAR10 数据集篇)!

我用 PyTorch 复现了 LeNet-5 神经网络(CIFAR10 数据集篇)!