本站原创文章,转载请说明来自《老饼讲解-深度学习》www.bbbdata.com
带动量、带权重衰减的SGD算法,是深度学习最基本的有效训练算法,它使得深度学习模型的训练得以实施
本文讲解带动量、带权重衰减的SGD算法流程,并展示一个具体的代码实例,用于训练MLP神经网络
通过本文可以了解什么是带动量、带权重衰减的SGD算法,以及它的意义,并进一步了解它的具体代码实现
本节讲解什么是带权重衰减、带动量的SGD算法,以及它的算法流程
什么是SGD算法-带动量、带权重衰减
带动量、带权重衰减的SGD算法,就是在动量梯度下降法中加入权重衰减、并随机小批进行训练
梯度下降法解决求解、动量梯度下降解决速度、权重衰减解决过拟合、SGD解决内存不足
总的来说,这一套组合使得深度学习的训练得以实施,它是深度学习最为基本的有效训练算法
SGD的算法流程(带动量、带权重衰减)
SGD(带权重衰减、带动量)的具体算法流程如下:
一、初始化
1. 初始化参数P
可以使用随机初始化,也可以使用其它的初始化算法
2. 初始化速度
二、训练t步(epoch),每步过程如下:
1. 将数据打乱,并分为n批
2. 逐批训练样本
(1) 计算本批次样本的参数P的梯度g
(2) 更新本次的速度
(2) 将参数往负梯度方向更新
3. 检验终止条件
终止条件如下:
(1) 如果epoch已经足够大,则终止训练
(2) 误差是否满足要求,如果满足,则退出训练
三、输出结果
输出参数P的最终训练结果
可以看到,它与动量梯度下降法并没有太大的区别,
只是分批进行训练,且速度的更新公式中加入了权重衰减
本节展示用带权重衰减、带动量的SGD训练一个MLP的例子与代码
SGD算法训练MLP(带动量、权重衰减)-代码示例
如下所示,在sin函数[-5,5]之间采集20个数据,我们需要训练一个三层MLP神经网络,来拟合sin函数x与y的关系
![]()
由于样本较为简单,我们不妨将三层MLP神经网络设为4个隐节点,并使用均方差作为损失函数
根据带动量、带权重衰减的SGD算法流程,对三层MLP进行训练,
具体代码实现如下:
import torch
import matplotlib.pyplot as plt
import random
torch.manual_seed(99) # 设定torch的随机种子,使每次结果一样
random.seed(99) # 设定python的随机种子,使每次结果一样
# -----计算网络输出:前馈式计算------
def forward(w1,b1,w2,b2,x):
return w2@torch.tanh(w1@x+b1)+b2
# ----计算损失函数: 使用均方差------
def loss(y,py):
return ((y-py)**2).mean()
# -----样本分批函数-----------------
def data_split(x,y,batch_size):
sample_num = x.shape[1] # 样本个数
batch_num = int(sample_num/batch_size) # 计算批数
idx = list(range(sample_num)) # 样本索引
random.shuffle(idx) # 对索引随机打乱
idx = idx[:batch_num*batch_size] # 只抽取batch_num*batch_size个样本
x_batch = x[:,idx] # 打乱x的顺序
y_batch = y[:,idx] # 打乱y的顺序
x_batch = x_batch.view(batch_num,x_batch.shape[0],batch_size) # 转换x的维度
y_batch = y_batch.view(batch_num,y_batch.shape[0],batch_size) # 转换y的维度
return x_batch,y_batch # 返回分批后的数据
# ------训练数据----------------
x = torch.linspace(-5,5,20).reshape(1,20) # 在[-5,5]之间生成20个数作为x
y = torch.sin(x) # 模型的输出值y
#-----------训练模型------------------------
in_num = x.shape[0] # 输入个数
out_num = y.shape[0] # 输出个数
hn = 4 # 隐节点个数
w1 = torch.randn([hn,in_num],requires_grad=True) # 初始化输入层到隐层的权重w1
b1 = torch.randn([hn,1],requires_grad=True) # 初始化隐层的阈值b1
w2 = torch.randn([out_num,hn],requires_grad=True) # 初始化隐层到输出层的权重w2
b2 = torch.randn([out_num,1],requires_grad=True) # 初始化输出层的阈值b2
lr = 0.01 # 学习率
mu = 0.9 # 动量系数
lamb = 0.0005 # 权重衰减系数
batch_size = 3 # 样本批大小
w1_v = 0 # 初始化w1的速度
b1_v = 0 # 初始化b1的速度
w2_v = 0 # 初始化w2的速度
b2_v = 0 # 初始化b2的速度
for epoch in range(5000): # 训练5000步
# 对样本进行分批,逐批训练
x_batch,y_batch = data_split(x,y,batch_size) # 对样本进行分批
for i in range(x_batch.shape[0]): # 逐批次训练
# 计算梯度
py = forward(w1,b1,w2,b2,x_batch[i]) # 计算网络的输出
L = loss(y_batch[i],py) # 计算损失函数
L.backward() # 用损失函数更新模型参数的梯度
# 更新速度
w1_v = mu*w1_v -lr*(1-mu)*(w1.grad+ lamb*w1) # 更新w1的速度
b1_v = mu*b1_v -lr*(1-mu)*(b1.grad+ lamb*b1) # 更新b1的速度
w2_v = mu*w2_v -lr*(1-mu)*(w2.grad+ lamb*w2) # 更新w2的速度
b2_v = mu*b2_v -lr*(1-mu)*(b2.grad+ lamb*b2) # 更新b2的速度
# 更新参数
w1.data=w1.data+w1_v # 更新模型系数w1
b1.data=b1.data+b1_v # 更新模型系数b1
w2.data=w2.data+w2_v # 更新模型系数w2
b2.data=b2.data+b2_v # 更新模型系数b2
# 清空梯度
w1.grad.zero_() # 清空w1梯度,以便下次backward
b1.grad.zero_() # 清空b1梯度,以便下次backward
w2.grad.zero_() # 清空w2梯度,以便下次backward
b2.grad.zero_() # 清空b2梯度,以便下次backward
# 计算当前的整体损失函数
py = forward(w1,b1,w2,b2,x) # 计算网络的输出
L = loss(y,py) # 计算损失函数
print('第',str(epoch),'轮:',L) # 打印当前损失函数值
if(L.item()<0.005): # 如果误差达到要求
break # 退出训练
px = torch.linspace(-5,5,100).reshape(1,100) # 测试数据,用于绘制网络的拟合曲线
py = forward(w1,b1,w2,b2,px).detach().numpy() # 网络的预测值
plt.scatter(x, y) # 绘制样本
plt.plot(px[0,:],py[0,:]) # 绘制拟合曲线
plt.show() # 展示画布
print('w1:',w1) # 打印w1
print('b1:',b1) # 打印b1
print('w2:',w2) # 打印w2
print('b2:',b2) # 打印b2
运行结果如下:
![]()
![]()
可以看到,模型根据训练数据,已经较好地拟合出sin函数曲线
将模型参数代回MLP神经网络的数学表达式,即可得到模型的数学表达式为:
好了,以上就是利用带权重衰减、带动量的SGD算法来训练一个MLP的流程与代码了~
End