? ? ? ? ? ?
搭建网络思路:
mnist数据集下载与处理 搭建神经网络
损失函数与优化函数的选择
定义可视化函数(不是本文的重点) 模型训练以及结果图像绘制
模型测试结果可视化与结果分析 代码实现
1.导入需要用到的安装包与模块:
这里我么直接使用Pytorch自带的mnist数据集,所以要用到torchvision安装包。
from torch.utils import data
from torchvision import datasets, transforms
from torch.nn import Sequential, Conv2d, ReLU, MaxPool2d, Linear, CrossEntropyLoss
from torch.optim import Adam
from torch.autograd import Variable from matplotlib import cm, pyplot as plt
from sklearn.manifold import TSNE # 将最后一层的输出降维处理,方便结果的可视化
import torch.nn as nn import torch import os
2.mnist数据集下载与处理:
直接下载下来的mnist数据集并不符合输入给网络的格式,所以我们需要对数据集做一些处理,以满足模型训练的要求。由于小编电脑配置较低,测试数据量为1800张图片。 LR = 0.01
BATCH_SIZE = 32
DOWNLOAD_MINIST = False EPOCHS = 1 HAS_SK = True
# 创建数据集目录
if not os.listdir(\ DOWNLOAD_MINIST = True # 训练数据集处理
train_data = datasets.MNIST(
root=\数据集需要保存的路径 train=True, # true: 训练数据 False: 测试数据
transform=transforms.ToTensor(), # 将PIL.Image或numpy.ndarray数据转换为形状为torch.FloatTensor(C x H x W),同时归一化
download=DOWNLOAD_MINIST # 下载数据集,如果有,就直接加载,如果如果没有,就去下载 )
# 将输入图片的shape转化为(50, 1, 28, 28) data_loader = data.DataLoader(
dataset=train_data,
batch_size=BATCH_SIZE, shuffle=True, )
test_data = datasets.MNIST(
root=\ train=False, )
test_x = torch.unsqueeze(test_data.test_data[:1800], dim=1).type(torch.FloatTensor) / 255. # 将测试数据的输入shape由原来的(10000, 28, 28)转化为(10000, 1, 28, 28)并且将输出数据归一化
test_y = test_data.test_labels[:1800] # 提取测试数据的标签值 3.搭建神经网络:
将模型数据预处理完之后,接下来才是我们这篇文章的重点,搭建一个卷积神经网络。
输入层数据格式:[32,,1, 28, 28] 第一卷积层:
卷积层:shape [32, 1, 28, 28] ---->>>>[32, 16, 28, 28]
这里的卷积层只是将原来的通道数由1变为16,图片大小没有变化
激活层:这里我们选择Relu作为激活函数对卷积层输出的数据进行去线性。
池化层:shape [32, 16, 28, 28] ----->>>>[32, 16, 14, 14] 池化层不改变通道数,只改变图片的大小 第二卷积层:
卷积层:shape [32, 16,14, 14] ---->>>>[32,32,14,14] 这里的卷
积层只是将上一层池化层输出的通道数由16变为32,图片大小没有变化
激活层:选择Relu作为激活函数对卷积层输出的数据进行去线性。
池化层:shape [32, 32, 14,14] ----->>>>[32, 32, 7, 7]池化层不改 变图片通道数,只改变图片的大小 全连接层:
数据降维处理:[32,32,7,7]---->>>>[32, 32*7*7] 首先将第二卷
积层池化层的输出降维处理为全连接层可以接收的数据格式
全连接层:shape [32, 32*7*7] ---->>>> [32, 10]
将降维处理完的数据格式作为全连接层的输入,使用一个[32*7*7, 10]的权重,将结果输出;
具体的网络结果如下图所示: class CNN(nn.Module): def __init__(self):
super(CNN, self).__init__()
self.conv_1 = Sequential( # 第一卷积层 Conv2d(
in_channels=1, out_channels=16, kernel_size=5, stride=1, padding=2 ),
ReLU(),
MaxPool2d(kernel_size=2) # 最大池化层 )
self.conv_2 = Sequential( # 第二卷积层 Conv2d(
in_channels=16, out_channels=32, kernel_size=5, stride=1, padding=2 ),
ReLU(),
MaxPool2d(kernel_size=2) # 最大池化层 )
self.out = Linear(32 * 7 * 7, 10) # 全连接层
def forward(self, x):
conv_1 = self.conv_1(x)
conv_2 = self.conv_2(conv_1)
fcl_input = conv_2.view(conv_2.size(0), -1) fcl_output = self.out(fcl_input) return fcl_output, fcl_input
cnn = CNN()
4.损失函数与优化函数
搭建完神经网络之后,接下来就需要选择目标函数和优化函数了。
对于分类问题,一般使用交叉熵(Cross-Entropy)作为损失进行最小优。 而对于优化函数,这里选择Adam是在于经过偏置校正后,每一次迭代学习率都有个确定范围,使得参数比较平稳。
optimizer = Adam(cnn.parameters(), lr=LR) loss_func = CrossEntropyLoss()
5.定义可视化函数:
这里定义这个函数主要是为了将最终的分结果展示出来,方便理解。本文的 重点是神经网络,对于结果展示代码看不懂就直接忽视。
def plot_with_labels(lowDWeights, labels): \
主要是将测试结果进行可视化。
:param lowDWeights: 进行降维处理后的测试集标签值 :param labels: 原测试集的标签值 \ plt.cla()
X, Y = lowDWeights[:, 0], lowDWeights[:, 1] for x, y, s in zip(X, Y, labels): c = cm.rainbow(int(255 * s / 9))
plt.text(x, y, s, backgroundcolor=c, fontsize=9) plt.xlim(X.min(), X.max()) plt.ylim(Y.min(), Y.max()) plt.title('Visualize last layer')
plt.savefig(\ plt.pause(0.1)
5.模型训练以及结果图像绘制:
将之前处理好的mnist数据集输入到搭建好的神经网络里面进行模型训练以及绘制测试结果的可视化。
for epoch in range(EPOCHS):
for step, (b_x, b_y) in enumerate(data_loader): batch_x, batch_y = Variable(b_x), Variable(b_y) pred_y = cnn(batch_x)[0]
loss = loss_func(pred_y, batch_y) optimizer.zero_grad() loss.backward() optimizer.step()
if step % 50 == 0:
test_output, last_layer = cnn(Variable(test_x))
test_y_pred = torch.max(test_output, 1)[1].data.squeeze().numpy() accuracy = float((test_y_pred == test_y.numpy()).astype(int).sum()) / float(test_y.size(0))
print(\ \
if HAS_SK: # 数据降维并且可视化
tsne = TSNE(perplexity=30, n_components=2, init='pca', n_iter=5000) plot_only = 500
low_dim_embs = tsne.fit_transform(last_layer.data.numpy()[:plot_only, :]) # 将输出数据降维
labels = test_y.numpy()[:plot_only]
plot_with_labels(low_dim_embs, labels) # 调用此函数,将数据传入并且展示出来 plt.ioff()
# print 10 predictions from test data test_output, _ = cnn(test_x[:10])
pred_y = torch.max(test_output, 1)[1].data.squeeze().numpy() print(pred_y, \
print(test_y[:10].numpy(), \
6.模型测试结果可视化与结果分析:
为了更形象说明搭建的神经网络对mnist数据集分类结果准确性,这里将每次训练与测试结果的对应的准确度和损失值的变化、分类结果的图像两个方面来分析。
图一:损失与准确度
图二:测试结果的可视化图
图一我们可以看到,模型训练初期,训练数据的损失值和测试的准确度都不能满足我们的要求,但随着训练批次的增加,损失值逐渐降低,测试数据的准确性也不断增大,最后稳定在0.97左右。
图二是模型训练第1800次时测试结果可视化之后的效果。由图可以看到,神经网络已经相当准确的将mnist数据集的数字进行了0-9的分类,虽然还存在个别错误分类的数字,但是这个几个异常点可以全完忽视不计。
其实,分类结果的准确定还可以再提高。由于当前的训练,我只取了测试集1800的数据集,同时只做了一次EPOCH训练。所以,可以从数据集的数量、增加EPOCH训练次数和改变学习率等方面在进行优化,使得分类效果达到一个更高的状态。