最近在折腾用 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这模式对LoRA这种小参数量更新场景确实不友好,编译开销摊不平。我试过在7B上开fullgraph配合dynamo的cudagraphs,吞吐也就提升10%左右,远没宣传的夸张。
显存变大很正常,因为编译会做算子融合和缓存中间buffer,你得把activation checkpointing开起来才能抵消。另外deepspeed stage2和torch.compile的算子重排有时会冲突,建议试试关掉zero的offload只留cpu offload。
要是主要瓶颈在通信而不是计算,编译收益确实有限。你可以先用torch.profiler看看GPU利用率,如果已经85%以上就别折腾了,不如调调batch size和梯度累积步数。
跟deepspeed一起用确实容易负优化,试试只编译backbone或者干脆关掉stage2,单独编译的收益明显些。
我测下来编译对计算密集的纯训练有效,但一旦挂上LoRA和deepspeed,通信和显存开销就把加速吃掉了,你这情况正常。
正常,reduce-overhead对训练场景优化有限,我们测过小模型才有点提升,大模型瓶颈在通信和显存带宽上。你可以试试max-autotune模式或者干脆关掉编译。
编译后显存变大是正常的,因为要存图,LoRA这种轻量微调真没必要上它,纯纯增加复杂度。
这问题我也踩过坑,实测下来torch.compile对LoRA这种小参数量更新确实不友好,编译开销直接吃掉了收益。你试试把mode换成default或者max-autotune,然后关掉deepspeed的stage2,纯用DDP跑一下,可能反而更快。显存变大是正常的,编译会缓存一些中间张量,我这边看到大概多占5%-10%。另外如果训练序列长度固定的话,可以给torch.compile传个dynamic=False,能省不少编译时间。
我之前跑过7B的full finetune,compile在A100上大概也就快15%左右,远没到宣传的30%。你用了deepspeed的话,它自己的kernel融合和compile可能有冲突,试试把zero stage降到1或者干脆不用。第一次编译慢是正常的,后面会缓存,但如果你经常改模型结构就白搭了。显存变大是因为compile会为了加速多存点activations,小batch下确实不划算。
实测下来,torch.compile在大模型训练里主要收益在forward的卷积和attention部分,但LoRA本身轻量,瓶颈反倒在通信和优化器更新上。建议你开一下torch.compile的profiler看看是哪部分变慢了,我上次发现是deepspeed的op和compile的graph不兼容,绕过去之后吞吐直接翻倍。显存变大正常,它默认会保留更多中间
说实话你这个情况我遇到过一模一样的,当时也是Llama 2 7B加LoRA,单卡A100,deepspeed stage2,torch.compile直接给我干沉默了。后来我仔细扒了下,问题出在reduce-overhead这个模式对静态shape和固定计算图特别敏感,LoRA这种动态插入的adaptor反而会打乱它的优化节奏,而且deepspeed的stage2本身有自己的一套内存管理和kernel fusion,跟compile的inductor后端容易互相踩踏。
我个人实测下来,纯原生bf16加deepspeed stage2,吞吐能到多少基本就是多少,compile顶多把attention那块儿的kernel稍微提提速,但整体收益被通信和梯度同步吃掉了。显存变大也正常,因为compile会额外缓存一些中间tensor和graph,尤其第一次编译时那个内存峰值能把人吓一跳。
我建议你试试mode="default"或者"max-autotune"对比下,别死磕reduce-overhead,那个主要是给推理或者固定batch的生成场景用的。另外如果你用的是最新版torch,可以试试把torch._dynamo的dynamic shape打开,或者干脆在deepspeed的config里把zero.optimizer的offload关掉再测,有时候是offload和compile的显存管理冲突了。
最后说句实话,大模型训练这块儿,compile的收益真没宣传的那么神,除非你整个训练循环都是标准transformer结构且不做任何自定义改动,否则大概率是负优化。我后来直接放弃compile,把时间花在调gradient checkpointing和flash attention的sequence length对齐上,效果反而更明显。你要是真不想折腾,就保持原生跑,等哪天社区把deepspeed加compile的成熟方案整出来再上车也不迟。
说实话reduce-overhead这模式对LoRA这种小参数量更新场景确实不友好,编译开销都摊在forward/backward上了,我试过用fullgraph=True配合max-autotune反而在A100上有点效果。显存变大正常,编译会额外缓存一些中间张量和CUDA graph,你可以试试把reduce-overhead换成default模式,或者干脆在deepspeed里关掉compile只用bf16,我这边7B微调吞吐反而稳了。不过你要是用batch size特别大或者序列特别长,compile的算子融合优势才能体现出来。
之前跑7B微调也踩过同样的坑,reduce-overhead在短序列场景下反而有额外调度开销,尤其第一次编译的triton核生成时间占比太高。后来换成mode="max-autotune"再配合gradient checkpointing,吞吐才勉强追平原生,但显存确实会涨10%左右,因为编译缓存和自动调优的临时buffer占用了空间。建议先确认是不是deepspeed的zero2和编译的显存优化冲突,这俩经常抢内存。另外可以试试只对attention层单独用compile,其他层保持原样,开销小很多。反正大模型场景下收益没吹得那么神,我最后直接关掉编译用原生了。
试过类似的配置,7B模型上torch.compile收益确实很玄学,尤其在deepspeed和bf16叠加时,图优化经常和stage2的通信逻辑打架。我后来把compile关掉,只开channels_last和max_autotune,反而稳定快15%左右。显存增加是正常的,编译会多存一些中间tensor做图优化,尤其reduce-overhead模式更吃显存。建议先试mode="default"或者只compile个别子模块,别一上来全模型编译。另外如果你用flash attention的话,检查下是不是和编译冲突了,这俩经常互相干扰。
说实话reduce-overhead在大模型场景下收益本来就有限,那个模式主要优化小算子启动开销,Llama这种大算子反而容易吃亏。我试过用mode="max-autotune"配fullgraph=True,在7B LoRA上勉强能到10%出头,但编译时间够我泡三杯咖啡了。显存变大正常,因为编译会生成额外缓存和中间buffer,尤其跟deepspeed的显存分片叠加后更明显。建议你直接试试不开compile,把精力放在gradient checkpointing和flash attention上,提升可能更实在。
我试过类似配置,编译开销在LoRA这种小模型上确实容易吃掉收益,换大batch或全参微调才划算。
显存涨正常,reduce-overhead本来就吃内存,试试max-autotune加dynamic=False,可能好点。
编译开销被deepspeed的通信掩盖了,小模型LoRA确实不明显,显存涨是CUDA graph缓存,正常。
正常,小模型+LoRA场景编译收益本来就有限,reduce-overhead还容易吃显存,可以试试max-autotune或者干脆关掉。
我这边7B全参微调用compile大概也就快10%左右,没到30%那么夸张。
我也踩过类似的坑,主要问题可能出在deepspeed和torch.compile的兼容性上,stage2的通讯开销会吃掉不少优化收益。你可以试试关掉deepspeed单独跑compile对比下,或者用mode="max-autotune"看看,虽然编译更慢但训练稳定后吞吐提升明显。显存变大很正常,编译会保留额外中间缓冲区,尤其是reduce-overhead模式,小batch下反而更吃亏。另外如果只跑LoRA,参数量小,编译的优化空间确实会被稀释,建议直接比较step时间而不是吞吐。
试过类似配置,reduce-overhead对LoRA确实不友好,换default模式加max-autotune可能好点。
编译吃显存正常,小batch下得不偿失,大batch才划算。
torch.compile在LoRA这种小参数量更新场景下确实容易白给,因为开销主要在通信和算子调度上,编译优化被反噬了。我之前试过full fine-tune反而能吃到一点红利,但也就10%左右,远没到吹的30%。显存变大正常,编译会做算子融合和额外缓存,建议你试试mode="default"加triton后端,可能比reduce-overhead稳。另外deepseed stage2本身已经优化了通信,跟compile叠加有时候会冲突,你可以关掉stage2单独跑下对比看看。
同感,我拿7B做SFT也试过compile,reduce-overhead模式下显存确实会涨,感觉是编译生成的临时buffer没复用好。我后来发现对LoRA来说瓶颈在显存带宽而不是算力,小矩阵乘居多,编译优化收益真不大。建议你先用torch.profiler看看kernel占用率,如果GPU利用率本来就高,那编译就没啥可榨的了。另外你试试mode="default"或者关掉cudagraphs,有时候反而比reduce-overhead稳,尤其配合deepspeed时graph捕获容易出问题。
说实话这个现象挺常见的,torch.compile的加速效果跟模型结构、显存带宽和算子融合度关系太大了,Llama这种纯decoder架构反而没那么吃编译红利。我之前在A100上试过7B全参微调,reduce-overhead模式确实会先吃一波显存,因为要预留编译缓存和额外图内存,这正常,但速度提升也就10%出头,远没宣传的夸张。
你现在用deepspeed stage2,本身就带算子融合和通信优化,和torch.compile的图优化逻辑有重叠,反而可能互相干扰。我建议你试试mode="default"或者"max-autotune",前者编译耗时短,后者对特定shape会做更多调优,有时候reduce-overhead在小batch下反而因为CUDA graph的launch开销变慢。另外你用的是LoRA,可训练参数少,forward占比高,编译收益天然就被稀释了。
还有个坑是bf16和deepspeed的zero2组合,torch.compile在动态shape和offsload场景下会频繁recompile,你可以把max-autotune的缓存路径设置到内存盘上,或者试试把input的max_length固定住。我自己的经验是,单卡A100上如果batch size能拉到16以上,编译后吞吐提升才明显,小batch下真的不如老实关掉。显存开销变大如果没爆就忍忍吧,你用LoRA的话本来省下的显存也够挥霍了。
同感,compile在小模型和CV上提升明显,但大模型Lora真不一定,显存增加我怀疑是图编译缓存和额外kernel导致的,可以试试max-autotune或者干脆关掉。
torch.compile在A100+LoRA这种小规模微调上确实容易翻车,我拿7B+单卡试过,编译开销直接吃掉了收益,尤其是reduce-overhead对显存带宽敏感的场景反而更糟。你要是想验证,试试把batch size拉大或者换mode="max-autotune"看看,但说实话大模型训练里瓶颈多半在通信和显存带宽,编译优化空间有限。我这边实测deepspeed+bf16下编译能提5%就烧高香了,显存涨是因为编译生成了额外buffer,正常现象。真要提速建议先查数据加载和梯度累积配置,别跟编译器死磕。
同款配置踩过坑,A100上跑LoRA用reduce-overhead确实容易负优化,这模式对计算密集型更友好,微调场景反而是inductor默认模式更稳。你把deepspeed的stage2和torch.compile叠一起会有算子融合冲突,试试关掉deepspeed只用compile跑一遍对比下。显存变大正常,编译缓存和额外buffer会吃几百兆,大batch下尤其明显。我最后是只在关键注意力层手动编译才拿到8%提升,建议多试试不同模式,别指望白嫖30%。