批量训练

数据量大了,每次喂全量太慢——把数据切成小块,让训练又快又稳。

知识课 · 约 25 分钟 · 更新于 2026-06-08

回顾:每次更新都用全部数据?

到目前为止,所有训练循环都是这样写的:

把 全部 N 个样本 都过一遍,求平均 loss,再做 一次 参数更新。 这种做法叫 批量梯度下降 (Batch Gradient Descent,简称 BGD)。

它的 好处 很直接——梯度是 全量平均 , 估计精确、噪声小,loss 曲线最稳定。但代价也很明显:

  • 慢 :当 N 很大(百万级),每一步都要算上百万次前向 + 反向, 一个 epoch 才能动一次参数
  • 容易卡住 :损失曲面光滑无噪—— 一旦掉到 局部最小值 附近梯度变小,就难以逃脱

另一个极端:随机梯度下降

既然全量更新慢,那干脆每次只用 一个样本 更新一次:

这就是 随机梯度下降 (Stochastic Gradient Descent,SGD)。

它的 好处 是 更新最频繁、单步最便宜 —— N 个样本就有 N 次参数更新,每一步只需要算一条样本的前向 + 反向。 但代价也很明显:

  • 梯度噪声大 :单样本梯度方向极不稳定, loss 曲线呈剧烈震荡,难以判断是否真正收敛
  • 浪费 GPU 算力 :GPU 一次能并行算上百条样本, 单条单条地喂会让它的算力闲着

最佳折中:mini-batch SGD

实际使用的是两者的折中——每次取 一小批 样本(比如 32 / 64 / 128 条) 计算平均梯度后更新:

式子里的 就是这一批的样本数——它有个专门的名字叫 batch_size (批量大小),是 mini-batch SGD 中最常见的超参之一,决定了每次参数更新一起参与计算的样本数。

这就是 mini-batch SGD ,是当今所有深度学习训练的默认选择。 它兼顾了 BGD 的稳定性与 SGD 的效率,并且能充分利用 GPU 的并行能力—— 一个 batch 一次性算完,吞吐远超单样本逐个算。

batch_size 的影响规律

越大,单步算的样本越多、梯度越接近全量平均; 越小则相反。所以选 32 还是 256 还是 1024 并非随意——这个超参的影响有迹可循:

粗略经验—— 能装下就用大点 ,但不要一味追求大 batch; 小 batch 带来的梯度噪声反而能帮模型逃出尖锐的局部最小值。

PyTorch 数据加载工具链

要做 mini-batch 训练,需要把数据切片成 batch 一个个喂给模型。 PyTorch 提供两个核心工具:

  • Dataset :定义"一份数据怎么取"——给定索引返回一对
  • DataLoader :自动把 Dataset 按 batch_size 切片、打乱、并行预取

重写训练循环

加上 batch 维度后,训练循环变成 外层 epoch + 内层 batch 的双层循环:

Playground:batch_size 对比实验

最后通过一个 Playground 直观感受 batch_size 对训练的影响—— 选择不同的 batch 大小,点击「训练一次」,下方折线图会按颜色叠加每次试验的 loss 曲线。

观察: batch=1 时单步用单样本梯度,loss 曲线锯齿剧烈; batch=32 已显著平滑; batch=256 的曲线几乎是一条平滑下降线,非常接近 全量 训练。

附录:张量批量操作语法

引入 batch 维度后,张量普遍会多出一个维度(典型形状 )。 所谓「批量友好」是指:这些工具能自动按 batch 维并行计算, 让你不必为 batch 写 for 循环。下面是几个最常被提到的:

记号约定 :下表中 始终表示 batch 维;其他大写字母( 、 、 、 )表示 样本本身 的维度, 与 batch 无关。