一、手写数字识别原理
模型的输入数据是包含手写数字信息的二维图像,将其输入到网络模型中,经过模型的前向计算得到输出的识别结果,通过损失函数度量计算输出结果与输入图像标签的差异度,并通过反向传播算法根据这个差异来调整网络各层的参数值,经过反复迭代输入,最终得到一个能准确识别输入图像的网络模型(输出的识别结果与标签一致)
二、网络结构
LetNet-5网络结构如下图,输入的二维图像经过两个卷积层、一个池化层,再经过三个全连接层将前层计算得到的特征空间映射样本标记空间,最后使用softmax分类作为输出层。
各层参数:
输入大小:28*28*1
卷积层①:5*5*6,padding=2
池化层:2*2最大池化
卷积层②:5*5*16,padding=0
全连接层①:输入400、输出120
全连接层②:输入120、输出84
全连接层③:输入84、输出10
输出层:softmax
三、代码实现
import torch
from torch.autograd import Variable
import torch.nn as nn
import torchvision
"""MNIST数据集"""
train_dataset = torchvision.datasets.MNIST("dataset", train=True,
transform=torchvision.transforms.ToTensor(), download=True)
test_dataset = train_dataset
# DataLoader
train_loader = torch.utils.data.DataLoader(dataset=train_dataset,
batch_size=128,
shuffle=True)
test_loader = torch.utils.data.DataLoader(dataset=test_dataset,
batch_size=100,
shuffle=False)
"""LetNet-5"""
class LeNet5(nn.Module):
def __init__(self):
super(LeNet5, self).__init__()
self.conv1 = nn.Conv2d(1, 6, kernel_size=5, padding=2) # padding = 2, 28+2+2=32
self.conv2 = nn.Conv2d(6, 16, kernel_size=5)
self.pool = nn.MaxPool2d(2)
self.relu = nn.ReLU()
self.fc1 = nn.Linear(400, 120) # 400=16*5*5
self.fc2 = nn.Linear(120, 84)
self.fc3 = nn.Linear(84, 10)
self.softmax = nn.Softmax()
def forward(self, x):
in_size = x.size(0)
out = self.relu(self.pool(self.conv1(x)))
out = self.relu(self.pool(self.conv2(out)))
out = out.view(in_size, -1)
out = self.relu(self.fc1(out))
out = self.relu(self.fc2(out))
out = self.fc3(out)
return self.softmax(out,)
model = LeNet5()
# 损失函数:交叉熵损失
loss_func = torch.nn.CrossEntropyLoss()
# 定义优化器
opt = torch.optim.Adam(model.parameters(), lr=0.001)
def train(epoch):
model.train()
for batch_index, (data, target) in enumerate(train_loader):
data, target = Variable(data), Variable(target)
opt.zero_grad() # backward前梯度清零
output = model(data)
loss = loss_func(output, target)
# 误差反向传播
loss.backward()
# 参数更新
opt.step()
if batch_index % 20 == 0:
print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(
epoch, batch_index * len(data), len(train_loader.dataset),
100. * batch_index / len(train_loader), loss.item()))
def test():
model.eval()
test_loss = 0
correct = 0
for data, target in test_loader:
data, target = Variable(data, volatile=True), Variable(target)
output = model(data)
# 叠加loss
test_loss += loss_func(output, target).item()
# 最大概率预测结果标签
pred = torch.max(output.data, 1)[1]
correct += pred.eq(target.data.view_as(pred)).cpu().sum()
test_loss /= len(test_loader.dataset)
print('Test set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)'.format(
test_loss, correct, len(test_loader.dataset),
100. * correct / len(test_loader.dataset)))
# 迭代10轮后测试
for epoch in range(1, 11):
train(epoch)
test()
四、实验结果
经过10轮训练,将训练后的网络模型用来测试原始数据集,60000张图像中识别正确的数量为59239,识别正确率为99%。