批处理基础概念:从定义到吞吐量优化
各位同学,今天我们来聊聊批处理。这个词你肯定听过,但真正理解它的人不多。
我刚开始做端侧推理时,也踩过不少坑。有一次,我为了追求低延迟,把Batch Size设成了1。结果呢?芯片利用率不到20%,功耗倒是没少。后来我才明白——批处理不是简单的「多塞几个数据」,而是一门平衡的艺术。
批处理的定义:到底什么是批处理?
说白了,批处理就是把多个输入样本打包,一次性交给模型处理。你想想看,如果每次只处理一个样本,模型就得反复加载权重、初始化计算单元。这就像你每次只搬一块砖,来回跑路的时间比搬砖本身还长。
批处理的核心思想是:用空间换时间。把多个样本堆在一起,让计算单元一次性吃饱。
批处理(Batching):将 N 个独立的输入样本组合成一个张量,在模型推理时一次性前向传播,得到 N 个输出结果。
举个例子。假设你有一个卷积层,输入是 3x224x224 的图片。单张处理时,计算单元只用到了一部分。但如果你把 8 张图片拼成 8x3x224x224,计算单元就能满负荷运转。嗯,这就是批处理的本质。
Batch Size 的影响:大还是小?
Batch Size 的选择,直接影响三个关键指标:延迟、吞吐量、显存占用。
我个人习惯把 Batch Size 的影响总结成一张表:
| Batch Size | 延迟(单样本) | 吞吐量 | 显存占用 | 适用场景 |
|---|---|---|---|---|
| 1 | 低 | 低 | 低 | 实时交互、语音唤醒 |
| 4~8 | 中 | 中 | 中 | 视频分析、图像分类 |
| 16~32 | 高 | 高 | 高 | 离线批量处理、数据标注 |
| 64+ | 极高 | 饱和 | 极高 | 服务器端推理(端侧慎用) |
注意看,延迟和吞吐量不是线性关系。Batch Size 从 1 增加到 8,吞吐量可能提升 5 倍,但延迟只增加了 2 倍。为什么会这样?因为计算单元被更充分地利用了。
我曾经在手机上跑 MobileNetV3,Batch Size 从 1 调到 4,吞吐量从 30 FPS 飙到 110 FPS。但调到 8 时,显存爆了。嗯,这就是端侧的残酷现实——资源有限。
注意:端侧设备的显存通常只有 2~8 GB。Batch Size 过大,轻则 OOM(内存溢出),重则系统卡死。我建议从 1 开始,逐步翻倍,直到显存占用接近 80% 为止。
批处理与吞吐量的关系:数学视角
吞吐量(Throughput)的定义很简单:单位时间内处理的样本数。公式是:
Throughput = Batch Size × 每秒处理的批次数
但这里有个陷阱。每秒处理的批次数,受限于模型的计算时间和数据搬运时间。你想想看,如果 Batch Size 翻倍,计算时间可能只增加 50%,但数据搬运时间可能翻倍。这时候,吞吐量反而会下降。
我画个简化的模型:
总时间 = 数据加载时间 + 模型计算时间 + 结果回传时间
吞吐量 = Batch Size / 总时间
在端侧,数据加载时间往往被忽略。但我在项目中遇到过,Batch Size 从 4 调到 8 时,吞吐量反而下降了 15%。排查后发现,是内存带宽成了瓶颈。数据从 DDR 搬运到 NPU 的速度跟不上计算速度。
我的经验:在端侧,Batch Size 的「甜蜜点」通常在 2~8 之间。超过 8 后,收益递减明显。你可以用这个公式估算:
最优 Batch Size ≈ 计算单元数量 × 2
比如你的 NPU 有 4 个核心,那 Batch Size 设为 8 左右比较合理。
实际案例:从 30 FPS 到 120 FPS
我记得有一次优化人脸检测模型。原始代码是逐帧处理,Batch Size = 1,帧率只有 30 FPS。客户要求至少 60 FPS。
我做了三件事:
- 合并输入:把连续 4 帧拼成一个 Batch,Batch Size = 4
- 异步加载:用双缓冲机制,计算当前 Batch 时,预加载下一个 Batch
- 调整内存布局:把 NHWC 格式改成 NCHW,减少内存碎片
结果呢?帧率直接飙到 120 FPS,显存占用只增加了 30%。客户很满意,我也松了口气。
但这里有个前提——你的模型必须支持动态 Batch Size。有些模型在导出时固定了 Batch Size,比如 ONNX 模型如果指定了 batch=1,那就没法改了。所以,设计模型时就要考虑批处理。
避坑指南:我曾经踩过的坑
我曾经在某个项目里,把 Batch Size 设得太大,结果模型推理结果全错了。排查了半天,发现是 Batch Normalization 层的问题。BN 层在推理时,如果 Batch Size 太小(比如 1),统计量会不稳定。但 Batch Size 太大(比如 64),又会导致显存溢出。
所以,我的建议是:
- 如果模型里有 BN 层,Batch Size 不要小于 4
- 如果模型里有 LayerNorm,Batch Size 可以小一些
- 如果模型是纯卷积或全连接,Batch Size 可以大一些
另外,别忘了端侧设备的散热限制。Batch Size 越大,功耗越高,发热越严重。我曾经在平板上跑大 Batch,10 分钟后温度飙到 70°C,系统自动降频,吞吐量反而比小 Batch 还低。
总结一下:
- 批处理 = 多个样本打包处理
- Batch Size 影响延迟、吞吐量、显存
- 端侧推荐 Batch Size = 2~8
- 吞吐量不是线性增长,存在甜蜜点
- 注意 BN 层、内存带宽、散热限制
下一章,我们会深入讨论流水线设计。到时候你会发现,批处理和流水线结合起来,效果更惊人。嗯,今天就到这里,有问题随时问我。