ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

AI工程从零搭建:ONNX+Triton推理服务实战

AI工程从零搭建:ONNX+Triton推理服务实战 1. 这不是调包是亲手搭起AI工程的骨架“ai-engineering-from-scratch”这个标题乍看像一句口号但在我带过二十多个工业级AI项目、亲手从零部署过七套推理服务、拆解过十二家大厂模型交付流水线之后我越来越确信真正卡住90%团队的从来不是模型精度差那0.3%而是当PyTorch训练完的.pt文件扔进生产环境时没人知道该往哪放、怎么跑、出错了查哪——更没人敢在凌晨三点对着一个OOM报错去翻CUDA内存池的分配日志。这不是算法问题是工程问题。而“from scratch”就是把所有被封装在pip install背后的黑箱一层层剥开亲手焊上电源、接好散热、拧紧每一颗螺丝。它不等于拒绝工具链而是先理解每条管线里流的是什么、为什么这么流、断了会从哪漏。关键词“ai-engineering”和“from-scratch”组合起来指向的是一套完整的能力图谱你得能写Dockerfile而不只是docker run -it能看懂Prometheus指标曲线而不只是等告警邮件能在K8s里精准调度GPU显存而不靠反复试错。它适合三类人刚从实验室毕业、发现论文代码跑不通生产环境的算法工程师想把业务模型真正落地、却被MLOps平台配置绕晕的产品技术负责人还有那些厌倦了“一键部署”幻觉、想搞清楚自己每天点的“上线按钮”背后到底发生了什么的后端开发者。这不是速成课但当你第一次手动编译ONNX Runtime并成功用C加载量化后的ResNet50看着inference_time_ms: 12.7稳定输出在终端里——那种掌控感是任何现成SDK给不了的。2. 项目整体设计与核心思路拆解2.1 为什么必须“从零开始”——避开三个典型工程陷阱很多团队一上来就冲向MLflow或KServe结果三个月后卡在模型版本回滚失败、特征服务延迟飙升、GPU资源争抢死锁上。根本原因在于他们跳过了对AI系统底层契约的理解。我见过最典型的三个陷阱全是“不从零”的代价第一是数据-模型-服务的隐式耦合陷阱。比如训练时用Pandas读CSV生产却用Spark Streaming拉Kafka字段类型、缺失值填充逻辑、时间戳时区处理全都不一致。线上AUC掉点排查三天才发现训练集里user_age是int64而实时特征里是float64模型权重在FP16推理时直接溢出。从scratch做第一步就是手写data_contract.py强制定义schema、校验规则、序列化协议Protobuf而非JSON让数据流经每个环节时都带着“身份证”。第二是硬件抽象泄漏陷阱。用HuggingFace Transformers默认devicecuda看似省事但当你要在A1024GB和L4048GB混部集群里调度时就会发现模型加载时显存预估完全不准——因为Transformers内部用torch.cuda.memory_reserved()估算而这个值在不同GPU架构上偏差高达37%。从scratch意味着要自己实现gpu_allocator.py基于nvidia-smi dmon实时采集PCIe带宽、NVLink拓扑、显存碎片率再结合模型计算图的tensor生命周期做动态分片。第三是可观测性盲区陷阱。监控只看CPU利用率和HTTP 5xx错误结果线上模型准确率缓慢下降两周才被发现。真实场景中关键指标是feature_drift_score特征分布偏移、inference_latency_p99尾部延迟、model_output_entropy预测置信度熵值。这些必须在服务启动时就注入OpenTelemetry SDK自定义span而不是等APM平台自动抓取。从scratch做的telemetry_injector.py会在每次predict前自动采样输入tensor的统计矩在predict后记录logits分布熵这些原始数据才是定位概念漂移的黄金线索。所以整个项目的设计哲学很直白用最小可行模块MVM代替最大可行平台MVP。不追求功能齐全而追求每个模块都能独立验证、可替换、可压测。比如推理服务模块我们不用FastAPIUvicorn打包而是拆成三个进程preprocessor纯NumPy做归一化、inference_engineC ONNX Runtime核心、postprocessorJSON序列化业务规则过滤。它们之间用Unix Domain Socket通信这样任何一个模块崩溃都不会拖垮全局且能单独压测inference_engine的QPS极限。2.2 架构选型逻辑为什么是ONNX Triton Prometheus而不是PyTorch Serving选型不是比参数而是比“失控时的可控性”。我们对比过四套主流方案方案启动时间GPU显存占用模型热更新调试难度关键缺陷PyTorch Serving8.2s1.8GB需重启高PythonC混合栈torch.jit.script对动态控制流支持差复杂模型编译失败率42%KServe12.4s2.1GB支持极高K8sCRD多层Operator一次配置错误导致整个Namespace的InferenceService不可用TorchServe5.7s1.5GB支持中JavaPythonJVM GC停顿导致p99延迟毛刺金融场景不可接受Triton Inference Server2.3s0.9GB原生支持低C核心清晰日志需手动转换ONNX但换来的是确定性Triton胜出的关键在于它的零抽象泄漏设计。它不试图“理解”模型只认ONNX/TensorRT/PyTorch Script三种格式的二进制字节码。这意味着训练侧无论用PyTorch Lightning还是DeepSpeed只要导出标准ONNXTriton就能加载推理侧无论用FP16还是INT8量化Triton的model_config.pbtxt里一行dynamic_batching { max_queue_delay_microseconds: 100 }就能开启动态批处理最重要的是当出现CUDA_ERROR_OUT_OF_MEMORY时Triton日志会精确到第几层Conv的weight tensor分配失败并给出当前显存块大小——这比PyTorch的CUDA out of memory模糊提示有用十倍。而选择ONNX作为中间表示是因为它解决了模型格式战争。我们实测过同一个ResNet50模型PyTorch原生格式加载耗时1.2sTensorRT引擎加载0.8s但ONNX格式在Triton里加载仅0.3s且跨框架兼容性100%。ONNX不是性能最优而是工程风险最低——它把模型定义、权重、算子语义全部固化为Protocol Buffer彻底消灭了“训练和推理环境Python包版本不一致”这类幽灵bug。Prometheus的选择则源于一个血泪教训某次线上事故Grafana面板显示GPU利用率95%但实际业务请求全超时。最后发现是NVLink带宽打满而NVIDIA DCGM exporter默认不采集dcgm_fabric_link_utilization指标。从scratch集成Prometheus意味着我们必须手写dcgm_exporter_config.yaml明确启用fabric link、PCIe重传、GPU温度突变检测等27个关键指标并用promql写告警规则“当dcgm_fabric_link_utilization{gpu0} 80持续30秒且dcgm_gpu_temp{gpu0} 70则触发NVLink拥塞告警”。这种颗粒度是任何开箱即用的监控方案给不了的。2.3 技术栈分层每一层都留出“可拔插”接口整个系统按职责严格分层每层只依赖下层的抽象接口绝不越界调用┌─────────────────────────────────────────────────────────────┐ │ Application Layer (业务逻辑) │ │ • 用户请求路由按user_id哈希到特定模型实例 │ │ • 业务规则过滤如金融风控需拦截score0.95的预测 │ │ • A/B测试分流10%流量走新模型v2 │ └─────────────────────────────────────────────────────────────┘ ↓ REST API / gRPC ┌─────────────────────────────────────────────────────────────┐ │ Serving Layer (服务编排) │ │ • Triton Model Repository管理自动reload变更 │ │ • 动态批处理策略按QPS自动调整max_batch_size │ │ • 健康检查探针/v2/health/ready, /v2/models/{name}/versions│ └─────────────────────────────────────────────────────────────┘ ↓ Shared Memory / IPC ┌─────────────────────────────────────────────────────────────┐ │ Inference Engine Layer (推理引擎) │ │ • ONNX Runtime with CUDA EP启用CUDA Graph优化 │ │ • 自定义CUDA Kernel针对特定算子加速如稀疏Attention │ │ • 显存池管理预分配1GB pinned memory避免malloc抖动 │ └─────────────────────────────────────────────────────────────┘ ↓ Driver API ┌─────────────────────────────────────────────────────────────┐ │ Hardware Abstraction Layer (硬件抽象) │ │ • NVIDIA Container Toolkit配置--gpus all --device/dev/nvidiactl│ │ • GPU拓扑感知调度numactl绑定CPU核GPU显存域 │ │ • 温度-频率闭环控制nvidia-smi -rgc设置功耗墙 │ └─────────────────────────────────────────────────────────────┘这种分层最硬核的价值在于当某天业务需要切换到Intel Gaudi芯片时只需重写Hardware Abstraction Layer的驱动调用上面三层代码一行不用改。我们去年就用这套设计三天内把推荐模型从A10集群迁移到Gaudi集群QPS反而提升了18%因为Gaudi的矩阵乘单元对稀疏特征更友好——这种敏捷性只有从scratch构建的系统才具备。3. 核心细节解析与实操要点3.1 ONNX模型转换不只是torch.onnx.export还有五个致命细节很多人以为导出ONNX就是一行命令的事结果线上推理直接报InvalidArgumentError: Input shape mismatch。我在三个项目里踩过坑总结出必须手工干预的五个细节第一动态轴dynamic axes的声明必须精确到业务语义。比如推荐系统的用户行为序列长度是动态的但torch.onnx.export默认把batch_size设为dynamic却把seq_len固定为训练时的值。正确做法是# 错误只声明batch维度动态 torch.onnx.export(model, x, model.onnx, input_names[input], dynamic_axes{input: {0: batch}}) # 正确按业务含义声明所有动态维度 torch.onnx.export(model, x, model.onnx, input_names[user_features, item_features, seq_input], dynamic_axes{ user_features: {0: batch}, item_features: {0: batch}, seq_input: {0: batch, 1: seq_len} # 明确seq_len可变 })否则Triton加载时会把seq_len硬编码为128线上遇到长度200的序列直接崩溃。第二PyTorch自定义算子必须提供ONNX注册。比如我们用torch.compile优化过的FlashAttention导出ONNX时会报Unsupported op: flash_attn_qkvpacked_func。解决方案不是放弃优化而是手写ONNX注册from torch.onnx import register_custom_op_symbolic import torch.onnx.symbolic_helper as sym_help def flash_attn_symbolic(g, q, k, v, dropout_p0.0, softmax_scaleNone): return g.op(com.microsoft::FlashAttention, q, k, v, dropout_p_fdropout_p, softmax_scale_fsoftmax_scale if softmax_scale else 1.0) register_custom_op_symbolic(flash_attn_qkvpacked_func, flash_attn_symbolic, 11)这个com.microsoft::FlashAttention算子名必须和Triton的custom backend里注册的名字完全一致否则加载失败。第三权重初始化必须冻结。PyTorch模型里如果存在nn.Parameter(torch.randn(...))导出ONNX时会把随机数固化进去导致每次加载模型权重都不同。必须在导出前for name, param in model.named_parameters(): if param.requires_grad: # 强制转为常量避免随机初始化污染ONNX param.data param.data.clone().detach()第四ONNX Opset版本必须匹配Triton支持范围。Triton 24.04只支持Opset 17但PyTorch 2.2默认用Opset 18。导出时必须显式指定torch.onnx.export(..., opset_version17) # 不加这行Triton加载报错第五输入输出tensor的dtype必须显式声明。PyTorch默认用float32但Triton在INT8量化时要求输入是uint8。导出时要# 声明输入为uint8适配量化模型 torch.onnx.export(..., input_names[input_uint8], output_names[output_float32], # 并在模型forward里做uint8-float32转换 )否则Triton会因dtype不匹配拒绝加载。提示每次导出ONNX后必须用onnx.checker.check_model()验证再用onnx.shape_inference.infer_shapes()补全shape信息。我们写了个CI脚本任何PR提交ONNX文件自动运行这两步失败则阻断合并。3.2 Triton模型仓库结构为什么config.pbtxt比模型文件还重要Triton不认模型文件名只认model_repository目录下的config.pbtxt。这个文件是整个服务的“宪法”写错一个参数服务就起不来。我们整理了生产环境必须配置的12个字段其中5个是生死线name字段必须小写下划线。Triton对模型名敏感RecommendModelV2会报错必须写recommend_model_v2。这是硬编码限制无解。platform字段决定执行引擎。pytorch_libtorch已废弃必须用onnxruntime_onnx。如果填错Triton启动时日志里只会有一行E0520 10:23:41.123456 1 model_repository_manager.cc:1234] failed to load xxx毫无上下文。正确写法platform: onnxruntime_onnxmax_batch_size不是越大越好。设为0表示禁用批处理设为8表示最多8个请求合并。但实测发现当模型有大量分支如if-else控制流时max_batch_size8会导致某些请求等待其他7个请求完成才开始推理p99延迟飙升300%。我们的解法是按模型复杂度分级简单CNNmax_batch_size32Transformer encodermax_batch_size8多模态融合模型max_batch_size1禁用批处理instance_group必须绑定GPU索引。默认[{kind: KIND_GPU}]会让Triton在所有GPU上启动实例但A10和L40混部时L40的显存更大应该优先调度。必须显式指定instance_group [ [ { kind: KIND_GPU, gpus: [0, 1] // 只在GPU 0和1上启动实例 } ] ]dynamic_batching的max_queue_delay_microseconds是延迟与吞吐的平衡点。设太小如100μs导致批处理失效QPS低设太大如10000μs导致请求排队p95延迟高。我们用压测数据拟合出公式optimal_delay 0.6 * avg_inference_time_ms * 1000比如平均推理耗时15ms则设max_queue_delay_microseconds: 9000。这个系数0.6是通过200轮压测得出的经验值兼顾了吞吐和延迟。注意config.pbtxt修改后Triton不会自动reload必须发送curl -X POST http://localhost:8000/v2/repository/models/recommend_model_v2/load。我们写了triton-reload.sh脚本自动检测config变更并触发reload避免人工遗漏。3.3 GPU显存精细化管理如何把A10的24GB榨出23.5GB可用显存不足是AI工程最痛的点。Triton默认配置下A10的24GB显存只能用18GB剩下6GB被CUDA Context、Triton自身、内存碎片吃掉。我们通过五层优化把可用显存提到23.5GB第一层CUDA Context预分配。Triton启动时会为每个GPU创建Context占约1.2GB。在config.pbtxt里加optimization { execution_accelerators [ { gpu_execution_accelerator: [ { name: tensorrt } ] } ] } # 这会复用TRT引擎的Context节省0.8GB第二层显存池预分配。Triton默认按需malloc显存产生碎片。在启动Triton时加参数tritonserver --model-repository/models \ --memory-profile \ --pinned-memory-pool-byte-size1073741824 \ # 预分配1GB pinned memory --cuda-memory-pool-byte-size0,2147483648 # GPU 0预分配2GB--cuda-memory-pool-byte-size0,2147483648表示GPU 0预分配2GB避免运行时malloc抖动。第三层TensorRT引擎显存优化。对ONNX模型用TRT优化时不只用trtexec --onnxmodel.onnx还要加trtexec --onnxmodel.onnx \ --fp16 \ --workspace4096 \ --minShapesinput:1x3x224x224 \ --optShapesinput:8x3x224x224 \ --maxShapesinput:32x3x224x224 \ --saveEnginemodel.plan关键是--workspace40964GB workspaceTRT编译时会用这个空间搜索最优kernel比默认的2GB workspace节省显存1.2GB。第四层CUDA Graph固化。对固定shape的模型启用CUDA Graph能减少kernel launch开销释放显存optimization { execution_accelerators [ { gpu_execution_accelerator: [ { name: graph } ] } ] }实测对ResNet50启用后显存占用降0.7GBQPS升12%。第五层显存碎片清理。即使做了以上长期运行后仍有碎片。我们写了个gpu-defrag.py每小时调用nvidia-smi --gpu-reset重置GPU需root权限并用torch.cuda.empty_cache()清空PyTorch缓存。虽然重置会中断正在推理的请求但我们在负载低谷期凌晨2-4点执行业务无感。实操心得每次上线新模型必须用nvidia-smi dmon -s u -d 1监控10分钟看fbframe buffer列是否稳定在目标值。如果波动超过5%说明有隐式显存泄漏要回溯ONNX转换步骤。4. 实操过程与核心环节实现4.1 从PyTorch模型到Triton服务的完整流水线整个流程不是线性的而是环形验证每一步输出都必须有自动化校验否则进入下一步就是灾难。我们用GitOps管理所有配置即代码。Step 1模型导出与ONNX验证耗时约8分钟在CI流水线里当PyTorch模型代码提交后自动触发# 1. 运行导出脚本 python export_onnx.py --model-path ./checkpoints/best.pt \ --output-dir ./onnx_models/ \ --opset 17 # 2. 验证ONNX模型可加载且shape正确 python -c import onnx model onnx.load(./onnx_models/recommender.onnx) onnx.checker.check_model(model) print(ONNX check passed) # 3. 用ONNX Runtime做前向验证确保数值一致性 python verify_onnx.py --pytorch-model ./checkpoints/best.pt \ --onnx-model ./onnx_models/recommender.onnx \ --tolerance 1e-3 # 允许1e-3误差verify_onnx.py会生成100组随机输入分别用PyTorch和ONNX Runtime运行对比输出tensor的torch.allclose(output_pt, output_onnx, atol1e-3)。不通过则阻断流水线。Step 2Triton模型仓库构建耗时约3分钟自动生成model_repository/recommender/1/model.onnx和model_repository/recommender/config.pbtxt# 用Jinja2模板生成config.pbtxt jinja2 templates/config.pbtxt.j2 \ -D namerecommender \ -D max_batch_size8 \ -D platformonnxruntime_onnx \ model_repository/recommender/config.pbtxt # 复制ONNX文件 cp ./onnx_models/recommender.onnx model_repository/recommender/1/模板config.pbtxt.j2里嵌入了业务规则比如max_batch_size根据模型类型自动选择避免人工填错。Step 3本地Triton服务启动与健康检查耗时约2分钟在开发机上用Docker启动Triton验证基础功能docker run --gpus1 --rm -p8000:8000 -p8001:8001 -p8002:8002 \ -v $(pwd)/model_repository:/models \ nvcr.io/nvidia/tritonserver:24.04-py3 \ tritonserver --model-repository/models --strict-model-configfalse # 等待服务就绪 curl -v http://localhost:8000/v2/health/ready # 应返回200 OK--strict-model-configfalse允许config.pbtxt有语法警告方便开发调试。Step 4端到端推理测试耗时约5分钟用Python client发真实请求验证全流程import tritonclient.http as httpclient client httpclient.InferenceServerClient(urllocalhost:8000) # 构造输入注意dtype和shape必须和config.pbtxt一致 inputs [] inputs.append(httpclient.InferInput(input, [1, 3, 224, 224], FP32)) inputs[0].set_data_from_numpy(np.random.rand(1,3,224,224).astype(np.float32)) # 发送请求 results client.infer(model_namerecommender, inputsinputs) output results.as_numpy(output) print(fOutput shape: {output.shape}, mean: {output.mean():.4f})这个测试必须覆盖所有输入输出tensor且验证输出值在合理范围内比如分类模型输出概率和为1。Step 5性能压测与基线对比耗时约20分钟用tritonperf工具压测生成性能报告# 安装tritonperf pip install tritonperf # 压测生成HTML报告 tritonperf --url localhost:8000 \ --model recommender \ --concurrency 16 \ --request-rate 100 \ --duration 300 \ --output report.html报告里关键看三列avg_latency_ms平均延迟、p95_latency_ms95分位延迟、success_rate成功率。必须满足p95_latency_ms 50ms且success_rate 100%才算通过。Step 6K8s部署与滚动更新耗时约15分钟用Helm Chart部署到生产集群# 渲染Helm模板 helm template triton-prod ./helm/triton \ --set modelRepository.storageClassssd \ --set resources.limits.nvidia.com/gpu1 \ triton-deploy.yaml # 应用部署 kubectl apply -f triton-deploy.yaml # 等待Pod就绪 kubectl wait --forconditionready pod -l apptriton --timeout300sHelm Chart里预置了GPU亲和性、显存限制、健康探针确保Pod只调度到有GPU的节点且不会因OOM被K8s kill。实操心得我们把整个流水线封装成make deploy命令开发人员只需git commit -m feat: new recommender modelCI自动完成从代码到生产服务的全部步骤。最关键是Step 4的端到端测试——它像一道闸门拦住了90%的配置错误。4.2 Prometheus监控体系搭建不只是看GPU利用率监控不是为了画好看图表而是为了在故障发生前10分钟预警。我们基于Triton的内置metrics构建了三层监控第一层基础设施层GPU硬件用NVIDIA DCGM Exporter采集27个指标重点监控dcgm_fabric_link_utilizationNVLink带宽使用率80%触发告警表明GPU间通信瓶颈dcgm_sm_clockSM频率若长期低于基频说明温度墙生效需检查散热dcgm_power_usage功耗突增20%可能预示内存泄漏第二层Triton服务层推理引擎Triton暴露/metrics端点我们重点关注nv_inference_request_success请求成功率99.9%触发P1告警nv_inference_queue_duration_us请求排队时间p95100000μs100ms触发P2告警nv_inference_exec_duration_us实际执行时间p9550000μs50ms触发P2告警第三层业务语义层模型效果在应用层注入OpenTelemetry采集model_output_entropy预测置信度熵值连续5分钟0.5说明模型对输入失去分辨力可能数据漂移feature_drift_score用KS检验计算输入特征分布偏移0.3触发数据质量告警ab_test_conversion_rateA/B测试转化率新模型vs旧模型差异1%则自动下线所有指标统一推送到Prometheus用Grafana看板分层展示。最关键的看板是“故障根因定位图”它把三层指标关联起来当nv_inference_queue_duration_us飙升时自动联动显示dcgm_fabric_link_utilization和model_output_entropy帮工程师10秒内判断是硬件瓶颈还是模型退化。注意Triton的metrics默认只暴露nv_前缀指标要启用业务指标必须在启动时加--allow-metricstrue --allow-gpu-metricstrue否则Prometheus抓不到数据。5. 常见问题与排查技巧实录5.1 Triton加载失败从日志里挖出真相的五个步骤Triton启动失败是最高频问题日志往往只有一行错误。我们总结出一套“日志深挖法”90%问题5分钟内定位Step 1看model_repository_manager.cc错误行号Triton日志里类似E0520 10:23:41.123456 1 model_repository_manager.cc:1234] failed to load xxx这个1234是源码行号。去GitHub搜triton-inference-server/model_repository_manager.cc定位到1234行附近看上下文判断是模型文件缺失、config语法错误还是权限问题。Step 2检查config.pbtxt语法用tritonserver --model-repository/models --strict-model-configtrue --log-verbose1启动--strict-model-configtrue会输出详细语法错误比如ERROR: failed to parse model config for recommender: config.pbtxt:5:17: error: expected string literal, got 8 max_batch_size: 8 ^说明第5行max_batch_size: 8后面少了换行应为max_batch_size: 8。Step 3验证ONNX模型完整性用onnxsim简化模型再验证pip install onnx-simplifier onnxsim ./model_repository/recommender/1/model.onnx ./model_repository/recommender/1/model_sim.onnx # 如果报错说明原始ONNX有损坏Step 4检查GPU驱动兼容性Triton 24.04要求NVIDIA driver 535.104.05。用nvidia-smi看驱动版本若低于此值必须升级驱动不能只升级CUDA toolkit。Step 5用strace抓系统调用当以上都正常但Triton仍卡在loading model时用strace看它在读什么文件strace -f -e traceopenat,open,read -p $(pgrep tritonserver) 21 | grep -E (model|config)会看到类似openat(AT_FDCWD, /models/recommender/1/model.onnx, O_RDONLY) 12如果返回-1说明文件路径或权限错误。实操心得我们把这五步写成triton-debug.sh脚本一线运维人员只需运行./triton-debug.sh recommender脚本自动执行全部步骤并高亮关键错误。最常犯的错是config.pbtxt里platform字段拼错比如写成onnxruntime_onnx 末尾空格Triton静默失败必须用Step 2的严格模式才能发现。5.2 推理延迟毛刺如何揪出那个偷偷吃CPU的Python线程线上p99延迟突然从20ms飙到200ms但GPU利用率只有30%。这种毛刺最难查因为不是硬件瓶颈而是软件干扰。我们用三步法定位Step 1用py-spy record抓Python线程火焰图在Triton容器里执行# 安装py-spy pip install py-spy # 抓30秒火焰图 py-spy record -p $(pgrep tritonserver) -o profile.svg -d 30打开profile.svg如果看到大量torch._C._autograd_init或numpy.core.multiarray说明是PyTorch或NumPy的Python线程在抢占CPU。Step 2检查Triton的Python backend配置Triton默认用Python backend执行预处理但Python GIL会阻塞。在config.pbtxt里禁用Python backend改用C# 删除所有python_backend相关配置 # 改用Triton内置的ensemble sequence_batching [ { control_input [ { name: START data_type: TYPE_BOOL } ] } ]Step 3用perf抓内核态热点如果火焰图没发现Python热点用perf看内核态perf record -g -p $(pgrep tritonserver) -g -- sleep 30 perf script perf.out分析perf.out如果看到大量nvlddm或nvidia_uvm说明是NVIDIA驱动bug需升级driver如果看到__libc_malloc说明有内存泄漏要检查ONNX Runtime的内存池配置。注意Triton的Python backend在高并发下必然产生毛刺这是GIL的固有缺陷。我们的生产规范是所有预处理必须用C或Triton内置算子如reshape,cast严禁用Python backend。这条红线写进了《AI工程红线手册》。5.3 模型热更新失败为什么model_repository变更不生效Triton支持热更新但经常不生效。根本原因是Triton的模型加载机制它只监听model_repository目录的inode变化不监听文件内容变化
返回列表