代码和文档在:https://github.com/nicktming/code/tree/dev/machine_learning/backpropagation
前言
继上篇用代码一步步理解梯度下降和神经网络(ANN)),今天这篇的目的主要是通过一个例子来理解反向传播是怎么一回事?
复习
前文中已经分析过了单层神经网络(没有隐藏层)的时候如何通过梯度下降法改变参数来使得最终定义的
cost_function
越来越小.
单层的时候或许比较好理解,毕竟直接求导就可以求出
cost_function
关于每个参数的偏导,对于多层的时候,面对那么每一层的每个参数,他们是如何往回传递错误信息的?如果每次都要从头到晚求一遍?是不是很麻烦?想到这里估计脑子就有点乱了,而且直接看公式也不是那么好明白.
所以我先给出答案哈,改变每一层的参数,都是需要求出
cost_function
关于每一层每个参数的偏导的,因为这样我才知道你对cost_function
的影响有多大?如果你有点看不懂我这里说的,建议先看一下我的前一篇文章用代码一步步理解梯度下降和神经网络(ANN)).至于要怎么求出来的,首先肯定不是从头到晚又求一次,我们先不看公式,先通过自己写的一个例子来看看到底是怎么一个情况?(我高中数学老师的一句话:如果看不懂,那么就把抽象问题具体化,通俗一点就是用例子)
例子: 2-layer ANN
图中是一个2层的神经网络,和数组的定义
激励函数采用sigmoid
,cost_function
采用最小平方
前向传递forward
对应代码
# training samples 2 inputs and 2 outputs
X = np.random.rand(m, 2)
Y = np.random.rand(m, 2)
#layer 2
W2 = np.ones((2, 3))
b2 = np.ones((1, 3))
in2 = np.dot(X, W2) + b2
out2 = sigmoid(in2)
#layer 3
W3 = np.ones((3, 2))
b3 = np.ones((1, 2))
in3 = np.dot(out2, W3) + b3
out3 = sigmoid(in3)
#initial cost
cost = cost_function(out3, Y)
print("start:", cost)
反向传播
反向传播主要是求导,求
cost_function
关于各个参数的偏导.
先解释一件事情,为什么求参数的偏导,上面求的是
cost_function
关于in
的偏导呢?你可以看一下前向传播中的in
的公式,如果我们求出了cost_function
关于in
的偏导,就可以cost_function
求出任意参数的偏导.
那既然我们已经确定了
cost_function
对in
偏导的作用,那你观察上面的in2
和in3
之间的关联,in2
是如何通过in3
可以求出来的.
在得到
in2
和in3
的关系了后,明显在所有隐藏层中都可以运用这个公式.自然而然输出层的in3
是第一步需要求的,因为后面所有隐藏层是依赖于上一层的cost_function
对in
偏导.
在明白了如何求得
cost_function
对in
偏导后,可以根据in
的前向传递公式就可以求得关于此层中in
关于参数的偏导进而就可以得到cost_function
关于这个参数的偏导,用矩阵表达式就是上图中的公式.
对应代码:
derivative_c_out3 = np.subtract(out3, Y) / m
derivative_out3_in3 = derivative_sigmoid(in3)
derivative_c_in3 = np.multiply(derivative_c_out3, derivative_out3_in3)
#find derivative of cost function to W3 and b3 in layer3
dw3 = np.dot(out2.T, derivative_c_in3)
db3 = np.sum(derivative_c_in3, axis=0)
#find derivative of cost function to in2 in layer2
derivative_out2_in2 = derivative_sigmoid(in2)
derivative_c_in2 = np.multiply(np.dot(derivative_c_in3, W3.T), derivative_out2_in2)
#find derivative of cost function to W2 and b2 in layer2
dw2 = np.dot(X.T, derivative_c_in2)
db2 = np.sum(derivative_c_in2, axis=0)
#update all variables
W3 = W3 - step * dw3
W2 = W2 - step * dw2
b3 = b3 - step * db3
b2 = b2 - step * db2
整体代码
目标是让
cost_function
的值小于0.1
import numpy as np
def sigmoid(x):
return 1/(1+np.exp(-x))
def derivative_sigmoid(x):
return np.multiply(1 - sigmoid(x), sigmoid(x))
def cost_function(yo, Y):
return 1./(2*m) * np.sum(np.square(np.subtract(yo, Y)))
#num of samples and learning rate
m = 10
step = 0.01
# training samples 2 inputs and 2 outputs
X = np.random.rand(m, 2)
Y = np.random.rand(m, 2)
#layer 2
W2 = np.ones((2, 3))
b2 = np.ones((1, 3))
in2 = np.dot(X, W2) + b2
out2 = sigmoid(in2)
#layer 3
W3 = np.ones((3, 2))
b3 = np.ones((1, 2))
in3 = np.dot(out2, W3) + b3
out3 = sigmoid(in3)
#initial cost
cost = cost_function(out3, Y)
print("start:", cost)
cnt = 0;
while not cost < 0.1 :
#find derivative of cost function to in2 in layer3
derivative_c_out3 = np.subtract(out3, Y) / m
derivative_out3_in3 = derivative_sigmoid(in3)
derivative_c_in3 = np.multiply(derivative_c_out3, derivative_out3_in3)
#find derivative of cost function to W3 and b3 in layer3
dw3 = np.dot(out2.T, derivative_c_in3)
db3 = np.sum(derivative_c_in3, axis=0)
#find derivative of cost function to in2 in layer2
derivative_out2_in2 = derivative_sigmoid(in2)
derivative_c_in2 = np.multiply(np.dot(derivative_c_in3, W3.T), derivative_out2_in2)
#find derivative of cost function to W2 and b2 in layer2
dw2 = np.dot(X.T, derivative_c_in2)
db2 = np.sum(derivative_c_in2, axis=0)
#update all variables
W3 = W3 - step * dw3
W2 = W2 - step * dw2
b3 = b3 - step * db3
b2 = b2 - step * db2
# forward to get new out3 with X
in2 = np.dot(X, W2) + b2
out2 = sigmoid(in2)
in3 = np.dot(out2, W3) + b3
out3 = sigmoid(in3)
# get new cost with new out3 with X
cost = cost_function(out3, Y)
if cnt % 100 == 0:
print("cost:", cost)
cnt += 1
#output how many times used to minimize cost
print("end:", cost)
print("cnt:", cnt)
结果:
公式
输出层:
隐藏层:
最后用一张网上的图来总结:
参考:
http://www.hankcs.com/ml/back-propagation-neural-network.html