PyTorch学习笔记(二) CNN
这次来用PyTorch实现一下CNN卷积神经网络, 数据我们采用 MNIST 这个手写数字识别的数据库, 完成一个多分类任务(判断是哪个数字)
不清楚PyTorch基本用法请移步 https://anti-entrophic.github.io/posts/10010.html
概述
最简单的CNN的结构是 “->卷积层->激活函数->池化层->线性层”,这里先简单介绍一下,后面会配合代码详细描述。
卷积层目标就是训练若干个卷积核,期望这些卷积核能够学到图像的某些特征。图像的各个通道会通过各个卷积核,得到卷积操作后的结果,然后经过ReLU激活函数。
池化层就如下图,目的是为了给图像降维,减少参数,并且期望能够捕捉一些关键特征,忽略不重要的细节
最后压缩维度后经过一个线性层,得到最终结果的概率分布,然后利用交叉熵损失函数来进行优化。
更详细的:https://zhuanlan.zhihu.com/p/630695553
数据
我们可以很方便的通过 torchvision
这个包下载到 MNIST 这个数据库
1 | import torch |
这样下载下来一个是训练集,一个是验证集。并且下载下来就是 torch.utils.data.Dataset
类,可以很好地适配 PyTorch 中常用的 Dataloader
1 | train_loader = Data.DataLoader( |
Dataloader
可以很方便地完成将数据组成batch,随机取样等操作。
可以简单看一下 MNIST 这个数据集,每张图片的大小都是 28*28,训练样本有60000个,测试样本有10000个
1 | print(train_data.data.shape) |
网络结构
卷积层的输入是三维的,第一维是图像的通道数。
这个 nn.Conv2d
,in_channels
就是输入图像的通道数,灰度图像就是1,RGB图像就是3。output_channels
就是卷积核数,也是输出图像的通道数。
如果in_channels
是3的话,那对每个卷积核,都是对3个通道各自卷积,然后加起来,会得到16个卷积后的通道,最后合在一起。
kernel_size
就是卷积核的大小,stride
是卷积核移动的步长,padding
是周围补0,控制卷积后图像的大小。
ReLU()
就激活一下,不过我有点疑惑的是,卷积操作完之后,会不会某些点的intensity超过255?因为这在图像中应该是不可能的情况,但是好像直接就没有处理;小于0的话经过ReLU()可以调回来。
nn.MaxPool2d
就是一个池化层,如文章开头图片所示,取2x2格中的最大值。
最终第一层的维度变化为 (batch_size, 1, 28, 28) -> (batch_size, 16, 14, 14)
第二层的维度变化为 (batch_size, 16, 14, 14) -> (batch_size, 32, 7, 7)
线性层的维度变化为 -> (batch, 3277) -> (batch, 10)
1 | class CNN(nn.Module): |
网络训练
对于分类的概率分布,损失函数用交叉熵损失,原因我在其它文章中也提到过,详细链接:https://zhuanlan.zhihu.com/p/115277553
优化器没有用SGD而是Adam,不知道具体会有什么差异
只训练一个epoch
1 | model = CNN() |
结果
看一下结果:
1 | # 这步unsqueeze让test_data从(10000,28,28)->(10000,1,28,28),适配CNN的输入 |
总结
只是最简单的CNN吧,不过结果确实挺好,网络就真的学到特征了。也没去试过换一下优化器啊激活函数会有什么效果,只是学一下基础知识顺便学习PyTorch用法吧