cs231n-反向传播与神经网络

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u012931582/article/details/57414061

反向传播与神经网络

反向传播

上一节我们介绍了梯度下降法以及在线性分类器上的应用,并且介绍了两种求解方法,一个是数值梯度,另外一个是分析梯度,其中数值梯度计算量大但是准确,分析梯度通过求梯度的方法得到,计算量小,但是通常需要进行验证.

分析梯度可以应用到线性分类器上,因为损失函数形式比较简单,通常用一个数学表达式就可以表示,但是在神经网络这种含有多层神经元的比较复杂的形式,尤其是深度学习网络比如下图,那么损失函数就完全不能够用数学表达式进行表达了,那么进行分析梯度显然也是不可能的,所以需要一种新的方法取更新权值矩阵,在这里,我们将会介绍反向传播算法.

cnn

举一个例子,有一个函数如下所示:
f(x,y,z)=(x+y)z ,可以看出一共有三个输入,两个运算,一个加法一个乘法,可以把两个运算抽象成两个神经元, q=x+y 代表着加法运算, f=qz 代表乘法运算,现在要求f关于x,y,z的导数.
可以表示成如下图所示:
ff

链式法则可知, αfαx=αfαqαqαx

本例中,结果为-4:

x

一个神经元可以表示为下面的形式,其中绿色为前向的激励,红色为反向传播的梯度,用来权重调整:

neutral

还有一个比较复杂的例子,红色为梯度,绿色为输出,计算过程并不难,这里不再赘述:

fuza

其中一些操作可以合并,成为一个模块,比如,就是把一个Sigmoid模块化,导数的公式可以提前就计算出来.

model

反向传播实践

如果有以下函数:

has

先写代码实现forward:

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)

在实现时,创建了一些中间变量sigy, num, sigx, xpy, xpysqr, den, invden,这些都是简单的表达式。在反向传播时,在这些变量前面加上d表示梯度

# 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输入了两次);那么在反向传播时要使用+=来代替=。我们要累积梯度,使用=会覆盖掉前面计算好的梯度。

在实际计算的时候,输入和输出都是向量,所以如果进行求导的结果是一个雅克比矩阵,不过雅克比矩阵太庞大,所以实际不会求出完整的雅克比矩阵,比如下面的例子,雅克比矩阵就基本上是一个单位矩阵,只不过对角线上元素有的为0.

yakebi

猜你喜欢

转载自blog.csdn.net/u012931582/article/details/57414061