梯度下降(Gradient Descent)
问题背景
穷举法
在上一节的线性回归中,所使用的思想基于穷举,即为提前设定好参数的准确值在某个区间内,并以某个步长进行穷举;
这样的思想在多维(多个参数)的情况下,会引起维度的诅咒,使得原问题不可解,因此需要对这个方法进行改进。
分治法
大化小,小化无,先对整体进行分割采样,在相对最低点进行进一步的采样,直到其步长与误差符合条件。
但是分治法仍然存在缺点:
- 容易只找到局部最优解,不易找到全最优解;
- 如果需要分得更加细致,则计算量仍然巨大。
由于上面这两个问题,所以我们需要优化参数,也就是求解使得loss最小的参数值:
梯度下降算法
梯度
梯度就是导数变化最大的值,其方向为导数变化最大的方向。
若设 Δx > 0 ,则对于增函数,梯度为上升方向,对于减函数,梯度为下降方向。如此方向都不是离极值点渐进的方向,因此需要梯度下降的方向(即梯度的反方向)作为变化方向。
梯度下降算法
以凸函数为例,对于当前所选择的w值,显然并不是最低点。而对于将来要到达的全局的最低点,当前点只能向下取值,即向梯度下降方向变化。
则取值点需要向下更新,所取的梯度即为cost对于w的偏导数,公式如下:
其中α为学习率,也就是下降的步长,不宜取太大。
局限性
- 梯度下降算法容易进入局部最优解(非凸函数),但是实际问题中的局部最优点很少,或已经基本可以当成全局最优点;
- 梯度下降算法容易陷入鞍点。
梯度公式
由线性回归中的公式:
可知:
代码和图示
import numpy as np
import matplotlib.pyplot as plt
x_data = [1.0, 2.0, 3.0]
y_data = [2.0, 4.0, 6.0]
_cost = []
w = 1.0
#前馈计算
def forward(x):
return x * w
#求MSE
def cost(xs, ys):
cost = 0
for x, y in zip(xs,ys):
y_pred = forward(x)
cost += (y_pred-y) ** 2
return cost/len(xs)
#求梯度
def gradient(xs, ys):
grad = 0
for x, y in zip(xs,ys):
temp = forward(x)
grad += 2*x*(temp-y)
return grad / len(xs)
for epoch in range(100):
cost_val = cost(x_data, y_data)
_cost.append(cost_val)
grad_val = gradient(x_data, y_data)
w -= 0.01*grad_val
print("Epoch: ",epoch, "w = ",w ,"loss = ", cost_val)
print("Predict(after training)",4,forward(4))
#绘图
plt.plot(_cost,range(100))
plt.ylabel("Cost")
plt.xlabel('Epoch')
plt.show()
随机梯度下降
随机选单个样本的损失为标准,即原公式变为:
其中:
代码
#随机梯度下降
import numpy as np
import matplotlib.pyplot as plt
x_data = [1.0, 2.0, 3.0]
y_data = [2.0, 4.0, 6.0]
_cost = []
w = 1.0
#前馈计算
def forward(x):
return x * w
#求单个loss
def loss(x, y):
y_pred = forward(x)
return (y_pred-y) ** 2
#求梯度
def gradient(x, y):
return 2*x*(x*w-y)
print("Predict(after training)",4,forward(4))
for epoch in range(100):
for x, y in zip(x_data,y_data):
grad=gradient(x,y)
w -= 0.01*grad
print("\tgrad: ",x,y,grad)
l = loss(x,y)
print("progress: ",epoch,"w=",w,"loss=",l)
print("Predict(after training)",4,forward(4))
批量梯度下降
在前面的阐述中,普通的梯度下降算法利用数据整体,不容易避免鞍点,算法性能上欠佳,但算法效率高。随机梯度下降需要利用每个的单个数据,虽然算法性能上良好,但计算过程环环相扣无法将样本抽离开并行运算,因此算法效率低,时间复杂度高。
综上可采取一种折中的方法,即批量梯度下降方法。
将若干个样本分为一组,记录一组的梯度用以代替随机梯度下降中的单个样本。
该方法最为常用,也是默认接口