【机器学习】P18 反向传播(导数、微积分、链式法则、前向传播、后向传播流程、神经网络)
反向传播
- 反向传播
- 反向传播中的数学
-
- 导数与python
- 链式法则
- 简单神经网络处理流程从而理解反向传播
-
- 神经网络与前向传播
- 神经网络与反向传播
反向传播
反向传播(back propagation)是一种用于训练神经网络的算法,其作用是计算神经网络中每个参数对损失函数的影响,从而进行参数更新,使得神经网络的预测结果更加准确。
具体来说,反向传播算法首先通过前向传播计算神经网络的预测结果,并与实际结果进行比较,得到损失函数的值。然后,反向传播算法计算每个参数对损失函数的影响,即参数的梯度。这些梯度可以告诉我们,在当前的参数取值下,将参数向梯度的相反方向移动可以减少损失函数的值。最后,通过梯度下降等优化算法,可以更新神经网络中的参数,使得损失函数的值逐渐减小,直到达到最小值。
上述涉及到两个主要公式:
-
损失函数公式:
J(w,b)=12m∑i=0m−1(fw,b(x(i))−y(i))J(w,b) = \\frac 1 {2m} \\sum _{i=0} ^{m-1} (f_{w,b}(x^{(i)})-y^{(i)})J(w,b)=2m1i=0∑m−1(fw,b(x(i))−y(i)) -
梯度下降公式:
{wj=wj−α∂J(w,b)∂wjb=b−α∂J(w,b)∂b\\begin{cases} w_j = w_j - \\alpha \\frac {\\partial J(w,b)} {\\partial w_j}\\\\ \\\\ b = b - \\alpha \\frac {\\partial J(w,b)} {\\partial b} \\end{cases} ⎩⎨⎧wj=wj−α∂wj∂J(w,b)b=b−α∂b∂J(w,b)
其中
{∂J(w,b)∂wj=1m∑i=0m−1(fw,b(x(i))−y(i))xj(i)∂J(w,b)∂b=1m∑i=0m−1(fw,b(x(i))−y(i))\\begin{cases} \\frac {\\partial J(w,b)} {\\partial w_j} = \\frac 1 m \\sum _{i=0} ^{m-1} (f_{w,b}(x^{(i)})-y^{(i)})x_j^{(i)}\\\\ \\\\ \\frac {\\partial J(w,b)} {\\partial b} = \\frac 1 m \\sum _{i=0} ^{m-1} (f_{w,b}(x^{(i)})-y^{(i)}) \\end{cases} ⎩⎨⎧∂wj∂J(w,b)=m1∑i=0m−1(fw,b(x(i))−y(i))xj(i)∂b∂J(w,b)=m1∑i=0m−1(fw,b(x(i))−y(i))
反向传播算法的作用是实现神经网络的自动学习。通过反向传播算法,神经网络可以从大量的训练样本中学习到数据的特征,并将这些特征表示为神经网络中的参数。这些参数可以在新的数据样本中进行预测,并且可以通过监督学习中的反向传播算法进行更新,以逐渐提高神经网络的预测准确率。
小结:
反向传播,目的就是为了实现神经网络的自动学习。
在整个优化模型参数的流程中,我们首先通过正向传播,得到预测值,通过损失函数公式计算损失值,通过反向传播算法可以计算每个神经元对损失函数的贡献,然后将这些贡献反向传播回网络中的每个神经元,从而确定每个神经元的梯度。然后可以使用梯度下降算法或其他优化算法来更新神经网络的参数,以最小化损失函数。这个过程就是通过反向传播计算梯度,再使用优化算法来更新模型参数的过程。
反向传播中的数学
反向传播用到了很多数学知识,最主要比如导数的计算以及微积分中的链式法则:
导数与python
e.g.1e.g.1e.g.1
求 ∂J(w)∂w\\frac {\\partial J(w)} {\\partial w}∂w∂J(w),J(w)=w2J(w) = w^2J(w)=w2
from sympy import symbols, diffJ, w = symbols('J,w')
J = w 2
dj_dw = diff(J,w)
print(dj_dw)
结果:
e.g.2e.g.2e.g.2
求 ∂J(w)∂w\\frac {\\partial J(w)} {\\partial w}∂w∂J(w),J(w)=1wJ(w) = \\frac 1 wJ(w)=w1
from sympy import symbols, diffJ, w = symbols('J,w')
J = 1/w
dj_dw = diff(J,w)
print(dj_dw)
结果:
e.g.3e.g.3e.g.3
求 ∂J(w)∂w\\frac {\\partial J(w)} {\\partial w}∂w∂J(w),J(w)=1w2J(w) = \\frac 1 {w^2}J(w)=w21
from sympy import symbols, diffJ, w = symbols('J,w')
J = 1/w2
dj_dw = diff(J,w)
print(dj_dw)
结果:
链式法则
假设我们有一个函数 f(x)f(x)f(x),即 f(x)=h(g(x))f(x) = h(g(x))f(x)=h(g(x)),其中:
- g(x)=2x+3g(x) = 2x + 3g(x)=2x+3
- h(y)=y3+5yh(y) = y^3 + 5yh(y)=y3+5y
现在我们想计算 f(x)f(x)f(x) 关于 xxx 的导数,即 dfdx\\frac {df} {dx}dxdf。
根据链式法则,有:
dfdx=dfdg∗dgdx\\frac {df} {dx} = \\frac {df} {dg} * \\frac {dg} {dx}dxdf=dgdf∗dxdg
其中,dfdg\\frac {df} {dg}dgdf 表示 fff 关于 ggg 的导数,dgdx\\frac {dg} {dx}dxdg 表示 ggg 关于 xxx 的导数。
-
首先计算 dfdg\\frac {df} {dg}dgdf。因为 f(x)=h(g(x))f(x) = h(g(x))f(x)=h(g(x)),所以:
dfdg=h′(g(x))=3∗g(x)2+5\\frac {df} {dg} = h'(g(x)) = 3*g(x)^2 + 5dgdf=h′(g(x))=3∗g(x)2+5 -
由 g(x)=2x+3g(x) = 2x+3g(x)=2x+3
dfdg=3∗(2x+3)2+5\\frac {df} {dg} = 3*(2x + 3)^2 + 5dgdf=3∗(2x+3)2+5 -
然后计算 dgdx\\frac {dg} {dx}dxdg。因为 g(x)=2x+3g(x) = 2x + 3g(x)=2x+3,所以
dgdx=2\\frac {dg} {dx} = 2dxdg=2 -
根据链式法则,有:
dfdx=dfdg∗dgdx=(3(2x+3)2+5)∗2=6(2x+3)2+10\\frac {df}{dx} = \\frac {df}{dg} * \\frac {dg} {dx} = (3(2x + 3)^2 + 5) * 2 = 6(2x+3)^2+10dxdf=dgdf∗dxdg=(3(2x+3)2+5)∗2=6(2x+3)2+10
因此,f(x)f(x)f(x) 关于 xxx 的导数为 6(2x+3)2+106(2x+3)^2+106(2x+3)2+10。
简单神经网络处理流程从而理解反向传播
神经网络与前向传播
一个简单的神经网路如上图,假定我们使用 ReLU 作为激活函数,
我们可以使用前向传播推出损失函数值
假设最初参数设定为:
- w[1]=2,b[1]=0w^{[1]}=2, b^{[1]} = 0w[1]=2,b[1]=0
- w[2]=3,b[2]=1w^{[2]}=3, b^{[2]}=1w[2]=3,b[2]=1
假定初始输入层值设定为:
- x=1x = 1x=1
- y=5y = 5y=5
根据神经网络计算公式,有:
a[1]=g(w[1]x+b[1])=g(2∗1+0)=2a^{[1]} = g(w^{[1]}x + b^{[1]})=g(2*1 + 0)=2a[1]=g(w[1]x+b[1])=g(2∗1+0)=2a[2]=g(w[2]a[1]+b[2])=g(3∗2+1)=7a^{[2]} = g(w^{[2]}a^{[1]} + b^{[2]})=g(3*2+1)=7a[2]=g(w[2]a[1]+b[2])=g(3∗2+1)=7
由实际值 y=5y = 5y=5 与预测值 a[2]=7a^{[2]}=7a[2]=7,得损失函数:
J(w,b)=12(a[2]−y)2=12(7−5)2=2J(w,b) = \\frac 1 2 (a^{[2]}-y)^2=\\frac 1 2 (7-5)^2=2J(w,b)=21(a[2]−y)2=21(7−5)2=2
我们可以将上述前向传播过程分解为如下步骤流程
到这里,稍微停顿一下,思考在神经网络中,我们的下一步要做什么?
反向传播,更新参数,从而使得预测值 a[2]=7a^{[2]}=7a[2]=7 更加趋近于实际值 y=5y=5y=5
神经网络与反向传播
神经网络
反向传播
梯度下降
链式法则
上述已经完成了前向传播的部分,我们剩下将使用反向传播方法,计算每个参数的梯度,然后使用梯度下降的方法更新参数。
其实到这里,我相信读者都记得这两个公式:
-
计算梯度的公式:
{∂J(w,b)∂wj=1m∑i=0m−1(fw,b(x(i))−y(i))xj(i)∂J(w,b)∂b=1m∑i=0m−1(fw,b(x(i))−y(i))\\begin{cases} \\frac {\\partial {J(w,b)}} {\\partial {w_j}} = \\frac 1 m \\sum _{i=0} ^{m-1} (f_{w,b}(x^{(i)})-y^{(i)})x_j^{(i)}\\\\ \\\\ \\frac {\\partial {J(w,b)}} {\\partial {b}} = \\frac 1 m \\sum _{i=0} ^{m-1} (f_{w,b}(x^{(i)})-y^{(i)}) \\end{cases} ⎩⎨⎧∂wj∂J(w,b)=m1∑i=0m−1(fw,b(x(i))−y(i))xj(i)∂b∂J(w,b)=m1∑i=0m−1(fw,b(x(i))−y(i)) -
更新参数公式:
{wj=wj−α∂J(w,b)∂wjb=b−α∂J(w,b)∂b\\begin{cases} w_j = w_j - \\alpha \\frac {\\partial {J(w,b)}} {\\partial w_j}\\\\ \\\\ b = b - \\alpha \\frac {\\partial {J(w,b)}} {\\partial b} \\end{cases} ⎩⎨⎧wj=wj−α∂wj∂J(w,b)b=b−α∂b∂J(w,b)
读者也都知道:
- 梯度下降目的是为了最小化损失函数;
- 在每个迭代步骤中,我们首先计算损失函数关于每个参数的梯度,然后根据梯度的方向和大小,调整参数的值,以使损失函数的值减少。这个过程会不断迭代,直到达到预定的停止条件;
- 反向传播更新神经网络参数;
- 链式法则是什么;
但是就是总感觉差点什么?画图来说:
其实就是少了一句非常重要的话:
- 梯度下降更新参数,只直接更新输出层参数,而隐藏层的参数,我们通过链式法则 “间接” 更新
在本案例中,我们存在一个隐藏层(且隐藏层中也只包含一个神经网络),一个输出层(输出层中只包含一个神经网络),即:
对于输出层参数 w[2],b[2]w^{[2]}, b^{[2]}w[2],b[2] 的更新,我们通过梯度下降直接更新:
- 计算梯度:
{∂J∂w[2]=(7−5)∗7=14∂J∂b[2]=7−5=2\\begin{cases} \\frac {\\partial {J}} {\\partial {w^{[2]}}} = (7-5)*7=14\\\\ \\\\ \\frac {\\partial {J}} {\\partial {b^{[2]}}} = 7-5=2 \\end{cases} ⎩⎨⎧∂w[2]∂J=(7−5)∗7=14∂b[2]∂J=7−5=2 - 更新参数:
{w[2]=w[2]−α∂J(w,b)∂w[2]=3−14∗αb[2]=b[2]−α∂J(w,b)∂b[2]=1−2∗α\\begin{cases} w^{[2]} = w^{[2]} - \\alpha \\frac {\\partial {J(w,b)}} {\\partial w^{[2]}} = 3-14*\\alpha\\\\ \\\\ b^{[2]} = b^{[2]} - \\alpha \\frac {\\partial {J(w,b)}} {\\partial b^{[2]}} = 1-2*\\alpha \\end{cases} ⎩⎨⎧w[2]=w[2]−α∂w[2]∂J(w,b)=3−14∗αb[2]=b[2]−α∂b[2]∂J(w,b)=1−2∗α
上述步骤就是通过梯度下降法,更新输出层参数 w[2]w^{[2]}w[2] 与 b[2]b^{[2]}b[2] 的步骤;
而对于隐藏层的参数 w[1],b[1]w^{[1]}, b^{[1]}w[1],b[1] 的更新,我们需要通过链式法则传递间接计算梯度,然后更新:
-
间接计算梯度:
{∂J∂w[1]=∂J∂a[2]∂a[2]∂a[1]∂a[1]∂w[1]∂J∂b[1]=∂J∂a[2]∂a[2]∂a[1]∂a[1]∂b[1]\\begin{cases} \\frac {\\partial {J}} {\\partial {w^{[1]}}} = \\frac {\\partial J} {\\partial a^{[2]}} \\frac {\\partial a^{[2]}} {\\partial a^{[1]}} \\frac {\\partial a^{[1]}} {\\partial w^{[1]}}\\\\ \\\\ \\frac {\\partial {J}} {\\partial {b^{[1]}}} = \\frac {\\partial J} {\\partial a^{[2]}} \\frac {\\partial a^{[2]}} {\\partial a^{[1]}} \\frac {\\partial a^{[1]}} {\\partial b^{[1]}} \\end{cases} ⎩⎨⎧∂w[1]∂J=∂a[2]∂J∂a[1]∂a[2]∂w[1]∂a[1]∂b[1]∂J=∂a[2]∂J∂a[1]∂a[2]∂b[1]∂a[1] -
由:
J=12(a[2]−y)2J = \\frac 1 2 (a^{[2]}-y)^2\\\\ J=21(a[2]−y)2a[2]=g(w[2]a[1]+b[2])a^{[2]} = g(w^{[2]}a^{[1]}+b^{[2]})\\\\ a[2]=g(w[2]a[1]+b[2])g(z)=max(0,z)(ReLU)g(z) = max(0,z)(ReLU)\\\\ g(z)=max(0,z)(ReLU)a[1]=g(w[1]x+b[1])a^{[1]} = g(w^{[1]}x+b^{[1]}) a[1]=g(w[1]x+b[1]) -
所以:
∂J∂a[2]=a[2]−y\\frac {\\partial J} {\\partial a^{[2]}} = a^{[2]}-y∂a[2]∂J=a[2]−y∂a[2]∂a[1]=w[2]\\frac {\\partial a^{[2]}} {\\partial a^{[1]}} = w^{[2]}∂a[1]∂a[2]=w[2]∂a[1]∂w[1]=x\\frac {\\partial a^{[1]}} {\\partial w^{[1]}} = x∂w[1]∂a[1]=x∂a[1]∂b[1]=1\\frac {\\partial a^{[1]}} {\\partial b^{[1]}} = 1∂b[1]∂a[1]=1 -
即:
∂J∂w[1]=∂J∂a[2]∂a[2]∂a[1]∂a[1]∂w[1]=(a[2]−y)∗w[2]∗x=(7−5)∗3∗1=6\\frac {\\partial {J}} {\\partial {w^{[1]}}} = \\frac {\\partial J} {\\partial a^{[2]}} \\frac {\\partial a^{[2]}} {\\partial a^{[1]}} \\frac {\\partial a^{[1]}} {\\partial w^{[1]}} = (a^{[2]}-y)*w^{[2]}*x = (7-5)*3*1=6∂w[1]∂J=∂a[2]∂J∂a[1]∂a[2]∂w[1]∂a[1]=(a[2]−y)∗w[2]∗x=(7−5)∗3∗1=6∂J∂b[1]=∂J∂a[2]∂a[2]∂a[1]∂a[1]∂b[1]=(a[2]−y)∗w[2]∗1=(7−5)∗3∗1=6\\frac {\\partial {J}} {\\partial {b^{[1]}}} = \\frac {\\partial J} {\\partial a^{[2]}} \\frac {\\partial a^{[2]}} {\\partial a^{[1]}} \\frac {\\partial a^{[1]}} {\\partial b^{[1]}} = (a^{[2]}-y)*w^{[2]}*1 = (7-5)*3*1=6∂b[1]∂J=∂a[2]∂J∂a[1]∂a[2]∂b[1]∂a[1]=(a[2]−y)∗w[2]∗1=(7−5)∗3∗1=6 -
修改参数值:
{w[1]=w[1]−α∂J(w,b)∂w[1]=2−6∗αb[1]=b[1]−α∂J(w,b)∂b[2]=0−6∗α\\begin{cases} w^{[1]} = w^{[1]} - \\alpha \\frac {\\partial {J(w,b)}} {\\partial w^{[1]}} = 2-6*\\alpha\\\\ \\\\ b^{[1]} = b^{[1]} - \\alpha \\frac {\\partial {J(w,b)}} {\\partial b^{[2]}} = 0-6*\\alpha \\end{cases} ⎩⎨⎧w[1]=w[1]−α∂w[1]∂J(w,b)=2−6∗αb[1]=b[1]−α∂b[2]∂J(w,b)=0−6∗α
上述过程就是通过链式法则,结合梯度下降法来更新参数 w[1]w^{[1]}w[1] 与 参数 b[1]b^{[1]}b[1] 的值;