本篇是对本人之前写的线性回归方法实现的改良版本。
梯度下降法理解
数学原理请移步相关搜索。
梯度下降法的总体思想,是按照连续函数的一阶微分的集合方向(梯度方向)进行不断递减,取极限到该店的梯度为<0>为止。(这里要注意一点,梯度方向是该点处下降最快的方向) 在迭代求解的过程中,通过计算该点处的梯度值乘上步长,进行不断的迭代寻找梯度为<0>时候的值。
梯度下降法在目前算是比较常用的迭代求解方法。下表为几种常见迭代方法比较:
梯度下降法: 优势:只要求函数一阶可微,函数收敛性较强,对初始点位置不敏感,实现简单直观。 缺点:收敛速度慢,而且步长也不好确定。
牛顿法: 优势:二阶收敛,比梯度下降法收敛更快。 缺点:hessian矩阵计算量较大,对初值敏感,可能导致函数不收敛。
高斯牛顿法: 优势:同样二次收敛,相比牛顿法,不需要计算hessian矩阵。 缺点:同样对初值敏感,可能导致函数不收敛或者收敛速度很慢。
阻尼最小二乘法: 优势:加入了阻尼因子,能兼顾高斯牛顿法的二阶收敛特性,也可在阻尼因子较大时,兼顾梯度下降法的初值不敏感特性。 缺点:存在矩阵求逆的操作,对于输入维度过大时,计算量也不小。
信赖域法: 优势:具有全局收敛特性,兼顾阻尼最小二乘法的优点。 缺点:(可能比较难,哈哈哈)
本次线性回归的例子采用了梯度下降法的三种方式进行实现。
三种梯度下降法
图片引用自:https://www.cnblogs.com/pinard/p/5970503.html
三种梯度下降法的实现
批量梯度下降
# 批量梯度下降法
def BGD(x1, x2, w, eta=0.02, n_iter=1000):
# 将输入的数列,列表等强制转化为np数列
x1 = np.array(x1)
x2 = np.array(x2)
w = np.array(w)
# 计算输入数列的维度,并添加上偏置值b
m = x1.shape[0]
add_one_row = np.ones(m)
x1 = np.row_stack((x1, add_one_row))
# 批量梯度迭代过程
for i in range(n_iter):
w = w - eta * np.sum(-2*np.dot((x2-np.dot(w, x1)), x1.T), axis=0) / m
return w
该方法把向量和偏置b结合到一起,进行梯度运算,每次对梯度方向上的点进行求和,然后返回给w进行迭代。(为上一篇的改良版本。)
随机梯度下降
# 随机梯度下降法
def SGD(x1, x2, w=10, b=10, eta=0.02, n_iter=100):
x1 = np.array(x1)
x2 = np.array(x2)
m = x1.shape[0]
for i in range(n_iter):
for j in range(m):
w = w - eta * (-2 * x1[j] * (x2[j] - w * x1[j] - b))
b = b - eta * (-2 * (x2[j] - w * x1[j] - b))
return w, b
这里其实可以通过import random.randint模块进行一个随机化的操作。但在操作过程中,我发现随机的效果不好,所以使用了一个for循环。
可以看到,这个计算次数明显要比批量少了很多。
小批量梯度下降
# 小批量梯度下降法
def MGD(x1, x2, w=10, b=10, eta=0.02, batch_size=10, n_iter=10000):
x1 = np.array(x1)
x2 = np.array(x2)
m = x1.shape[0]
for i in range(n_iter):
for j in range(m // batch_size):
batched_x1 = x1[batch_size*j:batch_size*(j+1)]
batched_x2 = x2[batch_size*j:batch_size*(j+1)]
w = w - eta * np.sum(-2*batched_x1.T*(batched_x2-w*batched_x1-b)) / m
b = b - eta * np.sum(-2*(batched_x2-w*batched_x1-b)) / m
return w, b
根据根据代码可以观察到,该计算量介于批量和随机的中间。而且根据结论来看,小批量的训练水平也不错。
运行结果
从结果可以看到,批量和小批量的训练结果都不错,而随机的方法好像线型整体偏上面一点。好像结果不那么尽如人意。
就好像上面的几个点被加权了一样。或者计算了多次。该问题有待进一步的完善。
批量和小批量方法在训练结果上都比较良好,在Iris数据集较小的时候,批量的计算时间也能控制在0.8秒左右,而小批量的计算时间能控制在0.7秒左右。可以想象,当数据量比较大的时候,小批量的方法能够大大减少计算量。
相关代码可以在本人的github库中找到:ML-In-Python
谢谢阅读!