参考链接: 卷积神经网络在mnist数据集上的应用 Python
本文将为尽可能多的代码作注释,用PyTorch实现对手写数字数据集MNIST的分类,我也是一个PyTorch的初学者,如果你也是一个刚学pytorch没多久的朋友,希望我的注释能够让您尽可能看明白。因个人水平有限,如有什么写错的地方,敬请指正。
代码如下:
import torch
from torch import nn,optim
from torch.autograd import Variable
from torch.utils.data import DataLoader
from torchvision import datasets,transforms
############################# 先定义网络结构 ################################
class Net(nn.Module): #如果不太熟悉python中 类 的一些使用,欢迎看我的另一篇讲解Python中类的基本使用方法的文章
def __init__(self):
super(Net,self).__init__()
self.conv=nn.Sequential( #输入的数据集里的图像大小为28行*28列*1通道
nn.Conv2d(1,64,kernel_size=3,padding=1), #卷积后,大小变为28*28*64
nn.BatchNorm2d(64), #卷积完之后来一下batch normalization,加快收敛
nn.ReLU(), #加入ReLU作为激活函数
nn.Conv2d(64,128,kernel_size=3,padding=1), #卷积后张量大小变为28*28*128
nn.BatchNorm2d(128),
nn.ReLU(),
nn.MaxPool2d(stride=2,kernel_size=2)) #pooling后变为 14*14*128
self.dense=nn.Sequential(
nn.Linear(14*14*128,1024), #经过一层全连接层,原张量大小变为1024
nn.ReLU(),
nn.Dropout(p=0.5), #加入dropout,防止过拟合,增强泛化能力
nn.Linear(1024,10)) #在经过一层全连接层,原张量大小变为10
def forward(self,x):
x=self.conv(x)
x=x.view(-1,14*14*128) #在从卷积层进入全连接层时,一定要有这个操作,view()是按行优先再一行一行重排
x=self.dense(x)
return x
######################### 定义超参数 ##########################################
batch_size=200 #定义每次对多少个样本样本求梯度来负梯度下降损失函数
num_epochs=3 #我没有GPU,跑这个特别慢,我就跑3个epoch意思一下,大概需要两个小时左右,做好心理准备
######################## 数据读取 #######################################
#定义数据预处理方式
data_tf=transforms.Compose( #Compose()把各种预处理操作组合到一起
[transforms.ToTensor(), #ToTensor()把图片转换成张量形式Tensor,在转化的过程中自动把图片标准化了,也就是说Tensor的范围是0~1,
transforms.Normalize([0.5],[0.5])]) #传入的参数分别为均值,方差,其实现的操作是减去均值再除以方差,这样,图片中每个像素的值就转换到了-1~1之间
#读取数据,初次下载需要等待一小会
train_dataset = datasets.MNIST(root='./data',train=True,transform=data_tf,download=True) #训练集
test_dataset=datasets.MNIST(root='./data',train=False,transform=data_tf,download=True) #测试集
train_loader=DataLoader(train_dataset,batch_size=batch_size,shuffle=True) #数据迭代器
test_loader=DataLoader(test_dataset,batch_size=batch_size,shuffle=False)
################## 导入网络并设计损失函数和优化方法 ####################################################
model=Net()
if torch.cuda.is_available(): #判断是否有显卡
model=model.cuda()
criterion=nn.CrossEntropyLoss() #使用交叉熵函数作为损失函数
optimizer=optim.Adam(model.parameters()) #使用Adam优化方法,自动调整学习速率参数
###############################训练模型####################################################
correct=0
total=0
for epoch in range(num_epochs):
for i, data in enumerate(train_loader): #enumeirate()的用法就像是一一列举,他得到的是 数据对应的编号 i, 和 数据data
img,label=data
if torch.cuda.is_available():
img=Variable(img).cuda()
label=Variable(label).cuda()
else:
img=Variable(img)
label=Variable(label)
#forward
out=model(img) #得到输出
loss=criterion(out,label) #输出和真实的值之间求损失函数(偏差了多少)
#backward
optimizer.zero_grad()
loss.backward()
optimizer.step()
predicted=torch.argmax(out,1)
total =label.size(0) #一个数据他有一个大小,就是这个size,通过比较输出predicted和 标签label 的每一个对应位置相比较,看有多少个位置是对的,这样预测对了的位置和总的所有位置total相除,就得到了准确率
correct =(predicted==label).sum().item() #(p==l).sum().item()就是看predicted和label有多少个对应位置相等,并把相等的位置个数加到correct中,如果你还不理解,试试去运行下下面这段注释里的代码
#import torch
#import numpy as np
#data1 = np.array([
# [1,2,3],
# [2,20,4]])
#data1_torch = torch.from_numpy(data1)
#data2 = np.array([
# [2,29,3],
# [2,3,4]]) #试试不断改变data1 和data2 中的值,看他们对应有几个数字相等,再观察输出
#data2_torch = torch.from_numpy(data2)
#p = (data1_torch == data2_torch) #对比后相同的值会为1,不同则会为0
#print (p)
#d1 = p.sum() #将所有的值相加,得到的仍是tensor类别的int值
#print (d1)
#d2 = d1.item() #转成python数字
#print (d2)
if (i 1)0==0:
print('Epoch[{}/{}],batch:{},loss:{:.6f},train_acc:{:.6f}'.format(epoch 1,num_epochs,i 1,loss.item(),correct/total))
########################## 测试 ########################################################
correct=0
total=0
for i,data in enumerate(test_loader):
img,label=data
preds=model(img)
predicted=torch.argmax(preds,1)
total =label.size(0)
correct =(predicted==label).sum().item()
accuracy=correct/total
print('测试数据准确率:{}'.format(accuracy))
运行结果如下:
Epoch[1/3],batch:100,loss:0.100244,train_acc:0.866000 Epoch[1/3],batch:200,loss:0.075039,train_acc:0.914100 Epoch[1/3],batch:300,loss:0.077120,train_acc:0.932650 Epoch[2/3],batch:100,loss:0.085433,train_acc:0.943863 Epoch[2/3],batch:200,loss:0.052274,train_acc:0.950950 Epoch[2/3],batch:300,loss:0.054377,train_acc:0.955475 Epoch[3/3],batch:100,loss:0.063429,train_acc:0.959350 Epoch[3/3],batch:200,loss:0.063174,train_acc:0.962219 Epoch[3/3],batch:300,loss:0.127647,train_acc:0.964394 测试数据准确率:0.9796