Pytorch 第六回:AlexNet卷积神经网络模型
Pytorch 第六回:AlexNet卷积神经网络模型
本次开启深度学习第六回,基于Pytorch的AlexNet卷积神经网络模型。在上回当中,我们采用深层神经网络,进行10分类;这次我们再拓展一下,采用卷积神经网络进行分类训练,分类的训练集采用CIFAR10。由于训练模型较为复杂,训练数据量较大,这里引入GPU进行数据训练。
本次学习,借助的平台是PyCharm 2024.1.3,python版本3.11 numpy版本是1.26.4,pytorch版本2.0.0+cu118
文章目录
- Pytorch 第六回:AlexNet卷积神经网络模型
- 前言
- 1、 卷积层
- 2、池化层
- 3、全连接层
- 4、AlexNet卷积神经网络
- 5、CIFAR10数据集
- 一、数据准备
- 1、CIFAR10数据集
- 2、数据加载器
- 二、模型准备
- 1、AlexNet模型准备
- 2、损失函数和优化器定义
- 3、引入GPU进行训练
- 二、模型训练
- 1、迭代训练
- 2、训练参数保存
- 3、输出展示
- 小结
前言
正文开启前,先简述几个概念:
1、 卷积层
卷积层(Convolutional Layer)是卷积神经网络(Convolutional Neural Networks, CNN)的核心部分。卷积层通过卷积计算来获得数据的特征。单层卷积可用来获得图片的边缘、线条等简单特征,但多层卷积迭代,可以获得图片的复杂特征。
卷积层是通过卷积核(filter或kernel)在数据图上以固定步幅(stride)滑动,并将相应数据与卷积核的计算结果填写在新的数据图(feature map)上。
该方式可以减少参数计算量,从而避免过拟合问题。
2、池化层
在神经网络中,池化层(Pooling Layer)采用滑动的方式来完成数据的下采样。常见的池化操作有两种:最大池化(Max Pooling)和平均池化(Average Pooling)。其中,最大池化选择每个窗口内的最大值作为输出值(保留最大特征);平均池化的输出值为窗口内的平均值(平滑数据)。
3、全连接层
全连接层会将前一层的所有神经元与本层神经元进行有权重的关联,从而实现数据特征的整合和分类。
4、AlexNet卷积神经网络
AlexNet卷积神经网络是经典的卷积神经网络。在2012年的 ImageNet 大规模视觉识别竞赛当中,AlexNet卷积神经网络大放异彩,一举夺得当年分类比赛的冠军。对此感兴趣的读者可以查查资料。
注:由于数据库和硬件原因,这里我没有一比一进行复现,只是取了其大致进行演示。
5、CIFAR10数据集
CIFAR-10 数据集由 60000 张 32x32 彩色图像组成,共有10个类别。其中,有 50000 张训练图像和 10000 张测试图像。类别中包括:鹿、狗、青蛙、飞机、汽车、鸟、猫、马、船和卡车。
接下来就是思路分享,先上引用代码:
import torch
from torch import nn
import numpy as np
import time
from torchvision.datasets import CIFAR10
一、数据准备
1、CIFAR10数据集
准备CIFAR10训练数据集 train_set ,并用data_treating函数进行数据变换。若数据不存在,则需要添加下载参数(上回中提到)。
def data_treating(x):
x = np.array(x, dtype='float32') / 255
x = (x - 0.5) / 0.5 #
x = x.transpose((2, 0, 1)) #
x = torch.from_numpy(x)
return x
train_set = CIFAR10('./data', train=True, transform=data_treating)
注:
为方便后续的数据训练,这里将图片格式从32323改变为33232。这样可以将数据理解为3个3232的数据,即3232的数据有三个通道。
2、数据加载器
使用DataLoader处理train_set数据:每个批次的样本设定为64,并做数据打乱处理。
train_data = torch.utils.data.DataLoader(train_set, batch_size=64, shuffle=True)
二、模型准备
1、AlexNet模型准备
在这里我是基于 nn.Sequential写了一个九层的神经网络:
其中前6层是特征提取:卷积层1->池化层1->卷积层2->池化层3->卷积层3->池化层3
(经过6层数据整合,数据从33232,转化为102411)
后三层是全连接层:用于特征的提取和分类
class AlexNet(nn.Module):
def __init__(self):
super().__init__()
# 第一层3*3的卷积,输入的 channels是3,输出的channels是64,步长是1,没有padding
self.conv1 = nn.Sequential(nn.Conv2d(3, 64,3,1),
nn.ReLU(True))
# 第二层4*4的池化,步长是2,没有填充
self.max_pool1 = nn.MaxPool2d(4, 2)
# 第三层3*3的卷积,输入的 channels是64,输出的channels是64,步长是1,没有填充
self.conv2 = nn.Sequential(nn.Conv2d(64,256,3,1),
nn.ReLU(True))
# 第四层是4*4的池化,步长是2,没有填充
self.max_pool2 = nn.MaxPool2d(4, 2)
# 第五层3*3的卷积,输入的 channels是64,输出的channels是64,步长是1,没有填充
self.conv3 = nn.Sequential(nn.Conv2d(256,1024,3,1),
nn.ReLU(True))
# 第六层是3*3的池化,步长是2,没有填充
self.max_pool3 = nn.MaxPool2d(3, 2)
# 第七层是全连接层,输入是1024,输出是256
self.fc1 = nn.Sequential(nn.Linear(1024,256),
nn.ReLU(True),
nn.Dropout())
# 第八层是全连接层,输入是256,输出是128
self.fc2 = nn.Sequential(nn.Linear(256,128),
nn.ReLU(True))
# 第九层是全连接层,输入是128,输出是10
self.fc3 = nn.Linear(128, 10)
def forward(self, x):
x = self.conv1(x)
x = self.max_pool1(x)
x = self.conv2(x)
x = self.max_pool2(x)
x = self.conv3(x)
x = self.max_pool3(x)
# 将数据转成一维
x = x.view(x.shape[0], -1)
x = self.fc1(x)
x = self.fc2(x)
x = self.fc3(x)
return x
注:
数据经过卷积和池化时,数据特征会整合(我理解为数据缩小,通道数增加),当数据处理量(特征图 Featuere Map)为通道数11时,是无法再继续数据卷积或池化的。由于篇幅考虑,这里不展示特征图的变换过程。
2、损失函数和优化器定义
定义了交叉熵损失函数;采用SGD优化器来进行梯度下降的计算,学习率设定为0.1。
Loss_f = nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(classify_AlexNet.parameters(), lr=1e-1)
3、引入GPU进行训练
引入GPU进行训练有三步:
第一步:模型需要转换成GPU类型(模型准备时)
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
classify_AlexNet = AlexNet().to(device)
第二步:训练数据需要转换成GPU类型(模型训练时)
x_data = x_data.to(device)
y_data = y_data.to(device)
第三步:损失数据需要转换成GPU类型(模型训练时)
loss_train = Loss_f(y_predict, y_data).to(device)
二、模型训练
1、迭代训练
这里先进行20次迭代训练:
time1 = time.time()
for k in range(20):
train_loss = 0
train_acc = 0
classify_AlexNet.train() # 将模型设为测试模式
for x_data, y_data in train_data:
x_data = x_data.to(device)
y_data = y_data.to(device)
# 前向传播
y_predict = classify_AlexNet(x_data)
loss_train = Loss_f(y_predict, y_data).to(device)
# 反向传播
optimizer.zero_grad() # 梯度清零
loss_train.backward() # 计算梯度
optimizer.step() # 使用优化器更新参数
# 记录误差
train_loss += loss_train
# 计算分类的准确率
_, pred = y_predict.max(1)
train_correct = (pred == y_data).sum().item() / x_data.shape[0]
train_acc += train_correct
time_consume = time.time() - time1
print('epoch:{},TrainLoss:{:.6f},TrainAcc:{:.6f},consume time:{:.3f}s'.format(k,
train_loss / len(train_data),
train_acc / len(train_data),
time_consume))
2、训练参数保存
由于训练时间较长,因此需要及时保存模型训练参数
torch.save(classify_AlexNet.state_dict(), 'classify_AlexNet_params.pth')
3、输出展示
epoch:0,TrainLoss:1.985443,TrainAcc:0.246284,consume time:44.312s
epoch:4,TrainLoss:0.895071,TrainAcc:0.688619,consume time:222.402s
epoch:8,TrainLoss:0.506490,TrainAcc:0.824009,consume time:398.314s
epoch:12,TrainLoss:0.269190,TrainAcc:0.908008,consume time:577.844s
epoch:16,TrainLoss:0.163928,TrainAcc:0.944953,consume time:757.611s
epoch:19,TrainLoss:0.104389,TrainAcc:0.964774,consume time:894.066s
从训练结果看,通过20次迭代训练,AlexNet网络模型对于训练数据可以得到一个比好的训练精度。
注:
对于模型的测试,可以参考第五回下半部分进行完成。由于代码改变量较小,这里就不再进行单独分享。
小结
1、数据准备:准备Pytorch自带的CIFAR10数据集;
2、模型准备:准备AlexNet网络模型,损失函数和优化器。需要注意引入GPU参入训练;
3、数据训练:20次迭代训练AlexNet网络模型。