前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >基于Pytorch构建LeNet网络对cifar-10进行分类

基于Pytorch构建LeNet网络对cifar-10进行分类

作者头像
python与大数据分析
发布2023-09-03 21:19:48
2480
发布2023-09-03 21:19:48
举报

LeNet5诞生于1994年,是最早的卷积神经网络之一,是Yann LeCun等人在多次研究后提出的最终卷积神经网络结构,是一种用于手写体字符识别非常高效的网络。一般LeNet即指代LeNet5。LeNet5 这个网络虽然很小,但是它包含了深度学习的基本模块:卷积层,池化层,全连接层,是其他深度学习模型的基础。

LeNet5由七层组成(不包括输入层),每一层都包含可训练权重。通过卷积、池化等操作进行特征提取,最后利用全连接实现分类识别。

LeNet5包含 3 个卷积层,2 个池化层,1 个全连接层。其中所有卷积层的所有卷积核都为 5x5,步长 strid=1,池化方法都为全局 pooling,激活函数为 Sigmoid。

下面是他的网络结构示意图:

CIFAR-10数据集由10个类别的60000张32x32彩色图像组成,每个类别有6000张图像。有50000个训练图像和10000个测试图像。

数据集分为五个训练批次和一个测试批次,每个批次有10000张图像。测试批次包含从每个类别中随机选择的1000幅图像。训练批包含随机顺序的剩余图像,但一些训练批可能包含一个类中的图像多于另一个类的图像。在它们之间,训练批次包含每个类别的正好5000个图像。

以下是数据集中的类,以及每个类的10张随机图像:

第一步,导入torch、numpy、matplotlib等包

  1. import time
  2. import torch
  3. import matplotlib.pyplot as plt
  4. import numpy as np
  5. import torch.nn.functional as F
  6. import torchvision
  7. from torch import nn, optim
  8. from torchvision.datasets import CIFAR10
  9. from torchvision.transforms importCompose, ToTensor, Normalize, Resize
  10. from torch.utils.data importDataLoader
  11. import torchvision.transforms as transforms
  12. from sklearn.metrics import accuracy_score

第二步,定义全局参数

  1. # 定义全局参数
  2. model_name='LeNet'# 定义模型名称
  3. BATCH_SIZE = 64# 批次大小
  4. EPOCHS = 20# 迭代轮数
  5. Loss= [] # 计算损失率
  6. Accuracy= [] # 计算准确率
  7. # 设备
  8. DEVICE = 'cuda'if torch.cuda.is_available() else'cpu'

第三步,数据转换设置,并进行数据加载

  1. # 数据转换
  2. transformers = Compose(transforms=[ToTensor(), Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])
  3. # 数据装载
  4. # MNIST 包含 0~9的手写数字, 共有 60000个训练集和 10000个测试集. 数据的格式为单通道 28*28的灰度图.
  5. dataset_train = CIFAR10(root='./data', train=True, download=True, transform=transformers)
  6. dataset_test = CIFAR10(root='./data', train=False, download=True, transform=transformers)
  7. dataloader_train = DataLoader(dataset=dataset_train, batch_size=BATCH_SIZE, shuffle=True)
  8. dataloader_test = DataLoader(dataset=dataset_test, batch_size=BATCH_SIZE, shuffle=True)
  9. classes = ('plane', 'car', 'bird', 'cat','deer', 'dog', 'frog', 'horse', 'ship', 'truck')

第四步,图片显示设置

  1. # 显示图片
  2. def imshow(img):
  3. img = img / 2+ 0.5# unnormalize
  4. npimg = img.numpy()
  5. # np.transpose 交换坐标轴,即将图片色素进行坐标翻转
  6. plt.imshow(np.transpose(npimg, (1, 2, 0)))

第五步,定义LeNet网络

  1. # 定义LeNet网络
  2. classLeNet(nn.Module):
  3. def __init__(self):
  4. super(LeNet, self).__init__()
  5. self.conv1 = nn.Conv2d(3, 6, 5) # 3表示输入是3通道
  6. # in_channels = 3输入图片通道数
  7. # out_channels = 6人为设定
  8. # kernel_size 卷积核的尺寸
  9. # stride=1卷积步长,就是卷积操作时每次移动的格子数
  10. # padding=0原图周围需要填充的格子行(列)数
  11. # output_padding=0输出特征图边缘需要填充的行(列)数,一般不设置
  12. # groups=1分组卷积的组数,一般默认设置为1,不用管
  13. # bias=True卷积偏置,一般设置为False,True的话可以增加模型的泛化能力
  14. # output_size=(input_size - kernel_size + 2*padding) / stride + 1= (32- 5+ 2*0)/1+ 1= 28
  15. # 输出为:6* 28* 28= 4704
  16. self.relu = nn.ReLU()
  17. self.maxpool1 = nn.MaxPool2d(2, 2)
  18. # output_size = 28/ 2= 14
  19. self.conv2 = nn.Conv2d(6, 16, 5)
  20. # output_size=(input_size - kernel_size + 2*padding) / stride + 1= (14- 5+ 2*0)/1+ 1= 10
  21. # 输出为:16* 10* 10= 4704
  22. self.maxpool2 = nn.MaxPool2d(2, 2)
  23. # output_size = 10/ 2= 5
  24. # 定义全连接层
  25. self.fc1 = nn.Linear(16*5*5, 120)
  26. # 定义全连接层
  27. self.fc2 = nn.Linear(120, 84)
  28. # 定义全连接层
  29. self.fc3 = nn.Linear(84, 10)
  30. def forward(self, x):
  31. x = self.conv1(x) # 卷积
  32. x = self.relu(x) # 激活函数
  33. x = self.maxpool1(x) # 池化
  34. x = self.conv2(x) # 卷积
  35. x = self.maxpool2(x) # 池化
  36. x = x.view(-1, 16*5*5) # 调整尺寸
  37. x = F.relu(self.fc1(x)) # 全连接 + 激活函数
  38. x = F.relu(self.fc2(x)) # 全连接 + 激活函数
  39. x = self.fc3(x) # 全连接
  40. output = F.log_softmax(x, dim=1) # 激活函数
  41. return output

第六步,定义损失函数和优化器

  1. # 定义模型输出模式,GPU和CPU均可
  2. model = LeNet().to(DEVICE)
  3. # 定义损失函数
  4. criterion = nn.CrossEntropyLoss()
  5. # 定义优化器
  6. # 使用 SGD(随机梯度下降)优化,学习率为 0.001,动量为 0.9
  7. optimizer = optim.SGD(model.parameters(), lr=0.001, momentum=0.9)

第七步,定义模型训练过程函数和模型验证过程函数

  1. # 定义模型输出模式,GPU和CPU均可
  2. # 定义模型训练过程
  3. def train_runner(model, device, trainloader, optimizer, epoch):
  4. #训练模型, 启用 BatchNormalization和 Dropout, 将BatchNormalization和Dropout置为True
  5. model.train()
  6. total = 0
  7. correct =0.0
  8. # enumerate迭代已加载的数据集,同时获取数据和数据下标
  9. for i, data in enumerate(trainloader, 0):
  10. inputs, labels = data
  11. # 把模型部署到device上
  12. inputs, labels = inputs.to(device), labels.to(device)
  13. # 初始化梯度
  14. optimizer.zero_grad()
  15. # 保存训练结果
  16. outputs = model(inputs).to(device)
  17. # 计算损失和
  18. # 多分类情况通常使用cross_entropy(交叉熵损失函数), 而对于二分类问题, 通常使用sigmod
  19. loss = F.cross_entropy(outputs, labels)
  20. # 获取最大概率的预测结果
  21. # dim=1表示返回每一行的最大值对应的列下标
  22. predict = outputs.argmax(dim=1)
  23. total += labels.size(0)
  24. correct += (predict == labels).sum().item()
  25. # 反向传播
  26. loss.backward()
  27. # 更新参数
  28. optimizer.step()
  29. if i % 1000== 0:
  30. # loss.item()表示当前loss的数值
  31. print("Train Epoch{} \t Loss: {:.6f}, accuracy: {:.6f}%".format(epoch, loss.item(), 100*(correct/total)))
  32. Loss.append(loss.item())
  33. Accuracy.append(correct/total)
  34. return loss.item(), correct/total
  35. # 定义模型验证过程
  36. def test_runner(model, device, testloader):
  37. # 模型验证, 必须要写, 否则只要有输入数据, 即使不训练, 它也会改变权值
  38. # 因为调用eval()将不启用 BatchNormalization和 Dropout, BatchNormalization和Dropout置为False
  39. model.eval()
  40. # 统计模型正确率, 设置初始值
  41. correct = 0.0
  42. test_loss = 0.0
  43. total = 0
  44. # torch.no_grad将不会计算梯度, 也不会进行反向传播
  45. with torch.no_grad():
  46. for data, label in testloader:
  47. data, label = data.to(device), label.to(device)
  48. output = model(data).to(device)
  49. test_loss += F.cross_entropy(output, label).item()
  50. predict = output.argmax(dim=1)
  51. # 计算正确数量
  52. total += label.size(0)
  53. correct += (predict == label).sum().item()
  54. # 计算损失值
  55. print("test_avarage_loss: {:.6f}, accuracy: {:.6f}%".format(test_loss/total, 100*(correct/total)))

以下为训练了20轮次的效果,可以看出准确率只有59%左右,还有很大的提升空间!

  1. start_time 2023-08-15 01:09:02
  2. Train Epoch1 Loss: 2.308738, accuracy: 4.687500%
  3. test_avarage_loss: 0.035032, accuracy: 19.680000%
  4. end_time: 2023-08-15 01:09:18
  5. ...
  6. start_time 2023-08-15 01:18:02
  7. Train Epoch20 Loss: 1.165504, accuracy: 59.375000%
  8. test_avarage_loss: 0.017934, accuracy: 59.450000%
  9. end_time: 2023-08-15 01:18:36

第八步,进行20轮次的训练和验证

  1. # 根据EPOCHS开展训练
  2. for epoch in range(1, EPOCHS+1):
  3. print("start_time",time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time())))
  4. loss, acc = train_runner(model, DEVICE, dataloader_train, optimizer, epoch)
  5. Loss.append(loss)
  6. Accuracy.append(acc)
  7. test_runner(model, DEVICE, dataloader_test)
  8. print("end_time: ",time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time())),'\n')
  9. # LeNet网络结构
  10. # LeNet(
  11. # (conv1): Conv2d(3, 6, kernel_size=(5, 5), stride=(1, 1))
  12. # (relu): ReLU()
  13. # (maxpool1): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  14. # (conv2): Conv2d(6, 16, kernel_size=(5, 5), stride=(1, 1))
  15. # (maxpool2): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  16. # (fc1): Linear(in_features=400, out_features=120, bias=True)
  17. # (fc2): Linear(in_features=120, out_features=84, bias=True)
  18. # (fc3): Linear(in_features=84, out_features=10, bias=True)
  19. # )
  20. torch.save(model, f'./model/cifar10_{model_name}.pkl') #保存模型
  21. print('Finished Training')

第九步,显示训练过程中的损失函数和准确率

  1. fig = plt.figure()
  2. plt.subplot(2,1,1)
  3. plt.plot(Loss)
  4. plt.title('Loss')
  5. plt.subplot(2,1,2)
  6. plt.plot(Accuracy)
  7. plt.title('Accuracy')
  8. plt.show()

通过matplotlib显示训练过程中的损失函数和准确率的曲线

第十步,对具体数据开展验证工作

  1. dataiter = iter(dataloader_test)
  2. images, labels = dataiter.__next__()
  3. # 显示图片
  4. imshow(torchvision.utils.make_grid(images))
  5. print('GroundTruth: ', ' '.join('%5s'% classes[labels[j]]
  6. for j in range(BATCH_SIZE)))
  7. plt.show()
  8. outputs = model(images.to(DEVICE).to(DEVICE))
  9. # 输出是10个标签的能量。一个类别的能量越大,神经网络越认为它是这个类别。所以让我们得到最高能量的标签
  10. _, predicted = torch.max(outputs, 1)
  11. print('Predicted: ', ' '.join('%5s'% classes[predicted[j]]
  12. for j in range(BATCH_SIZE)))

以下为前64张图片的预测和实际值

  1. GroundTruth: cat cat horse bird truck deer ship car horse car truck deer dog car ship truck horse cat car deer plane horse cat horse ship horse deer truck horse frog cat ship cat horse ship horse truck truck truck car car bird ship ship plane horse ship bird frog cat horse horse ship frog truck dog ship plane bird bird cat deer frog car
  2. Predicted: cat dog truck bird truck deer ship car horse car truck deer cat car ship plane horse dog car deer plane horse frog dog ship plane deer bird cat frog truck ship bird cat ship horse truck truck truck horse car bird ship ship plane horse ship bird cat cat cat deer ship frog frog frog plane plane bird horse plane bird frog car

以下为前64张图片的实际图片,可以看出来由于算法原因,以及本身图片的质量问题,导致预测结果不是十分理想!

不过这是基于深度学习开展图像识别的一个开始,后续将对一代一代的深度学习算法开展验证和测试,也帮助自己消化和理解深度学习。

本文参与?腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2023-08-15,如有侵权请联系?cloudcommunity@tencent.com 删除

本文分享自 python与大数据分析 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与?腾讯云自媒体分享计划? ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 第一步,导入torch、numpy、matplotlib等包
  • 第二步,定义全局参数
  • 第三步,数据转换设置,并进行数据加载
  • 第四步,图片显示设置
  • 第五步,定义LeNet网络
  • 第六步,定义损失函数和优化器
  • 第七步,定义模型训练过程函数和模型验证过程函数
  • 以下为训练了20轮次的效果,可以看出准确率只有59%左右,还有很大的提升空间!
  • 第八步,进行20轮次的训练和验证
  • 第九步,显示训练过程中的损失函数和准确率
  • 通过matplotlib显示训练过程中的损失函数和准确率的曲线
  • 第十步,对具体数据开展验证工作
  • 以下为前64张图片的预测和实际值
  • 以下为前64张图片的实际图片,可以看出来由于算法原因,以及本身图片的质量问题,导致预测结果不是十分理想!
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
http://www.vxiaotou.com