系列博客,原文在笔者所维护的github上:https://aka.ms/beginnerAI,
点击star加星不要吝啬,星越多笔者越努力。python
这三大概念是:反向传播,梯度降低,损失函数。git
神经网络训练的最基本的思想就是:先“猜”一个结果,咱们叫预测结果a,看看这个预测结果和事先标记好的训练集中的真实结果y之间的差距,而后调整策略,再试一次,这一次就不是“猜”了,而是有依据地向正确的方向靠近。如此反复屡次,一直到预测结果和真实结果之间相差无几,亦即|a-y|->0,就结束训练。github
在神经网络训练中,咱们把“猜”叫作初始化,能够随机,也能够根据之前的经验给定初始值。即便是“猜”,也是有技术含量的。安全
这三个概念是先后紧密相连的,讲到一个,确定会牵涉到另一个。但因为损失函数篇幅较大,咱们将在下一章中再详细介绍。网络
下面咱们举几个例子来直观的说明下这三个概念。机器学习
甲乙两我的玩儿猜数的游戏,数字的范围是[1,50]:函数
甲:我猜5post
乙:过小了学习
甲:50spa
乙:有点儿大
甲:30
乙:小了
......
在这个游戏里:
这里的损失函数是什么呢?就是“过小了”,“有点儿大”,很不精确!这个“所谓的”损失函数给出了两个信息:
假设有一个黑盒子如图2-1。
图2-1 黑盒子
咱们只能看到输入和输出的数值,看不到里面的样子,当输入1时,输出2.334,而后黑盒子有个信息显示:我须要输出值是4。而后咱们试了试输入2,结果输出5.332,一会儿比4大了不少。那么咱们第一次的损失值是\(2.334-4=-1.666\),而二次的损失值是\(5.332-4=1.332\)。
这里,咱们的损失函数就是一个简单的减法,用实际值减去目标值,可是它能够告诉你两个信息:1)方向,是大了仍是小了;2)差值,是0.1仍是1.1。这样就给了咱们下一次猜的依据。
小明拿了一支步枪,射击100米外的靶子。这支步枪没有准星,或者是准星有问题,或者是小明眼神儿很差看不清靶子,或者是雾很大,或者风很大,或者因为木星的影响而侧向引力场异常......反正就是遇到各类干扰因素。
第一次试枪后,拉回靶子一看,弹着点偏左了,因而在第二次试枪时,小明就会有意识地向右侧偏几毫米,再看靶子上的弹着点,如此反复几回,小明就会掌握这支步枪的脾气了。图2-2显示了小明的5次试枪过程。
图2-2 打靶的弹着点记录
在有监督的学习中,须要衡量神经网络输出和所预期的输出之间的差别大小。这种偏差函数须要可以反映出当前网络输出和实际结果之间一种量化以后的不一致程度,也就是说函数值越大,反映出模型预测的结果越不许确。
这个例子中,小明预期的目标是所有命中靶子的中心,最外圈是1分,以后越向靶子中心分数是2,3,4分,正中靶心能够得10分。
上图是每次单发点射,因此每次训练样本的个数是1。在实际的神经网络训练中,一般须要多个样本,作批量训练,以免单个样本自己采样时带来的偏差。在本例中,多个样本能够描述为连发射击,假设一次能够连打3发子弹,每次的离散程度都相似,如图2-3所示。
图2-3 连发弹着点记录
那小明每次射击结果和目标之间的差距是多少呢?在这个例子里面,用得分来衡量的话,就是说小明获得的反馈结果从差9分,到差8分,到差2分,到差1分,到差0分,这就是用一种量化的结果来表示小明的射击结果和目标之间差距的方式。也就是偏差函数的做用。由于是一次只有一个样本,因此这里采用的是偏差函数的称呼。若是一次有多个样本,就要叫作损失函数了。
其实射击还不这么简单,若是是远距离狙击,还要考虑空气阻力和风速,在神经网络里,空气阻力和风速能够对应到隐藏层的概念上。
在这个例子中:
损失函数的描述是这样的:
这里的损失函数也有两个信息:
因此,梯度,是个矢量! 它应该即告诉咱们方向,又告诉咱们数值。
以上三个例子比较简单,容易理解,咱们把黑盒子再请出来:黑盒子这件事真正的意义并非猜想当输入是多少时输出会是4。它的实际意义是:咱们要破解这个黑盒子!因而,咱们会有以下破解流程:
表2-1 样本数据表
样本ID | 输入(特征值) | 输出(标签) |
---|---|---|
1 | 1 | 2.21 |
2 | 1.1 | 2.431 |
3 | 1.2 | 2.652 |
4 | 2 | 4.42 |
从上面的过程能够看出,若是偏差值是正数,咱们就把权重下降一些;若是偏差值为负数,则升高权重。
简单总结一下反向传播与梯度降低的基本工做原理:
系列博客,原文在笔者所维护的github上:https://aka.ms/beginnerAI,
点击star加星不要吝啬,星越多笔者越努力。
假设咱们有一个函数:
\[z = x \cdot y \tag{1}\]
其中:
\[x = 2w + 3b \tag{2}\]
\[y = 2b + 1 \tag{3}\]
计算图如图2-4。
图2-4 简单线性计算的计算图
注意这里x, y, z不是变量,只是计算结果。w, b是才变量。由于在后面要学习的神经网络中,咱们要最终求解的是w和b的值,在这里先预热一下。
当w = 3, b = 4时,会获得图2-5的结果。
图2-5 计算结果
最终的z值,受到了前面不少因素的影响:变量w,变量b,计算式x,计算式y。常数是个定值,不考虑。
目前的z=162,若是咱们想让z变小一些,好比目标是z=150,w应该如何变化呢?为了简化问题,咱们先只考虑改变w的值,而令b值固定为4。
若是想解决这个问题,咱们能够在输入端一点一点的试,把w变成4试试,再变成3.5试试......直到满意为止。如今咱们将要学习一个更好的解决办法:反向传播。
咱们从z开始一层一层向回看,图中各节点关于变量w的偏导计算结果以下:
\[由于z = x \cdot y,其中x = 2w + 3b,y = 2b + 1\]
因此:
\[\frac{\partial{z}}{\partial{w}}=\frac{\partial{z}}{\partial{x}} \cdot \frac{\partial{x}}{\partial{w}}=y \cdot 2=18 \tag{4}\]
其中:
\[\frac{\partial{z}}{\partial{x}}=\frac{\partial{}}{\partial{x}}(x \cdot y)=y=9\]
\[\frac{\partial{x}}{\partial{w}}=\frac{\partial{}}{\partial{w}}(2w+3b)=2\]
图2-6 对w的偏导求解过程
图2-6其实就是链式法则的具体表现,z的偏差经过中间的x传递到w。若是不是用链式法则,而是直接用z的表达式计算对w的偏导数,会是什么样呢?咱们来试验一下。
根据公式一、二、3,咱们有:
\[z=x \cdot y=(2w+3b)(2b+1)=4wb+2w+6b^2+3b \tag{5}\]
对上式求w的偏导:
\[ {\partial z \over \partial w}=4b+2=4 \cdot 4 + 2=18 \tag{6} \]
公式4和公式6的结果彻底一致!因此,请你们相信链式法则的科学性。
公式4和公式6的含义是:当w变化一点点时,z会发生w的变化值的18倍的变化。记住咱们的目标是让z=150,目前在初始状态时是162,因此,问题转化为:当咱们须要z从162变到150时,w须要变化多少?
既然:
\[ \Delta z = 18 \cdot \Delta w \]
则:
\[ \Delta w = {\Delta z \over 18}={162-150 \over 18}= 0.6667 \]
因此:
\[w = w - 0.6667=2.3333\]
\[x=2w+3b=16.6667\]
\[z=x \cdot y=16.6667 \times 9=150.0003\]
咱们一会儿就成功地让z值变成了150.0003,与150的目标很是地接近,这就是偏导数的威力所在。
此次咱们令w的值固定为3,变化b的值,目标仍是让z=150。同上一小节同样,先求b的偏导数。
注意,在上一小节中,求w的导数只通过了一条路:从z到x到w。可是求b的导数时要通过两条路,如图2-7所示:
图2-7 对b的偏导求解过程
从复合导数公式来看,这二者应该是相加的关系,因此有:
\[\frac{\partial{z}}{\partial{b}}=\frac{\partial{z}}{\partial{x}} \cdot \frac{\partial{x}}{\partial{b}}+\frac{\partial{z}}{\partial{y}}\cdot\frac{\partial{y}}{\partial{b}}=y \cdot 3+x \cdot 2=63 \tag{7}\]
其中:
\[\frac{\partial{z}}{\partial{x}}=\frac{\partial{}}{\partial{x}}(x \cdot y)=y=9\]
\[\frac{\partial{z}}{\partial{y}}=\frac{\partial{}}{\partial{y}}(x \cdot y)=x=18\]
\[\frac{\partial{x}}{\partial{b}}=\frac{\partial{}}{\partial{b}}(2w+3b)=3\]
\[\frac{\partial{y}}{\partial{b}}=\frac{\partial{}}{\partial{b}}(2b+1)=2\]
咱们不妨再验证一下链式求导的正确性。把公式5再拿过来:
\[z=x \cdot y=(2w+3b)(2b+1)=4wb+2w+6b^2+3b \tag{5}\]
对上式求b的偏导:
\[ {\partial z \over \partial b}=4w+12b+3=12+48+3=63 \tag{8} \]
结果和公式7的链式法则同样。
公式7和公式8的含义是:当b变化一点点时,z会发生b的变化值的63倍的变化。记住咱们的目标是让z=150,目前在初始状态时是162,因此,问题转化为:当咱们须要z从162变到150时,b须要变化多少?
既然:
\[\Delta z = 63 \cdot \Delta b\]
则:
\[ \Delta b = {\Delta z \over 63}={162-150 \over 63}=0.1905 \]
因此:
\[ b=b-0.1905=3.8095 \]
\[x=2w+3b=17.4285\]
\[y=2b+1=8.619\]
\[z=x \cdot y=17.4285 \times 8.619=150.2162\]
这个结果也是与150很接近了,可是精度还不够。再迭代几回,应该能够近似等于150了,直到偏差不大于1e-4时,咱们就能够结束迭代了,对于计算机来讲,这些运算的执行速度很快。
这个问题用数学公式倒推求解一个二次方程,就能直接获得准确的b值吗?是的!可是咱们是要说明机器学习的方法,机器并不会解二次方程,并且不少时候不是用二次方程就能解决实际问题的。而上例所示,是用机器所擅长的迭代计算的方法来不断逼近真实解,这就是机器学习的真谛!并且这种方法是广泛适用的。
此次咱们要同时改变w和b,到达最终结果为z=150的目的。
已知\(\Delta z=12\),咱们不妨把这个偏差的一半算在w帐上,另一半算在b的帐上:
\[\Delta b=\frac{\Delta z / 2}{63} = \frac{12/2}{63}=0.095\]
\[\Delta w=\frac{\Delta z / 2}{18} = \frac{12/2}{18}=0.333\]
容易出现的问题:
\[ \frac{\partial{z}}{\partial{b}}=\frac{\partial{z}}{\partial{x}} \cdot \frac{\partial{x}}{\partial{b}}+\frac{\partial{z}}{\partial{y}}\cdot\frac{\partial{y}}{\partial{b}}=y \cdot 3+x \cdot 2=3y+2x \]
\[ \frac{\partial{z}}{\partial{w}}=\frac{\partial{z}}{\partial{x}} \cdot \frac{\partial{x}}{\partial{w}}+\frac{\partial{z}}{\partial{y}}\cdot\frac{\partial{y}}{\partial{w}}=y \cdot 2+x \cdot 0 = 2y \]
因此,在每次迭代中,要从新计算下面两个值:
\[ \Delta b=\frac{\Delta z}{3y+2x} \]
\[ \Delta w=\frac{\Delta z}{2y} \]
如下是程序的运行结果。
没有在迭代中从新计算Δb的贡献值:
single variable: b ----- w=3.000000,b=4.000000,z=162.000000,delta_z=12.000000 delta_b=0.190476 w=3.000000,b=3.809524,z=150.217687,delta_z=0.217687 delta_b=0.003455 w=3.000000,b=3.806068,z=150.007970,delta_z=0.007970 delta_b=0.000127 w=3.000000,b=3.805942,z=150.000294,delta_z=0.000294 delta_b=0.000005 w=3.000000,b=3.805937,z=150.000011,delta_z=0.000011 delta_b=0.000000 w=3.000000,b=3.805937,z=150.000000,delta_z=0.000000 done! final b=3.805937
在每次迭代中都从新计算Δb的贡献值:
single variable new: b ----- w=3.000000,b=4.000000,z=162.000000,delta_z=12.000000 factor_b=63.000000, delta_b=0.190476 w=3.000000,b=3.809524,z=150.217687,delta_z=0.217687 factor_b=60.714286, delta_b=0.003585 w=3.000000,b=3.805938,z=150.000077,delta_z=0.000077 factor_b=60.671261, delta_b=0.000001 w=3.000000,b=3.805937,z=150.000000,delta_z=0.000000 done! final b=3.805937
从以上两个结果对比中,能够看到三点:
对于双变量的迭代,有一样的问题:
没有在迭代中从新计算Δb,Δw的贡献值(factor_b和factor_w每次都保持63和18):
double variable: w, b ----- w=3.000000,b=4.000000,z=162.000000,delta_z=12.000000 delta_b=0.095238, delta_w=0.333333 w=2.666667,b=3.904762,z=150.181406,delta_z=0.181406 delta_b=0.001440, delta_w=0.005039 w=2.661628,b=3.903322,z=150.005526,delta_z=0.005526 delta_b=0.000044, delta_w=0.000154 w=2.661474,b=3.903278,z=150.000170,delta_z=0.000170 delta_b=0.000001, delta_w=0.000005 w=2.661469,b=3.903277,z=150.000005,delta_z=0.000005 done! final b=3.903277 final w=2.661469
在每次迭代中都从新计算Δb,Δw的贡献值(factor_b和factor_w每次都变化):
double variable new: w, b ----- w=3.000000,b=4.000000,z=162.000000,delta_z=12.000000 factor_b=63.000000, factor_w=18.000000, delta_b=0.095238, delta_w=0.333333 w=2.666667,b=3.904762,z=150.181406,delta_z=0.181406 factor_b=60.523810, factor_w=17.619048, delta_b=0.001499, delta_w=0.005148 w=2.661519,b=3.903263,z=150.000044,delta_z=0.000044 factor_b=60.485234, factor_w=17.613053, delta_b=0.000000, delta_w=0.000001 w=2.661517,b=3.903263,z=150.000000,delta_z=0.000000 done! final b=3.903263 final w=2.661517
这个与第一个单变量迭代不一样的地方是:这个问题能够有多个解,因此两种方式均可以获得各自的正确解,可是第二种方式效率高,并且知足梯度降低的概念。
http://colah.github.io/posts/2015-08-Backprop/
ch02, Level1
系列博客,原文在笔者所维护的github上:https://aka.ms/beginnerAI,
点击star加星不要吝啬,星越多笔者越努力。
在上面的线性例子中,咱们能够发现,偏差一次性地传递给了初始值w和b,即,只通过一步,直接修改w和b的值,就能作到偏差校订。由于从它的计算图看,不管中间计算过程有多么复杂,它都是线性的,因此能够一次传到底。缺点是这种线性的组合最多只能解决线性问题,不能解决更复杂的问题。这个咱们在神经网络基本原理中已经阐述过了,须要有激活函数链接两个线性单元。
下面咱们看一个非线性的例子,如图2-8所示。
图2-8 非线性的反向传播
其中\(1<x<=10,0<y<2.15\)。假设有5我的分别表明x、a、b、c、y:
提出问题:假设咱们想最后获得c=2.13的值,x应该是多少?(偏差小于0.001便可)
\[c=\sqrt{b}=\sqrt{\ln(a)}=\sqrt{\ln(x^2)}=2.13\]
\[x = 9.6653\]
\[ \frac{da}{dx}=\frac{d(x^2)}{dx}=2x=\frac{\Delta a}{\Delta x} \tag{1} \]
\[ \frac{db}{da} =\frac{d(\ln{a})}{da} =\frac{1}{a} = \frac{\Delta b}{\Delta a} \tag{2} \]
\[ \frac{dc}{db}=\frac{d(\sqrt{b})}{db}=\frac{1}{2\sqrt{b}}=\frac{\Delta c}{\Delta b} \tag{3} \]
所以获得以下一组公式,能够把最后一层\(\Delta c\)的偏差一直反向传播给最前面的\(\Delta x\),从而更新x值:
\[ \Delta c = c - y \tag{4} \]
\[ \Delta b = \Delta c \cdot 2\sqrt{b} \tag{根据式3} \]
\[ \Delta a = \Delta b \cdot a \tag{根据式2} \]
\[ \Delta x = \Delta a / 2x \tag{根据式1} \]
咱们给定初始值\(x=2,\Delta x=0\),依次计算结果如表2-2。
表2-2 正向与反向的迭代计算
方向 | 公式 | 迭代1 | 迭代2 | 迭代3 | 迭代4 | 迭代5 |
---|---|---|---|---|---|---|
正向 | \(x=x-\Delta x\) | 2 | 4.243 | 7.344 | 9.295 | 9.665 |
正向 | \(a=x^2\) | 4 | 18.005 | 53.934 | 86.404 | 93.233 |
正向 | \(b=\ln(a)\) | 1.386 | 2.891 | 3.988 | 4.459 | 4.535 |
正向 | \(c=\sqrt{b}\) | 1.177 | 1.700 | 1.997 | 2.112 | 2.129 |
标签值y | 2.13 | 2.13 | 2.13 | 2.13 | 2.13 | |
反向 | \(\Delta c = c - y\) | -0.953 | -0.430 | -0.133 | -0.018 | |
反向 | \(\Delta b = \Delta c \cdot 2\sqrt{b}\) | -2.243 | -1.462 | -0.531 | -0.078 | |
反向 | \(\Delta a = \Delta b \cdot a\) | -8.973 | -26.317 | -28.662 | -6.698 | |
反向 | \(\Delta x = \Delta a / 2x\) | -2.243 | -3.101 | -1.951 | -0.360 |
表2-2,先看“迭代-1”列,从上到下是一个完整的正向+反向的过程,最后一行是-2.243,回到“迭代-2”列的第一行,2-(-2.243)=4.243,而后继续向下。到第5轮时,正向计算获得的c=2.129,很是接近2.13了,迭代结束。
运行示例代码的话,能够获得以下结果:
how to play: 1) input x, 2) calculate c, 3) input target number but not faraway from c input x as initial number(1.2,10), you can try 1.3: 2 c=1.177410 input y as target number(0.5,2), you can try 1.8: 2.13 forward... x=2.000000,a=4.000000,b=1.386294,c=1.177410 backward... delta_c=-0.952590, delta_b=-2.243178, delta_a=-8.972712, delta_x=-2.243178 ...... forward... x=9.655706,a=93.232666,b=4.535098,c=2.129577 backward... done!
为节省篇幅只列出了第一步和最后一步(第5步)的结果,第一步时c=1.177410,最后一步时c=2.129577,中止迭代。
ch02, Level2
系列博客,原文在笔者所维护的github上:https://aka.ms/beginnerAI,
点击star加星不要吝啬,星越多笔者越努力。
在大多数文章中,都以“一我的被困在山上,须要迅速下到谷底”来举例,这我的会“寻找当前所处位置最陡峭的地方向下走”。这个例子中忽略了安全因素,这我的不可能沿着最陡峭的方向走,要考虑坡度。
在天然界中,梯度降低的最好例子,就是泉水下山的过程:
梯度降低的数学公式:
\[\theta_{n+1} = \theta_{n} - \eta \cdot \nabla J(\theta) \tag{1}\]
其中:
“梯度降低”包含了两层含义:
亦即与上升相反的方向运动,就是降低。
图2-9 梯度降低的步骤
图2-9解释了在函数极值点的两侧作梯度降低的计算过程,梯度降低的目的就是使得x值向极值点逼近。
假设一个单变量函数:
\[J(x) = x ^2\]
咱们的目的是找到该函数的最小值,因而计算其微分:
\[J'(x) = 2x\]
假设初始位置为:
\[x_0=1.2\]
假设学习率:
\[\eta = 0.3\]
根据公式(1),迭代公式:
\[x_{n+1} = x_{n} - \eta \cdot \nabla J(x)= x_{n} - \eta \cdot 2x\tag{1}\]
假设终止条件为J(x)<1e-2,迭代过程是:
x=0.480000, y=0.230400 x=0.192000, y=0.036864 x=0.076800, y=0.005898 x=0.030720, y=0.000944
上面的过程如图2-10所示。
图2-10 使用梯度降低法迭代的过程
假设一个双变量函数:
\[J(x,y) = x^2 + \sin^2(y)\]
咱们的目的是找到该函数的最小值,因而计算其微分:
\[{\partial{J(x,y)} \over \partial{x}} = 2x\]
\[{\partial{J(x,y)} \over \partial{y}} = 2 \sin y \cos y\]
假设初始位置为:
\[(x_0,y_0)=(3,1)\]
假设学习率:
\[\eta = 0.1\]
根据公式(1),迭代过程是的计算公式:
\[(x_{n+1},y_{n+1}) = (x_n,y_n) - \eta \cdot \nabla J(x,y)\]
\[ = (x_n,y_n) - \eta \cdot (2x,2 \cdot \sin y \cdot \cos y) \tag{1}\]
根据公式(1),假设终止条件为\(J(x,y)<1e-2\),迭代过程如表2-3所示。
表2-3 双变量梯度降低的迭代过程
迭代次数 | x | y | J(x,y) |
---|---|---|---|
1 | 3 | 1 | 9.708073 |
2 | 2.4 | 0.909070 | 6.382415 |
... | ... | ... | ... |
15 | 0.105553 | 0.063481 | 0.015166 |
16 | 0.084442 | 0.050819 | 0.009711 |
迭代16次后,J(x,y)的值为0.009711,知足小于1e-2的条件,中止迭代。
上面的过程如表2-4所示,因为是双变量,因此须要用三维图来解释。请注意看两张图中间那条隐隐的黑色线,表示梯度降低的过程,从红色的高地一直沿着坡度向下走,直到蓝色的洼地。
表2-4 在三维空间内的梯度降低过程
观察角度1 | 观察角度2 |
---|---|
![]() |
![]() |
在公式表达时,学习率被表示为\(\eta\)。在代码里,咱们把学习率定义为learning_rate,或者eta。针对上面的例子,试验不一样的学习率对迭代状况的影响,如表2-5所示。
表2-5 不一样学习率对迭代状况的影响
学习率 | 迭代路线图 | 说明 |
---|---|---|
1.0 | ![]() |
学习率太大,迭代的状况很糟糕,在一条水平线上跳来跳去,永远也不能降低。 |
0.8 | ![]() |
学习率大,会有这种左右跳跃的状况发生,这不利于神经网络的训练。 |
0.4 | ![]() |
学习率合适,损失值会从单侧降低,4步之后基本接近了理想值。 |
0.1 | ![]() |
学习率较小,损失值会从单侧降低,但降低速度很是慢,10步了尚未到达理想状态。 |
ch02, Level3, Level4, Level5