1.从最简单的神经网络基本开始
X=[x1,x2,x3]T,是一个三维的样本点
现在我们有一个4*3的权重矩阵W1
W1=[w11,w12,w13
w21,w22,w23
w31,w32,w33
w41,w42,w43
]
由于y = WX,而W1是4*3的矩阵,X是3*1的矩阵,所以最后得出来的y是4*1的矩阵[y1,y2,y3,y4]T
可以看到对于权重矩阵的行数,我们可以对应理解为一个小滤波器
例如W1[0],就是W1中的第一个滤波器用来提取特征,这一行中的每一个权重都和输入样本的每一个维度,也就是神经元结点相乘,假设第一层的滤波器W1有4层,那么就有4个滤波器,一共会产生4个输出
同理我们再看从y到z的过程,最后输出一个神经元结点,因此第二层的滤波器只有1个滤波器,W2是一个一行的滤波器,且权重个数与y的神经元个数相同W2 = 1*4
z = W2*y ------> 1*4 ^ 4*1,最后得到1*1的单神经元输出。
我们回头看逻辑回归可以发现,LR应该算一个没有隐藏层的最简单的神经网络
而根据我们的知识知道这里面的一个一行四列的权重W是一个线性分类器,所以我们更正之前的说法,W应该是多个线性分类器的叠加,如果W有n行则代表有n个线性分类器叠加在一起构成n,而单纯的线性叠加很难达到很好的效果,这也就是为什么后面会使用激活函数引入非线性因素(你可以想象成把之前的线性分类器边界进行弯曲)同时,我之前所说的滤波器更多的时候使用在CNN之中,即Filter用来提取特征。
2.卷积神经网络
在理解卷积神经网络之前,我们需要先迁移性地理解一点,那就是,将所在层的通道数类比于1中的神经元结点的个数,把卷积核类比于1中的线性分类器个数,我们知道有几个分类器就会有多少输出,所以在进行卷积神经网络的过程中,输出结果与输入的维度或者说通道数无关,只与卷积核的个数有关。
假设我们有一张图片作为输入,我们知道它是三通道的,那么可以将这张图片表示为W*H*3,实际上看源码也知道图片用ndarray格式保存的时候也是这种形式,然后假设我们有5个Kenel,那么我们实际的输出与kenel的个数是相等的,即输出了5张特征图,那么具体是什么工作的呢?
以R,G,B三通道为例,共有5个卷积核w1,w2,w3,w4,w5,那么与1中类似,我们先选取卷积核w1,注意这里有一个卷积核深度的概念,该层所有的卷积核深度等该层输入的通道数,可以理解为上面1中所说的w11,w12,w13.
以三通道来表示
我们的卷积核应该定义深度,个数,个数我们可以随意设置,而深度必须保持与当前输入的通道数一直
W=[w11,w12,w13
w21,w22,w23
w31,w32,w33
w41,w42,w43
]
那么这里有4个卷积核,例如W1 = [w11,w12,w13]我们分别将这三个特征图与每个通道进行卷积然后相加得到最终输入即
y1 = w11*R+w12*G+w13*B
然后我们有4个卷积核,因此最终输出的通道数为4.
类比:
通道数----->神经元结点个数, 你可以把这些通道数想象成从上往下依次展开的
卷积核深度------->每一个线性分类器的特征W维度 , 你可以把每个通道对应每个WIJ的过程想象成W*X的过程
卷积核个数---------->线性分类器个数, 你可以想象成到底有几个分类器。
有了以上概念来一波立即推
当前输入共有m个通道,那么我们应该用多深的卷积核?
立即推m个通道对应m个神经元结点,就应该有m个权重值,因此卷积核深度为m;
如果我用了n个卷积核,那么输出多少个通道的特征图?
立即推,n个卷积核对应了n次卷积相加的过程,因此共有n个通道的输出。
因此当我们定义模型的时候,我们只需要关心卷积核的个数是多少即可,因为卷积核的深度由当前的通道数决定,假设最后一层卷积层用到了M个卷积核,立即推,最后一层的深度为M,这也是深度学习的深度体现。
现在让来看一下卷积神经网络中一些常用的概念,和基本组成部件。
假设我们的输入为(Width=W,Height=W,Depth=N)代表了N张长宽均为W的特征图,我们的卷积层为(Kenel_size=F*F,Depth=N,Num=M),代表了M个深度为N的尺寸为F*F的卷积核,假定我们进行卷积操作的步长Stride = S,Padding为P,那么首先由N张特征图与一个卷积核的N层进行卷积操作得到新的边长为W* =(W-F+2P)/S + 1(请牢记这个公式)的N张新特征图,我们把这N张特征图按对应位置相加得到一张完整的新特征图,即完成了一个卷积核特征提取的操作,我们有M个卷积核,所以我们最终得到的输出为
(Width=(W-F+2P)/S + 1,Height=(W-F+2P)/S + 1,Depth=M)
之后再进行池化操作,一般采取最大池化,计算方式一样,假设步长为1
Padding
如果我们想使得输出的特征图尺寸与原特征图尺寸一致,我们就可以使用padding,padding=1代表我们在原图的周围加上一圈0。
Tensorflow中有主要有两种padding方式,“Same”和“Valid”,代表当滤波器或池化到边界的时候是否自动补0,Same方式结果向上取整,例如我们的输入边长为5,步长为2, 5/2=2.5,向上取整得到3,则最终输出一张3*3的特征图。
池化层
池化层的作用就是减小特征图的面积,使用最大池化,提取到的是特征图中每一小块区域中取值最大到的那个数,一定程度上代表了提取出特征图中的关键信息。例如我们只关心图像的轮廓和纹理变化。
降低输出规模,增加可解释性;
光滑信息,避免丢失更多信息。
对于没有经过最大池化的图片,从三维角度来看,取值高高低低,而提取出的都是每块区域中最大的值,相当于使得数据区域光滑。
而现在1个点就能代表以前的4个点,一定程度上代表增大了我们的感知野。
此外还有平均池化,即取区域中的平均值,有点像均值滤波。
激活函数
FC层(全连接层)
在完成所有卷积层之后,将所有输出特征图扁平化展开成一个列向量
例如3张2*2的特征图可以按顺序展开成1个12个神经元结点的输出,然后我们用12个带有12个参数的线性分类器,得到一个新的12个神经元结点的FC层,最后根据我们的需要连接上一个softmax函数或者sigmoid函数即可。
正则化
L1 =
L2 =
与传统机器学习方法一致,都是为了抑制模型复杂度。
损失函数
一般使用交叉熵损失函数
对于sigmoid函数直接带入以下交叉熵损失函数中
y代表标签值,y^代表预测值
对于softmax,由于是多分类,假设有1,2,3,4,5共5个分类,我们的输出为output=[0.1, 0.2, 0.4 0.1 0.2]
由于我们采用的one-hot编码,所以当我们看某一类时,其它的类别都为0
例如我们要算第3类时的损失函数
Loss = -[0*In0.1+0*In0.2+1*In0.4+0*In0.1+0*In0.2]
= -In0.4
即
反向传播
这里先补充一个概念就是张量,我们可以把张量理解为数字容器;
0维张量:一个数
1维张量:一个数组
2维张量:一个矩阵
3维张量:以特征图来说就是三维张量 高*宽*通道数
4维张量:以卷积核来说就是四维张量 高*宽*通道数*卷积核个数
再说反向传播
先从最简单的神经元结点之间的反向传播开始
反向传播就是遵从我们的链式求导法则
假设我们要求最后的损失值相对于图中W的偏导数,也就是W的变化会给损失值带来怎样的变化,假设这个偏导数为负数,则代表W增大时损失函数减小,而W减小时损失函数增大,我们更新W的时候就用这个梯度去更新 W = W - *,让我们来验证一下这个公式,偏导数为正的时候,W增大会使得损失函数增大,因此我们要减小W,对应于公式正好W是减小的,同理如果偏导数为负,则W增大会使得损失函数减小,因此我们就增大这个值。
具体来求一求L对W的偏导,由以下链式求导法则
然后我们一层一层来算
第一层假设我们最后用的是二分之一平方损失函数,那么第一层求导数值为,其中y为标签值。
第二层,是一个激活函数的求导,假设我们使用的是Relu激活函数,如果Z的值大于0,那么导数就为1,否则就为0,假设我们现在Z值大于0,那么这一层的导数值就为1
第三层,由于Z = W*a(L-1) + b,因此Z对W求导就是a(L-1)
最后我们把他们乘起来得到L对W的偏导值为(aL-y)*a(L-1)
然后计算W = W - *(aL-y)*a(L-1)即可
注意当我们用的批量的时候(aL-y)应该改为
然后很重要一点,假设我们再要求L-2层的权重的时候,
我们要先求最后的结果对a(l-1)层的偏导结果,我们把上面的第三步改一下就是
而a(L-1)又是由W(l-2)*a(l-2)+b(l-2)和一层激活层得到
因此
可以看出来对于每个数值上的点都有对应的偏导数,且对权值调整起着非常重要的作用
例如我记录,那么我再用a(l-1)对W(l-2)进行求偏导,然后根据链式法则相乘即可
所以对于每个数值点,我们有:损失函数对该数值点处的偏导数,再求改点对前面的权重或偏置的导数,相乘即可。
理解了这一点,就很好理解卷积神经网络中反向传播中的一些操作。
池化层的反向传播
从池化层开始,假设我们是最大池化
以图为例,我们计算并记录下了6这个点的导数,由于是最大池化,那么传播到它的之前的激活层的时候1处的导数为0,1处的导数为0,5处的导数为0,6处的导数为1,你可以这样理解,由于我们采取到了池化这个降采样操作,所以1,1,5这些点都废了,没啥用,甭调节它了;
对于平均池化来说,第一块儿的值为(1+1+5+6)/4,所以每一块儿的权重都是0.25,所以每一块儿的权重都是6这个位置计算所得的权重乘以0.25.
卷积层的反向传播
数值部分的传播
这里引用知乎大神南柯一梦宁沉沦的图(上面的部分图也取自他的图)
我们在理解前向反向传播过程中始终抓住一个核心点,就是前向传播的时候,哪些点对哪些点造成了什么影响,然后我们反向把这些影响给传播回去,传播就是求导,导数相乘的过程。例如上图,我们求得了C出的导数,然后我们相求A出的导数,怎么求?看C是怎么通过A得到的嘛,显然是C = A*B +C*D + E*F + G*H,显然我们这里只关心A,通过C对A求导,得到B,因此A处的导数值等于C处的导数值乘以B。
现在我们把A移动到如图所示的位置,还是抓住核心问题,这个点对后面哪些点产生了哪些影响,我们不断滑动卷积核,发现A参与了A*C得到D,然后还参与了A*B得到E,那么A处的导数值就应该等于D处的导数值乘以C加上E处的导数值乘以B。
卷积核的反向传播
与上面类似,我们始终关注一个核心点,我们要求的位置通过何种方式对哪些位置产生了影响,以下图来表示
在结果特征图里,我简单粗暴用de1--de4来代表4个位置的反向传播误差,然后我们想对卷积核中的1,2,3,4几个参数进行反向传播,我们就看1,1参与了与A相乘然后输出de1位置,1与B相乘然后输出de2位置,所以1处的误差为de1*A+de2*B,1处的权重应该更新为W-*(de1*A+de2*B)
但是注意一点的是,我们现在计算的是某一个通道乘以其中一个卷积核的某一个通道,而有几个卷积核,就能得到几张特征图,如下表示
假设我们输入了两张特征图,然后用两个深度为2的卷积核会得到两个特征图输出,那么我们在计算A点的误差时,应该等于deC*B+deD*E,即叠加!
综上!所有的反向传播,统统从一个角度考虑,就不需要记忆了,很简单,要求的位置对哪些点产生了哪些影响,然后通过求导和链式法则,然后相加就能得到这一点的导数。
dropout
就是让某些结点工作,某些结点不工作,可以类比于随机森林,每次都选择若干个特征进行构造决策树,每一层的dropout都可以设置一定的比例,例如dropout = 0.6,则代表有百分之六十的神经元工作,每一次的前向传播和误差反馈调节都可以看成是一棵决策树,每次dropout选择不工作的神经元都是随机选择的,那么每一次权重更新过程都可以类比为构造一棵决策树。
以该图为例,如果没有dropout,那么调节的权重个数为5*5+5*5+5*1 = 55个;
用图中dropout方式连接,则只有激活的神经元对应的权重参与调节,共3*2+2*3+3*1=15个;
如此看来使用dropout可以大大减轻我们的计算量,而且更重要的原因是dropout的方式很像随机森林的投票模式,这样能够大大增强网络的泛化能力,对抗过拟合情况的出现。
Batch Normalization(BN)
如果数据集体不呈正态分布,那么使用一些激活函数,例如sigmoid的时候,大量的数据可能集中在很小的调节范围内,极其容易产生梯度消失。
可以看到,如果数据都集中落在较大(或者较小)的区域,那么梯度就会很小很小趋近于0,到之后后面的网络基本上无法调节,最后定格在这里了,我们的模型很可能不会收敛。
BN层连接在激活层之前。
CNN整体架构
梯度弥散与梯度爆炸
梯度弥散就是在梯度反向传播中遵从链式法则,所有梯度相乘后可能出现一个很小的值,而梯度又代表了权重的更新快慢和方向,所以如果梯度消失,很有可能收敛地非常慢甚至不收敛;
对应梯度弥散的就是梯度爆炸,如果梯度值大于1,则经过若干层链式传播之后,很有可能梯度成指数级增长,这样造成的效果也很有可能不能收敛。