CNN 的特点:
- 能够有效的将大数据量的图片降维成小数据量。
- 能够有效的保留图片特征,符合图片处理的原则。
CNN 解决了什么问题:
- 图像需要处理的数据量太大,导致成本很高,效率很低。
- 图像在数字化的过程中很难保留原有的特征,导致图像处理的准确率不高。
典型的 CNN 由 3 个部分构成:
- 卷积层
- 池化层
- 全连接层
卷积层负责提取图像中的局部特征;池化层用来大幅降低参数量级(降维);全连接层类似传统神经网络的部分,用来输出想要的结果。
卷积层
- 卷积层是卷积核在上一级输入层上通过逐一滑动窗口计算而得,卷积核中的每一个参数都相当于传统神经网络中的权值参数,与对应的局部像素相连接,将卷积核的各个参数与对应的局部像素值相乘之和,(通常还要再加上一个偏置参数),得到卷积层上的结果。
- 卷积层输出值越高,就说明匹配程度越高,越能表现该图片的特征。卷积层的作用其实就是通过不断的改变卷积核,来确定能初步表征图片特征的有用的卷积核是哪些,再得到与相应的卷积核相乘后的输出矩阵。我们其实就可以把卷积核就理解为特征提取器。
池化/采样层
- 通过卷积层获得了图像的特征之后,理论上我们可以直接使用这些特征训练分类器(如softmax),但是这样做将面临巨大的计算量的挑战,而且容易产生过拟合的现象。为了进一步降低网络训练参数及模型的过拟合程度,我们对卷积层进行池化/采样(Pooling)处理。池化/采样的方式通常有以下两种:
- Max-Pooling: 选择Pooling窗口中的最大值作为采样值;
- Mean-Pooling: 将Pooling窗口中的所有值相加取平均,以平均值作为采样值;
经典CNN网络模型- -LeNet-5 网络详解:
image.png- C1 层是一个卷积层
- 6个特征图,每个特征图中的神经元与输入 5 * 5 的领域相连(可重叠),特征图大小为 28 * 28.
- 每个卷积神经元的参数数目:5*5 = 25 (还有一个bias参数)。
- 网络连接数目: (5 * 5 + 1) * 6 * (28 * 28)
- 参数共享:每个特征图内共享参数,既总参数:(5 * 5+1)* 6
- S2 层是一个下采样层
- 6个特征图,每个特征图中的神经元与 C1 输入 2 * 2 的领域相连(不可重叠),特征图大小为 14 * 14.
- S2 层每个单元的4个输入采样(max_pool),乘以一个可训练的参数 w, 再加上一个可训练偏置 b ,结果通过激活函数 sigmoid 函数计算.
- 网络连接数目:(1 + 1) * 6 * (14 * 14)
- 参数共享:每个特征图内共享参数,既总参数:(1+1) * 6.
- C3 层是一个卷积层
- 16个卷积核,得到16张特征图,特征图大小为 10 * 10 .
- 每个特征图中的每个神经元与 S2 输入某几层的多个 5 * 5 领域相连.
- 例如:对于 C3 层第 0 张特征图,其中每一个节点与 S2 层的第 0、1、2 特征图连接,总共 (5 * 5) * 3.(这个是如何连接? 是否有理论可循?)
- S4 层是一个下采样层
- 由 16 个 5 * 5 大小的特征图构成,特征图中的每个单元与 C3 中相应特征图的 2 * 2 领域相连.
- 网络连接数目: (1 + 1 ) * 5 * 5 * 16
- 参数共享:每个特征图共享参数,既总参数:(1 + 1) * 16
- C5 层是一个卷积层
- 120 个神经元,可以看作 120 个特征图,每张特征图大小为 1 * 1.
- 每个单元与 S4 层的全部 16 个单元的 5 * 5 领域相连(S4 和 C5 之间全连接).
- 网络连接数目:(5 * 5 * 16 + 1) * 120
- F6 层
- 有 84 个单元(之所以选这个数字的原因是来自于输出层的设计),与 C5 层全连接。
- F6 层计算输入向量和权重向量之间的点积,再加上一个偏置。
- 网络连接数目:(120 + 1) * 84
- 输出层
- 输出层采用欧式径向基函数(Euclidean Radial Basic Function)单元
- 给定一个输入模式,损失函数应使得 F6 的配置与 RBF 参数向量(既模式的期望分类)足够接近.
- 每类一个单元,每个单元连接 84 个输入,每个输入 RBF 单元计算输入向量和参数向量之间的欧式距离.
- RBF 输出可以理解为 F6 层配置空间的高斯分布的 [-log-likelihood]
Pytorch CNN 网络结构代码
- 自定义网络必须继承 nn.Module, 并且在其构造函数需调用 nn.Module 的构造函数,既 super(Net, self).int
- 在构造函数中必须自己定义可学习的参数.
- forward 函数实现前向传播过程,其输入可以是一个或多个 tensor.
- 不需要写反向传播函数,nn.Module能够利用 autograd 自动实现反向传播.
class conv_net(t.nn.Module):
"""
卷积神经网络
"""
def __init__(self):
super(conv_net, self).__init__()
# torch.nn.Sequential是一个Sequential容器,模块将按照构造函数中传递的顺序添加到模块中.
self.conv1 = t.nn.Sequential(
"""
卷积层
Conv2d(in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True)
in_channels: 输入通道数目/输入卷积层的图片厚度
out_channels: 输出通道数目/输出卷积层的图片厚度
kernel_size: 卷积核大小 n * n
stride: 步长
padding: 填充,原来的输入层基础上,上下左右各加 n 行
dilation: 内核元素之间的间距
groups: 卷积核个数
bias: 偏置项
"""
t.nn.Conv2d(1, 10, 5),
"""
池化层
池化操作计算输出特征图大小默认是向下取整的,与我们平常理解向上取 整不一样,如果稍有不注意会使得池化过程中出现边缘信息丢失的情况.
因此使用时需要注意ceil_mode参数设置。
"""
t.nn.MaxPool2d(2),
# 激活函数
t.nn.ReLU(),
# 标准化 BatchNorm2d(num_features, eps=1e-05, momentum=0.1, affine=True)
t.nn.BatchNorm2d(10)
)
self.conv2 = t.nn.Sequential(
t.nn.Conv2d(10, 20, 5),
t.nn.MaxPool2d(2),
t.nn.ReLU(),
t.nn.BatchNorm2d(20)
)
self.fc1 = t.nn.Sequential(
"""
原始输入:1 * 28 * 28
conv1 卷积之后:10 * 24 * 24 (24 = 28 - 5 + 1)
conv1 池化之后:10 * 12 * 12 (12 = 24 / 2)
conv2 卷积之后:20 * 8 * 8 (8 = 12 - 5 +1)
conv2 池化之后:20 * 4 * 4 (4 = 8 / 2 )
20 * 4 * 4 = 320
60 为自定义参数
"""
t.nn.Linear(320, 60),
"""
Dropout 常常用来降低过拟合
0.5 指的是随机有 50% 的神经元会被关闭/丢弃.
"""
t.nn.Dropout(0.5),
t.nn.ReLU()
)
self.fc2 = t.nn.Sequential(
t.nn.Linear(60, 20),
t.nn.Dropout(0.5),
t.nn.ReLU()
)
self.fc3 = t.nn.Linear(20, 10)
def forward(self, x):
x = self.conv1(x)
x = self.conv2(x)
x = x.view(-1, 320)
x = self.fc1(x)
x = self.fc2(x)
x = self.fc3(x)
return x
网友评论