最近在做一个基于ReAct的Agent项目,需要频繁调用小模型做工具选择的推理。看到PyTorch 2.0的torch.compile宣传很猛,就试着把里面的一个BERT-like的编码器包了一下。结果发现,第一次调用确实慢得要死(大概多了300ms的编译时间),但后续调用确实快了20%左右。
PyTorch 2.0的compile到底能不能用在Agent的在线推理里?
全部回复
共 106 条20%的收益在推理场景里其实挺尴尬的,尤其你还要先吃300ms的编译开销。ReAct这种agent每次工具选择都是独立请求吧?那编译成本基本就摊到每个session里了,除非你跑长对话或者批量推理,不然真不如直接用JIT或者干脆上ONNX。不过我好奇你测的是静态shape还是动态shape?BERT-like编码器要是seq_len经常变,torch.compile可能得反复recompile,那20%的提升估计还得打折扣。
我这边之前试过把小的T5也包进去,发现CUDA graphs那套在短序列上反而有额外延迟,后来干脆关掉graph模式只留inductor。还有个坑是如果你用了huggingface的tokenizer,那部分Python开销compile根本优化不到,得自己把预处理也向量化才行。说到底,agent在线推理的瓶颈往往不在模型forward,而在整个pipeline的调度和I/O,你这20%要是算上tokenize和tool call的通信时间,可能实际端到端就省了5%不到。
另外你提到“频繁调用小模型”,如果并发高的话,不如试试把多个推理请求batch在一起,那提升比compile猛多了。或者干脆换distilbert这种更小的架构,省下的显存带宽可能比编译优化更直接。你那边模型size和batch size大概什么量级?方便的话可以多对比几组数据,毕竟torch.compile在不同硬件上的表现差异挺大的。
说实话你碰到的情况跟我之前试llama.cpp的静态量化挺像的,编译开销摊薄的问题在短生命周期任务里特别明显。Agent在线推理的瓶颈往往不在单次前向,而是那个ReAct循环里反复切换不同模型、不同输入长度,torch.compile的图捕捉对这种动态shape可能并不友好,我猜你后面可能还得加padding或者固定序列长度才能稳住那20%的收益。还有个坑是编译缓存,如果你用多进程部署,每个worker都得重新触发一次编译,那300ms就变成300ms乘以worker数了,这时候不如直接上ONNX或者TensorRT,虽然调起来烦但至少预热是确定的。不过我也挺好奇你那个工具选择模型到底有多小,如果本身推理只要5ms,那20%的加速也就1ms,为了这个去忍受编译延迟和兼容性风险,感觉有点得不偿失。要是能做成类似“编译一次跑几百次”的批处理模式,比如把多个工具候选拼成一个batch喂进去,可能比compile带来的收益更实在。另外你测过CUDA graph吗?那个在固定shape下延迟更低,而且没有编译期那种突刺。
编译开销这个点其实要看你的Agent调用频率,如果单次会话里工具选择超过10次,那300ms摊薄下来完全能接受。不过我好奇你用的是动态shape吗?BERT-like模型如果输入长度经常变,torch.compile可能得加dynamic=True,不然重编译反而更亏。另外你这20%提升是纯模型前向还是包含了整个tool调用链?我这边试过把编译和vLLM结合,发现小模型瓶颈经常在Python侧的调度逻辑上,那部分优化空间可能比compile更大。
我之前在类似的场景里也踩过这个坑,编译那一下300ms在实时交互里确实肉疼。不过后来发现如果能把编译好的模型缓存起来,或者用torch.compile的mode='reduce-overhead'做预热,效果会好不少,20%的提升在长会话里其实挺可观的。倒是想问问你,那个BERT编码器是动态shape吗?如果是变长输入,重编译会不会频繁触发?我在处理多轮对话时就老被这个卡住。
编译开销摊到长会话里其实挺划算的,但要是单轮请求多那这300ms就有点肉疼了。
20%的加速对工具选择这种小模型挺香了,不过动态shape多的话建议先确认下CUDA graph会不会频繁recompile。
我之前也动过这个念头,拿一个T5-small做意图分类试了试,情况和你差不多。首次编译那一下真的挺劝退,尤其Agent场景经常是请求来了才触发,用户那边干等着多300ms体感很明显。我后来是把compile预热放到服务启动阶段,用几条假数据先跑一遍,正式流量进来才吃到加速。不过有个坑,如果Agent里工具选择的分支特别多、输入shape变化频繁,容易反复触发重编译,反而更慢,你得把dynamic shape那块调一调。所以我觉得能不能用,关键看你请求量够不够大、输入分布稳不稳定。量小或者流量稀疏的话,那点加速根本摊不平编译开销,还不如老老实实上ONNX或者TensorRT。