最近在折腾用 Llama 2 7B 做微调,看到 PyTorch 2.0 的 torch.compile 吹得很厉害,说能白嫖 30%-50% 的加速。但我试了下在单卡 A100 上跑 LoRA,torch.compile(mode="reduce-overhead") 反而比原生 torch 慢了一截,而且第一次编译要等好久。我用的 deepspeed stage2 加 bf16,是不是大模型场景下编译加速不明显,还是我哪里配错了?大佬们有没有实际对比过训练吞吐的?另外,编译后的显存开销好像也变大了,这正常吗?真心求教,不想把时间浪费在玄学调优上。
PyTorch 2.0 编译模式在大模型训练中真的比原生快很多吗?
全部回复
共 165 条说实话reduce-overhead这个模式在大模型场景下经常适得其反,它主要是针对小batch和动态shape优化的,你跑LoRA这种固定shape的大batch,反而会触发额外的布局转换开销。我建议你试试mode="max-autotune"配合fullgraph=True,至少在Llama微调上比默认模式稳定不少。至于显存升高是正常的,编译会缓存一些中间buffer,但如果你开gradient checkpointing应该能压回去。你deepspeed stage2和torch.compile的兼容性也得确认下,有些时候offload参数会和编译图冲突,可以先关掉cpu offload试试纯显存offload。
这问题我踩过一模一样的坑,reduce-overhead在A100上对LoRA这种小batch场景确实容易负优化,它那个cudagraphs把显存占用拉高不少。建议试试mode="max-autotune"或者干脆默认模式,然后配合deepspeed时把compile放到stage2初始化之后,我之前这样调能勉强追平原生速度。不过说实话,7B微调瓶颈多半在数据加载和通讯上,编译带来的收益真没宣传那么神,你不如把时间花在调gradient checkpointing上。
torch.compile 在大模型上确实不是无脑收益,尤其是你这种 LoRA + DeepSpeed 的组合,我怀疑是 compile 和 stage2 的通信原语没完全对齐,导致 graph break 频繁,反而把 kernel 融合的收益吃掉了。我自己在 7B 上试过,只开 bf16 不加 deepspeed 的时候,compile 大概能快 15% 左右,但一上 stage2 就基本打平甚至略慢,所以不是你的错觉。显存开销变大是正常的,因为 compile 会做算子缓存和额外的中间张量分配,尤其 reduce-overhead 模式会为了减少内核启动时间而多占一些显存,这在 80G 卡上还好,但小显存确实会吃紧。建议你试试 mode="default" 或者 max-autotune,有时候 reduce-overhead 在短序列场景下反而会引入同步开销。另外可以先关掉 compile 跑一次 profiling,看看是不是 attention 那块没走 flash attention 的融合路径,LoRA 的低秩分支如果拆分得太细,也容易打断编译器优化。我最后的妥协方案是小 batch 用原生,大 batch 开 compile,吞吐曲线会交叉,你可以画个 batch size 的扫描图,比盲调强多了。
说实话你这个现象挺典型的,我这边在70B上试过,torch.compile对LoRA这种参数高效微调收益确实很有限,因为瓶颈主要在显存带宽和通信上,而编译优化的是算子融合和内核调度,这俩在deepspeed stage2下反而容易打架。我第一次用reduce-overhead也遇到编译时间巨长的问题,后来发现得配合dynamic=False或者干脆用mode="default"才没那么离谱,而且你得把编译放在训练循环外只做一次预热,不然每轮都重新编译那肯定慢。显存开销变大是正常的,因为编译会生成额外的中间缓存和代码,尤其reduce-overhead会牺牲显存换速度,这在7B上可能不算啥,但你要是跑更大模型就得掂量了。建议你先试试关掉deepspeed只跑单卡纯DDP,看看编译有没有正收益,如果还是没有,大概率是你CUDA版本和pytorch的cudagraph不兼容,我上次就是12.1的CUDA配2.0.1的torch踩坑,升到2.1.0就好了。另外你可以看看nsys profile一下,看看是不是kernel launch overhead被掩盖了但实际上compute没提升,反正我觉得这功能对训练来说更多是玄学,推理时才真的香。
实话实说,torch.compile在LoRA这种小参数更新场景里真没那么神,尤其配了deepspeed以后,图优化和stage2的通信调度反而容易互相打架。我拿7B试过,reduce-overhead在batch size小的时候显存开销确实涨,因为编译器会做算子融合和缓存,你可以试试mode="default"或者max-autotune,有时候比硬上reduce-overhead稳定。另外第一次编译的耗时无所谓,关键是看steady state的吞吐,你要是跑长训练步数其实还是能回本的。不过你要是主要瓶颈在数据加载或者通信,那编译带来的收益确实会被摊薄。
同感,reduce-overhead在LoRA上基本负优化,试试mode=default或者max-autotune,顺便把deepspeed的通信压缩开下。
torch.compile在LoRA这种小参数量场景下编译开销覆盖不掉收益,换大模型全参数微调再对比下。
踩过一样的坑,reduce-overhead在deepspeed下确实容易负优化,试试mode="max-autotune"配fullgraph,吞吐能上来。
我试过类似配置,Lora下compile收益确实小,reduce-overhead还容易爆显存,不如直接关掉省心。
这玩意儿对小模型和CNN友好,大模型训练瓶颈在通信和显存带宽,编译优化空间真不大。
这问题太真实了,我试过reduce-overhead配deepspeed也是负优化,感觉小batch下编译开销根本摊不回来。
小模型上确实香,但大模型+deepspeed这组合编译收益容易抵消,显存涨是CUDA graph的锅,正常。
我试过类似配置,reduce-overhead对LoRA反而容易触发重编译,试试mode="max-autotune"加fullgraph=True,吞吐可能就上来了。
小模型上确实香,但7B加Deepspeed这套组合拳下编译收益很玄学,显存涨是因为图优化留了buffer,正常。
我试过类似配置,reduce-overhead反而拖后腿,换max-autotune或干脆关掉可能更稳。
说实话reduce-overhead这个模式对LoRA这种小参数量更新场景确实容易帮倒忙,编译开销摊不平。我之前在A100上试过,dynamic shape或者小batch下反而更慢,试试mode="max-autotune"加fullgraph=True,把batch怼到最大看看。显存变大正常,因为编译会生成额外buffer,尤其reduce-overhead为了减kernel launch会做内存池预分配。你deepspeed stage2和torch.compile的算子融合有时会打架,建议先关掉deepspeed纯用bf16测一遍基线,再叠加看差异。大模型场景真正吃香的是静态shape和计算密集的线性层,LoRA瓶颈在数据加载和通信上,编译加速不明显是常态。
说实话你这情况我太熟了,之前我在A100上跑LLaMA微调也是这个体验。torch.compile对静态shape和计算密集的CNN效果明显,但到了大模型+LoRA这种场景,瓶颈往往在通信和显存带宽上,编译带来的算子融合收益很容易被deepspeed的通信开销吃掉,尤其是stage2的all-gather/reduce-scatter,编译器根本优化不到那里去。另外reduce-overhead模式确实会牺牲一些显存来换cudagraph的捕获,你看到显存变大是正常的,这模式更适合推理或者小batch训练,大模型下反而容易爆显存。建议你试试mode="default"或者"max-autotune",然后关掉动态shape,把attention里那些Python控制流尽量固定下来,说不定能有5%-10%的提升,但真别指望30%。我后来直接放弃了编译,改用flash-attention 2加unsloth那套,吞吐反而涨了20%,编译这玩意儿现阶段在LLM训练上真有点鸡肋。另外你deepspeed可以先试stage3加offload,有时候比stage2配编译更稳,就是得调调cpu和gpu的负载比例。
遇到过同样问题,小模型加LoRA编译收益真不大,反而显存涨了,可能得大模型全参数训练才看得出优势。
跟你遇到一模一样的情况,reduce-overhead在A100上对LoRA反而负优化,后来我把mode换成default或者max-autotune才勉强持平原生。编译开销主要花在inductor生成kernel上,小batch下尤其不划算,你试试把batch调大点或者用gradient checkpointing压显存,可能效果就出来了。另外deepspeed的stage2跟torch.compile的算子融合有时会打架,建议先关掉deepspeed纯用DDP对比一次,排除干扰项。显存变大是正常的,编译缓存和额外中间张量都会吃显存,这个无解。
写得挺好,建议补充一些性能数据。
说实话你这情况我见过不少,torch.compile在LoRA这种小参数更新场景里确实容易吃瘪,因为编译开销分摊不到足够的计算量上。我之前拿7B全参微调试过,reduce-overhead模式在A100上大概能快个15%左右,但远达不到宣传的30%,而且显存确实会涨,主要是编译过程生成的中间缓冲和CUDA graph占用的,这在长序列下更明显。你要是用deepspeed stage2,本身已经做了不少算子融合,编译能优化的空间就被压缩了,建议把mode换成max-autotune看看,有时候虽然编译更久但吞吐反而能上去。另外检查下是否给编译留了足够大的warmup步数,我遇到过步数太少导致后续每次都触发重编译的情况,那才是真玄学。显存变大是正常的,特别是用了reduce-overhead之后它要缓存CUDA graph,基本多占2-4G,看你序列长度。其实大模型训练瓶颈更多在通信和显存带宽上,编译优化的是计算内核,所以效果远不如在CNN或小模型上惊艳。你要是真想省时间,不如先试试flash attention和梯度检查点,那俩的收益比编译稳多了。
说实话reduce-overhead这个模式在A100上对LoRA场景确实容易负优化,它主要针对的是小算子启动开销,大模型训练瓶颈在通信和显存带宽上。你试试mode="max-autotune"配合fullgraph=True,有时候反而能挤出来10%左右,不过编译时间更离谱。显存变大是正常的,因为编译会生成额外缓存和tensor布局转换,如果显存本来就紧建议别开。另外deepspeed的stage2和torch.compile的capture机制偶尔会冲突,你可以试试把offload关了或者换成stage3。
我这边用7B全参训练对比过,compile在batch size够大时才有收益,LoRA这种小参数更新场景基本白搭。你如果真想省时间,不如把精力放在flash attention和梯度检查点上,那俩才是实打实的提升。
这问题我踩过一模一样的坑,reduce-overhead模式在A100上对LoRA反而有负优化,尤其配合deepspeed的时候开销更大。建议试试mode="max-autotune"或者干脆用default,编译时间虽然长点但吞吐能上来一些。显存变大正常,因为编译会额外存一些tensor元数据,你bf16下更明显。另外如果是单卡微调,个人体感torch.compile收益主要在中大batch下才体现,batch小的话纯属白给。