卷积神经网络(Convolutional Neural Network,CNN)是一类包含卷积计算且具有深度结构的前馈神经网络,广泛地运用在图像识别,语音识别、自然语言处理、医学影像,甚至物理学和气象学等很多领域,几乎也是目前很多图像与视觉识别竞赛的基础。
前面介绍了全连接的神经网络,那为什么又出现卷积神经网络呢?因为在全连接的时候我们都将输入的数据进行了压平处理(都转成了一维,比如前面介绍的MNIST中的手写数字图片(1,28,28)-->(通道,高度,宽度)),但这样存在一些缺点,丢失了通道等一些特征信息,所以最好还是能够把输入数据的特征信息能够表现出来,这个时候就用到卷积神经网络了,对全连接层不是很熟悉的可以看本人以前的文章:全连接的多层神经网络结构(MultiLayerNet)https://blog.csdn.net/weixin_41896770/article/details/121451390
既然是卷积神经网络,就少不了卷积层(Convolution层)和池化层(Pooling层),卷积神经网络的结构:Conv-->ReLU-->Pooling-->Conv-->ReLU-->Pooling-->Conv-->ReLU-->Affine-->ReLU-->Affine-->Softmax
从这个结构可以看出,增加了卷积层和池化层,其余还是和全连接层一样,类似乐高积木的搭建。在靠近输出的层中使用了之前的“Affine-->ReLU”组合,在最后输出层使用之前的“Affine-->Softmax”组合,这些都是CNN的比较常见的结构。
特征图(feature map):就是卷积层的输入输出数据,输入数据叫做输入特征图,输出数据叫做输出特征图
卷积运算:卷积层进行的处理就是卷积运算,把输入数据应用滤波器(核),相当于图像处理中的“滤波器运算”,直观看图:
填充(padding):进行卷积层处理之前,有时需要向输入数据的周围填入固定数据(比如0等),在卷积运算中经常用到。在本文后面有附带“填充”的具体用法。
步幅(stride):应用滤波器的位置间隔为步幅,或说窗口滑动的间隔。
针对输入数据(H,W)在经过滤波器(FH,FW),填充(P)和步幅(S)之后的输出大小(OH,OW),我们可以通过下面公式计算获得:
OH=1+(H+2P-FH)/S
OW=1+(W+2P-FW)/S
比如输入大小:(4,4),滤波器大小:(3,3),填充:1,步幅:1,输出大小为
OH=1+(4+2*1-3)/1=4
OW=1+(4+2*1-3)/1=4
有时候会出现无法除尽的情况,这个时候可以取整数或者四舍五入,让结果不出现小数。
卷积层的功能是对输入数据进行特征提取,其内部包含多个卷积核,组成卷积核的每个元素都对应一个权重系数和一个偏差量,类似于一个前馈神经网络的神经元。
池化(Pooling)
池化的意思就是降采样,减少了输出的特征,或者简单来说就是一个池子装水,作用可以沉淀杂质,让水质变得更清澈。池化有最大池化(Max Pooling),平均池化(Average Pooling)等,一般都用最大池化,是将输入的图像划分成若干个区域(邻域),然后求每个区域的最大值。因为发现,这个特征它所在的精确位置没有与其他特征的相对位置的关系重要,所以移动或旋转之类都影响不大,平移不变性(Transitional invariance)。
填充(padding):进行卷积层处理之前,有时需要向输入数据的周围填入固定数据(比如0等),是numpy对数组边缘的数值填充,在卷积神经网络中使用很广泛,主要是在层级传输过程中防止图像形状变化或者说信息的丢失,所以进行一个填充来处理。
示例:
n=np.arange(3,11)#[3, 4, 5, 6, 7, 8, 9, 10]
np.pad(n,(0,2),'constant')#[ 3 4 5 6 7 8 9 10 0 0]
np.pad(n,(1,2),'constant')#[ 0, 3, 4, 5, 6, 7, 8, 9, 10, 0, 0]
可以看出,圆括号的数字代表的数组n前后填充的个数,constant是常量填充,默认为0
转成二维或多维的情况
n1=n.reshape(2,4)
array([[ 3, 4, 5, 6],
[ 7, 8, 9, 10]])
np.pad(n1,[(1,0),(1,2)],'constant')
array([[ 0, 0, 0, 0, 0, 0, 0],
[ 0, 3, 4, 5, 6, 0, 0],
[ 0, 7, 8, 9, 10, 0, 0]])
一维填充(1,0)宽度,二维填充(1,2)宽度,之后的形状就是 (3, 7)
转置(transpose):对数组的转置,如果是矩阵,即行列的调换,三维以及以上的维度,那么就是索引位置对应维度的调换。
示例:
x=np.arange(12).reshape(2,6)
array([[ 0, 1, 2, 3, 4, 5],
[ 6, 7, 8, 9, 10, 11]])
x.transpose() #等价于 x.T
array([[ 0, 6],
[ 1, 7],
[ 2, 8],
[ 3, 9],
[ 4, 10],
[ 5, 11]])
x=np.arange(12).reshape(2,3,2)
array([[[ 0, 1],
[ 2, 3],
[ 4, 5]],
[[ 6, 7],
[ 8, 9],
[10, 11]]])
x.transpose(0,2,1)#将2维和3维调换,形状将变成(2,2,3)
array([[[ 0, 2, 4],
[ 1, 3, 5]],
[[ 6, 8, 10],
[ 7, 9, 11]]])