机器学习基础:梯度下降与损失函数深度解析

0 阅读6分钟

1. 引言

机器学习的核心目标是找到一个最优的模型参数,使得模型在给定数据上的表现最好。这个过程本质上是一个优化问题:我们需要最小化(或最大化)某个目标函数。本教程将深入探讨梯度下降算法和损失函数的数学原理与实际应用。


2. 损失函数的本质

2.1 什么是损失函数?

损失函数(Loss Function)衡量模型预测值与真实值之间的差距。它是模型优化的"指南针"。

数学定义:

L(θ) = (1/n) Σ loss(f(x_i; θ), y_i)
  • θ: 模型参数
  • f(x_i; θ): 模型对输入 x_i 的预测
  • y_i: 真实标签
  • n: 样本数量

2.2 常见损失函数及其适用场景

(1) 均方误差 (MSE) - 回归任务

MSE = (1/n) Σ(y_i - ŷ_i)²

数学推导 - 为什么是平方?

从概率角度看,假设误差服从高斯分布 N(0, σ²):

P(y|x) = (1/√(2πσ²)) exp(-(y - f(x))²/(2σ²))

最大化似然函数:

L(θ) = Π P(y_i|x_i; θ)

取对数:

log L(θ) = Σ[-(y_i - f(x_i))²/(2σ²) - log(√(2πσ²))]

最大化 log L 等价于最小化 Σ(y_i - f(x_i))²,即 MSE。

梯度计算:

∂MSE/∂θ = (2/n) Σ(ŷ_i - y_i) · (∂ŷ_i/∂θ)

适用场景: 预测连续值,如房价预测、温度预测。

优缺点:

  • ✓ 可导,易于优化
  • ✓ 物理意义明确(欧式距离)
  • ✗ 对异常值敏感(平方放大误差)

(2) 交叉熵损失 (Cross-Entropy) - 分类任务

二分类:

BCE = -(1/n) Σ[y_i log(ŷ_i) + (1-y_i) log(1-ŷ_i)]

多分类:

CE = -(1/n) Σ Σ y_ij log(ŷ_ij)
      i  j

信息论视角:

交叉熵衡量两个概率分布之间的"距离":

H(P, Q) = -Σ P(x) log Q(x)
  • P: 真实分布
  • Q: 模型预测分布

与 KL 散度的关系:

KL(P||Q) = H(P,Q) - H(P)

因为 H(P) 是常数,最小化交叉熵等价于最小化 KL 散度。

梯度计算(配合 Softmax):

对于 Softmax + CE 的组合:

softmax(z_i) = exp(z_i) / Σ exp(z_j)

惊人的简洁梯度:

∂L/∂z_i = ŷ_i - y_i

推导过程:

∂L/∂z_k = Σ (∂L/∂ŷ_j) · (∂ŷ_j/∂z_k)
         j

其中:
∂L/∂ŷ_j = -y_j/ŷ_j

∂ŷ_j/∂z_k = {
  ŷ_j(1-ŷ_j),  j=k
  -ŷ_j·ŷ_k,    j≠k
}

最终化简得: ŷ_k - y_k

适用场景: 图像分类、情感分析、语音识别。


(3) Hinge Loss - 支持向量机

Hinge = (1/n) Σ max(0, 1 - y_i·f(x_i))

几何意义: 强制正确分类的样本距离决策边界至少有 1 个单位的 margin。

适用场景: 二分类问题,尤其是 SVM。


3. 梯度下降算法

3.1 核心思想

在多维参数空间中,沿着负梯度方向移动参数,逐步逼近最优解。

数学表达:

θ_(t+1) = θ_t - η · ∇L(θ_t)
  • η: 学习率(步长)
  • ∇L(θ_t): 损失函数在 θ_t 处的梯度

3.2 为什么是负梯度方向?

泰勒展开:

L(θ + Δθ) ≈ L(θ) + ∇L(θ)^T · Δθ

要使 L 减小,需要:

L(θ)^T · Δθ < 0

选择 Δθ = -η∇L(θ) 满足这个条件。

3.3 梯度下降的三种变体

(1) Batch Gradient Descent (BGD)

for epoch in range(num_epochs):
    gradient = compute_gradient(entire_dataset, θ)
    θ = θ - η * gradient

特点:

  • ✓ 准确的梯度估计
  • ✓ 稳定收敛
  • ✗ 计算慢(处理整个数据集)
  • ✗ 内存需求大

(2) Stochastic Gradient Descent (SGD)

for epoch in range(num_epochs):
    shuffle(dataset)
    for sample in dataset:
        gradient = compute_gradient(sample, θ)
        θ = θ - η * gradient

特点:

  • ✓ 快速更新
  • ✓ 可能逃离局部最优(噪声)
  • ✗ 梯度估计有噪声
  • ✗ 收敛曲线震荡

为什么有效?

期望梯度等于真实梯度:

E[∇L_i(θ)] = ∇L(θ)

(3) Mini-Batch Gradient Descent

for epoch in range(num_epochs):
    for batch in get_batches(dataset, batch_size):
        gradient = compute_gradient(batch, θ)
        θ = θ - η * gradient

特点:

  • ✓ 平衡速度与稳定性
  • ✓ 利用矩阵运算加速(GPU)
  • ✓ 梯度估计方差较小

batch_size 的选择:

  • 小 batch (32-64): 训练快,泛化好,但不稳定
  • 大 batch (256-512): 稳定,但可能陷入尖锐最小值

3.4 学习率的艺术

固定学习率的问题

η 太大 → 震荡或发散
η 太小 → 收敛慢

学习率衰减策略

(1) 阶梯衰减

η_t = η_0 * decay_rate^(epoch // decay_steps)

(2) 指数衰减

η_t = η_0 * exp(-decay_rate * epoch)

(3) 余弦退火

η_t = η_min + 0.5 * (η_max - η_min) * (1 + cos(π * epoch / T))

4. 高级优化算法

4.1 Momentum (动量)

问题: SGD 在平坦区域收敛慢,在陡峭方向震荡。

解决方案: 引入"速度"概念,累积历史梯度。

更新规则:

v_t = β·v_(t-1) + ∇L(θ_t)
θ_(t+1) = θ_t - η·v_t

物理类比: 小球滚下山坡,动量帮助越过小坑。

参数: β ≈ 0.9


4.2 Adam (Adaptive Moment Estimation)

核心思想: 自适应调整每个参数的学习率。

算法:

m_t = β1·m_(t-1) + (11)·∇L(θ_t)      # 一阶矩(均值)
v_t = β2·v_(t-1) + (12)·(∇L(θ_t))²   # 二阶矩(方差)

m̂_t = m_t / (1 - β1^t)                 # 偏差校正
v̂_t = v_t / (1 - β2^t)

θ_(t+1) = θ_t - η · m̂_t / (√v̂_t + ε)

参数设置:

  • β1 = 0.9
  • β2 = 0.999
  • ε = 1e-8

优势:

  • 自动调整学习率
  • 适合稀疏梯度
  • 鲁棒性强

5. 实战案例:线性回归从零实现

5.1 问题设定

给定数据 {(x_i, y_i)},拟合 y = wx + b

损失函数: MSE

5.2 代码实现

import numpy as np
import matplotlib.pyplot as plt

# 生成数据
np.random.seed(42)
X = np.random.rand(100, 1) * 10
y = 3 * X + 7 + np.random.randn(100, 1) * 2

# 初始化参数
w = np.random.randn(1, 1)
b = np.random.randn(1, 1)
learning_rate = 0.01
epochs = 1000

# 训练
losses = []
for epoch in range(epochs):
    # 前向传播
    y_pred = X @ w + b

    # 计算损失
    loss = np.mean((y_pred - y) ** 2)
    losses.append(loss)

    # 反向传播(手动计算梯度)
    dL_dw = (2 / len(X)) * X.T @ (y_pred - y)
    dL_db = (2 / len(X)) * np.sum(y_pred - y)

    # 更新参数
    w -= learning_rate * dL_dw
    b -= learning_rate * dL_db

    if epoch % 100 == 0:
        print(f"Epoch {epoch}, Loss: {loss:.4f}, w: {w[0,0]:.4f}, b: {b[0,0]:.4f}")

print(f"\n最终参数: w={w[0,0]:.4f}, b={b[0,0]:.4f}")
print(f"理论值: w=3.0, b=7.0")

5.3 梯度推导验证

损失函数:

L = (1/n) Σ(wx_i + b - y_i)²

偏导数:

∂L/∂w = (2/n) Σ(wx_i + b - y_i)·x_i = (2/n) X^T(Xw + b - y)
∂L/∂b = (2/n) Σ(wx_i + b - y_i)

6. 关键洞察

6.1 损失函数设计原则

  1. 可导性: 必须可微,否则无法用梯度下降
  2. 凸性: 凸函数保证全局最优(实践中神经网络非凸)
  3. 对称性: 考虑正负样本的平衡

6.2 梯度下降的局限性

  1. 局部最优: 非凸函数可能陷入局部极小值
  2. 鞍点: 高维空间中大量鞍点
  3. 梯度消失: 深度网络中梯度逐层衰减

6.3 调试技巧

  • 损失不下降: 学习率过大或过小,检查梯度计算
  • 损失震荡: 减小学习率或使用动量
  • 过拟合: 添加正则化(L1/L2)

7. 扩展阅读

数学理论

  • 凸优化基础
  • 随机优化理论
  • 泛化误差分析

实践技巧

  • Learning Rate Finder
  • Gradient Clipping
  • Warm-up 策略

前沿方向

  • 二阶优化方法(L-BFGS, 自然梯度)
  • 联邦学习中的优化
  • 神经架构搜索中的优化

8. 总结

梯度下降是机器学习的"发动机",损失函数是"方向盘"。理解它们的数学本质,能帮助你:

  • 设计更好的模型
  • 调试训练问题
  • 创新优化算法

记住:优化是手段,泛化是目的。不要过度追求训练集上的完美表现。