最近在折腾用 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 条这种体验其实挺常见的,torch.compile在小batch、简单模型上加速明显,但一到大模型+分布式+复杂优化器组合,收益就容易被通信和显存瓶颈吃掉。你那个mode="reduce-overhead"主要是针对小算子融合的,但LoRA本身已经把大部分计算量压到adaptor上,主模型权重更新反而少了,编译能优化的空间就有限。我自己在8卡A100上试过类似配置,开compile后第一次编译光trace图就花了快半小时,而且因为deepspeed stage2有分片梯度同步,编译后的动态图有时会跟ZeRO的通信逻辑冲突,反而增加延迟。显存开销变大也正常,编译模式会保留更多中间缓存的buffer来加速后续迭代,这对小模型友好,但7B这种规模下buffer膨胀就很肉疼。建议可以先关闭compile,专注调gradient checkpoint和batch size的平衡,或者试试torch.compile的"max-autotune"模式但慎用,它搜kernel的时间足够你跑两轮epoch了。另外有个取巧的办法:只对attention部分的QKV投影用compile,其他模块保持eager模式,这样既能吃到算子融合的红利,又不会让显存炸掉。
我也在单卡A100上试过类似配置,torch.compile对大模型LoRA训练确实不全是正向收益,尤其你开了deepspeed stage2之后,编译带来的计算图优化可能被通信和显存管理抵消掉一部分。第一次编译慢是正常的,但后续如果还是没提速,建议试试mode="max-autotune",虽然编译更久但跑起来可能好点。显存开销变大也遇到过,感觉是编译后保留的中间变量多了,可以配合gradient checkpointing缓解。不如先关掉编译跑个基准,再对比不同mode的实际吞吐,别盲目信宣传。
老实说,你遇到的情况我试过好几回,基本跟你差不多。torch.compile 在小模型或者单卡推理上确实能白嫖不少性能,但一上大模型加分布式训练,尤其配上 deepspeed stage2 和 bf16,编译反而容易变成瓶颈。我自己测过 Llama 2 7B 的 LoRA,用 mode=“reduce-overhead” 第一次编译那个等待时间特别离谱,而且跑起来后因为 graph break 太多,动态图的优化收益根本覆盖不了编译开销。你提到显存开销变大,这个我观察过,编译后编译器会保留一些中间缓存和优化后的图,确实比原生多占 10%-20% 的显存,在大模型场景下这一点就很要命。后来我试了把 torch.compile 只包在 forward 里,或者换 mode=“max-autotune” 配合 cudagraphs,但吞吐提升依然有限,远不如把时间花在数据加载和梯度 checkpoint 上划算。我觉得在大规模微调里,现阶段编译加速更适合单卡小 batch 或者纯推理场景,分布式训练还是老老实实靠 deepspeed 本身的 kernel fusion 和通信优化更靠谱。你用的 deepspeed stage2 加 bf16 本身就挺成熟了,如果吞吐没明显问题,建议先别折腾编译,不然真的容易变成玄学调优。
同感,我在用LLaMA 13B试torch.compile时也踩过类似的坑,尤其是deepspeed+bf16的组合下编译反而容易增加显存开销。感觉这个优化对计算密集型的小batch更友好,大模型场景里通信和显存瓶颈更突出,编译带来的收益被稀释了。建议你先关掉deepspeed单独测一下原生torch的编译效果,排除下框架冲突。另外可以试试mode="max-autotune"虽然编译更久,但跑稳后吞吐确实有提升,不过显存占用也会涨,得看你的LoRA rank能不能抗住。
确实,torch.compile 在小模型或者单卡简单场景下加速明显,但大模型+Deepspeed+LoRA 这种组合下,编译开销反而可能拖后腿,尤其是第一次编译的 JIT 耗时和显存上涨,我猜是图捕获阶段把一些动态 shape 或者控制流给卡住了。你可以试试 mode=“max-autotune” 或者关掉一些 fusion 选项,有时候 reduce-overhead 并不适合分布式训练。另外,我自己的经验是编译对纯 forward 推理帮助更大,训练场景尤其是带梯度累积和 offload 的时候,收益真不一定稳。
说实话你这情况挺常见的,torch.compile在小batch和复杂分布式策略下加速确实容易打折扣,尤其是deepspeed stage2本身就有自己的算子融合,编译反而可能干扰底层优化。我试过类似配置,把mode换成“max-autotune”后第一次编译更久,但稳定后吞吐能提升10%左右,没到30%那么夸张。显存开销变大是正常的,因为编译会缓存一些中间表示和优化后的代码,微调场景下如果batch size不大,这点代价可能划不来。建议你关掉deepspeed单独跑一次纯编译对比,或者试试先用torch.compile的“default”模式看看基线,有时候小改动就能拉开差距。
说实话我最近也在折腾这事,torch.compile 在小模型上确实能看出明显提速,但一上大模型加分布式训练,收益就玄学了。你用的 reduce-overhead 模式其实主要优化小算子调度,对大模型里那些大矩阵乘法反而不敏感,不如试试 mode=“max-autotune”,不过那个编译时间更感人。显存占用变大是正常的,因为编译后会有一些额外的缓存和融合后的中间变量,我在 7B 上跑也遇到了类似情况。另外 deepspeed stage2 和 torch.compile 的 operator fusion 可能会有冲突,有些算子在编译后反而被拆得更碎,建议你把 stage2 的 offload 关了再试试。还有个坑是 bf16 下 torch.compile 对某些算子支持不完善,可能会 fallback 到 eager 模式,你可以用 torch._dynamo.exc 的日志看看到底有没有成功编译。总体感觉目前在大模型训练场景下,torch.compile 还没到无脑开就能提效的阶段,尤其 LoRA 这种轻量微调,瓶颈往往在数据加载和通信上,编译优化的空间其实不大。
老实说我也踩过类似的坑,torch.compile在小batch size或者简单模型上确实香,但一上大模型加Deepspeed这种分布式优化器,编译带来的额外开销和显存占用反而容易拖后腿。你试的那个reduce-overhead模式本来就不是为超大模型设计的,换成max-autotune或者干脆关掉dynamic shape试试?另外我记得A100上bfloat16加上Deepspeed stage2,原生算子已经优化得挺好了,编译加速空间本来就不大,不如把精力放在数据加载和梯度累积上。
老实说我也踩过类似的坑,torch.compile在小batch和简单模型上提速明显,但一到LoRA+Deepspeed这种组合,编译本身的开销反而容易吃掉收益,尤其是第一次编译那几秒到几十秒的延迟在训练里特别亏。显存变大我这边也有,感觉像是编译后保留了更多中间变量做优化,建议你试试mode="default"或者把max-autotune关掉,有时候reduce-overhead对动态shape不友好。另外可以对比一下不用deepspeed只开compile的情况,说不定是stage2的梯度分片跟编译后端有冲突。
说实话你这情况我遇到过类似的,torch.compile 在小模型或者单卡推理上确实有惊喜,但一上大模型训练尤其是带 deepspeed 和 LoRA 的时候,收益就很不稳定了。我个人感觉主要问题是 compile 对动态图和算子融合的优化在 distributed training 场景下会被很多通信开销抵消掉,特别是 reduce-overhead 模式本身就是为了减少 kernel launch 的延迟,但 deepspeed stage2 的梯度累积和 offload 流程已经有一套自己的调度,两者的优化方向可能打架。另外显存开销变大是正常的,因为 torch.compile 会生成额外的中间缓存和编译后的 kernel 代码,对于 7B 这种规模来说,这点显存增量可能还不如直接多调大 batch size 带来的收益明显。我自己的测试结果是,在单卡 A100 上纯用原生 FSDP 加 bf16,配合 gradient checkpointing,反而比强行上 compile 更稳定,吞吐差别不大。不过有老哥说如果换成 inductor 后端并且把模式调成 max-autotune,多跑几轮 warmup 之后偶尔能追上 10% 左右,代价是编译时间能到十分钟级别。感觉这玩意儿目前更适合固定计算图的推理优化,训练场景尤其是大模型加分布式,还是得谨慎,不能无脑上。
实测过类似配置,torch.compile在小batch和大模型上确实容易负优化,尤其deepspeed+bf16这种场景下编译带来的图优化收益不大,反而显存占用会多个几G。你可以试试先关掉compile跑一版基线,再开mode="default"或者max-autotune对比下,reduce-overhead那个模式对大模型不太友好。第一次编译慢是正常的,但第二次开始应该会好点,如果还慢就检查下torch版本和CUDA驱动是否匹配。
说实话你遇到的情况我完全能理解,torch.compile在宣传上确实很诱人,但实际落地到大模型训练里坑还挺多的。我自己在A100上试过7B模型全参数微调,torch.compile(mode="reduce-overhead)在第一次编译时简直能把人急死,而且一旦用了deepspeed stage2或者ZeRO系列,编译后的图优化和分布式通信之间会有不少冲突,很多时候加速反而变负。你提到的显存开销变大也很正常,因为torch.compile会生成额外的中间表示和缓存,对显存敏感的场景其实不太友好。我个人经验是,对于LoRA这种本身计算量就不大的场景,编译带来的优化收益会被编译开销和显存压力抵消,尤其你用bf16已经挺快了,再加编译反而容易得不偿失。如果你真想试,可以试试mode="max-autotune"并配合torch._dynamo.mark_dynamic对输入shape做标记,但大概率还是不如直接跑原生的稳定。另外,我看到社区里有人提过在deepspeed下用torch.compile需要设置compile_mode=“default”并且关闭动态shape才能勉强有点收益,你可以往这个方向排查一下。说到底,这东西目前更适合推理解码或者单卡小模型训练,大模型场景下还是别太指望白嫖加速了。
正好我也踩过同样的坑,torch.compile 在小模型上效果明显,但大模型场景下编译开销和显存增长确实是常见问题。你这个配置建议关掉 reduce-overhead 试试默认模式,或者直接上 inductor,兼容性会好一些。另外 deepspeed stage2 和编译的交互有时候会出问题,可以试试只对 LoRA 部分单独编译,或者干脆等 PyTorch 2.2 的改进版,据说对大模型编译做了专门优化。
我正好也在碰类似的问题,7B 模型上 torch.compile 确实很难直接吃到加速红利,尤其是配合 ZeRO 和 bf16 时,编译带来的算子融合收益会被通信和精度转换稀释掉。你说的显存变大概率是因为编译过程中产生了额外的缓存和重算逻辑,这在长序列场景下更明显。我自己的经验是,先关掉 compile 跑一次 benchmark 当 baseline,然后试试 mode=“default” 或者只对 attention 部分做局部编译,可能会更可控一些。
这情况我太熟了,torch.compile在小模型和单卡推理上确实香,但一上大模型分布式训练就容易翻车。你用的reduce-overhead模式本身对动态图和复杂控制流就不友好,Llama这种带缓存和注意力掩码的模型,编译优化反而可能引入额外开销。我个人经验是,如果用了deepspeed stage2和bf16,编译的收益会被ZeRO本身的显存节省和通信开销稀释掉,尤其LoRA只更新少量参数,计算瓶颈本来就不在算子上。至于显存变大,正常,编译会保留中间张量做图优化,加上CUDA graph会固定内存池,显存占用比原版高个10%-20%挺常见的。建议你试试mode="max-autotune"加torch._dynamo.mark_dynamic,或者干脆只在attention计算上局部用compile,别全图编译。另外可以确认下编译日志里有没有fallback到eager模式的警告,有时候是算子不支持自动回退了。
说实话你遇到的问题我完全能理解,torch.compile 在小模型上确实有奇效,但一上大模型加分布式训练就很容易翻车。我自己也在 7B 级别的模型上试过,发现 reduce-overhead 模式在 deepspeed stage2 下反而会因为频繁的图编译和重编译导致吞吐下降,尤其第一次编译那几分钟真的很劝退。你说的显存开销变大也很正常,编译后会有一些中间表示和优化缓存占显存,如果本身显存就紧张,反而可能触发 OOM。我个人经验是,在 LoRA 这种轻量微调场景下,torch.compile 能带来的收益其实很有限,因为大部分计算都在少数几个适配器层上,而原生 PyTorch 的 eager 模式已经优化得不错了。不如试试把 compile 只用在 attention 或者 feed-forward 的某些模块上,配合 max-autotune 模式,有时候能避开全图编译的坑。另外你也可以看看是不是 torch版本和 CUDA 版本没对齐,我之前踩过坑,12.1 的 CUDA 配合 2.0.1 的 torch,compile 性能还不如 2.1 稳定。如果实在没时间调,现阶段大模型训练我还是更相信原生加 deepspeed 的稳定收益,等社区把大模型的编译缓存和动态 shape 支持做好了再上车也不迟。
torch.compile在小模型上提速明显,大模型加Deepspeed反而容易负优化,显存暴涨很常见。
我之前也踩过这个坑,torch.compile在小batch size或者模型结构简单的时候加速确实不明显,大模型场景下反而可能因为编译和重排导致显存峰值变高。你试试把mode换成“max-autotune”或者干脆不用reduce-overhead,有时候默认的“default”模式反而稳。另外deepspeed和torch.compile的兼容性一直有点玄学,建议先关掉deepspeed单独测一次原生+compile的吞吐,排除干扰项。
老实讲你这情况我完全能理解,torch.compile在大模型场景下确实不是无脑开的。我拿13B模型试过几次,发现它跟Deepspeed Stage2的梯度累积和显存管理策略有点冲突,特别是reduce-overhead模式会把一些本来可以异步的操作强行同步化,导致显存碎片反而变多。你提到的显存开销变大,我个人观察是编译后的CUDA graph会缓存额外的中间结果,尤其是LoRA那种需要额外参数更新的场景,显存占用涨个5%-10%挺常见的。至于首次编译慢这个真没办法,但如果你试一下mode="max-autotune"配合torch._dynamo的dynamic shape关闭,在batch size固定的情况下第二次开始会好很多。不过说实话,我自己的测试里7B模型用bf16+deepspeed stage2,torch.compile大概只有10%左右的吞吐提升,远不到吹的30%,可能小batch或者单卡场景收益更大。你要不要试试关掉deepspeed单独跑一次原生torch加上compile对比下?有时候框架之间的优化叠多了反而互相拖后腿。另外检查下是不是装了正确的CUDA版本和flash attention,我上次就是这两样没对齐导致编译后的kernel一直回退到慢速路径。
用reduce-overhead确实容易负优化,试试mode="default"或者max-autotune,在大模型上编译收益才明显。