参考:
关于梯度下降与Momentum通俗易懂的解释_ssswill的博客-CSDN博客_梯度 momentum
前言:
P9讲梯度的时候,讲到过这种算法的梯度更新方法
这边重点讲解一下原理
Momentum算法又叫做冲量算法,其迭代更新公式如下:
实验表明,相比于标准梯度下降算法,Momentum算法具有更快的收敛速度
目录:
1: 标准的梯度下降问题(w维度为1)
2: 标准的梯度下降问题(W维度为2)
3: Momentum
一 标准的梯度下降问题(w维度为1)
# -*- coding: utf-8 -*-
"""
Created on Tue Jan 3 21:48:15 2023
@author: cxf
"""
import numpy as np
import matplotlib.pyplot as plt
#计算梯度
def gradient(x):
return 2*x
'''
a: 搜索的起始点
step: 步伐
epoch: 迭代次数
'''
def gradient_descent(a, step, epoch):
x = a
for i in range(epoch):
grad = gradient(x)
x = x-step*grad
print('epoch:{},x= {},gradient={}'.format(i,round(x,3),round(grad,3)))
if abs(grad)<1e-6 :
return x
return x
if __name__ == "__main__":
x = np.linspace(-5,5,100)
y = x**2 #损失函数
plt.plot(x,y)
gradient_descent(4, 1.0,20)
1.1 学习率过小, 却使得学习过程过于缓慢
gradient_descent(4, 0.1,20)
1.2 学习率过大,无法收敛,发散
gradient_descent(4, 1.0,20)
二 标准的梯度下降问题(W维度为2)
假设权重系数为
假设损失函数
则
SGD 更新过程
问题:
红线是标准梯度下降法,可以看到收敛过程中产生了一些震荡。这些震荡在纵轴方向上()是均匀的,几乎可以相互抵消,也就是说如果直接沿着横轴方向迭代,收敛速度可以加快
对应的代码
# -*- coding: utf-8 -*-
"""
Created on Wed Jan 4 20:41:03 2023
@author: cxf
"""
import numpy as np
import pylab as plt
'''
显示等高线
'''
def get_contour():
w0 = np.linspace(-10, 10,100)
w1 = np.linspace(-10, 10,100)
X,Y = np.meshgrid(w0,w1)
Z = X**2+Y**2
return X,Y,Z
'''
计算梯度
'''
def gradient(w):
w = np.array(w)
w0 = w[0]
w1 = w[1]
grad = np.array([2*w0,100*w1])
return grad
'''
w: 相当于权重系数
step: 步伐
epoch: 迭代次数
'''
def SGD(w,step,epoch):
w = np.array(w,dtype='float64')
w_list=[]
for i in range(epoch):
t = w.copy()
w_list.append(t)
grad = gradient(w)
print('epoch: %d 权重系数x: [%5.3f %5.3f] 梯度 [%5.3f %5.3f ] '%(i,w[0],w[1],grad[0],grad[1]))
w= w- step*grad
if sum(abs(grad))<=1e-6:
return w
return w,w_list
'''
'''
def momentum(w0, step,mu, epoch):
w = np.array(w0)
w_list = []
pre_gd = np.array([0,0])
for i in range(epoch):
t = w.copy()
w_list.append(t)
grad = gradient(w)
pre_gd = mu*pre_gd+grad
w = w- step*pre_gd
print('epoch: %d 权重系数x: [%5.3f %5.3f] 梯度 [%5.3f %5.3f ] '%(i,w[0],w[1],grad[0],grad[1]))
if sum(abs(grad))<=1e-6:
return w
return w,w_list
'''
模拟SGD梯度下降训练的过程
'''
def main():
X,Y,Z = get_contour()
plt.figure(figsize=(15,7))
C= plt.contour(X,Y,Z,[1,10,20,40,80,100])#find_grad
plt.clabel(C, inline=True, fontsize=15)
plt.plot(0,0,marker='*',markersize=20,color='r')
mu =0.7
step = 0.02 #步伐
epoch = 50 #迭代次数
w =[10,10] #初始化的权重系数
#x, x_list = SGD(w, step,epoch)
x, x_list = momentum(w, step,mu, epoch)
N = len(x_list)
print("\n N",np.shape(x_list))
for i in range(N-1):
#print(i)
plt.plot([x_list[i][0],x_list[i+1][0]],[x_list[i][1],x_list[i+1][1]])
if __name__ == "__main__":
main()
问题1:steps = 0.015 #步伐 epoch = 50 #迭代次数 w =[10,10] #初始化的权重系数
发现收敛速度很慢
问题2: 增大 steps = 0.02
步伐 epoch = 50 #迭代次数
w =[10,10] #初始化的权重系数
参数震荡,无法收敛
三 Momentum
Momentum通过对原始梯度做了一个平滑,正好将纵轴方向的梯度抹平了(红线部分),使得参数更新方向更多地沿着横轴进行,因此速度更快。
code 跟上面一样,差别是参数更新过程
一个用的是SGD, 一个用的是momentum