在机器学习和深度学习领域,优化算法是寻找模型参数以最小化损失函数的关键工具。梯度下降算法是其中最常用的优化方法之一。本文将深入探讨梯度下降的工作原理、几何直觉、学习率的重要性以及如何在代码中实现这一算法。
假设有一个模型,其函数形式为 f(x) = 1 / (1 + exp(-wx + b)),目标是找到参数 w 和 b 使得损失函数 L(w, b) = Σ(yi - f(xi))^2 最小化。为了简化问题,假设模型只有一个输入 w 和一个偏置项 b。在没有精确方法的情况下,首先随机猜测 w 和 b 的初始值,例如 w=0.5 和 b=0,并用两个数据点来训练模型。
损失函数 L(w, b) 的值并未接近 0,因此需要继续猜测不同的 w 和 b 值,直到找到使损失接近 0 的值。通过观察损失的变化,可以随机猜测 w 和 b 的值,尽管这种方法是基于损失函数的,但它仍然是一个纯粹的暴力方法。随着参数数量和数据点数量的增加,不能依赖于任何暴力方法,需要一个更有效、更有原则的方法来达到误差表面的最小值。
梯度衡量的是所有权重(dw)相对于误差(dL)的变化。这个过程是迭代的,首先随机猜测值(考虑到只有一个输入 w 和偏置 b),然后计算每次迭代的损失,并使用梯度下降算法移动到第二次迭代,然后是第三次、第四次……直到损失收敛。
当随机猜测参数(w 和 b)的值时,梯度下降从正侧或负侧(顶部附近)开始。然后,它一步一步地沿着最陡的下降方向(从顶部到底部)移动。主要目标是到达局部最小值,因此继续进行,直到损失尽可能小。
让逐步理解:
梯度下降的整个理念是优化到达局部最小值的方法,可能想要采取大步来梯度下降到局部最小值的方向,或者可能想要更保守,只移动一小步,这些步长由学习率即“eta”决定。
案例 1:在凸函数之间反弹,未到达局部最小值。设置 eta = 1,结果 w(初始值)= 4,w(下一次迭代)= -4,w(第二次迭代)= 4。由于步长太大,它只是在梯度下降的凸函数之间来回跳跃。即使继续到第 i 次迭代,也不会到达局部最小值。
案例 2:在凸函数之间反弹,最终到达局部最小值。在这个例子中,考虑学习率(eta)= 0.9。在这种情况下,最初,它在凸函数之间来回反弹,但经过几次迭代后,它到达了局部最小值。
案例 3:非常小的学习率。再次考虑只移动一小步。因此,设置 eta = 0.05。在这个例子中,慢慢地向局部最小值移动,经过每次迭代后,最终在 30 次迭代后到达局部最小值。因此,为了优化这个过程,不应该选择一个非常低的学习率。
X = [0.5, 2.5]
Y = [0.2, 0.9]
# Sigmoid 函数,参数 w,b
def f(w,b,x):
return 1.0/(1.0+np.exp(-(w*x + b)))
# 使用均方误差
def error (w, b):
error = 0.0
for x,y in zip(X, Y):
fx = f(w, b, x)
err += 0.5 * (fx - y) **2
return err
# 计算梯度
def grad_b(w,b,x,y):
fx = f(w,b,x)
return (fx-y)*fx*(1-fx)
def grad_w(w,b,x,y):
fx = f(w,b,x)
return (fx-y)*fx*(1-fx)*x
# 主循环
def do_gradient_descent():
w, b, eta, max_epochs = -2, -2, 0.3, 1000
for i in range(max_epochs):
dw, db = 0, 0
for x,y in zip(X, Y):
dw += grad_w(w, b, x, y)
db += grad_b(w, b, x, y)
w = w - eta*dw
b = b - eta*db