本节继上一节反向传播:公式推导篇的代码演示,本节将从零开始演示反向传播训练参数的整个过程,除此之外还将使用TF2.0来进行快速求导作为拓展演示。
正文首先想一下训练模型的步骤:
1、创建一个模型
2、准备好模型的输入,以及标签
3、损失函数根据模型的输出以及标签求出损失值
4、求损失函数对各个参数的偏导
5、根据求出的偏导数值更新参数
由于是从零开始,所以这里我们使用一个非常简单的模型g(a,x,y)以方便求偏导,如下:
a表示模型的输入,x、y表示变量,也就是我们训练的值。
def g(a,x,y):
h1=a*(x**2+x)
h2=h1*y+2*y
return h2,h1
有了g(a,x,y)这个前向传播函数,我们就可以求出反向传播的偏导数,这里损失函数我们使用均方误差0.5*(g_predict - g_target)**2,加0.5是为了求导后更简单。
有高数基础的,我们可以轻易得出以下偏导数
#损失函数L对模型输出g的偏导
def _dL_dg(g_predict,g_target):
return g_predict-g_target
#g对参数y的偏导
def _dg_dy(h1,y):
return h1+2
#g对h1的偏导
def _dg_dh1(y):
return y
#h1对参数x的偏导
def _dh1_dx(a,x):
return a*(2*x + 1)
开始训练:
import numpy as np
import random
#初始化参数x、y
x=np.array(0.).astype("float32")
y=np.array(0.).astype("float32")
#这里手动设置你想要训练的最终的x、y的值。
#一方面可以得出标签,一方面能直观验证自己的模型的有没有训练成功
x_target=np.array(1)
y_target=np.array(5)
#定义学习率
lr=0.01
#开始训练
for i in range(1000):
#随机取输入
a = np.array(np.random.random()).astype("float32")
#根据自己设定的值,得出标签
g_target, _ = g(a,x_target,y_target)
#得出模型预测的值
g_predict, h1 = g(a,x,y)
#求出损失值
L=0.5*(g_predict-g_target)**2
#开始反向传播
dL_dg = _dL_dg(g_predict,g_target)
dg_dh1= _dg_dh1(y)
dh1_dx= _dh1_dx(a,x)
#根据链式法则,求出dg_dy,dg_dx
dg_dy = dL_dg * _dg_dy(h1, y)
dg_dx = dL_dg * dg_dh1 * dh1_dx
#根据学习率,以及梯度(偏导)dg_dy,dg_dx更新参数值
x=x - lr*dg_dx
y=y - lr*dg_dy
if i%100==0:
print('Loss:',L)
print('x:',x)
print('y:',y)
运行输出:
Loss: 121.5706952295294
Loss: 0.532752900621499
Loss: 0.01831088644040585
Loss: 0.004482554627769781
Loss: 0.0021340579303471266
Loss: 0.0011336842526728065
Loss: 6.456618332174425e-05
Loss: 1.3528191843236397e-07
Loss: 1.1819489879170875e-07
Loss: 2.6564044454382296e-07
x: 1.0000843120267124
y: 4.99975193425045
分析:我们可以看到训练1000次后,x=1.0000843120267124
y=4.99975193425045;与x_target=1,y_target=5非常接近。
待更新。。。