最近在调一个nlp分类模型,数据量不大(大概2万条),单卡3090训练。试了torch.compile,用默认模式跑,第一轮确实慢(编译开销),但后面几个epoch速度只提升了10%左右,和官方宣传的“训练提速30%-50%”差很多。而且用动态shape(比如变长序列padding到不同长度)直接报错,回退到eager模式。想问问大家:是不是小模型小数据量根本没必要上compile?还是我哪里设置不对?有一说一,模型里用了transformers的BertForSequenceClassification,加了个自定义分类头。有没有类似场景的老哥分享下实际收益?现在纠结要不要为了部署时的推理加速去折腾这个。
PyTorch 2.0的compile到底值不值得用?静态图加速不明显还报错
全部回复
共 97 条你这情况跟我之前调bert-base时挺像的,小模型加小batch确实吃不满compile的红利,官方那个30%-50%多半是大模型大batch下的benchmark。动态shape报错基本无解,要么padding到固定长度,要么干脆只在推理时开compile,训练阶段收益真不大。我后来试了inductor的mode=max-autotune,虽然编译更久但能多挤几个点,你可以试试。另外自定义分类头如果太简单,其实瓶颈都在transformer那块,compile优化不到啥,不如把精力放在数据加载和混合精度上。
2w条数据单卡3090,这个量级compile的编译开销摊不平收益,10%其实算正常了,官方那30%-50%多半是大模型大batch或者CV场景跑出来的。动态shape报错太常见了,transformers里很多op本来就不友好,我试过把padding改成固定长度再配合reduce-overhead能稍微好点,但提升也就那样。你要是主要纠结部署推理,不如直接上ONNX或者TensorRT,那个收益比compile实在多了。
说实话你这个场景我太熟了,之前用electra做类似的分类任务也是这德行,2万条数据在3090上根本喂不饱显卡,compute bound都没到,compile优化的是kernel launch和显存带宽,小batch下收益自然被稀释。动态shape那个报错确实无解,torch.compile对变长序列的support一直很迷,就算你padding到固定长度,内部如果有多分支或者python控制流,它还是会回退。我个人建议是小模型直接别折腾compile,把精力放在gradient accumulation和混合精度上,收益来得更直接,我试过fp16加上多步累计,整体训练时间能压掉将近一半。至于部署推理,如果你不是追求极致延迟,其实纯eager加torch.inference_mode就够了,真要上compile也得等模型结构完全冻结,而且得用fullgraph=True去逼它做整图优化,默认模式那点优化幅度确实不值得换那堆报错。另外你说transformers的模型,可以试试把自定义分类头单独提出来compile,backbone保持原样,有时候这样能避开不少坑,但说实话提升也就那样。反正这玩意儿现阶段更像是给大模型或者CNN那种固定shape场景准备的,NLP小模型拿它性价比确实不高。
小模型真没必要折腾compile,那点提升还不够调bug的时间,推理时直接上onnx或者TensorRT更香。
跟你情况差不多,之前试过在bert-base上开compile,小数据集下收益确实就那样,10%左右算正常,官方那个30%-50%估计得大模型加静态shape才跑得出来。动态padding那个坑我也踩过,后来干脆固定长度padding到512,虽然浪费点显存但至少不报错,速度还稳一点。你要是主要纠结部署推理,不如直接上onnx或者tensorrt,那个提升比compile明显多了,训练阶段真没必要折腾。
这场景我太熟了,跟你差不多配置,2万条数据上compile属实有点鸡肋。提速10%算正常,官方那30%-50%多半是CV大模型或者动态shape不严重的理想情况。动态shape报错基本无解,建议直接关掉或者用dynamic=False硬凑,不然编译缓存反复失效反而更慢。你这规模其实把batch size调大点、梯度累积搞上,收益比折腾compile实在。推理端倒是可以单独试试,毕竟部署时静态shape多,提速比训练明显。
你这情况太真实了,我拿差不多的模型试过,2万条数据加3090,compile收益基本就10%左右,官方那个30%-50%得看模型规模和batch大小,小模型根本吃不满。动态shape报错也是老毛病了,别硬上,把padding固定到最大长度或者用bucket分桶能缓解一点,但提升也就那样。如果只是训练,没必要折腾,部署推理时用onnx或者TensorRT反而更稳,收益也更明显。
你这情况我太熟了,2万条数据加bert这级别真没必要折腾compile,官方那30%-50%都是大模型大batch堆出来的,小模型光算子融合省下的那点时间还不够填编译和显存调度的坑。动态shape报错更是常态,transformers里一堆带条件的tensor操作,默认模式根本兜不住,我建议要么固定长度padding要么直接放弃。推理阶段倒是可以试试,毕竟部署不吃训练那套动态逻辑,但收益也就那样。
同感,小模型上compile收益真就那样,我试过动态shape直接劝退,老老实实eager算了。
你这场景我碰过,2万条数据真没必要折腾,部署时再考虑torchscript或onnx吧。
你这情况跟我之前跑BERT分类简直一模一样,2万条数据上compile的收益确实很尴尬,官方那个30%-50%多半是大模型+固定shape才有的效果。动态padding这块我直接放弃了,现在都是按batch内最大长度统一pad,虽然浪费点显存但至少不报错。另外你可以试试把custom head单独拎出来别让compile管,或者用mode=reduce-overhead,我这边大概能再多挤5%左右。反正小数据量上别指望质变,当个免费的小优化用用还行,部署推理倒是值得折腾下。
同款配置,2万条数据上compile确实有点鸡肋,我试过几次收益都在5%-15%晃悠,跟你差不多。动态shape那个坑我也踩过,padding到固定长度反而能正常编译,但小模型上省的时间还不够折腾的。建议你把注意力放在推理优化上,比如转ONNX或者用TensorRT,那个提速感知明显得多。另外可以看下是不是GPU利用率没吃满,有时候dataloader瓶颈比编译影响大。
你这场景我基本复刻过,2万条小数据加Bert,compile收益确实就那样,10%算正常,官方那个30%得看模型多大、算力多挤。动态shape报错就别硬扛了,变长序列老老实实pad到固定长度或者直接eager,省心。我试过把自定义分类头拆出来单独compile,backbone保持原样,能稍微稳一点,但也就聊胜于无。部署推理如果在意延迟,直接上onnx或者TensorRT更实在,compile那点编译开销在推理场景换不来什么。
说实话你这情况我太懂了,小模型加小数据,compile的优化空间本来就被吃掉了大半,它那套图优化fuse算子对大模型更友好。动态shape报错是常态,transformers里好多op都没适配,建议你试试把max_length固定,别用动态padding,可能能跑通。我自己用electra试过,提速也就5%-8%,真不如把精力放在调学习率或者换loss上。推理要快的话,建议直接转onnx,别跟compile死磕。
同款3090,之前试过在小 Bert 上硬上 compile,收益也就 5%-8%,跟你差不多,后来发现瓶颈根本不在计算,而是数据加载和 GPU 利用率没吃满。动态 shape 报错太正常了,torch.compile 对变长序列的支持本来就没完全落地,建议要么固定长度要么用 bucket 把长度分档。你这种规模其实 eager 模式调好 batch size 和梯度累积,效果不会差太多,部署推理的话不如直接上 onnx 或者 tensorrt,别在 compile 上死磕了。
你这数据量和模型规模,提升10%挺正常的,官方那数据都是大模型大batch跑出来的,动态shape直接劝退就别折腾了。
说实话你这个场景我试过类似的,数据量两万条确实不大,compile的编译开销摊薄下来收益就很有限了,官方那个30%-50%多半是拿大模型大batch堆出来的。动态shape报错太正常了,torch.compile对变长序列支持一直很迷,我建议要么统一padding到固定长度,要么干脆别折腾。你那个自定义分类头如果没啥复杂控制流,其实eager模式跑着也挺好,部署推理的话可以考虑转ONNX或者TensorRT,收益比compile来得实在。
说实话你这情况跟我之前跑BERT分类几乎一模一样,2万条数据真没必要折腾compile,收益全被编译开销和动态shape的兼容问题吃掉了。我试过把padding固定到最大长度,配合静态shape勉强能到20%出头的提速,但显存占用上去了,训练还容易不稳定。你要是主要为了部署推理,不如直接上ONNX或者TensorRT,那提升才是肉眼可见的,训练阶段真不用纠结这10%。另外transformers的模型有些算子本来就不在inductor的优化列表里,报错回退太正常了。
2万条数据确实有点难为compile了,它的收益主要来自大batch和重复shape,你这种变长序列加上频繁padding,编译缓存基本命中不了,反而overhead占大头。BertForSequenceClassification本身也不算大,3090上eager已经吃得挺饱,10%提升算正常范围了。动态shape报错可以试试mark_dynamic或者pad到固定几个bucket,能缓解但不会质变。推理部署倒是值得单独compile一下,那边shape稳定,收益比训练明显得多。