2021SC@SDUSC
第一部分:背景
为了优化原实验,本周开始研究底层原理和代码实现,这里主要分享一下前向传播和反向传播的代码实现。
第二部分:结合代码讲解
神经元本质是一个函数,用于拟合一些点
对于输入的特征个数,我们可设定函数为
y_pre = w1x1+w2x2+w3x3+...wixi+b
我们这里以i=1为例,对于实际情况,要使用多少层以及每层几个神经元都要根据集体数据集而定,我们在这里以三个神经元为例,每个神经元选用sigmoid函数作为激活函数
,其导数为
,引入该函数一来可以保证曲线非线性利于梯度下降,而来整体形式便于二分,对于不同问题采用的激活函数不同
从数据集中取出X,Y,并用numpy将初始的函数参数设置成随机值,这样的模型更便于训练,这里有个细节就是所有参数都是全局变量,既便于训练,训练后模型也可以直接用。
m = 100
X,Y = dataset.get_beans(m)
plot_utils.show_scatter(X,Y)
w11_1 = np.random.rand()
b1_1 = np.random.rand()
w12_1 = np.random.rand()
b2_1 = np.random.rand()
w11_2 = np.random.rand()
w21_2 = np.random.rand()
b1_2 = np.random.rand()
将sigmoid函数和前向传播封装起来,前向传播的本质就是按照函数的定义一层一层的向后计算,将计算的结果作为函数的计算结果。
def sigmoid(z): # 封装sigmoid方法
a = 1/(1+np.exp(-z))
return a
def forward_progration(x): # 把前向传播封装起来
z1_1 = w11_1*x+b1_1
a1_1 = sigmoid(z1_1)
z2_1 = w12_1*x+b2_1
a2_1 = sigmoid(z2_1)
z1_2 = w11_2*a1_1+w21_2*a2_1+b1_2
a1_2 = sigmoid(z1_2)
return a1_2,z1_2,a2_1,z2_1,a1_1,z1_1
这里对所用所有点训练一次作为一轮,设定训练500轮,并用最小二乘法作为损失函数。
for _ in range(500):
for i in range(m):
x = X[i]
y = Y[i]
a1_2,z1_2,a2_1,z2_1,a1_1,z1_1 = forward_progration(x)
e = (y-a1_2)**2
这里一次从e开始,利用链式求导法则,依次求到dedw11_2,dedw21_2,dedb1_2,dedw11_1,
dedb1_1,dedw12_1,dedb2_1,用于反向传播。
deda1_2 =(-2)*(y-a1_2)
da1_2dz1_2 = a1_2*(1-a1_2)
dz1_2dw11_2 = a1_1
dz1_2dw21_2 = a2_1
dz1_2db1_2 = 1
dedw11_2 =deda1_2*da1_2dz1_2*dz1_2dw11_2
dedw21_2 = deda1_2*da1_2dz1_2*dz1_2dw21_2
dedb1_2 =deda1_2*da1_2dz1_2*dz1_2db1_2
dz1_2da1_1 = w11_2
da1_1dz1_1 = a1_1*(1-a1_1)
dz1_1dw11_1 = x
dz1_1db1_1 = 1
dedw11_1 = deda1_2+da1_2dz1_2*dz1_2da1_1*da1_1dz1_1*dz1_1dw11_1
dedb1_1 = deda1_2+da1_2dz1_2*dz1_2da1_1*da1_1dz1_1*dz1_1db1_1
dz1_2da2_1 = w21_2
da1_1dz2_1 = a2_1 * (1 - a2_1)
dz2_1dw12_1 = x
dz2_1db2_1 = 1
dedw12_1 = deda1_2+da1_2dz1_2*dz1_2da2_1*da1_1dz2_1*dz2_1dw12_1
dedb2_1 = deda1_2+da1_2dz1_2*dz1_2da2_1*da1_1dz2_1*dz2_1db2_1
引入学习率alpha,这个值根据经验自己定,决定了模型训练的速度和效果。
# 反向传播
alpha = 0.01
w11_2 = w11_2 - alpha*dedw11_2
w21_2 = w21_2 - alpha*dedw21_2
b1_2 = b1_2 - alpha*dedb1_2
w11_1 = w11_1 - alpha*dedw11_1
b1_1 = b1_1 - alpha*dedb1_1
w12_1 = w12_1 - alpha*dedw12_1
b2_1 = b2_1 - alpha*dedb2_1
低端反向传播原理就是如此,我们可以看到,求导的过程相当简单但繁琐,对于更多神经元,以及更多层数,这个工作量将难以手动敲代码去实现,因此,接下来将介绍通过keras框架来实现上述代码。
第三部分:Keras框架
简介:Keras是基于Theano的一个深度学习框架,它的设计参考了Torch,用Python语言编写,是一个高度模块化的神经网络库,支持GPU和CPU。依赖了Tensorflow框架。
在下好tensorflow和Keras之后,引入相关的包
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
from keras.models import Sequential#导入keras
同样取出X,Y
m = 100
X,Y = dataset.get_beans(m)
plot_utils.show_scatter(X,Y)
生成一个model
model = Sequential()
添加第一层,并指定神经元个数为2,使用sigmoid作为激活函数,输入的特征数为1
添加第二层作为输出层,指定神经元为一个和sigmoid激活函数
model.add(Dense(units=2,activation='sigmoid',input_dim=1))
model.add(Dense(units=1,activation='sigmoid'))
设定最小二乘法作为损失函数,并设定学习率为0.05,metrics表示将打印的损失表示方法
model.compile(loss='mean_squared_error',optimizer=SGD(lr=0.05),metrics=['accuracy'])
开始训练,指定训练500轮,每一批为m个
model.fit(X,Y,epochs=500,batch_size=m)
用训练好的模型预测并作图
pres = model.predict(X)
plot_utils.show_scatter_surface(X,Y,model)
我们可以看到,之前花了几十行,和大量繁琐数学运算的反向传播计算,现在仅用简单的几行便可以完成,非常舒服
第四部分:总结
本周主要学习的底层前向传播和反向传播的基础,也是机器学习的本质之一,同时也学习了方便的Keras框架进行模型的构建和训练,在接下来的研究,也会采用框架来进行模型构建与训练,以上代码和注释皆为本人所写,如有问题,欢迎指正!