上一篇将了复杂一点的例子,是神经网络的一个小部分的bp算法,而且求的是梯度上升。我们会将算法应用到一个标准的神经网络中,让我们看看真正的反向传播算法是什么样的!大家对神经网络需要了解的可以点击链接
Lets get started!!!
我们将引入神经网络最常见的激活函数sigmoid函数!一般放在最后一层是它的衍生softmax激活函数。我们bp算法也是从最后往前推算的。
实现这个单一神经元很简单
import numpy as np
def sigmoid(x):
return 1/(1+np.exp(-x))
a=-2
f=sigmoid(a)
print(f) #outputs 0.1192
接下来依旧是老套路,我们试着使输出值增加。首先我们 就要计算Sigmoid的函数的导数,根据微分的法则,我们可以求出,
a即等价于x,等价于f(a)
把输入的x等价换成a,再带入公式即可
然后,就可以得到更新变量的方程, h是学习率:
我们用python实现:
import numpy as np
def sigmoid(x):
return 1./(1+np.exp(-x))
def derivative_sigmoid(x):
return sigmoid(x) * (1 - sigmoid(x))
a = -2
h = 0.1
a = a + h * derivative_sigmoid(a)
f = sigmoid(a)
print(f) #outputs 0.1203
观察输出结果,0.1203比0.1192大.所以我们的算法成功将输出值增加!
=========================真正的好戏现在开始=============================
现在我们已经知道如何对一个复杂的函数的神经元进行反向传播,从而改变输出值!那么,接下来我们就将复杂函数放到一个嵌套的神经网络结构中,看看如何进行反向传播的计算:
这个神经网络的结构就是在前文的基础上增加了一个sigmoid函数!我们先用python实现它的正向传播
import numpy as np
def addition(x,y):
return x+y
def product(x, y):
return x * y
def sigmoid(x):
return 1 / (1 + np.exp( -x ))
a=1
b=-2
c=-3
d=addition(a,b)
e=product(c,d)
f=sigmoid(e)
print(f) #outputs 0.952574
现在我们开始计算反向传播,首先很明确的是,h是学习率,要进行反向传播,就得求得所要更新变量的微分:
所以我们需要的计算就是a,b,c三个变量的偏导数!具体的求解规则和前文一样就是倒着从输出往回推,看看经过了哪些神经元的计算,然后利用链式法则:
希望读者能独立推导出上述的公式!这里就体现了梯度是一层一层的累乘出来的。越往前,累乘越长。或者在该层的基础之上的往后一层再求一次偏导。这些梯度第一次整个bp完成之后,可以保存计算公式下来,以后就是带具体数字进公式计算而已。
得到上述微分的计算公式,我们就要开始实际计算这些微分值,不难求出
如果读者对此推导过程依旧有疑问,请重新阅读前两篇文章即能理解!
最后,就是编写程序来实现反向传播了!
import numpy as np
def addition(x, y):
return x + y
def product(x, y):
return x * y
def sigmoid(x):
return 1 / (1 + np.exp(-x))
def derivative_sigmoid(x):
return sigmoid(x) * (1 - sigmoid(x))
# initialization
a = 1
b = -2
c = -3
# forward-propogation
d = addition(a, b)
e = product(c, d)
# step size
h = 0.1
# derivatives
derivative_f_e = derivative_sigmoid(e)
derivative_e_d = c
derivative_e_c = d
derivative_d_a = 1
derivative_d_b = 1
# backward-propogation (Chain rule)
derivative_f_a = derivative_f_e * derivative_e_d * derivative_d_a
derivative_f_b = derivative_f_e * derivative_e_d * derivative_d_b
derivative_f_c = derivative_f_e * derivative_e_c
# update-parameters
a = a + h * derivative_f_a
b = b + h * derivative_f_b
c = c + h * derivative_f_c
d = addition(a, b)
e = product(c, d)
f = sigmoid(e)
print(f) # prints 0.9563
输出结果是0.9563比0.9525大,可以看到,经过一次反向传播,我们的输出值成功增加!
经过练习,我们可以发现,不管网络多复杂,无非是链式法则求导是复杂一些,只要我们能求出微分,就能进行反向传播!
原作者:六尺帐篷
链接:https://www.jianshu.com/p/1ba80e1ffe1e