1.张量运算的导数:梯度
梯度(gradient)是张量运算的导数。它是导数这一概念向多元函数导数的推广。多元函数是以张量作为输入的函数。
假设有一个输入向量 x、一个矩阵 W、一个目标 y 和一个损失函数 loss。你可以用 W 来计算预测y_pred,然后计算损失,或者说预测值 y_pred 和目标 y 之间的距离。
y_pred = dot(W, x)
loss_value = loss(y_pred, y)
如果输入数据 x 和 y 保持不变,那么这可以看作将 W 映射到损失值的函数。
loss_value = f(W)
假设 W 的当前值为 W0。f 在 W0 点的导数是一个张量 gradient(f)(W0),其形状与 W 相同,每个系数 gradient(f)(W0)[i, j] 表示改变 W0[i, j] 时 loss_value 变化的方向和大小
2.梯度下降
1)什么是梯度下降?
因为梯度下降是一种思想,没有严格的定义,所以用一个比喻来解释什么是梯度下降
简单来说,梯度下降就是从山顶找一条最短的路走到山脚最低的地方。但是因为选择方向的原因,我们找到的最低点可能不是真正的最低点。如图所示,黑线标注的路线所指的方向并不是真正的地方。
实际上梯度下降就是随机选择一个方向,然后每次迈步都选择最陡的方向,直到这个方向上能达到的最低点。
2)梯度下降是用来做什么的?
在机器学习算法中,有时候需要对原始的模型构建损失函数,然后通过优化算法对损失函数进行优化,以便寻找到最优的参数,使得损失函数的值最小。而在求解机器学习参数的优化算法中,使用较多的就是基于梯度下降的优化算法(Gradient Descent, GD)。
3)优缺点
优点:效率。在梯度下降法的求解过程中,只需求解损失函数的一阶导数,计算的代价比较小,可以在很多大规模数据集上应用
缺点:求解的是局部最优值,即由于方向选择的问题,得到的结果不一定是全局最优
步长选择,过小使得函数收敛速度慢,过大又容易找不到最优解。
4)梯度下降的变形形式
根据处理的训练数据的不同,主要有以下三种形式:
1)批量梯度下降法BGD(Batch Gradient Descent):
针对的是整个数据集,通过对所有的样本的计算来求解梯度的方向。
优点:全局最优解;易于并行实现;
缺点:当样本数据很多时,计算量开销大,计算速度慢
2)小批量梯度下降法MBGD(mini-batch Gradient Descent)
把数据分为若干个批,按批来更新参数,这样,一个批中的一组数据共同决定了本次梯度的方向,下降起来就不容易跑偏,减少了随机性
优点:减少了计算的开销量,降低了随机性
3)随机梯度下降法SGD(stochastic gradient descent)
每个数据都计算算一下损失函数,然后求梯度更新参数。
优点:计算速度快
缺点:收敛性能不好
总结:SGD可以看作是MBGD的一个特例,及batch_size=1的情况。在深度学习及机器学习中,基本上都是使用的MBGD算法。
3.随机梯度下降(SGD)
随机梯度下降法是深度学习最常见的优化方法,它的目的是求出最小损失值函数对应的所有权重值。 如图所示,为学习率选择一个合适的值是很重要的。如果学习率太小,则沿着曲线下降需要迭代很多次,而且会陷入局部极限值。如果学习率太大,则更新权重值后可能会出现曲线完全随机的位置。 将权重w沿着梯度的反方向更新权重,损失每次都会变小一点。
代码实现:
BGD(Batch gradient descent)批量梯度下降法:每次迭代使用所有的样本
每次迭代都需要把所有样本都送入,这样的好处是每次迭代都顾及了全部的样本,做的是全局最优化
#-*- coding: utf-8 -*-
import random
#用y = Θ1*x1 + Θ2*x2来拟合下面的输入和输出
#input1 1 2 5 4
#input2 4 5 1 2
#output 19 26 19 20
input_x = [[1,4], [2,5], [5,1], [4,2]] #输入
y = [19,26,19,20] #输出
theta = [1,1] #θ参数初始化
loss = 10 #loss先定义一个数,为了进入循环迭代
step_size = 0.01 #步长
eps =0.0001 #精度要求
max_iters = 10000 #最大迭代次数
error =0 #损失值
iter_count = 0 #当前迭代次数
err1=[0,0,0,0] #求Θ1梯度的中间变量1
err2=[0,0,0,0] #求Θ2梯度的中间变量2
while( loss > eps and iter_count < max_iters): #迭代条件
loss = 0
err1sum = 0
err2sum = 0
for i in range (4): #每次迭代所有的样本都进行训练
pred_y = theta[0]*input_x[i][0]+theta[1]*input_x[i][1] #预测值
err1[i]=(pred_y-y[i])*input_x[i][0]
err1sum=err1sum+err1[i]
err2[i]=(pred_y-y[i])*input_x[i][1]
err2sum=err2sum+err2[i]
theta[0] = theta[0] - step_size * err1sum/4 #对应5式
theta[1] = theta[1] - step_size * err2sum/4 #对应5式
for i in range (4):
pred_y = theta[0]*input_x[i][0]+theta[1]*input_x[i][1] #预测值
error = (1/(2*4))*(pred_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)
SGD(Stochastic gradientdescent)随机梯度下降法:每次迭代使用一组样本
针对BGD算法训练速度过慢的缺点,提出了SGD算法,普通的BGD算法是每次迭代把所有样本都过一遍,每训练一组样本就把梯度更新一次。而SGD算法是从样本中随机抽出一组,训练后按梯度更新一次,然后再抽取一组,再更新一次,在样本量及其大的情况下,可能不用训练完所有的样本就可以获得一个损失值在可接受范围之内的模型了。
#-*- coding: utf-8 -*-
import random
#用y = Θ1*x1 + Θ2*x2来拟合下面的输入和输出
#input1 1 2 5 4
#input2 4 5 1 2
#output 19 26 19 20
input_x = [[1,4], [2,5], [5,1], [4,2]] #输入
y = [19,26,19,20] #输出
theta = [1,1] #θ参数初始化
loss = 10 #loss先定义一个数,为了进入循环迭代
step_size = 0.01 #步长
eps =0.0001 #精度要求
max_iters = 10000 #最大迭代次数
error =0 #损失值
iter_count = 0 #当前迭代次数
while( loss > eps and iter_count < max_iters): #迭代条件
loss = 0
i = random.randint(0,3) #每次迭代在input_x中随机选取一组样本进行权重的更新
pred_y = theta[0]*input_x[i][0]+theta[1]*input_x[i][1] #预测值
theta[0] = theta[0] - step_size * (pred_y - y[i]) * input_x[i][0]
theta[1] = theta[1] - step_size * (pred_y - y[i]) * input_x[i][1]
for i in range (3):
pred_y = theta[0]*input_x[i][0]+theta[1]*input_x[i][1] #预测值
error = 0.5*(pred_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)
MBGD(Mini-batch gradient descent)小批量梯度下降:每次迭代使用b组样本
SGD相对来说要快很多,但是也有存在问题,由于单个样本的训练可能会带来很多噪声,使得SGD并不是每次迭代都向着整体最优化方向,因此在刚开始训练时可能收敛得很快,但是训练一段时间后就会变得很慢。在此基础上又提出了小批量梯度下降法,它是每次从样本中随机抽取一小批进行训练,而不是一组。
#-*- coding: utf-8 -*-
import random
#用y = Θ1*x1 + Θ2*x2来拟合下面的输入和输出
#input1 1 2 5 4
#input2 4 5 1 2
#output 19 26 19 20
input_x = [[1,4], [2,5], [5,1], [4,2]] #输入
y = [19,26,19,20] #输出
theta = [1,1] #θ参数初始化
loss = 10 #loss先定义一个数,为了进入循环迭代
step_size = 0.01 #步长
eps =0.0001 #精度要求
max_iters = 10000 #最大迭代次数
error =0 #损失值
iter_count = 0 #当前迭代次数
while( loss > eps and iter_count < max_iters): #迭代条件
loss = 0
#这里每次批量选取的是2组样本进行更新,另一个点是随机点+1的相邻点
i = random.randint(0,3) #随机抽取一组样本
j = (i+1)%4 #抽取另一组样本,j=i+1
pred_y0 = theta[0]*input_x[i][0]+theta[1]*input_x[i][1] #预测值1
pred_y1 = theta[0]*input_x[j][0]+theta[1]*input_x[j][1] #预测值2
theta[0] = theta[0] - step_size * (1/2) * ((pred_y0 - y[i]) * input_x[i][0]+(pred_y1 - y[j]) * input_x[j][0]) #对应5式
theta[1] = theta[1] - step_size * (1/2) * ((pred_y0 - y[i]) * input_x[i][1]+(pred_y1 - y[j]) * input_x[j][1]) #对应5式
for i in range (3):
pred_y = theta[0]*input_x[i][0]+theta[1]*input_x[i][1] #总预测值
error = (1/(2*2))*(pred_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)