神经网络算法的目标是通过训练一步一步的将参数调到最优,以无线逼近正确结果,调参的过程涉及到反向传播,即将本次神经元的输出结果与正确结果计算交叉熵,在通过反向传播,利用梯度下降发求得最优参数,
先看链式传播法则的通俗理解:
1.链式法则。
假设一个场景,一辆汽车20万元,要收10%的购置税,如果要买2辆,则正向传播的过程可以画成:
汽车单价20万,最终需要支付44万,我现在想知道汽车单价每波动1万,对最终支付价格的影响是多少。参看下图:我们从右向左依次求导,得到的值分别为
①44/44=1
②44/40=1.1
③40/20=2
那么最终价格相对于汽车单价的导数就是①×②×③=2.2
这就是链式法则。我们只需要知道每个节点导数值,然后求乘积就可以了。
链式法则的一种定义*是:
如果某个函数由复合函数表示,则该复合函数的导数可以用构成复合函数的各个函数的导数的乘积表示。
所以我们只需要关注每个节点的导数值即可。
2、反向传播
下边介绍几种典型节点的反向传播算法。
2.1 加法节点
如下图:该节点可以写作z=x+y
很容易知道,z对x求导等于1,对y求导也等于1,所以在加法节点反向传递时,输入的值会原封不动地流入下一个节点。比如:
2.2 乘法节点
如下图,该节点可以写作z=x*y
同样很容易知道,z对x求导等于y,对y求导等于x,所以在加法节点反向传递时,输入的值交叉相乘然后流入下一个节点。比如:
2.3 仿射变换
所谓仿射变换就是这个式子,如果觉得眼生就去看上一篇文章。
仿射变换公式
画成图的话就是:
这是神经网络里的一个重要形式单元。这个图片看起来虽然复杂,但其实和乘法节点是类似的,我们对X求导,结果就是W1;对W1求导,结果就是X,到这里和乘法节点是一样的;对b1求导,结果为1,原封不动地流入即可。不过需要注意的一点是,这里的相乘是向量之间的乘法。
2.4 ReLU层
激活层我们就以ReLU为例。回忆一下,ReLU层的形式是这样的:
因为当x>0时,y=x,求导为1,也就是原封不动传递。
当x<=0时,y=0,求导为0,也就是传递值为0。
2.5 Softmax-with-Loss
Softmax-with-Loss指的就是Softmax和交叉熵损失的合称。这是我们之前提到的神经网络的最后一个环节。这部分的反向传播推导过程比较复杂,这里直接上结论吧(对推导过程感兴趣的话可以看文末参考文献*的附录A):
其中
从前面的层输入的是(a1, a2, a3),softmax层输出(y1, y2, y3)。此外,教师标签是(t1, t2, t3),Cross Entropy Error层输出损失L。
所谓教师标签,就是表示是否分类正确的标签,比如正确分类应该是第一行的结果时,(t1, t2, t3)就是(1,0,0)。
从上图可以看出,Softmax-with-Loss的反向传播的结果为(y1 − t1, y2 − t2, y3 − t3)。
3、参数更新
参数的更新对象其实就是W和b,具体的在2.3中对其更新方法进行了描述,简单来说,dW就是输入值乘以X,db就等于输入值。这里用dW和db表示反向传播到W和b节点时的计算结果。
那现在该怎样更新W和b呢?
直接用W=W-dW;b=b-db么?
可以,但不太好。
其一,需要引入正则化惩罚项。这是为了避免最后求出的W过于集中所设置的项,比如[1/3,1/3,1/3]和[1,0,0],这两个结果明显前一个结果更为分散,也是我们更想要的。为了衡量分散度,我们用[公式] 来表示。对该式求导,结果就是W。设正则化惩罚项的系数值为reg,那么修正后的dW可以写为:
其二,是步子迈的有点大。直接反向传播回来的量值可能会比较大,在寻找最优解的过程中可能会直接将最优解越过去,所以在这里设置一个参数:学习率。这个数通常很小,比如设学习率为0.0001这样。我们将学习率用epsilon表示,那么最终更新后的W和b写为:
假设,你有这样一个网络层:
第一层是输入层,包含两个神经元i1,i2,和截距项b1;第二层是隐含层,包含两个神经元h1,h2和截距项b2,第三层是输出o1,o2,每条线上标的wi是层与层之间连接的权重,激活函数我们默认为sigmoid函数。现在对他们赋上初值,如下图:
其中,输入数据 i1=0.05,i2=0.10;
输出数据 o1=0.01,o2=0.99;
初始权重 w1=0.15,w2=0.20,w3=0.25,w4=0.30;
w5=0.40,w6=0.45,w7=0.50,w8=0.55
目标:给出输入数据i1,i2(0.05和0.10),使输出尽可能与原始输出o1,o2(0.01和0.99)接近。
Step 1 前向传播
1.输入层---->隐含层:
计算神经元h1的输入加权和:
神经元h1的输出o1:(此处用到激活函数为sigmoid函数):
同理,可计算出神经元h2的输出o2:
2.隐含层---->输出层:计算输出层神经元o1和o2的值:
这样前向传播的过程就结束了,我们得到输出值为[0.75136079 , 0.772928465],与实际值[0.01 , 0.99]相差还很远,现在我们对误差进行反向传播,更新权值,重新计算输出。
Step 2 反向传播
1.计算总误差
总误差:(square error)
但是有两个输出,所以分别计算o1和o2的误差,总误差为两者之和:
2.隐含层---->输出层的权值更新:以权重参数w5为例,如果我们想知道w5对整体误差产生了多少影响,可以用整体误差对w5求偏导求出:(链式法则)
下面的图可以更直观的看清楚误差是怎样反向传播的:
现在我们来分别计算每个式子的值:计算
计算
(这一步实际上就是对sigmoid函数求导,比较简单,可以自己推导一下)计算
最后三者相乘:
这样我们就计算出整体误差E(total)对w5的偏导值。回过头来再看看上面的公式,我们发现:
为了表达方便,用
来表示输出层的误差:
因此,整体误差E(total)对w5的偏导公式可以写成:
如果输出层误差计为负的话,也可以写成:
最后我们来更新w5的值:
(其中,是n学习速率,这里我们取0.5)同理,可更新w6,w7,w8:
3.隐含层---->隐含层的权值更新:方法其实与上面说的差不多,但是有个地方需要变一下,在上文计算总误差对w5的偏导时,是从out(o1)---->net(o1)---->w5,但是在隐含层之间的权值更新时,是out(h1)---->net(h1)---->w1,而out(h1)会接受E(o1)和E(o2)两个地方传来的误差,所以这个地方两个都要计算。
计算
先计算
同理,计算出:
两者相加得到总值:
再计算
再计算:
最后,三者相乘:
为了简化公式,用sigma(h1)表示隐含层单元h1的误差:
最后,更新w1的权值:
同理,额可更新w2,w3,w4的权值:
这样误差反向传播法就完成了,最后我们再把更新的权值重新计算,不停地迭代,在这个例子中第一次迭代之后,总误差E(total)由0.298371109下降至0.291027924。迭代10000次后,总误差为0.000035085,输出为[0.015912196,0.984065734]vs[0.01,0.99]),证明效果还是不错的。