3、Batch Size的物理意义:吞吐量与延迟的跷跷板效应
聊到Batch Size,很多人第一反应就是「调大一点,跑得快」。嗯,这话没错,但只说对了一半。
我个人习惯把Batch Size看作一个资源分配器。它决定了你手里的计算资源(GPU显存、算力)怎么分给每个样本。你给每个样本分得越少,一次处理的样本就越多——这就是吞吐量。但代价呢?每个样本等得越久——这就是延迟。
说白了,这就是一个跷跷板。一头压下去,另一头就翘起来。
3.1 吞吐量:你到底有多快?
吞吐量,单位时间能处理多少样本。公式很简单:
吞吐量 = Batch Size × 每秒处理的Batch数
你可能会想:「那我Batch Size翻倍,吞吐量不就翻倍了?」
理想很丰满,现实很骨感。我在项目中遇到过这种情况:把Batch Size从32调到64,吞吐量只涨了60%。为什么?因为GPU的利用率不是线性的。
GPU就像一条流水线。小Batch时,流水线经常「空转」——计算单元等着数据加载。大Batch时,流水线填满了,但内存带宽又成了瓶颈。
我建议你记住这个经验值:
| Batch Size范围 | 吞吐量增长趋势 | 瓶颈在哪 |
|---|---|---|
| 1 ~ 8 | 接近线性增长 | GPU利用率低 |
| 8 ~ 64 | 亚线性增长(60%~80%) | 内存带宽 |
| 64 ~ 256 | 增长缓慢(20%~40%) | 计算单元饱和 |
| 256+ | 几乎不再增长 | 显存容量 |
核心结论:吞吐量不是越大越好。找到那个「拐点」——再增大Batch Size,吞吐量几乎不涨了——才是最优解。
3.2 延迟:每个样本的等待时间
延迟,就是单个样本从进来到出去的时间。你想想看,Batch Size越大,一个样本就得等整个Batch处理完才能出去。这不就慢了嘛。
延迟分两种:
- 计算延迟:模型真正算这个样本的时间。这部分基本固定,跟Batch Size关系不大。
- 排队延迟:样本在队列里等前面样本处理完的时间。这部分跟Batch Size强相关。
举个例子。假设你处理一个样本需要10ms,Batch Size是32。那么:
- 第一个样本:等0ms + 算10ms = 10ms
- 第16个样本:等150ms + 算10ms = 160ms
- 第32个样本:等310ms + 算10ms = 320ms
看到了吗?最后一个样本的延迟是第一个的32倍!
注意:如果你做的是实时推理(比如在线推荐、语音识别),延迟就是生命线。我曾经见过一个团队把Batch Size从64调到128,吞吐量涨了15%,但P99延迟直接翻倍——线上服务直接超时报警。得不偿失。
3.3 跷跷板效应:怎么找到平衡点?
吞吐量和延迟,就像鱼和熊掌。你不可能同时拿到最大吞吐量和最低延迟。
我个人的经验是:先明确你的业务场景,再决定往哪边倾斜。
场景一:离线批处理
比如训练模型、数据清洗。延迟无所谓,吞吐量越高越好。那就往死里怼Batch Size,怼到显存快爆为止。
# 伪代码示例:找到最大Batch Size
max_batch_size = 1
while True:
try:
model(batch_size=max_batch_size * 2)
max_batch_size *= 2
except RuntimeError: # OOM
break
print(f"最大Batch Size: {max_batch_size}")
场景二:在线实时服务
比如API接口、游戏AI。延迟有硬性要求(比如<100ms),那就得牺牲吞吐量。我建议从Batch Size=1开始,慢慢往上加,直到延迟接近阈值。
# 伪代码示例:找到满足延迟的Batch Size
latency_threshold = 100 # ms
batch_size = 1
while True:
latency = measure_latency(batch_size)
if latency > latency_threshold:
break
batch_size += 1
print(f"最大可用Batch Size: {batch_size - 1}")
场景三:混合场景
大部分场景其实都是混合的。既要吞吐量,又不能太慢。这时候我建议用动态Batch——根据当前负载自动调整。
一个小技巧:我曾经在广告推荐系统里用过「自适应Batch」。做法很简单:监控队列长度,队列短就用大Batch(提高吞吐),队列长就用小Batch(降低延迟)。效果出奇的好,吞吐量提升了30%,P99延迟还降了20%。
3.4 一张图看懂:吞吐量与延迟的跷跷板
下面这张SVG图,把整个逻辑串起来了。你一看就明白。
这张图很直观。左边是小Batch,延迟高但吞吐量低;右边是大Batch,吞吐量高但延迟也高。中间那个黄色圆点,就是你要找的平衡点。
3.5 避坑指南
最后,分享几个我踩过的坑:
- 别只看平均值:平均延迟好看,但P99延迟可能已经炸了。我建议重点关注P99甚至P999。
- 显存不是唯一限制:有时候显存没爆,但内存带宽先爆了。用
nvidia-smi看看GPU利用率,如果一直100%但吞吐量不涨,那就是带宽瓶颈。 - 动态Batch不是万能药:它增加了系统复杂度。如果你的负载很稳定,固定Batch Size反而更靠谱。
一句话总结:Batch Size没有「最佳值」,只有「最适合你场景的值」。先搞清楚你要吞吐量还是低延迟,再动手调。别盲目跟风,也别死守一个值。
好了,这一章就到这里。记住跷跷板效应,下一章我们聊聊怎么用工具实际测量这些指标。