背景
初次接触反向传播算法,根据C语言中文网的站长提供的思路,照着做一遍找一下感觉,其中链接如下
注意
站长提供的图片有点小问题,我们更正如下
问题
根据上图所示,我们有已知
#输入层
i1=0.05
i2=0.1
#输出层
o1=0.01
o2=0.99
这个神经网络是我们假想的,我们假想从输入层[i1,i2]==>>[o1,o2]的过程是这样的
神经元h1的输入(h1 input 简写为 hi1)=w1*i1+w2*i2+b1
神经元h2的输入 (hi2)=w3*i1+w4*i2+b1
神经元h1接收到输入后,通过非线性转换函数【这里选择Sigmoid函数】变换得到神经元h1的输出
神经元h1的输出 (ho1)=1.0/(1+math.exp((-1)*神经元h1的输入))
同理
神经元h2的输出 (ho2)=1.0/(1+math.exp((-1)*神经元h2的输入))
接下来我们再把隐藏层当作输入层,输出层当作隐藏层,类比推出有关神经元o1,神经元o2的一些表达式
神经元o1的输入 (oi1)=w5*ho1+w6*ho2+b2
神经元o2的输入 (oi2)=w7*ho1+w8*ho2+b2
再经过非线性变换Sigmoid函数得到
神经元o1的输出 (oo1)=1.0/(1+math.exp((-1)*oi1))
神经元o2的输出 (oo2)=1.0/(1+math.exp((-1)*oi2))
我们将得到的神经元o1输出,神经元o2输出跟我们知道的期望值o1,o2进行比对,定义其损失函数为
损失值 ( error 简写为 eo)=((oo1-o1)^2+(oo2-o2)^2)/2
由于我们的期望值精确到小数点后两位,损失函数为平方,所以我们仅需让损失容忍度(eo_allow)调整到1e-5即可满足
学习次数 (learning_time 简写为 lt)我们限定最大为10000次
学习率 (learning_rate 简写为 lr)我们设定为0.5
依次求解代求参数
w1~w8,以及b1,b2
跟
损失值 (eo) 的偏导数
再更新该参数,更新公式为
参数_new=参数-学习率*偏导(eo,参数)
随后进入下一轮学习
终止条件(满足其中一个即可停止训练)
1.学习次数达到上限
2.损失值达到可容忍的范围
导数
f(x)=1/(1+e^(-x))的导数是
f'(x)=f(x)*(1-f(x))
源码
import math
#参考自网址【http://c.biancheng.net/ml_alg/ann-principle.html】
#网址中图片有误,请看我博文上的图片
#输入层
i1=0.05
i2=0.1
#权值参数
w1=0.15
w2=0.2
w3=0.25
w4=0.3
w5=0.4
w6=0.45
w7=0.5
w8=0.55
#输出层标记(即期望值)
o1=0.01
o2=0.99
#偏置项参数
b1=0.35
b2=0.6
#学习率
lr=0.5
#学习周期
lt=0
max_lt=10000
#允许误差
eo_allow=1e-5
#线性转换
def linear(w_one,w_two,i_one,i_two,b):
return w_one*i_one+w_two*i_two+b
#非线性转换
def none_linear(i):
return 1.0/(1+math.exp(-i))
print("训练开始")
#学习周期结束前一直学习
while lt<max_lt:
lt+=1
#求h1和h2输入值
hi1=linear(w1,w2,i1,i2,b1)
hi2=linear(w3,w4,i1,i2,b1)
#求h1和h2输出值
ho1=none_linear(hi1)
ho2=none_linear(hi2)
#求o1和o2输入值
oi1=linear(w5,w6,ho1,ho2,b2)
oi2=linear(w7,w8,ho1,ho2,b2)
#求o1和o2输出值
oo1=none_linear(oi1)
oo2=none_linear(oi2)
#求当前计算总误差
eo=(math.pow(oo1-o1,2)+math.pow(oo2-o2,2))/2
print(f"第{lt}次训练,当前计算总误差={eo}")
#误差已经在允许范围,退出训练
if eo<eo_allow:
print("误差已经在允许范围,训练结束\n")
break
#偏导
d_eo_oo1=oo1-o1
d_eo_oo2=oo2-o2
d_oo1_oi1=oo1*(1-oo1)
d_oo2_oi2=oo2*(1-oo2)
d_eo_oi1=d_eo_oo1*d_oo1_oi1
d_eo_oi2=d_eo_oo2*d_oo2_oi2
#求w5_new
d_oi1_w5=ho1
d_eo_w5=d_eo_oi1*d_oi1_w5
w5_new=w5-lr*d_eo_w5
#求w6_new
d_oi1_w6=ho2
d_eo_w6=d_eo_oi1*d_oi1_w6
w6_new=w6-lr*d_eo_w6
#求w7_new
d_oi2_w7=ho1
d_eo_w7=d_eo_oi2*d_oi2_w7
w7_new=w7-lr*d_eo_w7
#求w8_new
d_oi2_w8=ho2
d_eo_w8=d_eo_oi2*d_oi2_w8
w8_new=w8-lr*d_eo_w8
#求b2_new
d_oi1_b2=1
d_oi2_b2=1
d_eo_b2=d_eo_oi1*d_oi1_b2+d_eo_oi2*d_oi2_b2
b2_new=b2-lr*d_eo_b2
d_oi1_ho1=w5
d_oi1_ho2=w6
d_oi2_ho1=w7
d_oi2_ho2=w8
d_eo_ho1=d_eo_oi1*d_oi1_ho1+d_eo_oi2*d_oi2_ho1
d_eo_ho2=d_eo_oi1*d_oi1_ho2+d_eo_oi2*d_oi2_ho2
d_ho1_hi1=ho1*(1-ho1)
d_ho2_hi2=ho2*(1-ho2)
d_eo_hi1=d_eo_ho1*d_ho1_hi1
d_eo_hi2=d_eo_ho2*d_ho2_hi2
#求w1_new
d_hi1_w1=i1
d_eo_w1=d_eo_hi1*d_hi1_w1
w1_new=w1-lr*d_eo_w1
#求w2_new
d_hi1_w2=i2
d_eo_w2=d_eo_hi1*d_hi1_w2
w2_new=w2-lr*d_eo_w2
#求w3_new
d_hi2_w3=i1
d_eo_w3=d_eo_hi2*d_hi2_w3
w3_new=w3-lr*d_eo_w3
#求w4_new
d_hi2_w4=i2
d_eo_w4=d_eo_hi2*d_hi2_w4
w4_new=w4-lr*d_eo_w4
#求b1_new
d_hi1_b1=1
d_hi2_b1=1
d_eo_b1=d_eo_hi1*d_hi1_b1+d_eo_hi2*d_hi2_b1
b1_new=b1-lr*d_eo_b1
#更新反向传播
w1=w1_new
w2=w2_new
w3=w3_new
w4=w4_new
b1=b1_new
w5=w5_new
w6=w6_new
w7=w7_new
w8=w8_new
b2=b2_new
print(f"当前计算总误差={eo}")
print(f"w1={w1}\nw2={w2}\nw3={w3}\nw4={w4}\nb1={b1}\n")
print(f"w5={w5}\nw6={w6}\nw7={w7}\nw8={w8}\nb2={b2}\n")
print(f"期望值:[{o1},{o2}],预测值:[{oo1},{oo2}]")
结果
结语
可以看到,在经过七千多次训练之后,我们找到了一组参数满足我们假想的关系,本次人工神经网络训练完成,反向传播算法体验结果良好。
补充
程序中d_{a}_{b}格式的变量表示a对b偏导