# cs231n-(4)反向传播

## 简单表达式和解释梯度

f(x,y)=xyfx=yfy=x

f$\nabla f$表示偏导数向量，f=[fx,fy]=[y,x]$\nabla f = [\frac{\partial f}{\partial x}, \frac{\partial f}{\partial y}] = [y, x]$

f(x,y)=x+yfx=1fy=1

f(x,y)=max(x,y)fx=1(x>=y)fy=1(y>=x)

## 模块化：Sigmoid例子

f(w,x)=11+e(w0x0+w1x1+w2)

f(x)=1xdfdx=1/x2fc(x)=c+xdfdx=1f(x)=exdfdx=exfa(x)=axdfdx=a

sigmoid函数是常用的激活函数，对它的求导，计算如下

σ(x)=11+exdσ(x)dx=ex(1+ex)2=(1+ex11+ex)(11+ex)=(1σ(x))σ(x)

## 反向传播实践：分段计算

f(x,y)=x+σ(y)σ(x)+(x+y)2

x = 3 # example values
y = -4

# forward pass
sigy = 1.0 / (1 + math.exp(-y)) # sigmoid in numerator   #(1)
num = x + sigy # numerator                               #(2)
sigx = 1.0 / (1 + math.exp(-x)) # sigmoid in denominator #(3)
xpy = x + y                                              #(4)
xpysqr = xpy**2                                          #(5)
den = sigx + xpysqr # denominator                        #(6)
invden = 1.0 / den                                       #(7)
f = num * invden # done!                                 #(8)

# backprop f = num * invden
dnum = invden # gradient on numerator                             #(8)
dinvden = num                                                     #(8)
# backprop invden = 1.0 / den
dden = (-1.0 / (den**2)) * dinvden                                #(7)
# backprop den = sigx + xpysqr
dsigx = (1) * dden                                                #(6)
dxpysqr = (1) * dden                                              #(6)
# backprop xpysqr = xpy**2
dxpy = (2 * xpy) * dxpysqr                                        #(5)
# backprop xpy = x + y
dx = (1) * dxpy                                                   #(4)
dy = (1) * dxpy                                                   #(4)
# backprop sigx = 1.0 / (1 + math.exp(-x))
dx += ((1 - sigx) * sigx) * dsigx # Notice += !! See notes below  #(3)
# backprop num = x + sigy
dx += (1) * dnum                                                  #(2)
dsigy = (1) * dnum                                                #(2)
# backprop sigy = 1.0 / (1 + math.exp(-y))
dy += ((1 - sigy) * sigy) * dsigy                                 #(1)
# done! phew

1、对前向传播过程中的变量进行缓存，因为在反向传播时也会用到。
2、如果x,y$x,y$在前向传播时，使用了多次；那么在反向传播时要使用+=来代替=。我们要累积梯度，使用=会覆盖掉前面计算好的梯度。

## 方向传播流的模式

max:max算子是把梯度分到值比较大的一个单元。
mul:乘法是把梯度乘以一个值传到下一个门单元。f=xy$f=xy$，那么传到x$x$的梯度要乘以y$y$，同理y$y$的梯度。

## 向量化梯度操作

# forward pass
W = np.random.randn(5, 10)
X = np.random.randn(10, 3)
D = W.dot(X)

# now suppose we had the gradient on D from above in the circuit
dD = np.random.randn(*D.shape) # same shape as D
dW = dD.dot(X.T) #.T gives the transpose of the matrix
dX = W.T.dot(dD)

## 总结

1、对梯度有了直观理解，知道梯度如何在网络中传播，如何影响输出。
2、对梯度计算时，使用分段计算。把函数分为更小的模块，可以更好地计算梯度，使用链式法则得到最终梯度。

## 参考

Automatic differentiation in machine learning: a survey