文章目录
卷积神经网络(CNN)
本blog先介绍对卷积的理解,然后介绍卷积神经网络,同时介绍了较为简单的LeNet-5卷积神经网络。卷积神经网络的输入可以是,一维、二维甚至三维的数据,所以在图像识别等计算机视觉领域以及自然语言处理领域用的较多。
1. 卷积
1.1. 离散卷积的理解
以离散卷积为例,对序列 x ( n ) x(n) x(n)与 h ( n ) h(n) h(n),我们熟知的卷积定义如下 y ( n ) = ∑ − ∞ i = ∞ x ( i ) h ( n − i ) = x ( n ) ∗ h ( n ) y(n)=\sum\limits^{i=\infty}_{-\infty}x(i)h(n-i)=x(n)*h(n) y(n)=−∞∑i=∞x(i)h(n−i)=x(n)∗h(n)
直观来看,这是两个序列进行卷积得到另一个序列,属于泛函分析范畴。具体来看, x ( n 1 ) x(n_{1}) x(n1)的自变量取值与 h ( n 2 ) h(n_{2}) h(n2)的自变量取值满足某种约束,即 n 1 + n 2 = n n_{1}+n_{2}=n n1+n2=n,也就是说, x ( n 1 ) x(n_{1}) x(n1)的自变量 n 1 n_{1} n1与 h ( n 2 ) h(n_{2}) h(n2)的自变量 n 2 n_{2} n2在坐标轴上关于 n 2 \frac{n}{2} 2n对称,所有的 n 1 n_{1} n1都有关于 n 2 \frac{n}{2} 2n对称的 n 2 n_{2} n2,我们对 x ( n 1 ) x(n_{1}) x(n1)与 h ( n 2 ) h(n_{2}) h(n2)的所有乘积求和就是卷积的结果 y ( n ) y(n) y(n)。
从实际运算来看,假设 x ( − 1 ) = a , x ( 0 ) = b , x ( 1 ) = c , h ( 3 ) = i , h ( 4 ) = g , h ( 5 ) = t x(-1)=a,x(0)=b,x(1)=c,h(3)=i,h(4)=g,h(5)=t x(−1)=a,x(0)=b,x(1)=c,h(3)=i,h(4)=g,h(5)=t,其余的值均为0,则 y ( n ) = ∑ − ∞ i = ∞ x ( i ) h ( n − i ) = x ( n ) ∗ h ( n ) y(n)=\sum\limits^{i=\infty}_{-\infty}x(i)h(n-i)=x(n)*h(n) y(n)=−∞∑i=∞x(i)h(n−i)=x(n)∗h(n)的分解运算如下图所示
![](https://img-blog.csdnimg.cn/20190220090224411.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0xlb25fd2ludGVy,size_16,color_FFFFFF,t_70)
根据上面的说明, h ( α − n ) h(\alpha-n) h(α−n)就是把 h ( n ) h(n) h(n)做关于点 α 2 \frac{\alpha}{2} 2α的对称,在与 x ( n ) x(n) x(n)相乘并求和得到 y ( α ) y(\alpha) y(α),选择不同的 α \alpha α, h ( α − n ) h(\alpha-n) h(α−n)的翻转参考点不同,效果就像是 h ( α − n ) h(\alpha-n) h(α−n)在坐标轴上平移(如上图)。这一系列步骤就是我们在求卷积时熟知的"翻转、相乘、相加、平移"。
重点看图中的平行四边形画出的部分,这一部分才有对应的 y y y值(其余 y y y值为0),我们是否也可以这样理解卷积,把序列 x ( − 1 ) 、 x ( 0 ) 、 x ( 1 ) x(-1)、x(0)、x(1) x(−1)、x(0)、x(1)与 h ( 3 ) h(3) h(3)相乘,结果分配到 y ′ ( 2 ) 、 y ′ ( 3 ) 、 y ′ ( 4 ) y'(2)、y'(3)、y'(4) y′(2)、y′(3)、y′(4),类似的把序列 x ( − 1 ) 、 x ( 0 ) 、 x ( 1 ) x(-1)、x(0)、x(1) x(−1)、x(0)、x(1)分别与 h ( 4 ) 、 h ( 5 ) h(4)、h(5) h(4)、h(5)相乘,结果分别分配到 y ′ ( 3 ) 、 y ′ ( 4 ) 、 y ′ ( 5 ) y'(3)、y'(4)、y'(5) y′(3)、y′(4)、y′(5)与 y ′ ( 4 ) 、 y ′ ( 5 ) 、 y ′ ( 6 ) y'(4)、y'(5)、y'(6) y′(4)、y′(5)、y′(6), y ′ y' y′表示是 y y y的中间结果,然后把分配到 y ′ ( 2 ) , y ′ ( 3 ) , y ′ ( 4 ) , y ′ ( 5 ) , y ′ ( 6 ) y'(2),y'(3),y'(4),y'(5),y'(6) y′(2),y′(3),y′(4),y′(5),y′(6)上的值相加,就是最终的结果。这就引出了卷积的另一个理解,即一个序列在另一个序列上的加权叠加。
如何确定第一个非零的 y y y值的位置?从上面的分析中,我们其实可以总结出来规律: x ( n ) x(n) x(n)序列的第一个非零元素对应的自变量值与 h ( n ) h(n) h(n)序列的第一个非零元素对应的自变量值的和,即是卷积结果 y ( n ) y(n) y(n)的第一个非零元素对应的自变量值。以上面的例子为例, y ( n ) y(n) y(n)的第一个非零元素就是 y ( 3 + ( − 1 ) ) y(3+(-1)) y(3+(−1))。
1.2. 离散卷积的实际应用例子
举一个离散卷积的应用场景,假设我们先后投一枚骰子,两次投掷结果的概率分别记为 f 1 ( n ) f_{1}(n) f1(n)与 f 2 ( n ) f_{2}(n) f2(n),在 n = 1 , 2 … 6 n=1,2\dots 6 n=1,2…6时才有非零概率,其余的 n n n值对应概率均为0,现在我们想求两次投掷结果之和等于4的概率,用卷积的运算很容易就可以描述这种求解 y ( 4 ) = ∑ − ∞ i = ∞ f 1 ( i ) f 2 ( 4 − i ) = f 1 ( 0 ) f 2 ( 3 ) + f 1 ( 2 ) f 2 ( 2 ) + f 1 ( 3 ) f 2 ( 1 ) y(4)=\sum\limits^{i=\infty}_{-\infty}f_{1}(i)f_{2}(4-i)=f_{1}(0)f_{2}(3)+f_{1}(2)f_{2}(2)+f_{1}(3)f_{2}(1) y(4)=−∞∑i=∞f1(i)f2(4−i)=f1(0)f2(3)+f1(2)f2(2)+f1(3)f2(1)
1.3. 卷积的矩阵用法
如果我们的卷积对象不再是两个一维序列,而是两张图(二维矩阵图),卷积操作依然会按照旋转,相乘,相加,平移的流程执行。假设我们有这样两个矩阵 A = [ a ( 0 , 0 ) a ( 0 , 1 ) a ( 0 , 2 ) a ( 0 , 3 ) a ( 0 , 4 ) a ( 1 , 0 ) a ( 1 , 1 ) a ( 1 , 2 ) a ( 1 , 3 ) a ( 1 , 4 ) a ( 2 , 0 ) a ( 2 , 1 ) a ( 2 , 2 ) a ( 2 , 3 ) a ( 2 , 4 ) a ( 3 , 0 ) a ( 3 , 1 ) a ( 3 , 2 ) a ( 3 , 3 ) a ( 3 , 4 ) a ( 4 , 0 ) a ( 4 , 1 ) a ( 4 , 2 ) a ( 4 , 3 ) a ( 4 , 4 ) ] A=\left [ \begin{matrix} a_{(0,0)} & a_{(0,1)} & a_{(0,2)} & a_{(0,3)} & a_{(0,4)} \\ a_{(1,0)} & a_{(1,1)} & a_{(1,2)} & a_{(1,3)} & a_{(1,4)} \\ a_{(2,0)} & a_{(2,1)} & a_{(2,2)} & a_{(2,3)} & a_{(2,4)} \\ a_{(3,0)} & a_{(3,1)} & a_{(3,2)} & a_{(3,3)} & a_{(3,4)} \\ a_{(4,0)} & a_{(4,1)} & a_{(4,2)} & a_{(4,3)} & a_{(4,4)} \\ \end{matrix} \right ] A=⎣⎢⎢⎢⎢⎡a(0,0)a(1,0)a(2,0)a(3,0)a(4,0)a(0,1)a(1,1)a(2,1)a(3,1)a(4,1)a(0,2)a(1,2)a(2,2)a(3,2)a(4,2)a(0,3)a(1,3)a(2,3)a(3,3)a(4,3)a(0,4)a(1,4)a(2,4)a(3,4)a(4,4)⎦⎥⎥⎥⎥⎤ B = [ b ( − 1 , − 1 ) b ( − 1 , − 1 ) b ( − 1 , − 1 ) b ( 0 , 0 ) b ( 0 , 0 ) b ( 0 , 0 ) b ( 1 , 1 ) b ( 1 , 1 ) b ( 1 , 1 ) ] B=\left [ \begin{matrix} b_{(-1,-1)} & b_{(-1,-1)} & b_{(-1,-1)} \\ b_{(0,0)} & b_{(0,0)} & b_{(0,0)}\\ b_{(1,1)} & b_{(1,1)} & b_{(1,1)} \end{matrix} \right ] B=⎣⎡b(−1,−1)b(0,0)b(1,1)b(−1,−1)b(0,0)b(1,1)b(−1,−1)b(0,0)b(1,1)⎦⎤
注意B矩阵的下标从-1开始,而A矩阵的下标从0开始,这样是为了保证,B矩阵在A矩阵上投影的中心位置,和卷积结果的中心位置一致(都是(m,n))。则矩阵的卷积定义如下: Y ( m , n ) = A ∗ B = ∑ x ∑ y A ( x , y ) × B ( m − x , n − y ) Y(m,n) = A*B=\sum\limits_{x}^{}\sum\limits_{y}^{}A(x,y) \times B(m-x,n-y) Y(m,n)=A∗B=x∑y∑A(x,y)×B(m−x,n−y)
这样A,B矩阵的对应元素位置,就关于 ( m 2 , n 2 ) (\frac{m}{2},\frac{n}{2}) (2m,2n)对称,和一维序列的卷积类似。当 m , n m,n m,n递增,就会出现B矩阵在A矩阵上滑动的效果,如下图,这里 B B B矩阵已经经过翻转, m , n = { 1 , 2 , 3 } m,n=\{1,2,3\} m,n={ 1,2,3}:
![](https://mlnotebook.github.io/img/CNN/convSobel.gif)
同时,考虑A矩阵的边界,当 m = 0 m=0 m=0或 n = 0 n=0 n=0时, B B B矩阵以 ( m 2 , n 2 ) (\frac{m}{2},\frac{n}{2}) (2m,2n)为中心翻转后,有一部分值对应在 A A A矩阵中的位置,没有对应的数据,为了解决这一问题,我们在A矩阵外围,填充(padding)一圈数据,如下图
![](https://mlnotebook.github.io/img/CNN/convZeros.png)
这样, A A A矩阵就有了位置下标是-1的数据,同时,我们卷积得到的矩阵结果,就和A矩阵大小一样。原则上,可以在A矩阵外填充两层0,但是这样得到的矩阵结果就大于A矩阵,所以一般不这么做;如果在A矩阵外填充更多层的0,这些位置的卷积结果都是0,更没有意义去考虑。
矩阵卷积是CNN的基础,同时也用在图像平滑处理等多个领域。
由于我们可以把矩阵B在存储时就存成翻转后的格式,所以在实际卷积时,只用考虑"相乘、相加、平移",不用进行翻转操作,后面blog中的 " ∗ " "*" "∗"默认也是不发生翻转的卷积。
1.4. 矩阵的卷积转化成矩阵运算
这里的卷积操作不考虑翻转过程,也就是说,存储时就存成了翻转后的形式。定义 A , B A,B A,B矩阵如下 A = [ a ( 0 , 0 ) a ( 0 , 1 ) a ( 0 , 2 ) a ( 0 ,