一、梯度下降法
上一篇分享中使用了求解方程组的方法求得了最小二乘法的解析解,但是当数据较多或者模型是非线性模型时,求解解析解会变得相当困难,甚至不可能。
因此,衍生出来了新的方法,就是梯度下降法。
梯度下降法的优点是在求解过程中只需损失函数的一阶导数,计算相对简单,这就是梯度下降法适用于大规模数据的原因。
梯度下降法的核心思想是,通过当前点的梯度方向寻找新的迭代点,不断迭代,直到找到最优参数。
二、梯度下降法的基本原理
- 初始点:选择一个初始点 x(0) 作为算法的起始点。
- 梯度计算:计算当前点的梯度,即损失函数对参数的偏导数。梯度指向函数增长最快的方向。
- 参数更新:将当前点的参数向梯度的相反方向更新,以减小损失函数的值。更新公式通常为:
其中, x(k) 是第 k 次迭代的参数, ∇f(x(k)) 是损失函数在x(k) 处的梯度,而 η 是学习率,决定了步长的大小
迭代:重复步骤2和3,直到满足停止条件,如梯度足够小、达到预定的迭代次数或损失函数值不再显著减小。
三、梯度下降法的算法实现
下面将使用剃度下降法来求解a和b,实现最小二乘法的拟合
# 最小二乘的梯度下降法求解
import matplotlib.pyplot as plt
import numpy as np
import sklearn
# 生成数据
data_num = 50
X = np.random.rand(data_num, 1)*10
Y = X * 3 + 4 + 4*np.random.randn(data_num, 1)
N = X.shape[0]
# 设置参数
n_epoch = 500 # 迭代次数
a, b = 1, 1 # 初始模型参数
epsilon = 0.001 # 学习率
# 对每次迭代
for i in range(n_epoch):
data_idx = list(range(N))
np.random.shuffle(data_idx)
# 对每个数据
for j in data_idx:
a = a + 2 * epsilon * (Y[j] - a * X[j] - b) * X[j]
b = b + 2 * epsilon * (Y[j] - a * X[j] - b)
# 计算损失函数
L = 0
for j in range(N):
L = L + (Y[j] - a * X[j] - b) ** 2
if i % 100 == 0:
print("代 %4d: loss = %f, a = %f, b = %f" % (i, L, a, b))
# 画出结果
x_min = np.min(X)
x_max = np.max(X)
y_min = a * x_min + b
y_max = a * x_max + b
plt.scatter(X, Y, label='original data')
plt.plot([x_min, x_max], [y_min, y_max], 'r', label='model')
plt.legend()
plt.show()
拟合结果:
效果也还不错。
由此可以看出,不管是用求解析解的方法还是用梯度下降法最终都能较好的求出a和b,从而拟合出一个比较好的结果。
在模型复杂和数据量较大的情况下一般求解解析解非常困难,梯度下降法很好的作了一个补充,事实上,在神经网络等机器学习中常用的方法是梯度下降法。
所以这是一个非常重要的概念,一定要掌握,后面会经常用用到。
|