1.什么是LeNet模型
LeNet分为卷积层块和全连接层块两个部分。下面我们分别介绍这两个模块。
卷积层块里的基本单位是卷积层后接最大池化层:卷积层用来识别图像里的空间模式,如线条和物体局部,之后的最大池化层则用来降低卷积层对位置的敏感性。卷积层块由两个这样的基本单位重复堆叠构成。在卷积层块中,每个卷积层都使用5×55×5的窗口,并在输出上使用sigmoid激活函数。第一个卷积层输出通道数为6,第二个卷积层输出通道数则增加到16。这是因为第二个卷积层比第一个卷积层的输入的高和宽要小,所以增加输出通道使两个卷积层的参数尺寸类似。卷积层块的两个最大池化层的窗口形状均为2×22×2,且步幅为2。由于池化窗口与步幅形状相同,池化窗口在输入上每次滑动所覆盖的区域互不重叠。
卷积层块的输出形状为(批量大小, 通道, 高, 宽)。当卷积层块的输出传入全连接层块时,全连接层块会将小批量中每个样本变平(flatten)。也就是说,全连接层的输入形状将变成二维,其中第一维是小批量中的样本,第二维是每个样本变平后的向量表示,且向量长度为通道、高和宽的乘积。全连接层块含3个全连接层。它们的输出个数分别是120、84和10,其中10为输出的类别个数。
2.导入数据包
import torch
import torchvision
import torchvision.transforms as transforms
import torch.nn as nn
import matplotlib.pyplot as plt
3.加载图片,并显示第一张图片的尺寸
train_data = torchvision.datasets.MNIST(root='E:\PycharmProjects\data',train=True, download=True, transform=transforms.ToTensor())
test_data = torchvision.datasets.MNIST(root='E:\PycharmProjects\data',train=False, download=True, transform=transforms.ToTensor())
train_data[0][0].shape
train_data分为2个部分,train_data[0][0]是第一张图像,train_data[0][1]是第一张图像的正确类别
4.显示前十张数字
def show_image(images):
_,figs = plt.subplots(1,10,figsize=(12,12))
for fig,img in zip(figs,images):
fig.imshow(img.view(28,28))
fig.axes.get_xaxis().set_visible(False)
fig.axes.get_yaxis().set_visible(False)
plt.show()
x=[]
for i in range(10):
x.append(train_data[i][0])
show_image(x)
5.构造LeNet网络
net = nn.Sequential(
nn.Conv2d(1,6,kernel_size=5,padding=2),
#因为传入的x.shape=256*28*28,所以在原来模型基础上,增加padding,使与后面LeNet网络对应
nn.Sigmoid(),#每个卷积层之后需要接一个激活函数
nn.MaxPool2d(kernel_size=2,stride=2),#最大池化,减少参数量
nn.Conv2d(6,16,kernel_size=5),
nn.Sigmoid(),
nn.MaxPool2d(kernel_size=2,stride=2),
nn.Flatten(),#将图片拉直为一维向量
nn.Linear(16*5*5,120),
nn.Sigmoid(),
nn.Linear(120,84),
nn.Sigmoid(),
nn.Linear(84,10),
)
net
6.精确函数
def evaluate_accuracy(data_iter,net):
acc_sum, n = 0.0, 0
for x,y in data_iter:
acc_sum += (net(x).argmax(dim=1)==y).float().sum().item()
n += len(y)
return acc_sum / n
7.训练数据
import torch.optim as optim
import time
batch_size= 256
train_iter = torch.utils.data.DataLoader(train_data,batch_size)
test_iter = torch.utils.data.DataLoader(test_data,batch_size)
lr=0.01
optimizer=optim.Adam(net.parameters(),lr)
loss=nn.CrossEntropyLoss()
for epoch in range(4):
train_l,test_l,start=0.0,0.0,time.time()
for x,y in train_iter:
y_hat=net(x)
l=loss(y_hat,y).sum()/len(y)
optimizer.zero_grad()
l.backward()
optimizer.step()
train_l = evaluate_accuracy(train_iter,net)
test_l = evaluate_accuracy(test_iter,net)
print('loss= %.4f, train_l= %.4f, test_l= %.4f, time= %.2f' % (l,train_l,test_l,time.time()-start))
总结 以上训练结果,可以先用一个批量测试一下
for x,y in train_iter:
print(net(x).argmax(dim=1)-y)
break
#不等于0 表示分类错误