TorchServe 部署昇腾模型:从 .om 到上线

前言
拿到一个 ResNet50 的 .om 文件,要部署成推理服务。用 TorchServe,一天时间能走完全流程。
一、环境搭建(09:00-10:30)
安装 TorchServe
官方文档说 pip install torchserve,但昇腾版本要换源:
pip install torchserve torch-model-archiver -i https://pypi.tuna.tsinghua.edu.cn/simple
装完之后启动服务:
torchserve --start --model-store ./model_store
报错:libtorch_npu.so not found。原因是 TorchServe 默认用 CPU 版本的 PyTorch,需要手动指定 NPU 版本。
安装 torch_npu
pip uninstall torch
pip install torch_npu -f https://repo.huaweicloud.com/kunpeng/pypi/simple
再次启动 TorchServe,这次成功了。访问 http://localhost:8080/predictions/resnet50,返回 500 错误。日志显示:Model not found。
二、Handler 开发(10:30-12:00)
Handler 是什么
Handler 是 TorchServe 调用模型的入口,负责三个步骤:
- 预处理:解析请求,转 tensor,归一化
- 推理:调用
.om模型 - 后处理:tensor 转 JSON,返回结果
Handler 代码示例
# handler.py
import torch
import torch_npu
import json
from torchvision import transforms
class ResNetHandler:
def initialize(self, context):
# 加载 .om 模型
self.model = torch.jit.load("resnet50.om", map_location="npu:0")
self.model.eval()
# 预处理 pipeline
self.preprocess = transforms.Compose([
transforms.Resize(256),
transforms.CenterCrop(224),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
])
def handle(self, data, context):
# 解析请求
images = [self.preprocess(img) for img in data]
input_tensor = torch.stack(images).to("npu:0")
# 推理
with torch.no_grad():
output = self.model(input_tensor)
# 后处理:取 top5 类别
probs = torch.nn.functional.softmax(output, dim=1)
top5 = torch.topk(probs, 5)
return [{"labels": top5.indices.tolist(), "probs": top5.values.tolist()}]
Handler 的核心是 initialize 和 handle 两个方法。initialize 在模型加载时调用一次,handle 在每次推理时调用。
三、打包 .mar 文件(12:00-14:00)
什么是 .mar 文件
.mar(Model Archive)是 TorchServe 的模型打包格式,包含:
- 模型文件(
.om) - Handler 代码
- 依赖列表
- 配置文件
打包命令
torch-model-archiver \
--model-name resnet50 \
--version 1.0 \
--handler handler.py \
--extra-files resnet50.om \
--export-path ./model_store
参数说明:
--model-name:模型名称,调用时用这个名字--handler:Handler 文件路径--extra-files:额外的文件(比如.om文件)--export-path:输出目录
四、注册与测试(14:00-16:00)
注册模型
curl -X POST "http://localhost:8081/models?url=resnet50.mar&model_name=resnet50"
返回 200 OK,模型注册成功。
测试推理
curl -X POST "http://localhost:8080/predictions/resnet50" -T cat.jpg
返回:
{
"labels": [281, 282, 285, 287, 289],
"probs": [0.873, 0.041, 0.023, 0.012, 0.008]
}
单次推理延迟 15ms,满足要求。
推理流程示意图
客户端请求 → TorchServe → Handler.preprocess → .om 推理 → Handler.postprocess → 返回结果
五、性能调优(16:00-17:30)
Worker 数量调优
默认 worker 数量是 1,只用了单核。压测结果:
ab -n 1000 -c 50 http://localhost:8080/predictions/resnet50
QPS 180,P99 延迟 320ms。QPS 偏低(单卡理论上能到 400+)。
修改 worker 数量:
curl -X PUT "http://localhost:8081/models/resnet50?min_worker=4&max_worker=4"
重新压测:QPS 提到 620,P99 延迟 85ms。
性能对比表
| 配置 | QPS | P99 延迟 | AICore 利用率 |
|---|---|---|---|
| worker=1 | 180 | 320ms | 45% |
| worker=4 | 620 | 85ms | 78% |
| worker=8 | 580 | 92ms | 72%(下降) |
Worker 数量不是越多越好。4 个 worker 时,每个 worker 独占一个 AICore,利用率最高。8 个 worker 时,多个 worker 竞争同一个 AICore,反而下降。
六、监控与告警(17:30-18:00)
Prometheus 指标
TorchServe 自带 metrics 接口:
curl http://localhost:8082/metrics
返回 Prometheus 格式的指标:
torchserve_requests_total{model="resnet50"} 1523
torchserve_inference_latency_seconds{model="resnet50"} 0.015
torchserve_model_load_time_seconds{model="resnet50"} 2.3
Grafana 配置
接入 Grafana 后,配置告警规则:
- P99 延迟 > 500ms 持续 5 分钟 → 发钉钉通知
- QPS < 100 持续 10 分钟 → 发邮件通知
- 错误率 > 1% 持续 2 分钟 → 发短信通知
七、回滚方案
GPU 版本的模型还在,如果 NPU 版本出问题,可以立刻切回去。
准备两个 .mar 文件:
resnet50_npu.mar:NPU 版本resnet50_gpu.mar:GPU 版本
切换方法:
# config.properties
load_models=resnet50_gpu.mar # 默认加载 GPU 版本
切到 NPU 版本:改一行 load_models=resnet50_npu.mar,重启 TorchServe。
参考资源
- TorchServe 官方文档:https://pytorch.org/serve/
- 昇腾模型部署指南:https://www.hiascend.com/document
- torch_npu 安装指南:https://gitee.com/ascend/pytorch
总结
从 .om 文件到 TorchServe 上线,核心步骤是:环境搭建(换 torch_npu)→ Handler 开发 → 打包 .mar → 注册模型 → Worker 调优 → 配监控。最花时间的是处理 NPU 环境的依赖,Handler 和打包是标准流程。Worker 数量调到 4,单卡 QPS 能到 600+,满足大多数在线服务需求。监控和回滚是上线前必做的,避免线上翻车。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)