线性的例子
z = x ⋅ y z = x \cdot y z=x⋅y
其中:
x = 2 w + 3 b x = 2w + 3b x=2w+3b
y = 2 b + 1 y = 2b + 1 y=2b+1
计算图如下:
注意这里x, y, z不是变量,只是计算结果。w, b是才变量。因为在后面要学习的神经网络中,我们要最终求解的是w和b的值,在这里先预热一下。
当w = 3, b = 4时,会得到如下结果
最终的z值,受到了前面很多因素的影响:变量w,变量b,计算式x,计算式y。常数是个定值,不考虑。
反向传播
目前的z=162,如果我们想让z变小一些,比如150,w和b应该如何变化呢?
如果想解决这个问题,我们可以在输入端一点一点的试,知道满意为止。现在,我们学习一个更好的解决办法:反向传播。
我们从z开始一层一层向回看,图中各节点关于变量b的偏导计算结果如下:
因 为 z = x ⋅ y , 其 中 x = 2 w + 3 b , y = 2 b + 1 因为z = x \cdot y,其中x = 2w + 3b,y = 2b + 1 因为z=x⋅y,其中x=2w+3b,y=2b+1
所以:
∂ z ∂ b = ∂ z ∂ x ⋅ ∂ x ∂ b + ∂ z ∂ y ⋅ ∂ y ∂ b = y ⋅ 3 + x ⋅ 2 = 9 ⋅ 3 + 18 ⋅ 2 = 63 \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=9 \cdot 3+18 \cdot 2=63 ∂b∂z=∂x∂z⋅∂b∂x+∂y∂z⋅∂b∂y=y⋅3+x⋅2=9⋅3+18⋅2=63
其中:
∂ z ∂ x = ∂ ∂ x ( x ⋅ y ) = y = 9 \frac{\partial{z}}{\partial{x}}=\frac{\partial{}}{\partial{x}}(x \cdot y)=y=9 ∂x∂z=∂x∂(x⋅y)=y=9 ∂ z ∂ y = ∂ ∂ y ( x ⋅ y ) = x = 18 \frac{\partial{z}}{\partial{y}}=\frac{\partial{}}{\partial{y}}(x \cdot y)=x=18 ∂y∂z=∂y∂(x⋅y)=x=18 ∂ x ∂ b = ∂ ∂ b ( 2 w + 3 b ) = 3 \frac{\partial{x}}{\partial{b}}=\frac{\partial{}}{\partial{b}}(2w+3b)=3 ∂b∂x=∂b∂(2w+3b)=3 ∂ y ∂ b = ∂ ∂ b ( 2 b + 1 ) = 2 \frac{\partial{y}}{\partial{b}}=\frac{\partial{}}{\partial{b}}(2b+1)=2 ∂b∂y=∂b∂(2b+1)=2
从上图可以看出,反向微分保留了所有变量(包括中间变量)对结果z的影响。若z为误差函数,则对图进行一次计算,可以得到所有节点对z的影响,即梯度值,下一步就可以利用这些梯度值来更新w和b的权重。
w的变化和b的变化,哪一个对z的变化贡献大?从图中还可以注意到:
∂ z ∂ b = 63 \frac{\partial{z}}{\partial{b}}=63 ∂b∂z=63
【课堂练习:推导z对w的偏导数】
所以每次w和b的变化对z的影响是不同的,b的变化会比w大很多。
反向传播的实际计算过程(单变量b)
还是用上面的例子,目前:
w
=
3
w = 3
w=3
b
=
4
b=4
b=4
x
=
2
w
+
3
b
=
18
x = 2w+3b = 18
x=2w+3b=18
y
=
2
b
+
1
=
9
y = 2b+1 = 9
y=2b+1=9
z
=
x
⋅
y
=
162
z = x \cdot y=162
z=x⋅y=162
假设我们最终的目的想让z = 150,只改变b的值,如何实现?
答案就是偏导数:
∂ z ∂ b = Δ z Δ b = 63 \frac{\partial{z}}{\partial{b}}=\frac{\Delta{z}}{\Delta{b}}=63 ∂b∂z=ΔbΔz=63
所以我们令 Δ z = 162 − 150 = 12 \Delta{z}=162-150=12 Δz=162−150=12(这里的减法实际就是损失函数的概念),则:
Δ z Δ b = 63 = 12 Δ b \frac{\Delta{z}}{\Delta{b}}=63=\frac{12}{\Delta{b}} ΔbΔz=63=Δb12
所以(这就是反向传播):
Δ b = 12 / 63 = 0.19 \Delta{b} = 12/63=0.19 Δb=12/63=0.19
再带入式子中(下面这个计算过程就叫做前向计算)
w
=
3
w = 3
w=3
b
=
4
−
0.19
=
3.81
b=4-0.19=3.81
b=4−0.19=3.81(梯度下降)
x
=
2
w
+
3
b
=
2
×
3
+
3
×
3.81
=
17.43
x=2w+3b=2 \times 3+3 \times 3.81=17.43
x=2w+3b=2×3+3×3.81=17.43
y
=
2
b
+
1
=
2
×
3.81
+
1
=
8.62
y = 2b+1 = 2 \times 3.81+1=8.62
y=2b+1=2×3.81+1=8.62
z
=
x
×
y
=
17.43
×
8.62
=
150.246
z = x \times y=17.43 \times 8.62=150.246
z=x×y=17.43×8.62=150.246
咦哈!十分接近150了!再迭代几次,应该可以近似等于150了,直到误差不大于1e-4时,我们就可以结束迭代了,对于计算机来说,这些运算的执行速度很快。
练习:请自己尝试手动继续迭代两次,看看误差的精度可以达到多少?
这个问题用数学公式倒推求解一个二次方程,就能直接得到准确的b值吗?是的!但是我们是要说明机器学习的方法,机器并不会解二次方程,而且很多时候不是用二次方程就能解决实际问题的。而上例所示,是用机器所擅长的迭代计算的方法来不断逼近真实解,这就是机器学习的真谛!而且这种方法是普遍适用的。
反向传播的实际计算过程(双变量)
这次我们要同时改变w和b,到达最终结果为150的目的。
已知 Δ z = 12 \Delta z=12 Δz=12,我们不妨把这个误差的一半算在w账上,另外一半算在b的账上:
Δ b = Δ z / 2 63 = 12 / 2 63 = 0.095 \Delta b=\frac{\Delta z / 2}{63} = \frac{12/2}{63}=0.095 Δb=63Δz/2=6312/2=0.095
Δ w = Δ z / 2 18 = 12 / 2 18 = 0.333 \Delta w=\frac{\Delta z / 2}{18} = \frac{12/2}{18}=0.333 Δw=18Δz/2=1812/2=0.333
w
=
w
−
Δ
w
=
3
−
0.333
=
2.667
w = w-\Delta w=3-0.333=2.667
w=w−Δw=3−0.333=2.667
b
=
b
−
Δ
b
=
4
−
0.095
=
3.905
b = b - \Delta b=4-0.095=3.905
b=b−Δb=4−0.095=3.905
x
=
2
w
+
3
b
=
2
×
2.667
+
3
×
3.905
=
17.049
x=2w+3b=2 \times 2.667+3 \times 3.905=17.049
x=2w+3b=2×2.667+3×3.905=17.049
y
=
2
b
+
1
=
2
×
3.905
+
1
=
8.81
y=2b+1=2 \times 3.905+1=8.81
y=2b+1=2×3.905+1=8.81
z
=
x
×
y
=
17.049
×
8.81
=
150.2
z=x \times y=17.049 \times 8.81=150.2
z=x×y=17.049×8.81=150.2
【课堂练习:用Python代码实现以上双变量的反向传播计算过程】
容易出现的问题:
在检查Δz时的值时,注意要用绝对值,因为有可能是个负数
在计算Δb和Δw时,第一次时,它们对z的贡献值分别是1/63和1/18,但是第二次时,由于b和w值的变化,对于z的贡献值也会有微小变化,所以要重新计算。具体解释如下:
∂
z
∂
b
=
∂
z
∂
x
⋅
∂
x
∂
b
+
∂
z
∂
y
⋅
∂
y
∂
b
=
y
⋅
3
+
x
⋅
2
=
3
y
+
2
x
\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
∂b∂z=∂x∂z⋅∂b∂x+∂y∂z⋅∂b∂y=y⋅3+x⋅2=3y+2x
∂
z
∂
w
=
∂
z
∂
x
⋅
∂
x
∂
w
+
∂
z
∂
y
⋅
∂
y
∂
w
=
y
⋅
2
+
x
⋅
0
=
2
y
\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
∂w∂z=∂x∂z⋅∂w∂x+∂y∂z⋅∂w∂y=y⋅2+x⋅0=2y 所以,在每次迭代中,要重新计算下面两个值:
Δ
b
=
Δ
z
3
y
+
2
x
\Delta b=\frac{\Delta z}{3y+2x}
Δb=3y+2xΔz
Δ
w
=
Δ
z
2
y
\Delta w=\frac{\Delta z}{2y}
Δw=2yΔz
以下是程序的运行结果。
没有在迭代中重新计算Δ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
从以上两个结果对比中,可以看到三点:
factor_b第一次是63,以后每次都会略微降低一些
第二个函数迭代了3次就结束了,而第一个函数迭代了5次,效率不一样
最后得到的结果是一样的,因为这个问题只有一个解
对于双变量的迭代,有同样的问题:
没有在迭代中重新计算Δ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
这个与第一个单变量迭代不同的地方是:这个问题可以有多个解,所以两种方式都可以得到各自的正确解,但是第二种方式效率高,而且满足梯度下降的概念。
https://github.com/microsoft/ai-edu/blob/master/B-教学案例与实践/B6-神经网络基本原理简明教程/02.1-线性反向传播.md