import torch
from torch import nn#定义张量x,它的尺寸是5x1x28x28
#表示了5个单通道28x28大小的数据
x=torch.zeros([5,1,28,28])#定义一个输入通道是1,输出通道是6,卷积核大小是5x5的卷积层
conv=nn.Conv2d(in_channels=1,out_channels=6,kernel_size=5)#将x,输入至conv,计算出结果
c=conv(x)
#经过conv计算,得到5x6x24x24大小的输出张量,经过卷积层的处理后得到6x24x24大小的特征图print(c.shape)#程序输出:torch.Size([5,6,24,24])#继续输入至池化层,计算后会得到6x12x12大小的特征图
pool=nn.MaxPool2d(2)#定义最大池化层
s=pool(c) 将卷积层计算得到的整整图c,输入至pool#接下来继续到第2个卷积层,计算出16个8x8的输出特征图
#再输入到第2个池化层,计算得到16个4x4大小的特征图
#池化层输出后,将特征图进行展平:16个4x4 -> 1x256的向量
#展平flatten:将每个图片中的每个像素放成一排,就是256维度的一维向量
#后面是全连接层 最后3个全连接层的大小为,256×120、120×84、84×10。
#经过这三个全连接层后:会计算出1×120、1×84、1×10的向量。1×10的向量,就对应了最终的10个分类结果。
LeNet5网络实现:
import torch
from torch.nn import Module
from torch import nnclass LeNet5(Module):def _init_(self):#说明了这个网络中有什么,定义网络结构super(LeNet5, self)._init_()#第1个卷积块self.convl = nn.Sequential(nn.Conv2d(1,6,5),nn.ReLU(),nn.MaxPool2d(2))#第2个卷积块self.conv2= nn.Sequential(nn.Conv2d(6, 16, 5),nn.ReLU(),nn.MaxPool2d(2))#全连接层1self.fcl = nn.Sequential(nn.Linear(256,120),#线性层nn.ReLU())#全连接层2self.fc2 = nn.Sequential(nn.Linear(120,84),nn.ReLU())#全连接层3self.fc3= nn.Linear(84,10) def forward(self,x):#输入张量x 进入到神经网络后,它尺寸会如何变化。#说明了,这个网络“如何算”!#最初输入的x是nx1x28x28大小的,其中n是数据数量x = self.convl(x)# [n, 6, 12,12]x = self.conv2(x)# [n, 16, 4, 4]#在x输入至全连接层前#需要使用view函数,将张量的维度从n×16x4x4展平为nx256x= x.view(-1,256)# [n,256]x = self.fcl(x)# [n,120]X = self.fc2(x)# [n,84]x = self.fc3(x)# [n,10]return x"""在函数中,输入张量x会按照顺序,进入conv1、conv2、fc1、fc2、fc3,进行计算。在旁边注释中,标记了张量x,经过每一层计算后,变化的尺寸。例如,最初输入的x是n×1×28×28大小的。这里n表示了数据的数量。因此,x经过conv1,就会计算得到n×6×12×12大小的张量。接着,x经过conv2,会计算出n×16×4×4的张量。备注:这里的conv1和conv2中,包含了池化层,所以特征图尺寸会减半。然后,在x输入至全连接层前,需要使用view函数:将张量的维度从n×16×4×4展平为n×256。接着再按照顺序,将x输入至全连接层fc1、fc2、fc3计算。最终函数返回一个n×10大小的结果。"""
训练:
for epoch in range(10):#外层循环,代表了整个训练数据集的遍历次数#内层循环使用train_loader,进行小批量的数据读取for batch_idx, (data, label) in enumerate(train_loader):#每次内层循环,都会进行一次梯度下降算法#梯度下降算法,包括了5个步骤:output=model(data)#1.计算神经网络的前向传播结果loss=criterion(output,label)#2.计算output和标签label之间的损失lossloss.backward() #3.使用backward计算梯度#每次内层循环,都会进行一次梯度下降算法。optimizer.step()#4.使用optimizer.step更新参数optimizer.zero_grad() # 5.将梯度清零#每迭代100个小批量,就打印一次模型的损失,观察训练的过程if batch_idx100 =0:print(f"Epoch (epoch + 1)/10 "f"| Batch (batch_idx)/(len(train_loader)}"f"i Loss: (loss.item():.4f)")
torch.save(model.state_dict(),'mnist_lenet5.pth')