梯度下降在深度学习里很常见,最近也在学习深度学习的基础知识,这里对于几种常用的梯度下降法做个简单的总结。
BGD:批量梯度下降法,SGD:随机梯度下降法,MBGD:小批量梯度下降
一 :那么什么是梯度下降呢?(我们借例子来说一下)
假设我们提供了这样的数据样本(样本值取自于y=2*x1+3*x2):
x1 x2 y 1 4 15 3 5 21 5 1 13 4 2 14
x1和x2是样本值,y是预测目标,我们需要以一条直线来拟合上面的数据,待拟合的函数如下:
(1)
我们的目的就是要求出θ1和θ2的值,让h(θ)尽量逼近目标值y。
这是一个线性回归问题,若对线性回归有所了解的同学就知道:利用最小二乘法则和梯度下降法可以求出两个参数,而深度学习也同样可以利用这两种方法求得所有的网络参数,因此,在这里用这个数学模型来解释BGD、SGD、MBGD这几个概念。
二 、先熟悉一下梯度下降法(注:在实际的编程中也可以不用写总数量 m ,这里加上它是为了便于大家理解):
我们首先确定损失函数:
(2)
其中,J(θ)是损失函数,m代表每次取多少样本进行训练,如果采用SGD进行训练,那每次随机取一组样本,m=1;如果是批处理,则m等于每次抽取作为训练样本的数量。θ是参数,对应(1式)的θ1和θ2。求出了θ1和θ2,h(x)的表达式就出来了:
(3)
我们的目标是让损失函数J(θ)的值最小,根据梯度下降法,首先要用J(θ)对θ求偏导:
(4)
由于是要最小化损失函数(2式),所以参数θ按其负梯度方向来更新:
(5)
由上面的推导,我们可以基本了解了什么是梯度下降,下面将分情况描述BGD SGD MBGD几种常用的梯度下降法。
三 几种梯度下降的特点和实现
3.1
BGD(Batch gradient descent)批量梯度下降法:每次迭代使用所有的样本
该方法每次迭代都需要把所有样本都送入,好处是每次迭代都顾及了全部的样本,做的是全局最优化.当数据量很大的时候,运行效率较低。
Python代码实现:
#-*- coding: utf-8 -*-
import numpy as np
# #BGD:批量梯度下降 每次迭代使用全部的样本数据
# #用y = Θ1*x1 + Θ2*x2来拟合下面的输入和输出
# #input1 1 3 5 4
# #input2 4 5 1 2
# #output 15 21 13 14
# #实际的式子是:y=2*x1+3*x2
input_x=[[1,4],[3,5],[5,1],[4,2]]#输入
input_x=np.array(input_x)
y=[14,21,13,14]#输出
y=np.array(y)
theta=np.ones(input_x.shape[1])#设置Θ初值 为 1*2矩阵
loss=1 #使损失先定义一个数,为了进入循环
step_size=0.01 #学习率/步长
eps=0.0001#准确率
max_iters=10000 #最大迭代次数
error=0 #损失值
iter_count=0#当前的迭代数
err1=np.zeros(input_x.shape[0])#定义Θ1求梯度的中间变量
err2=np.zeros(input_x.shape[0])#定义Θ2求梯度的中间变量
while (loss > eps and iter_count < max_iters):
loss=0#初始化本次的实验误差
err1Sum=0#初始化Θ1梯度的误差损失和
err2Sum = 0 # 初始化Θ2梯度的误差损失和
for i in range(input_x.shape[0]):
pre_y=theta[0]*input_x[i][0]+theta[1]*input_x[i][1]#得到预测值
err1[i]=(pre_y-y[i])*input_x[i][0] #第i步是对Θ1求导得到的
err1Sum+=err1[i]
err2[i] = (pre_y - y[i]) * input_x[i][1] # 该步是对Θ2求导得到的
err2Sum += err2[i]
theta[0]-=step_size*err1Sum/4 #得到下一步的thea[0]
theta[1]-=step_size*err2Sum / 4 # 得到下一步的thea[1]
for i in range((input_x.shape[0])):
pre_y=theta[0]*input_x[i][0]+theta[1]*input_x[i][1]#得到预测值
error=(1/(2*(input_x.shape[0])))*(pre_y-y[i])**2 #得到损失值(2*(input_x.shape[0]))这个也可以为2
loss+=error#该次总损失
iter_count+=1#记录迭代次数
print("iter_count:",iter_count)
print("loss:",loss)
print("theta:",theta)
print("final loss value:",loss)
print("total iters:",iter_count)
可以运行后试验下,这里不知道为什么,我的结果截图上传不了。
3.2
SGD(Stochastic gradientdescent)随机梯度下降法:每次迭代使用一组样本
针对BGD算法训练速度过慢的缺点,提出了SGD算法,普通的BGD算法是每次迭代把所有样本都过一遍,每训练一组样本就把梯度更新一次。而SGD算法是从样本中随机抽出一组,训练后按梯度更新一次,然后再抽取一组,再更新一次,在样本量及其大的情况下,可能不用训练完所有的样本就可以获得一个损失值在可接受范围之内的模型了。
Python代码实现:、
#-*- coding: utf-8 -*-
import numpy as np
#SGD:随机梯度下降法 input_x=[[1,4],[3,5],[5,1],[4,2]]#输入 input_x=np.array(input_x) y=[14,21,13,14]#输出 y=np.array(y) theta=np.ones(input_x.shape[1])#设置Θ初值 为 1*2矩阵 loss=1 #使损失先定义一个数,为了进入循环 step_size=0.01 #学习率/步长 eps=0.0001#准确率 max_iters=10000 #最大迭代次数 error=0 #损失值 iter_count=0#当前的迭代数 err1=np.zeros(input_x.shape[0])#定义Θ1求梯度的中间变量 err2=np.zeros(input_x.shape[0])#定义Θ2求梯度的中间变量 while (loss>eps and iter_count<max_iters): loss=0 i=np.random.randint(0,input_x.shape[0])#随机抽样 pre_y=theta[0]*input_x[i][0]+theta[1]*input_x[i][1]#预测值 theta[0]-=step_size*(pre_y-y[i])*input_x[i][0] theta[1] -= step_size * (pre_y - y[i]) * input_x[i][1] for i in np.arange(input_x.shape[0]): pre_y = theta[0] * input_x[i][0] + theta[1] * input_x[i][1] # 预测 error=0.5*(pre_y-y[i])**2 loss+=error iter_count+=1 print("iter_count:",iter_count) print("theta:",theta) print("final loss:",loss) print("iters:",iter_count)
可以自行复制粘贴运行结果,本实验结果截图没办法上传。
3.3
MBGD(Mini-batch gradient descent)小批量梯度下降:每次迭代使用b组样本
MBGD为BGD和SGD的折中。SGD相对来说要快很多,但是也有存在问题,由于单个样本的训练可能会带来很多噪声,使得SGD并不是每次迭代都向着整体最优化方向,因此在刚开始训练时可能收敛得很快,但是训练一段时间后就会变得很慢。在此基础上又提出了小批量梯度下降法,它是每次从样本中随机抽取一小批进行训练,而不是一组。
Python代码实现:
#-*- coding: utf-8 -*-
import numpy as np
MBGD:小批量梯度下降 从数据中抽取一小组数据测试 input_x=[[1,4],[3,5],[5,1],[4,2]]#输入 input_x=np.array(input_x) y=[14,21,13,14]#输出 y=np.array(y) theta=np.ones(input_x.shape[1])#设置Θ初值 为 1*2矩阵 loss=1 #使损失先定义一个数,为了进入循环 step_size=0.01 #学习率/步长 eps=0.0001#准确率 max_iters=10000 #最大迭代次数 error=0 #损失值 iter_count=0#当前的迭代数 err1=np.zeros(input_x.shape[0])#定义Θ1求梯度的中间变量(1*4:[0,0,0,0]) err2=np.zeros(input_x.shape[0])#定义Θ2求梯度的中间变量 while (loss>eps and iter_count<max_iters): loss=0 #ij 为抽取的两个数 i=np.random.randint(0,input_x.shape[0]) j=(i+1)%input_x.shape[0] pre_y0=theta[0] * input_x[i][0] + theta[1] * input_x[i][1] pre_y1=theta[0] * input_x[j][0] + theta[1] * input_x[j][1] theta[0]-=step_size * (1/2) * ((pre_y0 - y[i]) * input_x[i][0]+(pre_y1 - y[j]) * input_x[j][0]) #对第一个参数求导 theta[1]-=step_size * (1 / 2) * ( (pre_y0 - y[i]) * input_x[i][1] + (pre_y1 - y[j]) * input_x[j][1]) # 对应5式 for i in range(3): pre_y = theta[0] * input_x[i][0] + theta[1] * input_x[i][1] # 总预测值 error = (1 / (2 * 2)) * (pre_y - y[i]) ** 2 # 损失值 loss = loss + error # 总损失值 iter_count += 1 print('iters_count', iter_count) print('theta: ', theta) print('final loss: ', loss) print('iters: ', iter_count)
可自行用代码测试。
希望可以帮到大家理解这个方法。