梯度下降入门
梯度是用来指明方向的,引导未知参数找到最优解(即导数接近0的时候)
步骤:
1.先进行一个参数的初始化w0(神经网络中可以加载预训练参数的方式,让w0一开始就处于一个优势,那么在这种情况下,w0可能经过几次训练就达到收敛),并设置学习率就是步长(常用的就是step descend和consine descend,学习率是逐渐减小的,防止步长过大不收敛)
2.在w0的基础的进行迭代,并进行梯度下降
GD梯度下降
- 优化一个函数f(t)即找到它的最小值,常用的方法叫做 Gradient Descent (GD), 就是每次沿着当前位置的导数方向走一小步,走啊走啊就能够走到一个好地方了。
- 下面假设函数只有两变量θ1,θ2,数据集大小=2,进行公式推导
现在仿真时,用矩阵是非常方便的,所以以下是矩阵推导
给定数据集都是列向量
,为拟合y=1* x1 + 2* x2 实验
import numpy as np
theta =np.array([[0.,0.]]).T
alpha = 0.01 # 学习率
threshold = 0.0001 # 停止迭代的错误阈值
iterations = 150000 # 迭代次数
error=0##初始错误为0
x=np.array([[1,1],[1,2],[2,1],[2,3],[3,2],[4,1],[4,2],[4,3]])
y=np.array([[3,5,4,8,7,6,8,10]])
y=y.T
for i in range(iterations):
y_hat=np.dot(x,theta)
error=(1/2)*np.dot((y_hat-y).T,(y_hat-y))
if error<=threshold:
break
theta+=alpha/2*(np.dot(x.T,(y-np.dot(x,theta))))
print('迭代次数:%d' % (i + 1), 'theta:', theta, 'error:%f' % error)
>>迭代次数:185 theta: [[ 1.00326097]
[ 1.99511771]] error:0.000097
两个缺点
在机器学习的应用中,我们都会面临非常大的数据集,通过上面的迭代公式可以看出,GD每次参数的迭代时,要考虑所有的数据,然后还只能走一小步。一般 GD 要几千步几万步才能收敛,所以是非常耗时的,所以就产生了随机梯度下降法SGD
在神经网络中经证明很少存在局部最优点,最大的问题在于鞍点的存在,适用梯度下降法GD时,容易陷入了鞍点,或者比较差的局部最优点,GD 算法就跑不出来了,因为这些点的导数是 0。
SGD随机梯度下降
GD梯度更新时,要考虑所有的样本。SGD梯度更新时,只考虑一个样本。
-
因为这个样本是随机的,所以每次迭代没有办法得到一个准确的梯度,这样一来虽然每一次迭代得到的损失函数不一定是朝着全局最优方向,但是大体的方向还是朝着全局最优解的方向靠近,直到最后,得到的结果通常就会在全局最优解的附近。这种算法相比普通的梯度下降算法,收敛的速度更快,所以在一般神经网络模型训练中,随机梯度下降算法 SGD 是一种非常常见的优化算法。
SGD 就像是喝醉了酒的 GD,它依稀认得路,最后也能自己走回家,但是走得歪歪扭扭。(红色的是 GD 的路线,偏粉红的是 SGD 的路线)
外面的i循环是epoch,里面的j循环是样本,可以看出一次迭代只与一个样本有关,无求和。
-
实现
import numpy as np
theta =np.array([[0.,0.]]).T
alpha = 0.01 # 学习率
threshold = 0.0001 # 停止迭代的错误阈值
iterations = 1500 # 迭代次数
error=0##初始错误为0
x=np.array([[1,1],[1,2],[2,1],[2,3],[3,2],[4,1],[4,2],[4,3]])
y=np.array([[3,5,4,8,7,6,8,10]])
y=y.T
for i in range(iterations):
for j in range(len(y)):
y_hat=np.dot(x,theta)
error=(1/2)*np.dot((y_hat-y).T,(y_hat-y))
if error<=threshold:
break
theta+=alpha/2*(np.dot(x[[j]].T,(y[[j]]-np.dot(x[[j]],theta))))
print('迭代次数:%d' % (i + 1), 'theta:', theta, 'error:%f' % error)
GD,SGD,Mini-batch Gradient Descent对比
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif']=['STSong'] # 中文宋体
theta =np.array([[0.,0.]]).T
theta1 =np.array([[0.,0.]]).T
alpha = 0.01 # 学习率
threshold = 0.0001 # 停止迭代的错误阈值
iterations = 150000 # 迭代次数
error1=0##初始错误为0
x=np.array([[1,1],[1,2],[2,1],[2,3],[3,2],[4,1],[4,2],[4,3]])
y=np.array([[3,5,4,8,7,6,8,10]])
y=y.T
record1=[]
for i in range(iterations):
y_hat=np.dot(x,theta)
error1=(1/2)*np.dot((y_hat-y).T,(y_hat-y))
record1.append(error1[0,0])
if error1<=threshold:
break
theta+=alpha/2*(np.dot(x.T,(y-np.dot(x,theta))))
record2=[]
for i in range(iterations):
j=i%8
y_hat=np.dot(x,theta1)
error=(1/2)*np.dot((y_hat-y).T,(y_hat-y))
if error<=threshold:
break
theta1+=alpha/2*(np.dot(x[[j]].T,(y[[j]]-np.dot(x[[j]],theta1))))
record2.append(error[0,0])
print(record1)
print(record2)
plt.figure('林', figsize=(8, 6))
plt.plot( record1, c='red', label='GD',linewidth = 1)
plt.plot( record2, c='green', label='SGD',linewidth = 1)
plt.xlim(0,500)
plt.legend(loc='best')
plt.xlabel("迭代次数",size=22)
plt.ylabel("error",size=22)
plt.title("GD,SGD对比图",size=22)
plt.show()
如果有对matplotlib画图感兴趣的
,参看这一篇
- GD
优点:全局最优解;易于并行实现;每次迭代一小步需要所有数据,下降方向准确
缺点:当样本数目很多时,训练过程会很慢。 - SGD
优点:训练速度快;
缺点:准确度下降,并不是全局最优;不易于并行实现。
SGD每次需要一个数据,下降方向摇摇晃晃(相当于有噪声,可以采用小步长来弥补),但用时短。 - Mini-batch Gradient Descent
GD考虑的是全部样本,SGD考虑的是单个样本,MBGD就是折中的每次迭代考虑一小批
BP(Back Propagation)反向传播算法
BP算法其实和梯度下降是一样的,只不过是应用于深层网络。
神经网络中梯度下降算法
a.用随机值初始化权重和偏差
b.把输入传入网络,得到输出值
c.计算预测值和真实值之间的误差
d.对每一个产生误差的神经元,调整相应的(权重)值以减小误差
e.重复迭代,直至得到网络权重的最佳值
- 下左图没有激活函数时,最终会等效成一个线性函数,所以引入激活函数。
反向传播的过程其实就是对loss求x,w偏导的过程,其中导数中会涉及到y - y_hat的值,所以也称误差的反向传播
,只要求出f模块的梯度,存到pytorch的变量中,等着loss返传就行。
解决的核心问题损失函数c与w,b求偏导
BP算法的核心思想:使用梯度下降来搜索可能的权向量W的假设空间,以找到最佳的拟合样例的权向量。即利用损失函数,每次向损失函数负梯度方向移动,直到损失函数取得最小值。
例子
对下图使用BP算法,根据loss_function,反向传播,不断优化神经网络中的权重W, V
参考