1)卷积神经网络(CNN)简介
关于什么是卷积神经网络(CNN),请自行查阅资料进行学习。如果是初学者,这里推荐一下台湾的李宏毅的深度学习课程。链接就不给了,这些资料网站上随处可见。
值得一提的是,CNN虽然在图像处理的领域具有不可阻挡的势头,但是它绝对不仅仅只能用来图像处理领域,大家熟知的alphaGo下围棋也可以通过CNN的结构进行处理,因为下围棋与图像有着相似之处,所以说,CNN提供给我们的是一种处理问题的思想,有学者归纳出了可以用CNN解决的问题所具备的三个性质:
局部性
对于一张图片而言,需要检测图片中的特征来决定图片的类别,通常情况下这些特征都不是由整张图片决定的,而是由一些局部的区域决定的。例如在某张图片中的某个局部检测出了鸟喙,那么基本可以判定图片中有鸟这种动物。
相同性
对于不同的图片,它们具有同样的特征,这些特征会出现在图片的不同位置,也就是说可以用同样的检测模式去检测不同图片的相同特征,只不过这些特征处于图片中不同的位置,但是特征检测所做的操作几乎一样。例如在不同的图片中,虽然鸟喙处于不同的位置,但是我们可以用相同的模式去检测。
不变性
对于一张图片,如果我们进行下采样,那么图片的性质基本保持不变。
2)PyTorch中的卷积神经网络
简要介绍一下PyTorch中卷积神经网络中用到的一些方法。
卷积层:nn.Conv2d()
其参数如下:
参数· | 含义 |
in_channels | 输入信号的通道数. |
out_channels | 卷积后输出结果的通道数. |
kernel_size | 卷积核的形状. 例如kernel_size=(3, 2)表示3X2的卷积核,如果宽和高相同,可以只用一个数字表示 |
stride | 卷积每次移动的步长, 默认为1. |
padding | 处理边界时填充0的数量, 默认为0(不填充). |
dilation | 采样间隔数量, 默认为1, 无间隔采样. |
groups | 输入与输出通道的分组数量. 当不为1时, 默认为1(全连接). |
bias | 为 True 时, 添加偏置. |
当然,这么多参数有一些是不常用的,读者只需要在实践中慢慢体会一些常用的即可,其他参数需要将理论打扎实之后去官网查阅。
池化层:nn.MaxPool2d()
其参数如下:
参数 | 含义 |
kernel_size | 最大池化操作时的窗口大小 |
stride | 最大池化操作时窗口移动的步长, 默认值是 kernel_size |
padding | 输入的每条边隐式补0的数量 |
dilation | 用于控制窗口中元素的步长的参数 |
return_indices | 如果等于 True, 在返回 max pooling 结果的同时返回最大值的索引 这在之后的 Unpooling 时很有用 |
ceil_mode | 如果等于 True, 在计算输出大小时,将采用向上取整来代替默认的向下取整的方式 |
3)实现MNIST手写数字识别
一共定义了五层,其中两层卷积层,两层池化层,最后一层为FC层进行分类输出。其网络结构如下:
中间一行表示当前数据块的维度,第一个维度为深度,后面两个为宽度和高度。输入数据为灰度图,所以深度为1,图片像素为28*28的图片,后面经过卷积,池化,会发现深度不断加深,而宽度和高度会逐渐减少,因此,最后CNN处理过的图片只是一个局部的图片,换句话说,计算机在进行CNN对图片进行识别的时候,它通过观察图片局部的信息来进行分类的,这一点和我们通过人眼来观察图片进行分类是不一样的。
下面是CNN网络的代码实现:
# !/usr/bin/python
# coding: utf8
# @Time : 2018-08-05 19:22
# @Author : Liam
# @Email : luyu.real@qq.com
# @Software: PyCharm
# .::::.
# .::::::::.
# :::::::::::
# ..:::::::::::'
# '::::::::::::'
# .::::::::::
# '::::::::::::::..
# ..::::::::::::.
# ``::::::::::::::::
# ::::``:::::::::' .:::.
# ::::' ':::::' .::::::::.
# .::::' :::: .:::::::'::::.
# .:::' ::::: .:::::::::' ':::::.
# .::' :::::.:::::::::' ':::::.
# .::' ::::::::::::::' ``::::.
# ...::: ::::::::::::' ``::.
# ```` ':. ':::::::::' ::::..
# '.:::::' ':'````..
# 美女保佑 永无BUG
from torch import nn
class CNN(nn.Module):
def __init__(self):
super(CNN, self).__init__()
self.layer1 = nn.Sequential(
nn.Conv2d(1, 25, kernel_size=3),
nn.BatchNorm2d(25),
nn.ReLU(inplace=True)
)
self.layer2 = nn.Sequential(
nn.MaxPool2d(kernel_size=2, stride=2)
)
self.layer3 = nn.Sequential(
nn.Conv2d(25, 50, kernel_size=3),
nn.BatchNorm2d(50),
nn.ReLU(inplace=True)
)
self.layer4 = nn.Sequential(
nn.MaxPool2d(kernel_size=2, stride=2)
)
self.fc = nn.Sequential(
nn.Linear(50 * 5 * 5, 1024),
nn.ReLU(inplace=True),
nn.Linear(1024, 128),
nn.ReLU(inplace=True),
nn.Linear(128, 10)
)
def forward(self, x):
x = self.layer1(x)
x = self.layer2(x)
x = self.layer3(x)
x = self.layer4(x)
x = x.view(x.size(0), -1)
x = self.fc(x)
return x
然后利用上述模型进行处理,其处理的方法和上一篇博文中的方法是一样的,这里不再赘述。
可以看到处理结果比上一次好多了: