1、卷积神经网络简介
卷积神经网络(Convolutional Neural Network,CNN或ConvNet)是一种具有局部连接、权重共享等特性的深层前馈神经网络。卷积神经网络最早是主要用来处理图像信息。如果用全连接前馈网络来处理图像时,会存在以下两个问题:(1)参数太多(2)局部不变性特征
卷积神经网络是受生物学上感受野的机制而提出。感受野(Receptive Field)主要是指听觉、视觉等神经系统中一些神经元的特性,即神经元只接受其所支配的刺激区域内的信号。在视觉神经系统中,视觉皮层中的神经细胞的输出依赖于视网膜上的光感受器。视网膜上的光感受器受刺激兴奋时,将神经冲动信号传到视觉皮层,但不是所有视觉皮层中的神经元都会接受这些信号。一个神经元的感受野是指视网膜上的特定区域,只有这个区域内的刺激才能够激活该神经元。
目前的卷积神经网络一般是由卷积层、汇聚层和全连接层交叉堆叠而成的前馈神经网络,使用反向传播算法进行训练。卷积神经网络有三个结构上的特性:局部连接,权重共享以及汇聚。这些特性使得卷积神经网络具有一定程度上的平移、缩放和旋转不变性。和前馈神经网络相比,卷积神经网络的参数更少。
2、卷积名词杂烩
-
卷积(Convolution):是一种数学操作。
-
滤波器(filter):
-
简单移动平均:一般情况下滤波器的长度m远小于信号序列长度n。当滤波器wk = 1/m, 1 ≤ k ≤ m时,卷积相当于信号序列的简单移动平均(窗口大小为m)。
-
特征映射(Feature Map):在图像处理中,卷积经常作为特征提取的有效方法。一幅图像在经过卷积操作后得到结果
-
互相关(Cross-Correlation):互相关(Cross-Correlation)是一个衡翻转就是从两个维度(从上到下、从左到右)颠倒次序,即旋转180 度。量两个序列相关性的函数,通常是用滑动窗口的点积计算来实现。
-
滤波器的步长(Stride):指滤波器在滑动时的时间间隔。
-
零填充(Zero Padding):是在输入向量两端进行补零。
-
汇聚层(Pooling Layer):汇聚层(Pooling Layer)也叫子采样层(Subsampling Layer),其作用是进行特征选择,降低特征数量,并从而减少参数数量。
-
汇聚(Pooling):对每个区域进行下采样(Down Sampling)得到一个值,作为这个区域的概括。
-
净输入:没有经过非线性激活函数的净活性值(Net Activation)。
3、卷积操作辨别:
-
卷积与互相关的区别仅仅在于卷积核是否进行翻转,也可以理解为图像是否进行翻转
-
窄卷积与宽卷积、等宽卷积:
- 窄卷积:步长s = 1,两端不补零p = 0,卷积后输出长度为n − m + 1。
- 宽卷积:步长s = 1,两端补零p = m − 1,卷积后输出长度n + m − 1。
- 等宽卷积:步长s = 1,两端补零p = (m −1)/2,卷积后输出长度n。
-
常用的汇集函数:
-
最大汇聚(Maxlmun Pooling):一般是取一个区域内所有神经元的最
大值。
Y d m , n = max i ∈ R d m , n x i Y^d{_m,_n} = \max_{i\in R^d{_m,_n}}x_i Ydm,n=i∈Rdm,nmaxxi -
平均汇聚(Mean Pooling):一般是取区域内所有神经元的平均值
Y d m , n = 1 ∣ R d m , n ∣ ∑ i ∈ R d m , n x i Y^d{_m,_n} = \tfrac{1}{\vert {R^d{_m,_n}} \vert}\sum_{i\in R^d{_m,_n}}x_i Ydm,n=∣Rdm,n∣1i∈Rdm,n∑xi
-
-
上采样与下采样:
-
上采样:放大图像(或称为上采样(upsampling)或图像插值(interpolating))的主要目的是放大原图像,从而可以显示在更高分辨率的显示设备上。对图像的缩放操作并不能带来更多关于该图像的信息, 因此图像的质量将不可避免地受到影响。然而,确实有一些缩放方法能够增加图像的信息,从而使得缩放后的图像质量超过原图质量的。
上采样原理:图像放大几乎都是采用内插值方法,即在原有图像像素的基础上在像素点之间采用合适的插值算法插入新的元素。
-
下采样的原理:对于一幅图像I尺寸为MN,对其进行s倍下采样,即得到(M/s)(N/s)尺寸的得分辨率图像,当然s应该是M和N的公约数才行,如果考虑的是矩阵形式的图像,就是把原始图像s*s窗口内的图像变成一个像素,这个像素点的值就是窗口内所有像素的均值
-
常见的卷积神经网络
-
LeNet-5
1. 输入层:输入图像大小为32 × 32 = 1024。
2. C1层是卷积层,使用6 个5×5 的滤波器,得到6 组大小为28×28 = 784 的特征映射。因此,C1 层的神经元数量为6 × 784 = 4, 704,可训练参数数量为6×25+6 = 156,连接数为156×784 = 122, 304(包括偏置在内,下同)。
3. S2 层为汇聚层,采样窗口为2×2,使用平均汇聚,并使用一个非线性函数。神经元个数为6 × 14 × 14 = 1, 176,可训练参数数量为6 × (1 + 1) = 12,连接数为6 × 196 × (4 + 1) = 5, 880。
4. C3 层为卷积层。LeNet-5 中用一个连接表来定义输入和输出特征映射之间的依赖关系,如图5.11所示,共使用60 个5 × 5 的滤波器,得到16 组大小为10 × 10 的特征映射。神经元数量为16 × 100 = 1, 600,可训练参数数量为(60 × 25) + 16 = 1, 516,连接数为100 × 1, 516 = 151, 600。
5. S4 层是一个汇聚层,采样窗口为2×2,得到16 个5×5 大小的特征映射,可训练参数数量为16 × 2 = 32,连接数为16 × 25 × (4 + 1) = 2000。
6. C5 层是一个卷积层,使用120 × 16 = 1, 920 个5 × 5 的滤波器,得到120组大小为1 × 1 的特征映射。C5层的神经元数量为120,可训练参数数量为1, 920 × 25 + 120 = 48, 120,连接数为120 × (16 × 25 + 1) = 48, 120。
7. F6层是一个全连接层,有84 个神经元,可训练参数数量为84×(120+1) =10, 164。连接数和可训练参数个数相同,为10, 164。
8. 输出层:输出层由10 个欧氏径向基函数(Radial Basis Function,RBF)函数组成。这里不再详述。 -
AlexNet
1. 输入层,大小为224 × 224 × 3 的图像;
2. 第一个卷积层,使用两个大小为11 × 11 × 3 × 48 的卷积核,步长s = 4,零填充p = 3,得到两个大小为55 × 55 × 48 的特征映射组。
3. 第一个汇聚层,使用大小为3 × 3 的最大汇聚操作,步长s = 2,得到两个27 × 27 × 48 的特征映射组。
4. 第二个卷积层,使用两个大小为5 × 5 × 48 × 128 的卷积核,步长s = 1,零填充p = 2,得到两个大小为27 × 27 × 128 的特征映射组。
5. 第二个汇聚层,使用大小为3 × 3 的最大汇聚操作,步长s = 2,得到两个大小为13 × 13 × 128 的特征映射组。
6. 第三个卷积层为两个路径的融合,使用一个大小为3 × 3 × 256 × 384 的卷积核,步长s = 1,零填充p = 1,得到两个大小为13 × 13 × 192 的特征映射组。
7. 第四个卷积层,使用两个大小为3×3×192×192 的卷积核,步长s = 1,零填充p = 1,得到两个大小为13 × 13 × 192 的特征映射组。
8. 第五个卷积层,使用两个大小为3×3×192×128 的卷积核,步长s = 1,零填充p = 1,得到两个大小为13 × 13 × 128 的特征映射组。
9. 汇聚层,使用大小为3 × 3 的最大汇聚操作,步长s = 2,得到两个大小为6 × 6 × 128 的特征映射组。
10. 三个全连接层,神经元数量分别为4096,4096 和1000。 -
Inception
-
残差网络
Pytorch构建CNN模型
在上一章节我们讲解了如何使用Pytorch来读取赛题数据集,本节我们使用本章学习到的知识构件一个简单的CNN模型,完成字符识别功能。
在Pytorch中构建CNN模型非常简单,只需要定义好模型的参数和正向传播即可,Pytorch会根据正向传播自动计算反向传播。
在本章我们会构建一个非常简单的CNN,然后进行训练。这个CNN模型包括两个卷积层,最后并联6个全连接层进行分类。
import torch
torch.manual_seed(0)
torch.backends.cudnn.deterministic = False
torch.backends.cudnn.benchmark = True
import torchvision.models as models
import torchvision.transforms as transforms
import torchvision.datasets as datasets
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torch.autograd import Variable
from torch.utils.data.dataset import Dataset
# 定义模型
class SVHN_Model1(nn.Module):
def __init__(self):
super(SVHN_Model1, self).__init__()
# CNN提取特征模块
self.cnn = nn.Sequential(
nn.Conv2d(3, 16, kernel_size=(3, 3), stride=(2, 2)),
nn.ReLU(),
nn.MaxPool2d(2),
nn.Conv2d(16, 32, kernel_size=(3, 3), stride=(2, 2)),
nn.ReLU(),
nn.MaxPool2d(2),
)
#
self.fc1 = nn.Linear(32*3*7, 11)
self.fc2 = nn.Linear(32*3*7, 11)
self.fc3 = nn.Linear(32*3*7, 11)
self.fc4 = nn.Linear(32*3*7, 11)
self.fc5 = nn.Linear(32*3*7, 11)
self.fc6 = nn.Linear(32*3*7, 11)
def forward(self, img):
feat = self.cnn(img)
feat = feat.view(feat.shape[0], -1)
c1 = self.fc1(feat)
c2 = self.fc2(feat)
c3 = self.fc3(feat)
c4 = self.fc4(feat)
c5 = self.fc5(feat)
c6 = self.fc6(feat)
return c1, c2, c3, c4, c5, c6
model = SVHN_Model1()
接下来是训练代码:
# 损失函数
criterion = nn.CrossEntropyLoss()
# 优化器
optimizer = torch.optim.Adam(model.parameters(), 0.005)
loss_plot, c0_plot = [], []
# 迭代10个Epoch
for epoch in range(10):
for data in train_loader:
c0, c1, c2, c3, c4, c5 = model(data[0])
loss = criterion(c0, data[1][:, 0]) + \
criterion(c1, data[1][:, 1]) + \
criterion(c2, data[1][:, 2]) + \
criterion(c3, data[1][:, 3]) + \
criterion(c4, data[1][:, 4]) + \
criterion(c5, data[1][:, 5])
loss /= 6
optimizer.zero_grad()
loss.backward()
optimizer.step()
loss_plot.append(loss.item())
c0_plot.append((c0.argmax(1) == data[1][:, 0]).sum().item()*1.0 / c0.shape[0])
print(epoch)
在训练完成后我们可以将训练过程中的损失和准确率进行绘制,如下图所示。从图中可以看出模型的损失在迭代过程中逐渐减小,字符预测的准确率逐渐升高。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8so2quJs-1590501949558)(IMG/Task03/loss.png)]
当然为了追求精度,也可以使用在ImageNet数据集上的预训练模型,具体方法如下:
class SVHN_Model2(nn.Module):
def __init__(self):
super(SVHN_Model1, self).__init__()
model_conv = models.resnet18(pretrained=True)
model_conv.avgpool = nn.AdaptiveAvgPool2d(1)
model_conv = nn.Sequential(*list(model_conv.children())[:-1])
self.cnn = model_conv
self.fc1 = nn.Linear(512, 11)
self.fc2 = nn.Linear(512, 11)
self.fc3 = nn.Linear(512, 11)
self.fc4 = nn.Linear(512, 11)
self.fc5 = nn.Linear(512, 11)
def forward(self, img):
feat = self.cnn(img)
# print(feat.shape)
feat = feat.view(feat.shape[0], -1)
c1 = self.fc1(feat)
c2 = self.fc2(feat)
c3 = self.fc3(feat)
c4 = self.fc4(feat)
c5 = self.fc5(feat)
return c1, c2, c3, c4, c5
后记
本文是由自《神经网络与深度学习》做的笔记。
引用
https://blog.csdn.net/stf1065716904/article/details/78450997
神经网络与深度学习