python卷积神经网络多元分类_卷积神经网络分类MNIST

本文介绍了使用PyTorch构建并训练一个卷积神经网络,用于MNIST手写数字的分类任务。文章详细展示了网络结构、训练过程以及可视化技巧,包括损失函数、优化器的选择和训练过程中的精度监测。
摘要由CSDN通过智能技术生成

# 卷积神经网络分类MNIST

之前两期简单介绍了神经网络的基础知识(由于我懒,一张插图都没有上)。

这一期我们来介绍一个简单的实现。基于Pytorch,训练一个简单的卷积神经网络用于分类MNIST数据集。同样ipynb文件到我的群里下载。后边写得比较多了以后考虑整理一下放到Github上。

数据集的导入之前已经介绍过,所以就不重复了。

## 神经网络的搭建

Pytorch中的神经网络搭建都要构造成类。类中确定了神经网络的结构。训练的时候就要构造一个具体的实例。训练好实例后,还要用这个实例去预测。

```python

# 定义网络

import torch.nn as nn

import torch.nn.functional as F

# 卷积之后,全连接层输入向量的长度。

# 由卷积结果的通道数乘以卷积结果的长再乘以卷积结果的宽得到。

# 这里没有用sigmoid函数,而是使用了softmax层

FC_SIZE = 16*2*2

class ClassificationMNIST(nn.Module):

def __init__(self):

super(ClassificationMNIST,self).__init__()

self.conv=nn.Sequential(nn.Conv2d(in_channels=1, out_channels=4, kernel_size=3, stride=1,padding=2),nn.ReLU(), nn.MaxPool2d(kernel_size=2),

nn.Conv2d(4, 8, 3, 1),nn.ReLU(), nn.MaxPool2d(kernel_size=2),

nn.Conv2d(8, 16, 3, 1),nn.ReLU(), nn.MaxPool2d(kernel_size=2))

#self.fc = nn.Linear(FC_SIZE,10)

self.fc = nn.Sequential(nn.Linear(FC_SIZE, 10), nn.Softmax())

def forward(self, x):

x = self.conv(x)

x = x.view(-1,FC_SIZE)

#output = torch.sigmoid(x)

output = self.fc(x)

return output

```

基本的神经网络需要写两个方法。在`__init__`中列出所有要用到的卷积层。注意这里的卷积层,全连接层可以自己写。但是更推荐直接调用`torch.nn`中的。

>  这里的`nn.Conv2d`等函数,的返回值实际上也是一个可调用对象。而且你构造的神经网络类的实例本身也是可调用对象。

第二个必须写的方法是`forward`方法。这个方法表示当你的神经网络对象被调用的时候,要执行的方法。

## 神经网络的训练

在训练开始之前要设置几个参数。

```python

# 初始化网络,及相关函数

cnn=ClassificationMNIST().to(device)

EPOCH = 10

# 学习率是个超参数,这东西是实验出来的

LR = 0.001

# 定义损失函数和优化器

optimizer = torch.optim.Adam(cnn.parameters(), lr=LR)

loss_func = torch.nn.CrossEntropyLoss(size_average=False)

```

其中的`loss_func`是损失函数。`optimizer`是优化器。损失函数就如前边所说是,判定我们的网络和目标函数近似程度的。`optimizer`则确定梯度更新的策略。它们都有很多选择,这里我们就先直接用,以后再讨论有哪些选择,以及不同选择的优劣。

接下来的训练过程其实就是一个大循环。由于一般图像数据量巨大,我们不能一次用上所有的数据。我们就把整个图像数据集分为若干batch。通过内层循环遍历所有数据。循环体中则是每次正向求出网络的分类结果,然后求和正确结果之间的loss,然后逆向求导,更新参数。

> 可以看到我的代码中,出了正向计算和反向传播,还多了一些内容。这些是用于隔一段时间,计算一下在测试集上的预测正确率,然后输出的。防止我们在等神经网络出结果的过程中太过无聊。

```python

# 训练

for epoch in range(EPOCH):

for i,data in enumerate(train_loader):

# 获取数据并把训练用数据转移到GPU上

b_x,b_y = data

b_x = b_x.to(device)

b_y = b_y.to(device)

# 前馈和计算损失

output = cnn(b_x)

loss = loss_func(output, b_y)

# 反馈

optimizer.zero_grad()

loss.backward()

optimizer.step()

if i% 500 == 0:

for j,testdata in enumerate(test_loader):

tx,ty =testdata

tx = tx.to(device)

ty = ty.to(device)

test_output = cnn(tx)

pred_y = torch.max(test_output, 1)[1].data.squeeze()  # move the computation in GPU

accuracy = torch.sum(pred_y == ty).type(torch.FloatTensor) / ty.size(0)

print('Epoch: ', epoch, '| train loss: %.4f' % loss.data.cpu().numpy(), '| test accuracy: %.2f' % accuracy)

break

pass # 防止提示语法错误写了个pass。其实没有什么语法错误。可能是语法检查器的问题。

```

把所有的样本batch都用一次,称为一个epoch。实际当中,训练一个epoch就能达到最佳效果的情况基本不存在。所以一般我们都要训练很多个epoch。外层循环就是控制训练的epoch数的。

## 可视化

神经网络很多时候被看作一个黑箱。把卷积核以及神经网络运算中一些中间过程以图像形式显示出来可以让这个模型显得更加直观。

具体方法并不复杂,但是大多是和pytorch框架有有关的代码层面的内容。和算法原理的关系不大。我在ipynb文件中做了示范。这里就不重复了。放两张效果图。

![下载 (正文03.assets/下载 (1).png)](正文03.assets/卷积核1.png)

![卷积核2](正文03.assets/卷积核2.png)

![卷积核3](正文03.assets/卷积核3.png)

图:部分卷积核的可视化

![图像原图](正文03.assets/原图.png)

图:图像原图

![特征图1](正文03.assets/特征图1.png)

![特征图2](正文03.assets/特征图2.png)

图:部分卷积运算中间结果

利用tensorflow实现卷积神经网络来进行MNIST手写数字图像的分类。 #导入numpy模块 import numpy as np #导入tensorflow模块,程序使用tensorflow来实现卷积神经网络 import tensorflow as tf #下载mnist数据集,并从mnist_data目录中读取数据 from tensorflow.examples.tutorials.mnist import input_data mnist = input_data.read_data_sets('mnist_data',one_hot=True) #(1)这里的“mnist_data” 是和当前文件相同目录下的一个文件夹。自己先手工建立这个文件夹,然后从https://yann.lecun.com/exdb/mnist/ 下载所需的4个文件(即该网址中第三段“Four files are available on this site:”后面的四个文件),并放到目录MNIST_data下即可。 #(2)MNIST数据集是手写数字字符的数据集。每个样本都是一张28*28像素的灰度手写数字图片。 #(3)one_hot表示独热编码,其值被设为true。在分类问题的数据集标注时,如何不采用独热编码的方式, 类别通常就是一个符号而已,比如说是9。但如果采用独热编码的方式,则每个类表示为一个列表list,共计有10个数值,但只有一个为1,其余均为0。例如,“9”的独热编码可以为[00000 00001]. #定义输入数据x和输出y的形状。函数tf.placeholder的目的是定义输入,可以理解为采用占位符进行占位。 #None这个位置的参数在这里被用于表示样本的个数,而由于样本个数此时具体是多少还无法确定,所以这设为None。而每个输入样本的特征数目是确定的,即为28*28。 input_x = tf.placeholder(tf.float32,[None,28*28])/255 #因为每个像素的取值范围是 0~255 output_y = tf.placeholder(tf.int32,[None,10]) #10表示10个类别 #输入层的输入数据input_x被reshape成四维数据,其中第一维的数据代表了图片数量 input_x_images = tf.reshape(input_x,[-1,28,28,1]) test_x = mnist.test.images[:3000] #读取测试集图片的特征,读取3000个图片 test_y = mnist.test.labels[:3000] #读取测试集图片的标签。就是这3000个图片所对应的标签
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值