参考文章:csdn - 安全中心
计算机视觉网络的架构:
-
平移不变性:不管检测对象出现在图像中的哪个位置,神经网络的前面几层应该对相同的图像区域具有相似的反应,即为平移不变性。
-
图像的平移不变性使我们以相同的方式处理局部图像,而不在乎它的位置。
-
-
局部性:神经网络的前面几层应该只探索输入图像中的局部区域,而不过度在意图像中相隔较远区域的关系,这就是“局部性”原则。最终可以聚合这些局部特征,以在整个图像级别进行预测。
-
局部性意味着计算相应的隐藏表示只需一小部分局部图像像素。
-
CNN网络结构:
卷积要点总结
总结来说,卷积的要点有下:
-
卷积的目的就是进行图像的特征提取。
-
卷积的特性:
-
具有局部感知机制,因为是以滑动窗口的形式滑动计算的,所以说具备局部感知能力。
-
权值共享,因为每次滑动计算都用的同一个卷积核,这个卷积核的值在这次卷积中是不发生变化的,权值共享的优势就在于极大的减少了参数量。
-
卷积核的通道数channel与输入特征矩阵的channel相同。如输入是3维的,那么卷积核也是3维的。
-
卷积后输出特征矩阵channel与卷积核个数相同。比如用2个卷积核,那么输出矩阵的深度就是2。
-
卷积层参数总结
卷积层中需要用到卷积核与图像特征矩阵进行点乘运算,利用卷积核与对应特征感受野进行滑窗式运算时,需要设定卷积核对应的大小、步长、个数及填充方式。
在卷积过程中,卷积后的尺寸由以下几个因素决定:
卷积之后的尺寸大小计算公式为:
padding的两种方式 “SAME” 和 “VALID”:
-
padding = “SAME”时,会在图像的周围填 “0”,
-
padding = “VALID”则不需要,即 P=0。
-
一般会选“SAME”,一来减缓图像变小的速度,二来防止边界信息丢失(即有些图像边界的信息发挥作用较少)。
由于卷积操作是输入矩阵与卷积核进行相乘的过程,是线性变化,所以需要通过激活函数进行非线性激活。即在卷积层输出结果的基础上套一个激活函数,让输入的特征图具有非线性关系。
卷积核的权重和偏置也要和FC一样随机初始化。
池化层
池化层又称为降采样层,作用是对感受野内的特征进行筛选,提取区域内具有代表性的特征,能够有效的减小输出特征尺度,进而减少模型所需要的参数量。
按操作类型通常分为最大池化(max pooling)、平均池化(average pooling)、求和池化(sum pooling),它们分别提取感受野内最大、平均、总和的特征值作为输出,cv中最常用的就是max pooling。
总结来说:
-
对卷积后的特征图进行稀疏处理,减少数据运算量;
-
它只在原始的特征图上求最大值或平均值,所以不需要训练参数;
-
它只改变特征矩阵的宽度和高度,并不会改变深度channel;
-
一般池化和大小poolsize和步距stride相同的,比如2*2,步长也为2,就能将特征图的大小缩小为原来的一半,计算也方便;
卷积层和池化层的区别
全连接层
得到卷积提取的图片特征进行非线性学习,最后一层神经元个数对应分类的类别数。
当然全连接和卷积层也可以互相转换:
-
对于任意一个卷积层,转成全连接只需要展平一下即可;
-
相反的对于任何一个全连接也可以变成卷积,也就是把卷积核大小设置为整个输入层的大小。
torch搭建LeNet网络
'''
pytorch tensor通道顺序:[batch_size, channel, height, width],通道数、高、宽
nn.Conv2d(in_channels, out_channels, kernel_size, stride=1, padding=0, bias=True, )
+ in_channels:输入通道数,如彩色图像RGB就是3
+ out_channels:输出通道数,即使用卷积核的个数,输出特征矩阵的channel和卷积核个数相等
+ kernel_size:卷积核大小
+ stride:步距默认为1
+ padding:填充默认为0
+ bias:默认有偏置
nn.MaxPool2d(kernel_size)
+ kernel_size:池化和大小,池化层只改变特征矩阵的高和宽,不影响深度,池化和大小为2,就是将高度和宽度缩减为原来的一半
+ stride:步距
'''
class LeNet(nn.Module):
def __init__(self):
super(LeNet, self).__init__()
# 方便维度注释,这里没用nn.Sequential
self.conv1 = nn.Conv2d(3, 16, 5) # 输入通道为3、16个卷积核、卷积核大小是5*5
self.pool1 = nn.MaxPool2d(2, 2)
self.conv2 = nn.Conv2d(16, 32, 5)
self.pool2 = nn.MaxPool2d(2, 2)
self.fc1 = nn.Linear(32*5*5, 120)
self.fc2 = nn.Linear(120, 84)
self.fc3 = nn.Linear(84, 10)
def forward(self, x):
# 下面维度忽略了batch_size
x = F.relu(self.conv1(x)) # input(3, 32, 32) output(16, 28, 28)
x = self.pool1(x) # output(16, 14, 14)
x = F.relu(self.conv2(x)) # output(32, 10, 10)
x = self.pool2(x) # output(32, 5, 5)
x = x.view(-1, 32*5*5) # output(32*5*5)
x = F.relu(self.fc1(x)) # output(120)
x = F.relu(self.fc2(x)) # output(84)
x = self.fc3(x) # output(10)
return x