单卡训练的瓶颈:显存墙、计算墙、通信墙,以及单卡时代的无奈
说实话,我刚入行那会儿,觉得单卡训练挺香的。
一张卡,一个脚本,跑起来就完事了。模型不大,数据不多,日子过得挺滋润。但后来模型越做越大,数据越堆越多,单卡就开始「喘不过气」了。
今天咱们聊聊,单卡训练到底卡在哪。我把它总结成三堵墙:显存墙、计算墙、通信墙。嗯,这三堵墙,每一堵都让人头疼。
第一堵墙:显存墙
显存墙,说白了就是「装不下」。
你想想看,一个 7B 参数的模型,光参数就要占 14GB 左右(FP16)。再加上梯度、优化器状态(比如 Adam 需要存一阶和二阶动量),轻松翻倍到 28GB。这还没算中间激活值呢。
我在项目中遇到过,一个 13B 的模型,单卡 A100(80GB)根本跑不起来。强行跑,OOM 报错,直接崩掉。
| 组件 | 显存占用(FP16) |
|---|---|
| 模型参数 | ~14 GB |
| 梯度 | ~14 GB |
| 优化器状态(Adam) | ~28 GB |
| 中间激活值(batch_size=1) | ~2-5 GB |
| 总计 | ~58-61 GB |
你看,光参数和优化器就占了 56GB,留给激活值的空间没多少了。想加大 batch size?门都没有。
第二堵墙:计算墙
计算墙,就是「算不动」。
单卡的计算能力是有限的。一张 A100 的 FP16 算力大约是 312 TFLOPS。听起来很猛对吧?但模型大了,数据多了,这点算力根本不够看。
举个例子,训练一个 175B 的 GPT-3,单卡 A100 需要跑多久?我算过,大概要 288 年。你没看错,是年,不是天。
为什么会这样?因为计算量跟模型参数量、数据量成正比。模型越大,计算量越大。单卡的计算能力是固定的,所以训练时间线性增长。
- 一次前向+反向的计算量 ≈ 6 × 参数量 × 数据量(token数)
- 175B 模型,训练 300B tokens:6 × 175B × 300B ≈ 3.15 × 10^23 FLOPs
- 单卡 A100(312 TFLOPS):3.15 × 10^23 / (312 × 10^12) ≈ 1.01 × 10^9 秒 ≈ 32 年
嗯,32 年。等你训练完,下一代模型都该出来了。
第三堵墙:通信墙
通信墙,这个在单卡时代其实不明显。但当你开始尝试多卡时,它就会冒出来。
单卡训练没有通信开销,因为所有数据都在一张卡上。但这也意味着,你无法利用多卡并行来加速。
你想想看,单卡训练时,CPU 把数据加载到内存,然后拷贝到 GPU 显存。这个 PCIe 传输过程,其实就是一个隐形的通信瓶颈。数据加载慢了,GPU 就得等着。
我在项目中遇到过,数据加载用了 DataLoader 的 num_workers=0,结果 GPU 利用率只有 30%。说白了,GPU 在等数据,闲着呢。
单卡时代的无奈
这三堵墙加在一起,让单卡训练变得很无奈。
- 模型不能太大:显存放不下,强行放就得用梯度累积,训练速度更慢。
- 数据不能太多:计算时间太长,等不起。
- 实验迭代慢:改个超参数,跑一次要几天,试错成本极高。
说白了,单卡训练就像一个人搬砖。砖少还行,砖多了,你搬不动也搬不快。
- 模型参数量 < 1B
- 训练数据 < 10GB
- 快速原型验证
- 调试代码和超参数
一旦超出这个范围,单卡就力不从心了。这时候,你就得考虑多卡分布式训练。
知识体系:单卡瓶颈全景图
下面这张图,是我自己整理的。它把单卡训练的三大瓶颈和它们之间的关系画出来了。你看一眼,就能明白为什么单卡时代那么无奈。
你看,这三堵墙是相互关联的。显存放不下,你就得用更小的 batch size,计算效率更低。计算太慢,你就得等,实验周期拉长。数据加载有瓶颈,GPU 利用率上不去,算力浪费。
嗯,单卡时代就是这么无奈。
好了,单卡的瓶颈咱们聊完了。下一节,咱们看看多卡是怎么打破这三堵墙的。
想要更多资料,联系可可