梯度下降(Gradient Descent)
梯度下降是训练几乎所有机器学习模型的核心优化算法。它做的事很单纯:不断微调模型参数,让损失函数(模型的”错误程度”)一点点变小,直到找到(近似)最优参数。 从线性回归到神经网络到大语言模型,训练本质都是在跑梯度下降。
一句话类比:梯度下降就像在浓雾中下山。你看不到山谷在哪(不知道最优解),但能感觉到脚下哪个方向最陡(梯度)。于是你朝最陡的下坡方向迈一小步,到新位置再感受一次,反复迈步,最终走到谷底(损失最小处)。步子的大小就是学习率。
关联:训练模型 = “定义一个衡量错误的损失函数(见
cross-entropy-loss.md)→ 用梯度下降最小化它”。single-layer-perceptron.md里的更新规则,其实就是梯度下降的一个特例(见第 8 节)。
1. 为什么需要它:训练 = 最小化损失
模型里有一堆参数(权重 w、偏置 b)。训练的目标是找到一组参数,让模型预测得尽量准,也就是让损失函数 L(参数) 尽量小。
问题是:参数动辄成千上万乃至上亿,损失函数是个超高维的复杂曲面,没法直接解出最小值。于是改用”迭代逼近”:从一个随机起点出发,每一步都往”损失更小”的方向挪一点,慢慢逼近谷底。
关键认知:梯度下降不保证找到全局最优,它找的是”从当前起点出发,一路下坡能到的最低点”。 但实践中,对高维神经网络这通常已经足够好。
2. 核心直觉:梯度指向”最陡上升”,所以要往反方向走
- 梯度 (Gradient) ∇L:损失函数对每个参数的偏导数组成的向量。它指向函数值上升最快的方向。
- 我们要让损失下降,所以往**梯度的反方向(负梯度)**走。
- 梯度的大小反映坡度陡不陡:越陡(离最优越远)步子迈得越大,越平(接近谷底)步子自然越小。
损失 L
│ ╲ ╱
│ ╲ 负梯度方向 ╱
│ ╲ ◀──────── ╱
│ ╲___ _╱
│ ╲___ ___╱ ← 谷底:梯度≈0,停下
│ ╲__╱
└──────────────────────────▶ 参数 θ
当前位置,坡度向右上,
所以往左(负梯度)走
一维直觉:
dL/dθ > 0说明”θ 增大损失增大”,那就减小 θ;dL/dθ < 0说明”θ 增大损失减小”,那就增大 θ。无论哪种,θ 都是朝导数的反方向动——这正是下面公式里那个减号的来历。
3. 参数更新公式(整个算法就这一行)
| 符号 | 含义 |
|---|---|
| 参数(权重、偏置) | |
| 损失对参数的梯度(最陡上升方向) | |
| (eta) | 学习率 (learning rate),步长 |
| 减号 | 往梯度反方向走 = 下坡 |
算法流程:
1. 随机初始化参数 θ
2. 重复直到收敛:
a. 用当前 θ 算损失 L 和梯度 ∇L
b. θ ← θ − η · ∇L # 朝负梯度走一步
3. 得到(近似)最优 θ
4. 学习率 η:最关键的超参数
学习率决定每步迈多大,直接影响训不训得好:
| 学习率 | 现象 | 后果 |
|---|---|---|
| 太小 | 步子太小 | 收敛极慢,训练半天不动 |
| 合适 | 稳步下降 | 平滑收敛到谷底 |
| 太大 | 步子太大 | 在谷底两侧来回震荡,甚至越走越高发散 |
太小: ·→·→·→· 慢慢挪,半天到不了底
合适: ·→ · → · ↘ 稳稳到底
太大: · → · ← · → · ← 左右横跳,下不去
呼应
single-layer-perceptron.md第 8 节的网格搜索:那里试lr=0.003/0.01/0.03,太小学不动、太大有波动、0.01 刚好——就是这里”学习率取舍”的实例。实践中还常用学习率调度(先大后小)和自适应优化器(见第 7 节)。
5. 三大变体:一次用多少数据算梯度
区别在于每次更新用多少样本来估计梯度:
| 变体 | 每步用的数据 | 优点 | 缺点 |
|---|---|---|---|
| 批量梯度下降 (BGD) | 全部训练数据 | 梯度准、下降平稳 | 慢、吃内存,大数据集跑不动 |
| 随机梯度下降 (SGD) | 每次 1 个样本 | 快、能跳出局部最优 | 抖动大、不稳定 |
| 小批量 (Mini-batch) | 一小批(如 32/64/128) | 兼顾速度与稳定,能用 GPU 并行 | 需选 batch size |
实践里 99% 用 Mini-batch(虽然代码里的优化器常叫
SGD,但一般喂的是小批量)。相关概念:把整个训练集过一遍叫一个 epoch;每次更新用的那一小批叫一个 batch;一个 epoch 里更新的次数 = 样本数 / batch size。
6. 代码:从手写到框架
手写一个线性回归的梯度下降(拟合 y = wx + b,损失用 MSE):
import numpy as np
# 造点数据:真实关系 y ≈ 2x + 1
X = np.array([1, 2, 3, 4, 5], dtype=float)
y = np.array([3, 5, 7, 9, 11], dtype=float)
w, b = 0.0, 0.0 # 参数初始化
lr = 0.01 # 学习率
n = len(X)
for step in range(1000):
y_pred = w * X + b # 前向:当前预测
error = y_pred - y # 预测 - 真实
# MSE 损失 L = mean(error^2),对 w、b 求偏导得到梯度:
grad_w = (2/n) * np.sum(error * X) # ∂L/∂w
grad_b = (2/n) * np.sum(error) # ∂L/∂b
w -= lr * grad_w # 朝负梯度走一步(就是第 3 节公式)
b -= lr * grad_b
print(w, b) # → 接近 2 和 1用 PyTorch(autograd 自动求梯度,不用手推):
import torch
X = torch.tensor([1, 2, 3, 4, 5.])
y = torch.tensor([3, 5, 7, 9, 11.])
w = torch.tensor(0.0, requires_grad=True) # 标记:要对它求梯度
b = torch.tensor(0.0, requires_grad=True)
optimizer = torch.optim.SGD([w, b], lr=0.01) # 优化器负责执行更新
for step in range(1000):
y_pred = w * X + b
loss = ((y_pred - y) ** 2).mean() # MSE
optimizer.zero_grad() # ① 清空上一轮的梯度(不清会累加!常见坑)
loss.backward() # ② 自动反向传播算出所有梯度 (.grad)
optimizer.step() # ③ 按 θ -= lr*grad 更新参数
print(w.item(), b.item())三步
zero_grad → backward → step是 PyTorch 训练的固定节奏。backward()靠反向传播 (backpropagation) 自动算梯度——这是神经网络能高效求梯度的关键,梯度下降负责”怎么走”,反向传播负责”算出往哪走”。详见../python/torch.md。
7. 进阶优化器(梯度下降的改良版)
朴素梯度下降有缺点(震荡、对学习率敏感、各参数用同一个步长)。实用中常用改良版:
| 优化器 | 核心思想 | 一句话 |
|---|---|---|
| Momentum(动量) | 累积过去的梯度方向,像滚下山的球带惯性 | 加速收敛、抑制震荡 |
| AdaGrad / RMSProp | 给每个参数自适应不同的学习率 | 稀疏/不同尺度参数更友好 |
| Adam | Momentum + 自适应学习率的结合 | 最常用的默认选择,通常无脑用它 |
记忆锚点:朴素 SGD 是”匀速直线下山”,Momentum 加了”惯性”,Adam 再加”每个方向单独调速”。 不知道用啥时,先上 Adam。
8. 和感知机更新规则的关系(打通已有笔记)
single-layer-perceptron.md 第 6 节的更新规则:
w = w + lr * (y_i - y_pred) * x_i它和梯度下降是同一个套路:(y_i - y_pred) 是误差,* x_i 来自对参数求导的链式法则,lr 是学习率,整体就是”沿着减小误差的方向调整 w”。
换句话说:感知机的”遇错就改”,就是梯度下降在特定损失下的具体形态。 你已经会的东西,其实就是梯度下降。理解了这条主线,从感知机到神经网络的过渡就顺了。
9. 常见坑 / 误区(复习重点)
- ❌ “梯度下降一定能找到全局最优” → 只保证局部最优;高维里更多是鞍点问题,靠 SGD 的随机性、Momentum 等帮助逃离
- ❌ “学习率随便设” → 最关键的超参数:太小学不动、太大会震荡甚至发散(见第 4 节)
- ❌ “不做特征归一化也行” → 各特征尺度差很大时,损失曲面被”拉长”,梯度下降会来回横跳、收敛极慢。训练前务必归一化(呼应感知机笔记第 9 节)
- ❌ “PyTorch 里忘了
zero_grad()” → 梯度会累加到上一轮,导致更新错乱。每轮backward前必须清零 - ❌ “梯度消失/爆炸不用管” → 深层网络里梯度连乘会趋近 0(学不动)或爆炸(发散);靠合适的激活函数、归一化层、梯度裁剪缓解
- ❌ “loss 不降就是模型不行” → 先查学习率、归一化、数据/标签、是否 zero_grad,多数是这些工程问题
- ❌ “batch 越大越好” → 大 batch 稳但泛化可能变差、吃显存;小 batch 抖动大但有正则效果,需权衡
10. 延伸阅读 / 关联概念
- 交叉熵损失 — 梯度下降最小化的目标之一(分类任务);见
cross-entropy-loss.md - 单层感知机 — 其更新规则是梯度下降的特例;见
single-layer-perceptron.md - PyTorch — autograd 自动求梯度、优化器;见
../python/torch.md - 矩阵运算 / 点积 — 梯度计算的数学基础;见
../python/matrix-operations.md - 广播 — 向量化实现梯度计算;见
../python/broadcasting.md - 反向传播 (Backpropagation) — 神经网络里高效计算梯度的算法,梯度下降的搭档
- SFT / 基座模型训练 — 大模型训练同样靠梯度下降 + 交叉熵;见
../ai-agent-guide/foundation_model.md - 学习率调度 / 优化器 (Adam) — 让梯度下降更快更稳的工程手段