图解反向传播流程
如上图所示,前向传播为从输入计算到输出,反向传播从尾部开始,根据链式法则递归地向前计算梯度(显示为红色),一直到网络的输入端。可以认为,梯度是从计算链路中回流。
-
反向传播计算过程如下:
① \(\frac{\partial f}{\partial f}=1\)
② \(f=q*z\)
\(\frac{\partial f}{\partial z}=q=3\) ; \(\frac{\partial f}{\partial q}=z=-4\)
③ \(q=x+y\)
\(\frac{\partial f}{\partial x}=\frac{\partial f}{\partial q}*\frac{\partial q}{\partial x}=z*1=-4\) ; \(\frac{\partial f}{\partial y}=\frac{\partial f}{\partial q}*\frac{\partial q}{\partial y}=z*1=-4\)
-
Python代码实现
# 设置输入值
x = ‐2; y = 5; z = ‐4
# 进行前向传播
q = x + y # q becomes 3
f = q * z # f becomes ‐12
# 进行反向传播:
# 首先回传到 f = q * z
dfdz = q # df/dz = q, 所以关于z的梯度是3
dfdq = z # df/dq = z, 所以关于q的梯度是‐4
# 现在回传到q = x + y
dfdx = 1.0 * dfdq # dq/dx = 1. 这里的乘法是因为链式法则
dfdy = 1.0 * dfdq # dq/dy = 1
- 反向传播可以看做是门单元之间在通过梯度信号相互通信,只要让它们的输入沿着梯度方向变化,无论它们
自己的输出值在何种程度上升或降低,都是为了让整个网络的输出值更高。
门是相对随意的,任何可微分的函数都可以看做门。可以将多个门组合成一个门,也可以根据需要将一
个函数分拆成多个门。如下列表达式:
-
反向传播计算过程如下:
- [local gradient] x [upstream gradient]
① \(\frac{\partial f}{\partial f}=1\)
② \(f(x)=\frac{1}{x}\) \(\frac{\partial f}{\partial x}=-\frac{1}{x^2}=-\frac{1}{1.37^2}=-0.53\) \(-0.53*1=-0.53\)
③ \(f_7(x)=x+1\) $\frac{\partial f}{\partial x}=$1 \(1*(-0.53)=-0.53\)
④\(f_6(x)=e^x\) \(\frac{\partial f}{\partial x}=e^x=e^{-1}=0.37\) \(0.37*(-0.53)=-0.20\)
⑤\(f_5(x)=x*(-1)\) \(\frac{\partial f}{\partial x}=-1\) $ -1*(-0.20)=0.20$
⑥\(f_4(x)=f_3+w_2\) \(\frac{\partial f_4}{\partial f_3}=1\) \(1*0.20=0.20\)
\(\frac{\partial f_4}{\partial w_2}=1\) \(1*0.20=0.20\)
⑦\(f_3(x)=f_1+f_2\) \(\frac{\partial f_3}{\partial f_1}=1\) \(1*0.20=0.20\)
\(\frac{\partial f_3}{\partial f_2}=1\) \(1*0.20=0.20\)
⑧\(f_2(x)=w_0*x_0\) \(\frac{\partial f_2}{\partial w_0}=x_0=-1\) \((-1)*0.20=-0.20\)
\(\frac{\partial f_2}{\partial x_0}=w_0=2\) \(2*0.20=0.40\)
⑨ \(f_1(x)=w_1*x_1\) \(\frac{\partial f_1}{\partial w_1}=x_1=-2\) \((-2)*0.20=-0.40\)
\(\frac{\partial f_1}{\partial x_1}=w_1=-3\) \((-3)*0.20=-0.60\)
-
\(f_4\)到\(f\)之间的运算可以简化为sigmoid函数\(\sigma(x)\)
-
Python代码实现
为了使反向传播过程更加简洁,把向前传播分成不同的阶段将是很有帮助的。比如我们创建了一个中间变量dot,它装着w和x的点乘结果。在反向传播的时,就可以(反向地)计算出装着w和x等的梯度的对应的变量(比如ddot,dx和dw)。
w = [2,‐3,‐3] # 假设一些随机数据和权重
x = [‐1, ‐2]
# 前向传播
dot = w[0]*x[0] + w[1]*x[1] + w[2]
f = 1.0 / (1 + math.exp(‐dot)) # sigmoid函数
# 对神经元反向传播
ddot = (1 ‐ f) * f # 点积变量的梯度, 使用sigmoid函数求导
dx = [w[0] * ddot, w[1] * ddot] # 回传到x
dw = [x[0] * ddot, x[1] * ddot, 1.0 * ddot] # 回传到w
# 完成!得到输入的梯度
参考链接
【1】CS231n 课堂slider