最近在折腾用 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 条同感,小模型上确实玄学,大模型场景下编译收益不稳定,蹲个详细的对比数据。
显存变大是正常的,graph保存和codegen都有开销,小batch下尤其明显。
同款A100试过,reduce-overhead在LoRA上确实容易负优化,尤其是序列短的时候,编译开销摊不薄。你可以试试mode=“default”或者把dynamic=True打开,有时候反而更稳。显存变大正常,编译会留额外buffer,小batch下尤其明显。另外deepspeed和torch.compile的兼容性一直有点微妙,stage2下建议先关掉编译跑个baseline,再开编译对比,排除是通信层面的瓶颈。
同感,reduce-overhead在deepspeed下基本白给,我试过还不如关掉,compile更适合单卡小batch。显存变大正常,cudagraphs会吃buffer。
遇到过同样问题,reduce-overhead在LoRA小模型上反而负优化,换mode="max-autotune"试试,但编译时间更酸爽。
torch.compile在大模型上确实容易负优化,我试过几次都直接关掉了,小模型上收益才明显。
同感,我拿7B做LoRA时也是reduce-overhead反而负优化,后来换成default模式才稍微好点。编译对大模型训练加速真没那么神,尤其你上了Deepspeed,图优化和通信优化可能还打架,显存涨大概率是编译缓存和CUDA graph占的。建议你先关掉deepspeed单独测torch.compile,再叠加看瓶颈在哪,或者直接看下torch.compile的inductor日志里有没有什么kernel fusion没生效的警告。
同样配置试过,compile对LoRA收益真不大,反而显存涨一截,deepspeed下更明显。
同款配置踩过坑,reduce-overhead在deepspeed下确实容易负优化,尤其小batch时编译开销摊不薄。建议试试mode="max-autotune"加torch._dynamo的dynamic=True,或者干脆把compile只包在单卡纯模型上对比。显存变大正常,编译会多存一份图,我这边大概涨了5-8%。吞吐提升得看序列长度和batch,我跑7B全参微调也就快了15%,LoRA真没必要折腾这个。
说实话你这个情况我太熟了,之前我在A100上跑GLM-6B的LoRA也遇到一模一样的坑。torch.compile对动态shape和复杂控制流特别敏感,LoRA那套注入低秩矩阵的操作其实挺碎,reduce-overhead模式会把图切得很碎,反而让CUDA kernel launch和显存分配开销压过计算收益。我自己实测下来,单卡上纯原生bf16加deepspeed stage2,吞吐大概在每秒多少样本我忘了,但compile之后不仅没快,显存还涨了快2G,后来查了下发现是编译器为了做算子融合保留了更多中间buffer。
我觉得大模型场景下compile的收益主要在生成阶段或者纯推理,训练时反向传播的梯度计算和优化器更新那部分,编译器很难做出什么质变。你如果真想榨性能,不如先检查下是不是dataloader或者CPU预处理成了瓶颈,有时候这种IO问题看起来像编译导致的慢。另外试试mode="default"而不是reduce-overhead,或者干脆给torch.compile加个fullgraph=False,有时候放宽图拆分限制反而能触发更好的融合。
显存变大我觉得不算太离谱,毕竟编译后有些activation被缓存起来复用,但如果你卡在显存边缘,那确实得不偿失。我现在的做法是混合用,小batch或长序列场景开compile,常规训练直接关掉,省心。你也别太纠结这个,A100上7B微调瓶颈多半在数据吞吐和通讯上,编译器救不了大局。
实话实说,reduce-overhead那个模式在A100上对LoRA反而容易负优化,我试过几次也是这德行,编译开销抵不过小步长迭代的收益。你试试mode="max-autotune"加fullgraph=True,或者干脆把编译范围限定在注意力模块上,别整个模型都包进去。显存变大正常,编译会生成额外缓存和中间变量,不过你这配置下我个人感觉deepspeed本身就和torch.compile有兼容性冲突,stage2的梯度分区跟inductor的代码生成经常打架。我最后是直接关掉deepspeed,纯用FSDP加compile,吞吐反而涨了15%左右,你可以往这个方向排查下。
说实话你这个现象我见过不少,reduce-overhead模式对动态shape和显存管理特别敏感,LoRA加deepspeed stage2本身就引入了不少额外开销,编译图里一旦有通信原语穿插,那个优化空间很容易被吃掉。我自己跑过7B和13B的lora微调,体感是torch.compile在纯单卡、固定batch、没有deepspeed的情况下加速最明显,大概能到10-20%,但一上stage2基本就持平甚至略慢,尤其你第一次编译那几分钟的等待根本不值当。显存变大也很正常,编译会做算子融合和缓存,中间变量保留策略变了,我这边大概多了1-2G,如果卡紧的话确实有点难受。建议你试试mode="max-autotune"加fullgraph=True,有时候比reduce-overhead稳定,但前提是模型结构别太动态。另外可以查一下你deepspeed的zero阶段是不是把参数分区了,那会让编译捕获的图碎掉,优化效果直接打折。反正我的结论是,小规模实验或者快速迭代别开编译,真到长训练周期、固定shape、能忍受预热时间的时候再考虑,节省的时间才能覆盖编译成本。
跟你同配置,A100+LoRA+deepspeed stage2,torch.compile在bf16下确实容易负优化,尤其reduce-overhead对显存带宽敏感的小batch特别不友好。我后来把mode换成default,配合max-autotune只对attention部分编译,吞吐才勉强比原生高个10%左右,编译时间倒是能忍。显存变大是正常的,因为编译会生成额外CUDA context和辅助buffer,尤其跟deepspeed的offload混用时会放大。建议你先关掉deepspeed单独测compile,再叠加看是哪个环节打架,我怀疑是stage2的partition和编译图优化冲突了。
说实话你这个问题我踩过一模一样的坑,torch.compile在LoRA这种小参数更新场景里确实容易负优化,因为编译开销摊不到足够的计算量上。我之前在A100上跑7B全参微调,compile开inductor能稳定快20%左右,但换到LoRA就基本持平甚至略慢,尤其是reduce-overhead那个模式,它本身是为推理设计的,训练场景下反而可能因为CUDA graph重放限制搞出额外显存碎片。你显存变大有可能是编译缓存了额外的工作区,或者deepspeed的stage2和inductor的算子融合有冲突,建议试试先关掉deepspeed光用bf16跑一遍对比,或者把mode换成default而不是reduce-overhead,我这边default模式比reduce-overhead稳定很多。另外第一次编译那个等待是正常的,之后会走缓存,但如果你每次改模型结构都得重新编译,那这个等待时间确实得不偿失。个人经验是,如果单卡训练且batch size不够大,编译加速基本被通讯和内存拷贝吃掉,不如直接调大batch或者用gradient checkpointing实在。
我也踩过类似的坑,LoRA微调本身可训练参数少,compile的优化空间被压缩了,而且reduce-overhead在bf16下经常跟deepspeed的通信逻辑打架。建议试试mode="max-autotune"加fullgraph=True,至少能抵消编译开销,另外把编译后的显存增加关掉cudagraphs的capture试试。我这边2.1版本跑7B,compile提效得配合gradient checkpointing才明显,纯LoRA真不如手动把attention和mlp的kernel手写优化。
同感,我拿7B在单卡上试过,reduce-overhead对LoRA这种小显存操作反而有额外调度开销,编译收益被反噬了。你换成mode="default"或者max-autotune试试,至少第一次优化后稳定步进会正常点。显存变大正常,编译会保留额外中间缓冲,特别是和deepspeed的stage2叠加时,activation和梯度buffer被重复分配了。大模型场景真别迷信编译,数据加载和通信优化优先级高多了,你先把gradient checkpointing开了再看看。
另外,同配置下我对比过,纯原生+deepspeed的吞吐和torch.compile差不到5%,编译时间倒是多花十分钟。想提速不如直接调微调的batch size和梯度累积步数,省下的显存还能塞更大batch。最后问下,你用的是deepspeed的zero2还是zero3?zero3下编译的显存飙升会更明显,建议先关掉offload再测一轮。
同感,我拿7B全参训练试过几次,compile在单卡A100上确实没占到便宜,尤其是小batch下显存还涨一截。后来看issue说reduce-overhead主要利好小算子密集的CV/小模型,大模型瓶颈在通信和显存带宽,编译优化空间反而被deepspeed的算子融合挤掉了。建议你试试mode="max-autotune"配inductor的cudagraphs,或者干脆关掉compile,把精力放在gradient checkpointing和offload上,可能收益更直接。另外第一次编译等几分钟是正常的,但第二次有缓存会快不少,如果跑多轮epoch还是慢,那基本可以判定这场景不适合。
reduce-overhead这个模式在小batch下确实容易负优化,它主要针对的是CPU bound场景,A100上显存带宽早就喂饱了,编译那点kernel融合收益填不平额外开销。我自己试过用max-autotune配合fullgraph=true,在Llama微调时能勉强和原生打平,但提升也就个位数,远没宣传那么神。显存变大倒是真的,因为编译会保留更多中间buffer,尤其LoRA这种参数少但激活多的场景更明显。建议你试试把batch size加大到显存上限再对比,或者干脆关掉编译用原生+sdp,省下的折腾时间够跑好几轮实验了。
这情况太真实了,大模型场景compile收益真没宣传的那么神,显存变大是正常的,建议直接关掉别折腾。
说实话reduce-overhead在大模型场景下确实容易适得其反,它主要是优化小算子启动开销的,Llama这种大算子反而容易触发不必要的重排。我试过用mode="max-autotune"加fullgraph=True,在A100上跑7B LoRA吞吐大概能提15%左右,但前提是关掉deepspeed的offload,不然显存会炸。你显存开销变大很可能是编译图里保留了激活值,试试把static memory planning打开或者用inductor的memory planner优化一下。另外第一次编译那几分钟忍忍就过去了,关键是看稳定后的step time。
同感,小模型和LoRA场景下compile收益真不大,反而显存和编译时间吃亏,大模型还得看分布式优化。
我试过7B全参也差不多,图模式优化对动态shape不友好,建议直接关掉专注deepspeed配置。