200字范文,内容丰富有趣,生活中的好帮手!
200字范文 > 基于PyTorch框架的多层全连接神经网络实现MNIST手写数字分类

基于PyTorch框架的多层全连接神经网络实现MNIST手写数字分类

时间:2019-11-28 22:21:43

相关推荐

基于PyTorch框架的多层全连接神经网络实现MNIST手写数字分类

多层全连接神经网络实现MNIST手写数字分类

1 简单的三层全连接神经网络2 添加激活函数3 添加批标准化4 训练网络5 结论参考资料

先用PyTorch实现最简单的三层全连接神经网络,然后添加激活层查看实验结果,最后再加上批标准化验证是否能够更加有效。

1 简单的三层全连接神经网络

对于这个三层网络,需要传递进去的参数包括:输入的维度,第一次网络的神经元个数,第二层网络神经元的个数,以及第三层网络(输出层)神经元个数。

import torchimport torch.nn as nnfrom torch.autograd.variable import Variableimport numpy as np# 定义三层全连接神经网络class SimpleNet(nn.Module):def __init__(self, in_dim, n_hidden_1, n_hidden_2, out_dim):super(SimpleNet, self).__init__()self.layer1 = nn.Linear(in_dim, n_hidden_1)self.layer2 = nn.Linear(n_hidden_1, n_hidden_2)self.layer3 = nn.Linear(n_hidden_2, out_dim)def forward(self, x):x = self.layer1(x)x = self.layer2(x)x = self.layer3(x)return x

2 添加激活函数

接着改进一下网络,添加激活函数增加网络的非线性

# 添加激活函数,增加网络的非线性class Activation_Net(nn.Module):def __init__(self, in_dim, n_hidden_1, n_hidden_2, out_dim):super(Activation_Net, self).__init__()self.layer1 = nn.Sequential(nn.Linear(in_dim, n_hidden_1), nn.ReLU(True))self.layer2 = nn.Sequential(nn.Linear(n_hidden_1, n_hidden_2))self.layer3 = nn.Sequential(nn.Linear(n_hidden_2, out_dim))def forward(self, x):x = self.layer1(x)x = self.layer2(x)x = self.layer3(x)return x

这里只需要在每层网络的输出部分添加激活函数就可以了,nn.Sequential()这个函数是将网络的层组合到一起,比如上面将nn.Linear()和nn.ReLU()组合到一起作为self.layer。最后一层输出层不能添加激活函数,因为输出的结果表示的是实际的得分。

3 添加批标准化

最后添加一个加快收敛速度的方法–批标准化。

class Batch_Net(nn.Module):def __init__(self, in_dim, n_hidden_1, n_hidden_2, out_dim):super(Batch_Net, self).__init__()self.layer1 = nn.Sequential(nn.Linear(in_dim, n_hidden_1),nn.BatchNorm1d(n_hidden_1),nn.ReLU(True))self.layer2 = nn.Sequential(nn.Linear(n_hidden_1, n_hidden_2),nn.BatchNorm1d(n_hidden_2),nn.ReLU(True))self.layer3 = nn.Sequential(nn.Linear(n_hidden_2, out_dim))def forward(self, x):x = self.layer1(x)x = self.layer2(x)x = self.layer3(x)return x

同样使用nn.Sequential()将nn.BatchNorm1d()组合到网络层中,注意批标准化一般放在全连接层的后面,非线性层(激活函数)的前面。

4 训练网络

网络的定义较简单,现在用MNIST数据集训练网络并测试一下每种网络的结果。MNIST数据集是一个手写字体数据集,包括0~9这10个数字,其中有55000张训练集,10000张测试集,5000张验证集,图片是28*28的灰度图。

导入需要用的包

import torchfrom torch import nn, optimfrom torch.autograd import Variablefrom torch.utils.data import DataLoaderfrom torchvision import datasets, transformsimport net

定义超参数

# 超参数 Hyper parametersbatch_size = 64learning_rate = 1e-2num_epochs = 20

数据预处理,需要将数据标准化,运用的函数是torchvision.transforms,它提供了很多图片预处理的方法。transforms.ToTensor()将图片转换成PyTorch中处理的对象Tensor,在转换的过程中,PyTorch自动将图片标准化,即Tensor的范围是0~1。transforms.Normalize()需要传入两个参数,第一个是均值,第二个是方差,做的处理就是减均值,再除以方差。

pose()将各种预处理操作组合到一起,transforms.Normalize([0.5], [0.5])表示减去0.5再除以0.5,这样图片转换到-1到1之间。因为图片是灰度图片,所以只有一个通道,如果是彩色图像,有三个通道,用transforms.Normalize([mean_r,mean_g,mean_b], [var_r,var_g,var_b])来表示每个通道对应的均值和方差。

# 数据预处理data_tf = pose([# 将图片转换成PyTorch中处理的对象Tensor,在转换的过程中自动将图片标准化,即Tensor的范围是0~1transforms.ToTensor(),# 第一个参数是均值,第二个参数是方差,做的处理就是减均值,再除以方差transforms.Normalize([0.5], [0.5])])

读取数据集。通过PyTorch的内置函数torchvision.datasets.MNIST导入数据集,传入数据预处理。使用torch.utils.data.DataLoader建立一个数据迭代器,传入数据集和batch_size,通过shuffle=True,来表示每次迭代数据的时候是否将数据打乱。

# 下载训练集MNIST手写数字训练集train_dataset = datasets.MNIST(root='./data',train=True,transform=data_tf,download=True)test_dataset = datasets.MNIST(root='./data',train=False,transform=data_tf)train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)test_loader = DataLoader(test_dataset, batch_size=batch_size, shuffle=False)

导入网络,定义损失函数和优化方法。通过net.SimpleNet定义简单三层网络,里面的参数是2828,300,100,10,其中输入的维度是2828,因为输入图片大小是28*28,然后定义两个隐藏层分别是300和100。最后输出的结果必须是10,因为这是一个分类问题,一共有0~9这10个数字,所以是10分类。损失函数定义为分类问题中最常见的损失函数交叉熵,使用随机梯度下降来优化损失函数。

# 导入网络model = net.SimpleNet(28 * 28, 300, 100, 10)if torch.cuda.is_available():model = model.cuda()# 定义损失函数和优化方法criterion = nn.CrossEntropyLoss()optimizer = optim.SGD(model.parameters(), lr=learning_rate)

开始训练网络img = Variable(img, volatile=True)里面的volatile=True表示前向传播时,不会保留缓存,因为对于测试集,不需要做反向传播,所以在前向传播时释放内存,节约内存空间。

# 开始训练网络model.eval()eval_loss = 0eval_acc = 0for data in test_loader:img, label = dataimg = img.view(img.size(0), -1)if torch.cuda.is_available():img = Variable(img, volatile=True).cuda()label = Variable(label, volatile=True).cuda()else:img = Variable(img, volatile=True)label = Variable(label, volatile=True)out = model(img)loss = criterion(out, label)eval_loss += loss.data[0] * label.size(0)_, pred = torch.max(out, 1)num_correct = (pred == label).sum()eval_acc += num_correct.data[0]print('Test Loss:{:.6f},ACC:{:.6f}'.format(eval_loss / (len(test_dataset)),eval_acc / (len(test_dataset))))

5 结论

依次测试简单三层网络、添加激活层的网络、添加批标准化的网络,网络的预测准确率越来越高,同时还可以通过Dropout、正则化,增加网络的泛化能力。

import torchimport torch.nnfrom torchvision import datasetsfrom torchvision import transformsfrom torch.utils.data import DataLoaderimport torch.nn.functional as Fdevice = torch.device('cuda:0'if torch.cuda.is_available()else 'cpu')batch_size = 32transform = pose([transforms.ToTensor()])train_set = datasets.MNIST(root='./dataset/mnist',train=True,transform=transform)train_loader = DataLoader(dataset=train_set,batch_size=batch_size,shuffle=True,num_workers=2)test_set = datasets.MNIST(root='./dataset/mnist',train=False,transform=transform)test_loader = DataLoader(dataset=test_set,batch_size=batch_size,shuffle=False,num_workers=2)class Net(torch.nn.Module):def __init__(self):super(Net, self).__init__()self.conv1 = torch.nn.Conv2d(in_channels=1, out_channels=10, kernel_size=5)self.conv2 = torch.nn.Conv2d(in_channels=10, out_channels=20, kernel_size=5)self.pooling = torch.nn.MaxPool2d(kernel_size=2)self.fc = torch.nn.Linear(320, 10)def forward(self, x):# Flatten data from (n,1,28,28) to (n,784)batch_size = x.size(0)x = F.relu(self.pooling(self.conv1(x)))x = F.relu(self.pooling(self.conv2(x)))x = x.view(batch_size, -1) # Flattenx = self.fc(x)return xmodel = Net().to(device)criterion = torch.nn.CrossEntropyLoss()optimizer = torch.optim.SGD(params=model.parameters(),lr=0.01, momentum=0.5)def train(epoch):running_loss = 0for batch_idx, data in enumerate(train_loader):images, labels = dataimages = images.to(device)labels = labels.to(device)optimizer.zero_grad()outputs = model(images)loss = criterion(outputs, labels)loss.backward()optimizer.step()running_loss += loss.item()if (batch_idx + 1) % 300 == 0:print('[%d,%d],loss is %.2f' %(epoch, batch_idx, running_loss / 300))running_loss = 0def test():correct = 0total = 0with torch.no_grad():for data in test_loader:images, labels = dataimages = images.to(device)labels = labels.to(device)outputs = model(images)_, predict = torch.max(outputs, dim=1)correct += (labels == predict).sum().item()total += labels.size(0)print('correct/total:%d/%d,Accuracy:%.2f%%' % (correct, total, 100 * (correct / total)))if __name__ == '__main__':for epoch in range(10):train(epoch)test()

参考资料

廖星宇《深度学习入门之PyTorch》电子工业出版社

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。