AIGC标识 机器学习数学基础专题【左扬精讲】— 梯度下降:从批量到自适应的参数优化演进

机器学习数学基础专题【左扬精讲】— 梯度下降:从批量到自适应的参数优化演进

梯度下降算法(Gradient Descent)是机器学习、深度学习、优化理论中最核心的算法之一。

它是训练神经网络、求解最小二乘问题、机器学习模型参数优化的基石。本篇文章将深入剖析梯度下降算法的数学原理、几何直觉、各种变体,以及在实际工程中的调参技巧。

梯度下降 优化算法 学习率 收敛 批量/随机/小批量

学习重点

必须掌握:

  • 梯度下降的核心思想:沿梯度负方向迭代
  • 学习率(learning rate)对收敛的影响
  • 批量梯度下降、随机梯度下降、小批量梯度下降的区别
  • 梯度消失与梯度爆炸问题

需要了解:

  • 动量(Momentum)、Adam 等自适应学习率方法
  • 学习率衰减策略
  • 梯度下降与正规方程的对比

一、梯度下降的核心思想

What — 梯度下降是什么?

梯度下降是一种一阶迭代优化算法,用于找到函数的局部最小值。其核心思想是:从一个初始点出发,沿着函数值下降最快的方向(即负梯度方向)逐步移动,直到达到一个局部最小值(或近似最小值)。

Why — 为什么沿负梯度方向下降最快?

在多元函数微分学中,梯度 ∇ f(x) 指向函数增长最快的方向。因此,沿 -∇ f(x) 方向,函数值下降最快。

用数学语言描述:对于函数 f(x),在 x_k 处的泰勒展开:

f(x_k + α d) ≈ f(x_k) + α d^T ∇ f(x_k)

其中 d 是搜索方向。当 d = -∇ f(x_k) 时,d^T ∇ f = -||∇ f||^2 < 0,函数值必然下降。

没有梯度下降会发生什么?

  • 无法高效求解大规模非线性优化问题
  • 神经网络的参数无法训练,因为损失函数通常没有解析解
  • 只能依赖暴力搜索或随机采样,效率极低
几何直觉:登山者的比喻

想象你站在一座山上(函数曲面的某点),想要走到山谷(局部最小值)。由于大雾弥漫,你只能看到脚下的坡度(梯度信息)。最明智的选择是:沿着坡度最陡的方向下山。这个"沿最陡方向下山"的过程,就是梯度下降。

但这个比喻也有局限性:登山者可能最终只到达了一个小山谷(局部最小),而不是最深的山谷(全局最小)。这也是梯度下降的固有问题。


      函数 f(x,y) 的等高线图
      
                等高线
              ╱    ╲
             ╱  峰   ╲        ↑
           ╱    ↖    ╲      梯度
          ╱          ╲      方向
         ╱            ╲      ↓
        ╱    ↘梯度   ╲    ╱ ╲
       ╱      方向     ╲  ╱   ╲
      ╱                ╲╱     ╲
     ╱________________________╲
     
     从起点开始,沿负梯度方向迭代
     最终收敛到局部最小值点
  

二、梯度下降的数学推导

What — 梯度下降的迭代公式

梯度下降的基本迭代公式为:

x_k+1 = x_k - α ∇ f(x_k

其中:

  • x_k 是第 k 次迭代的参数向量
  • α > 0学习率(step size / learning rate)
  • ∇ f(x_k 是目标函数在 x_k 处的梯度

How — 收敛性分析

对于凸函数,梯度下降可以收敛到全局最优解。收敛速度取决于:

  1. 学习率 α:太大导致振荡,太小收敛慢
  2. 条件数 κκ = (λ_max)/(λ_min),条件数越大,收敛越慢

对于二次函数 f(x) = (1)/(2_x^TA)/(x) - b)^Tx)A) 对称正定),收敛速度为:

||x_k - x)^*||_2 ≤ ((κ - 1)/(κ + 1)^k ||x_0 - x)^*||_2

可以看到,当 κ 很大时,收敛速度接近线性,但很慢。

学习率选择经验法则

对于标准化后的特征,学习率 α ∈ [0.001, 1.0] 是常见的搜索范围。具体值需要通过实验确定:

  • 太小:收敛太慢,浪费计算资源
  • 太大:在最优点附近振荡,无法收敛
  • 最佳:刚好能在最小值附近稳定振荡

三、三种梯度下降变体

三种变体的核心区别在于每次迭代使用的样本数量

类型每次迭代样本优点缺点
批量梯度下降 (BGD) 全部样本 n 个 收敛稳定,方向准确 计算慢,内存大
随机梯度下降 (SGD) 1 个样本 快,支持在线学习 方向噪声大,振荡
小批量梯度下降 (MBGD) b 个样本 (b << n) 平衡速度和稳定性 需要调参 batch_size

Batch Gradient Descent(批量梯度下降)

使用全部 n 个样本计算梯度:

θ := θ - α (1)/(n)Σ_i=1^n∇_θ L^(i)(θ)

特点:

  • 梯度方向准确,每次下降稳定
  • 计算复杂度 O(n),对于大规模数据非常慢
  • 无法处理无法一次性载入内存的数据集
def batch_gradient_descent(X, y, theta, alpha, n_iterations):
      """
      批量梯度下降
      
      参数:
          X: 特征矩阵 (n_samples, n_features)
          y: 目标向量 (n_samples,)
          theta: 初始参数 (n_features,)
          alpha: 学习率
          n_iterations: 迭代次数
      返回:
          theta: 优化后的参数
      """
      m = len(y)
      
      for i in range(n_iterations):
          # 计算全部样本的预测值
          predictions = X @ theta
          
          # 计算全部样本的平均梯度
          gradients = (1/m) * X.T @ (predictions - y)
          
          # 更新参数
          theta = theta - alpha * gradients
          
          # 每100次打印损失
          if i % 100 == 0:
              cost = (1/(2*m)) * np.sum((predictions - y) ** 2)
              print(f"Iteration {i}: Cost = {cost:.6f}")
      
      return theta
  

Stochastic Gradient Descent(随机梯度下降)

每次只使用 1 个样本:

θ := θ - α ∇_θ L^(i)(θ)

特点:

  • 计算极快,适合大规模数据
  • 梯度有噪声,可以逃离局部最优
  • 收敛路径振荡,需要更多迭代次数
  • 支持在线学习(流式数据)
import numpy as np
  
  def stochastic_gradient_descent(X, y, theta, alpha, n_epochs):
      """
      随机梯度下降
      
      每次迭代随机选择一个样本更新
      """
      m = len(y)
      
      for epoch in range(n_epochs):
          # 打乱数据顺序
          indices = np.random.permutation(m)
          
          for i in indices:
              # 单个样本的预测
              xi = X[i:i+1]  # shape: (1, n_features)
              yi = y[i]
              
              # 计算单个样本的梯度
              prediction = xi @ theta
              gradient = xi.T * (prediction - yi)  # shape: (n_features, 1)
              
              # 更新参数
              theta = theta - alpha * gradient.flatten()
          
          # 每个epoch计算一次总损失
          predictions = X @ theta
          cost = (1/(2*m)) * np.sum((predictions - y) ** 2)
          print(f"Epoch {epoch}: Cost = {cost:.6f}")
      
      return theta
  

Mini-Batch Gradient Descent(小批量梯度下降)

每次使用 b 个样本(通常 b ∈ [32, 256]):

θ := θ - α (1)/(b)Σ_i=j^j+b-1∇_θ L^(i)(θ)

特点:

  • 利用向量化加速,计算效率高
  • 梯度噪声适中,稳定性与速度平衡
  • 是深度学习中的标准方法(TensorFlow、PyTorch 默认使用)
import numpy as np
  
  def mini_batch_gradient_descent(X, y, theta, alpha, batch_size, n_epochs):
      """
      小批量梯度下降(深度学习标准做法)
      
      参数:
          batch_size: 每个batch的样本数(通常32/64/128/256)
      """
      m = len(y)
      n_batches = int(np.ceil(m / batch_size))
      
      for epoch in range(n_epochs):
          # 打乱数据
          indices = np.random.permutation(m)
          X_shuffled = X[indices]
          y_shuffled = y[indices]
          
          for b in range(n_batches):
              start_idx = b * batch_size
              end_idx = min((b + 1) * batch_size, m)
              
              X_batch = X_shuffled[start_idx:end_idx]
              y_batch = y_shuffled[start_idx:end_idx]
              
              # 计算batch梯度
              predictions = X_batch @ theta
              gradients = (1/batch_size) * X_batch.T @ (predictions - y_batch)
              
              # 更新参数
              theta = theta - alpha * gradients
          
          # 每个epoch计算一次总损失
          predictions = X @ theta
          cost = (1/(2*m)) * np.sum((predictions - y) ** 2)
          print(f"Epoch {epoch}: Cost = {cost:.6f}")
      
      return theta
  

三种梯度下降对比总结

  • BGD:适合小数据集、离线训练、需要稳定收敛的场景
  • SGD:适合超大规模数据、在线学习、需要探索能力的场景
  • MBGD:深度学习标配,batch_size 通常设为 32/64/128/256

四、学习率的选择与衰减策略

学习率是梯度下降最重要的超参数

学习率 α 决定了每次更新的步长。如果 α 太大,算法会在最优点附近振荡甚至发散;如果 α 太小,收敛速度会非常慢。

常见的学习率衰减策略

  1. 步长衰减(Step Decay):每隔固定 epoch 将学习率降低一个因子

    α_t = α_0 · γ^⌊ t / T ⌋

  2. 指数衰减(Exponential Decay)

    α_t = α_0 · e^-λ t

  3. 余弦退火(Cosine Annealing)

    α_t = α_min + (1)/(2)(α_max - α_min)(1 + cos((tπ)/(T)

  4. 学习率 warmup:开始时逐渐增大学习率,稳定后再衰减
import numpy as np
  
  class LearningRateScheduler:
      """学习率调度器"""
      
      def __init__(self, initial_lr, decay_type='step', decay_rate=0.1, 
                   decay_epochs=30, warmup_epochs=5):
          self.initial_lr = initial_lr
          self.decay_type = decay_type
          self.decay_rate = decay_rate
          self.decay_epochs = decay_epochs
          self.warmup_epochs = warmup_epochs
      
      def get_lr(self, epoch):
          """获取当前epoch的学习率"""
          # Warmup阶段
          if epoch < self.warmup_epochs:
              return self.initial_lr * (epoch + 1) / self.warmup_epochs
          
          # 衰减阶段
          if self.decay_type == 'step':
              # 步长衰减
              factor = self.decay_rate ** (epoch // self.decay_epochs)
              return self.initial_lr * factor
          elif self.decay_type == 'exponential':
              # 指数衰减
              return self.initial_lr * np.exp(-0.1 * epoch)
          elif self.decay_type == 'cosine':
              # 余弦退火
              T = 100  # 总epoch数
              return self.initial_lr * (1 + np.cos(np.pi * epoch / T)) / 2
          else:
              return self.initial_lr
  
  # 使用示例
  scheduler = LearningRateScheduler(
      initial_lr=0.1,
      decay_type='step',
      decay_rate=0.1,
      decay_epochs=30
  )
  
  for epoch in range(100):
      lr = scheduler.get_lr(epoch)
      if epoch % 10 == 0:
          print(f"Epoch {epoch}: LR = {lr:.6f}")
  

如何调试学习率

建议使用 Learning Rate Finder 方法:从很小的学习率(如 10^-8)开始,每次迭代增大学习率,记录损失函数的变化。找到损失开始下降最快的区间,选择该区间内偏小的值作为初始学习率。

五、梯度下降的 Python 实现

实战:使用梯度下降求解线性回归

让我们用梯度下降来实现一个完整的线性回归模型,对比三种变体的效果。

import numpy as np
  import matplotlib.pyplot as plt
  
  # 生成模拟数据
  np.random.seed(42)
  n_samples = 1000
  X = 2 * np.random.rand(n_samples, 1)
  y = 4 + 3 * X + np.random.randn(n_samples, 1) * 0.5
  
  # 添加偏置项
  X_b = np.c_[np.ones((n_samples, 1)), X]
  
  # 可视化
  plt.figure(figsize=(10, 4))
  plt.scatter(X, y, alpha=0.5)
  plt.xlabel('x')
  plt.ylabel('y')
  plt.title('模拟数据集')
  plt.show()
  
def gradient_descent_linear_regression(X, y, alpha=0.1, n_iterations=1000, 
                                        batch_size=None, verbose=True):
      """
      通用梯度下降线性回归
      
      参数:
          batch_size: None表示批量, 1表示随机, >1表示小批量
      """
      m, n = X.shape
      theta = np.zeros((n, 1))  # 初始化参数
      
      history = []  # 记录损失历史
      
      for iteration in range(n_iterations):
          if batch_size is None:
              # 批量梯度下降
              predictions = X @ theta
              gradients = (1/m) * X.T @ (predictions - y)
          elif batch_size == 1:
              # 随机梯度下降
              idx = np.random.randint(m)
              xi = X[idx:idx+1]
              yi = y[idx]
              prediction = xi @ theta
              gradient = xi.T * (prediction - yi)
              gradients = gradient
          else:
              # 小批量梯度下降
              indices = np.random.choice(m, batch_size, replace=False)
              X_batch = X[indices]
              y_batch = y[indices]
              predictions = X_batch @ theta
              gradients = (1/batch_size) * X_batch.T @ (predictions - y_batch)
          
          # 更新参数
          theta = theta - alpha * gradients
          
          # 记录损失
          cost = (1/(2*m)) * np.sum((X @ theta - y) ** 2)
          history.append(cost)
          
          if verbose and iteration % 100 == 0:
              print(f"Iteration {iteration}: Cost = {cost:.4f}")
      
      return theta, history
  
  # 测试三种方法
  print("=" * 50)
  print("批量梯度下降 (BGD)")
  print("=" * 50)
  theta_bgd, _ = gradient_descent_linear_regression(X_b, y, alpha=0.1, n_iterations=1000, batch_size=None)
  
  print("\n" + "=" * 50)
  print("随机梯度下降 (SGD)")
  print("=" * 50)
  theta_sgd, _ = gradient_descent_linear_regression(X_b, y, alpha=0.1, n_iterations=1000, batch_size=1)
  
  print("\n" + "=" * 50)
  print("小批量梯度下降 (MBGD, batch=32)")
  print("=" * 50)
  theta_mbgd, _ = gradient_descent_linear_regression(X_b, y, alpha=0.1, n_iterations=1000, batch_size=32)
  
  print(f"\n真实参数: [4, 3]")
  print(f"BGD 估计: [{theta_bgd[0,0]:.4f}, {theta_bgd[1,0]:.4f}]")
  print(f"SGD 估计: [{theta_sgd[0,0]:.4f}, {theta_sgd[1,0]:.4f}]")
  print(f"MBGD 估计: [{theta_mbgd[0,0]:.4f}, {theta_mbgd[1,0]:.4f}]")
  

六、梯度消失与梯度爆炸

深层神经网络的天敌

当神经网络层数很深时,梯度在反向传播过程中可能会变得非常小(梯度消失)或非常大(梯度爆炸),导致训练困难。

梯度消失(Vanishing Gradient)

在反向传播中,梯度通过链式法则传递:

(∂ L)/(∂ W^[1]) = (∂ L)/(∂ A^[n]) · (∂ A^[n])/(∂ Z^[n]) · … · (∂ Z^[2])/(∂ A^[1]) · (∂ A^[1])/(∂ W^[1])

如果每层的梯度都小于 1,连乘后梯度会指数级衰减趋近于零。

后果:前几层的参数几乎不更新,网络无法有效学习深层特征。

梯度爆炸(Exploding Gradient)

如果每层的梯度都大于 1,连乘后梯度会指数级增长。

后果:参数更新步长过大,导致权重震荡或溢出(NaN)。

解决方案

1. 权重初始化策略

  • Xavier 初始化:W ∼ N)(0, (2)/(n_in+n_out)
  • He 初始化:W ∼ N)(0, (2)/(n_in)(适合 ReLU)

2. 激活函数选择

  • ReLU 及其变体(Leaky ReLU, PReLU)可以缓解梯度消失
  • 避免使用 Sigmoid/Tanh(梯度饱和)

3. 残差连接(ResNet)

a^[l+1] = a^[l] + Conv(a^[l])

梯度可以直接流过恒等路径,避免连乘效应。

4. 梯度裁剪(Gradient Clipping)

当梯度范数超过阈值时,将其缩放到阈值范围内。

def gradient_clipping(gradients, max_norm=5.0):
      """
      梯度裁剪:防止梯度爆炸
      
      如果梯度的L2范数超过max_norm,
      将梯度缩放到max_norm
      """
      total_norm = np.sqrt(np.sum([np.sum(g**2) for g in gradients]))
      
      clip_coef = max_norm / (total_norm + 1e-6)
      
      if clip_coef < 1:
          clipped_gradients = [g * clip_coef for g in gradients]
          return clipped_gradients, True  # 表示进行了裁剪
      
      return gradients, False  # 没有裁剪
  
  # 示例
  gradients = [np.array([2.0, 3.0, 5.0]), np.array([1.0, 4.0])]
  clipped, was_clipped = gradient_clipping(gradients, max_norm=5.0)
  print(f"裁剪前梯度范数: {np.sqrt(2**2 + 3**2 + 5**2 + 1**2 + 4**2):.4f}")
  print(f"裁剪后梯度范数: {np.sqrt(np.sum([np.sum(g**2) for g in clipped])):.4f}")
  print(f"是否裁剪: {was_clipped}")
  

七、改进算法:动量与 Adam

为什么需要改进?

标准梯度下降的收敛路径在某些方向上振荡大、收敛慢。动量法和 Adam 等自适应方法通过改进更新规则,加速收敛。

Momentum(动量法)

引入"速度"概念,累积历史梯度方向,减少振荡:

v_t = β v_t-1 + (1-β) ∇_θ J(θ)

θ = θ - α v_t

其中 β ∈ [0.9, 0.999] 是动量系数。

def gradient_descent_with_momentum(X, y, theta, alpha, beta, n_iterations):
      """
      带动量的梯度下降
      """
      m = len(y)
      v = np.zeros_like(theta)  # 速度向量
      
      for i in range(n_iterations):
          predictions = X @ theta
          gradients = (1/m) * X.T @ (predictions - y)
          
          # 更新速度
          v = beta * v + (1 - beta) * gradients
          
          # 使用速度更新参数
          theta = theta - alpha * v
          
          if i % 100 == 0:
              cost = (1/(2*m)) * np.sum((predictions - y) ** 2)
              print(f"Iteration {i}: Cost = {cost:.6f}")
      
      return theta
  

Adam(Adaptive Moment Estimation)

Adam 结合了动量和 RMSProp 的思想,使用自适应学习率:

m_t = β_1 m_t-1 + (1-β_1_g_t (一阶矩估计:类似动量))

v_t = β_2 v_t-1 + (1-β_2_g_t^2 (二阶矩估计:类似 RMSProp))

m_t^corrected = (m_t)/(1-β_1^t_v_t^corrected = (v_t)/(1-β_2^t)

θ = θ - α (m_t^corrected)/(√v_t^corrected) + ε)

def adam_optimizer(theta, gradients, t, m, v, 
                     alpha=0.001, beta1=0.9, beta2=0.999, epsilon=1e-8):
      """
      Adam 优化器
      
      参数:
          theta: 当前参数
          gradients: 当前梯度
          t: 当前时间步
          m: 一阶矩估计(动量)
          v: 二阶矩估计(RMSProp)
          alpha: 学习率
          beta1, beta2: 衰减系数
          epsilon: 防止除零
      """
      # 更新一阶矩估计
      m = beta1 * m + (1 - beta1) * gradients
      
      # 更新二阶矩估计
      v = beta2 * v + (1 - beta2) * (gradients ** 2)
      
      # 偏差校正
      m_hat = m / (1 - beta1 ** t)
      v_hat = v / (1 - beta2 ** t)
      
      # 更新参数
      theta = theta - alpha * m_hat / (np.sqrt(v_hat) + epsilon)
      
      return theta, m, v
  
  def adam_linear_regression(X, y, alpha=0.1, n_iterations=1000):
      """使用 Adam 的线性回归"""
      m, n = X.shape
      theta = np.zeros((n, 1))
      
      # Adam 状态
      t = 0
      m_moment = np.zeros((n, 1))
      v_moment = np.zeros((n, 1))
      
      for iteration in range(n_iterations):
          predictions = X @ theta
          gradients = (1/m) * X.T @ (predictions - y)
          
          t += 1
          theta, m_moment, v_moment = adam_optimizer(
              theta, gradients, t, m_moment, v_moment, alpha
          )
          
          if iteration % 100 == 0:
              cost = (1/(2*m)) * np.sum((predictions - y) ** 2)
              print(f"Iteration {iteration}: Cost = {cost:.6f}")
      
      return theta
  

优化算法选择建议

  • SGD + Momentum:计算机视觉任务,效果稳定
  • Adam:NLP、强化学习、推荐系统,默认好用的选择
  • AdamW:带权重衰减的 Adam,正则化效果更好
  • Lion:2023 年新提出的简化版优化器,只用动量

FAQ 常见问题解答

Q1. 梯度下降一定能收敛到全局最优吗?

不一定。对于凸函数,梯度下降收敛到全局最优。对于非凸函数(如神经网络),只能保证收敛到局部最优或鞍点。但通过合适的初始化和超参数,可以找到足够好的局部最优。

Q2. 学习率太大或太小会怎样?

太大:参数在最优解附近振荡,甚至越过最优点导致发散。太小:收敛速度极慢,需要很多次迭代才能接近最优解,浪费计算资源。

Q3. 批量梯度下降和随机梯度下降哪个更好?

取决于场景。小数据集用批量梯度下降,大数据集用小批量梯度下降。随机梯度下降适合在线学习,但收敛振荡大。深度学习标配是小批量梯度下降(batch_size=32/64/128)。

Q4. 什么是鞍点?为什么梯度下降会在鞍点卡住?

鞍点是梯度为零但不是局部极值的点(如马鞍的形状)。在鞍点,梯度在各方向都接近零,参数更新变慢。随机梯度下降的噪声可以帮助逃离鞍点。

Q5. 为什么需要学习率衰减?

前期用较大学习率快速接近最优点,后期用较小学习率精细调整。开始时离最优点远,大学习率加速收敛;接近最优点时,大学习率会导致振荡,需要衰减。

Q6. 动量法和 Adam 的区别是什么?

动量法只使用历史梯度的指数加权平均(方向),Adam同时使用一阶矩(方向)和二阶矩(梯度大小)来自适应学习率。Adam 通常比纯动量法收敛更快更稳定。

Q7. 梯度消失和梯度爆炸的根本原因是什么?

链式法则的连乘效应。深层网络中,梯度通过每层的偏导数连乘。如果偏导数持续小于 1(梯度消失)或大于 1(梯度爆炸),多层的连乘会导致梯度极小或极大。

Q8. 如何选择 batch_size?

常见选择 32/64/128/256。小 batch_size 梯度噪声大,有助于探索但收敛不稳定;大 batch_size 梯度准确但需要更多内存。实践中常用 2 的幂次方以利用 GPU 并行计算。

Q9. 什么是 early stopping?为什么用它?

Early stopping是在验证集损失开始上升时停止训练,防止过拟合。当训练损失继续下降但验证损失开始上升,说明模型开始过拟合训练数据,此时停止训练可以保留最佳模型。

Q10. 梯度下降和正规方程有什么区别?

正规方程一步求出解析解 θ = (X^TX)^-1X^Ty,但需要矩阵求逆(O(p^3)),且不适用于非线性问题。梯度下降是迭代求解,适合大规模数据和非线性问题,但可能只能找到近似解。

Q11. 什么是二阶优化方法?为什么不用?

二阶方法使用二阶导数(Hessian矩阵)信息,如牛顿法、拟牛顿法。收敛更快,但计算 Hessian 矩阵及其逆的复杂度是 O(p^2),内存消耗大。深度学习场景基本不用。

Q12. 如何判断梯度下降是否收敛?

两种方法:① 观察损失函数曲线,当损失变化小于阈值时停止;② 设置最大迭代次数。实践中常用第二种,简单有效。

Q13. 什么是学习率 finder?

Learning Rate Finder是 Leslie Smith 提出的找最优学习率的方法。从极小学习率开始,每步指数增加,记录损失,绘制学习率 vs 损失曲线。找到损失下降最快的区间,选择该区间偏小的值。

Q14. 随机梯度下降的期望等于批量梯度吗?

是。随机梯度是对真实梯度的无偏估计:E[∇_θ L^(i)(θ)] = ∇_θ L(θ)。因此理论上 SGD 可以收敛到同一点,只是路径更曲折。

Q15. 什么是 Nesterov 动量?

Nesterov Accelerated Gradient(NAG)是一种改进的动量法。先按历史动量方向更新,再计算梯度并修正。比起标准动量,NAG 在碰到陡坡时能更早减速,更快收敛。

Q16. 梯度为 0 一定是最优点吗?

不一定。梯度为 0 的点可能是:① 局部最小值;② 局部最大值;③ 鞍点。需要检查 Hessian 矩阵或使用二阶信息来区分。

Q17. 为什么要对特征做归一化/标准化?

加速收敛。不同特征尺度差异大时,损失函数的等高线是椭圆形,梯度下降路径曲折。归一化后等高线接近圆形,梯度下降可以沿直线更快到达圆心。

Q18. Adam 为什么需要偏差校正?

因为初始化时一阶、二阶矩估计为零。在训练初期(t 很小),m_t = (1-β_1^t_m_true 远小于真实值,需要除以 (1-β_1^t) 来校正。后期(t 大时)β^t ≈ 0,校正效果可以忽略。

Q19. 什么是 Learning Rate Schedule?

Learning Rate Schedule是预先定义的学习率衰减策略,如 step decay、cosine annealing、warmup。与自适应方法(Adam)不同,schedule 是全局统一调整,不针对每个参数。

Q20. 深度学习框架默认用什么优化器?

PyTorch/TensorFlow 默认通常是 SGD + Momentum。但社区广泛使用 Adam 作为默认选择,因为它收敛快、调参少。实际项目中,CV 任务常用 SGD+Momentum,NLP 任务常用 Adam/AdamW。

本文核心知识点回顾

  • 1 个核心公式θ_k+1 = θ_k - α ∇ f(θ_k)
  • 2 个问题:梯度消失 + 梯度爆炸
  • 3 种变体:BGD(批量)、SGD(随机)、MBGD(小批量)
  • 4 个关键超参数:学习率 α、batch_size、动量 β、衰减策略
  • 5 个常用优化器:SGD、Momentum、AdaGrad、RMSProp、Adam

Roadmap 后续预告

在理解了梯度下降算法之后,第三篇我们将学习最小二乘法的梯度下降算法及 Python 实现。这篇将深入探讨:

  • 如何用梯度下降法求解最小二乘问题
  • 从正规方程到迭代优化的桥梁
  • 大规模最小二乘问题的分布式求解
  • 实战:用 NumPy/PyTorch 实现完整的最小二乘梯度下降
posted @ 2026-07-10 17:52  左扬  阅读(22)  评论(0)    收藏  举报