参照知乎上的文章,自己又手动推理了一遍,加深理解
实际操作代码,下面是参照原文自己又手动敲了一遍,对里面做了一些改动,并添加了一些注释:
import numpy as np
def nonlin(x,deriv=False):
if(deriv==True):
return x*(1-x) # 如果deriv为true,求导数
return 1/(1+np.exp(-x)) # sigmoid激活函数
X = np.array([[0.35], [0.9]]) # 输入层 ([[x1],[x2]])
y = np.array([[0.5]]) # 输出值
np.random.seed(1) # 随机种子
W0=np.array([[0.1, 0.8], [0.4, 0.6]]) # ([[w31,w32],[w41,w42]])
W1=np.array([[0.3, 0.9]]) # ([[w53,w54]])
print("original W0,W1:\n",W0,'\n',W1)
for j in range(2): # 迭代n次
print("round ", j+1)
l0=X # 相当于文章中的z0
l1=nonlin(np.dot(W0,l0)) # 相当于文章中的y1
l2=nonlin(np.dot(W1,l1)) # 相当于文章中的y2
l2_error=y-l2 # 求偏导数中的 y2-yout
Error=1/2.0*(y-l2)**2 # 相当于文章中的C
print("Error:",Error)
l2_delta= l2_error*nonlin(l2,deriv=True) # (y2-yout)*f(z2)*(1-f(z2))
l1_error=l2_delta*W1 # 对w53,w54求偏导数(y2-yout)*f(z2)*(1-f(z2))*[[w53],[w54]]
# 对w31,w32,w41,w42求偏导数(y2-yout)*f(z2)*(1-f(z2))*w53]*f(z3)(1-f(z3))(示意)
l1_delta=l1_error*nonlin(l1,deriv=True)
W1+=l2_delta*l1.T # W53=w53+(y2-yout)*f(z2)(1-f(z2)) *y3 (示意)
W0+=l0.T.dot(l1_delta) # (y2-yout)*f(z2)*(1-f(z2))*w53]*f(z3)(1-f(z3)) *x1(示意)
print(W0,"\n",W1) # 输出更新后的权重W
下面只是迭代了2次的结果,为的是验证上面的理论。代码执行结果如下:
下面是迭代1000次的结果,从结果中可以看出,最后的损失值C=6.16297582e-33,可以说非常非常小了,说明预测的结果非常接近真实值,当然这只是一个简单的实例,实际复杂的模型很难达到这么好的效果,不过总体的思路是这样的。