经过几天的研究,参考了许多文章之后,终于用pytorch搭建了两个完整的神经网络,并且基本上每句代码都弄清楚了,一个是只有全连接层的网络,另一个则是加入卷积层和池化层的CNN,实现的步骤总结如下:
首先对上一篇博客中定义的类进行扩充:
class Net(nn.Module):
def __init__(self):
super().__init__()
self.layer=nn.Sequential(
nn.Linear(in_dim,hidden1_dim),
nn.ReLU(),
nn.Linear(hidden1_dim,hidden2_dim),
nn.ReLU(),
nn.Linear(hidden2_dim,out_dim))
def forward(self,x):
x=self.layer(x)
return x
在这里引入Sequential的用法,这可以理解为一个容器,可以把一系列神经网络的操作按顺序排列在其中,把输入数据传送到网络中时,网络就会按这个容器里设置的操作顺序进行计算,省去了一层一层计算的步骤。该网络的结构为:Affine-ReLU-Affine-ReLU-Affine,输出层用的是恒等函数。
接下来就是下载MNIST数据集、接着载入数据集进行训练了,完整的程序及注释如下:
import torch
import torch.nn as nn
import time#用于计时
from torch import optim #用于获取梯度下降的方法
from torch.autograd import variable#用于数据类型转换
from torch.utils.data.dataloader import DataLoader#用于载入数据
from torchvision import datasets,transforms#用于下载并转换数据集
#各层神经元数目
in_dim=784
hidden1_dim=200
hidden2_dim=100
out_dim=10
epoch=10#神经网络学完样本集中所有的样本为一个epoch,例如mnist有60000张训练样本,则训练到60000张时为一个epoch
batch_num=60#采用mini-batch的方式训练
lr_rate=0.01#学习率
sum_loss=0.0
class Net(nn.Module):#定义网络
def __init__(self):
super().__init__()
self.layer=nn.Sequential(
nn.Linear(in_dim,hidden1_dim),
nn.ReLU(),
nn.Linear(hidden1_dim,hidden2_dim),
nn.ReLU(),
nn.Linear(hidden2_dim,out_dim))
def forward(self,x):
x=self.layer(x)
return x
data_tf=transforms.ToTensor()#数据转换为tensor类型,也就是pytorch能处理的类型
train_set=datasets.MNIST(root='data',train=True,transform=data_tf,download=True)#下载mnist训练数据集并转换
test_set=datasets.MNIST(root='data',train=False,transform=data_tf,download=True)#载mnist测试数据集并转换
train_loader=DataLoader(train_set,batch_size=batch_num,shuffle=True)#载入mnist训练数据集
test_loader=DataLoader(test_set,batch_size=batch_num,shuffle=False)#载入mnist测试数据集
since = time.time()#开始计时
net=Net()
if torch.cuda.is_available():#用gpu计算,没有可用gpu可以把这段删掉
net = net.cuda()
criterion = nn.CrossEntropyLoss()#交叉熵损失函数
optimizer = optim.SGD(net.parameters(), lr=lr_rate)#SGD梯度下降法,也可以选择其他方法
for e in range(epoch):#设置循环开始训练
for data in train_loader:
img,label=data
img = img.view(img.size(0), -1)
'''这句话很关键,意思是将img矩阵重新排列成(img.size(0), -1)的形状,因为采用mini-batch
训练方式,上面参数中的batch-size意思就是将所有样本分成若干份,每份的数量为
batch—size张,每次训练时将这一份中的所有图片一起训练,所以img.size(0)就应该等于batch—size
-1表示自动获取,因为img.size(0)已经是一个确定的数了,所以第二个维数可以通过计算获取,
因此就不想要我们手动填了'''
if torch.cuda.is_available():#用gpu计算,没有可用gpu可以把这段删掉
img = img.cuda()
label = label.cuda()
img=variable(img)#还是转换数据类型
label=variable(label)
output=net(img)#将处理好的图像矩阵输入到神经网络
loss=criterion(output,label)#通过损失函数计算损失值
optimizer.zero_grad()#将梯度置零
loss.backward()#反向传播
optimizer.step()#可以理解为更新模型的参数
sum_loss+=loss.item()#计算每个batch损失的和
print('loss is :{:.16f}'.format(sum_loss/len(train_set)))#求损失的平均
sum_loss=0.0
sum_true=0
#if epoch % 10 == 0:
for data in test_loader:# 每个epoch完后都测试一下识别准确率
img,label=data
img = img.view(img.size(0), -1)
if torch.cuda.is_available():
img = img.cuda()
label = label.cuda()
out=net(img)
_,predict=torch.max(out,1)
num_true=(predict==label).sum()#求每个batch中识别正确的样本总数
sum_true+=num_true.item()#求全部识别正确的样本和
print('accuracy rate is :{:.4f}'.format(sum_true/len(test_set)))
time_elapsed = time.time() - since#计时结束并打印时间
print('Training complete in {:.0f}s'.format(time_elapsed) )
另外需注明的是数据下载有可能会不成功,多运行几次就可以了,下载时会在该python程序所在文件夹中生成一个名叫data的文件,mnist数据就在其中,下载完之后再运行程序就不会重复下载过程了。以下为epoch设置为10轮的运行结果:
下一期将用卷积神经网络进行手写数字识别,并和这个结果简单的对比