import torch 
from torch import nn

x=torch.zeros([5,1,28,28]) #定义张量x,它的尺寸是5x1x28x28,表示了5个单通道28x28大小的数据
conv=nn.Conv2d(in_channels=1,out_channels=6,kernel_size=5) #定义一个输入通道是1,输出通道是6,卷积核大小是5x5的卷积层
c=conv(x) #将x,输入至conv,经过计算,得到5x6x24x24的输出张量,经过卷积层后得到6x24x24大小的特征图
print(c.shape)#程序输出:torch.Size([5,6,24,24])

pool=nn.MaxPool2d(2)#定义最大池化层
s=pool(c) #继续输入至池化层,计算后会得到6x12x12大小的特征图,将卷积层计算得到的整整图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 nn

class 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)
        )
        #全连接层1
        self.fcl = nn.Sequential(
            nn.Linear(256,120),#线性层
            nn.ReLU()
        )
        #全连接层2
        self.fc2 = nn.Sequential(
            nn.Linear(120,84),
            nn.ReLU()
        )
        #全连接层3
        self.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展平为nx256
        x= 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之间的损失loss
        loss.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')

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐