将 HuggingFace 上 HumanCompatibleAI/ppo-Pendulum-v1(Stable-Baselines3 PPO 强化学习模型,PyTorch 框架)迁移到本地昇腾 Ascend910 NPU,并提供 HTTP 服务化推理。
| 项目 | 说明 |
|---|---|
| 模型 | HumanCompatibleAI/ppo-Pendulum-v1 (PPO / MlpPolicy [64, 64]) |
| 任务 | Pendulum-v1 倒立摆控制(观测 3 维,动作 1 维扭矩 [-2, 2]) |
| 官方基线 | mean_reward = -189.25 ± 66.36(10 幕,deterministic) |
| 迁移框架 | PyTorch 2.9.0 + torch_npu 2.9.0.post1 |
| 推理硬件 | 昇腾 Ascend910 (Ascend910_9382) × 8 卡 |
| 服务框架 | FastAPI + Uvicorn |
| 本机实测 | mean_reward = -177.38(3 幕自测);单步推理平均延迟 4.45 ms |
ppo-Pendulum-v1-npu/
├── README.md # 本指南
├── requirements.txt # 运行环境依赖
├── inference.py # NPU 服务化推理脚本 (FastAPI)
├── test_inference.py # 自动化测试用例
├── make_screenshots.py # 截图渲染工具(终端风格)
├── assets/ # 截图
│ ├── npu_device_call.png # NPU 设备调用截图
│ ├── model_result.png # 测试结果截图
│ └── agent_workflow.png # 适配过程截图
└── results/
├── test_results.json # 测试结果 (JSON)
├── test_results.txt # 测试结果 (文本)
└── server.log # 服务运行日志# 1. 加载 CANN 环境
source /usr/local/Ascend/ascend-toolkit/set_env.sh
# 2. 安装依赖(华为镜像源)
export PIP_INDEX_URL=https://repo.huaweicloud.com/repository/pypi/simple/
pip install -r requirements.txt
# 3. 校验 NPU 可用
npu-smi info
python -c "import torch, torch_npu; print(torch.randn(3, 4).npu() + torch.randn(3, 4).npu())"export ASCEND_RT_VISIBLE_DEVICES=0 # 指定使用第 0 卡
python inference.py --host 0.0.0.0 --port 8000启动成功后将打印模型、设备信息(可对照 assets/npu_device_call.png),并监听 HTTP 服务。
# 自动启动服务 → 测试 4 个接口 → 结果写入 results/
python test_inference.py --episodes 5预期输出(对照 assets/model_result.png):
[PASS] /health 设备=npu:0 NPU可用=True
[PASS] /model_info 算法=PPO 策略=ActorCriticPolicy 设备=npu:0
[PASS] /predict 20 次调用通过, 平均延迟 4.452 ms, 设备=npu:0
[PASS] /episode 5 幕: mean_reward=-224.2194 std=122.5887 max=-135.9141 设备=npu:0
[PASS] 全部测试用例通过 ✅python inference.py --self-test --episodes 3| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /health | 健康检查,返回服务与 NPU 设备状态 |
| GET | /model_info | 模型结构、观测/动作空间、推理设备 |
| POST | /predict | 单步推理:{"observation": [cos, sin, vel], "deterministic": true} → {"action": [...]} |
| POST | /episode | 完整幕测试:{"episodes": 5, "deterministic": true, "seed": 42} → 每幕步数与 reward |
调用示例:
# 单步推理
curl -s http://127.0.0.1:8000/predict \
-H "Content-Type: application/json" \
-d '{"observation": [0.5, 0.87, 0.1], "deterministic": true}'
# => {"action":[2.0],"action_mean":[2.0],"device":"npu:0","latency_ms":4.4}
# 完整幕测试
curl -s http://127.0.0.1:8000/episode \
-H "Content-Type: application/json" \
-d '{"episodes": 10, "deterministic": true, "seed": 42}'本模型的迁移过程(对照 assets/agent_workflow.png)主要包含以下适配点:
inference.py 顶部)import torch_npu # 注册昇腾 NPU 后端
from torch_npu.contrib import transfer_to_npu # CUDA API → NPU API 自动映射transfer_to_npu 自动完成:torch.cuda.is_available() → True、.cuda() → .npu()、
torch.device('cuda') → torch.device('npu')、DDP backend nccl → hccl 等映射。
扫描 stable-baselines3 2.9.0 源码:无任何 torch.cuda.* 直接调用,
因此仅需在加载模型时指定设备即可:
model = PPO.load(MODEL_PATH, device="npu:0") # 策略网络权重加载至 NPU模型训练于 Python 3.8 + SB3 2.2.0a3,其序列化的 clip_range / lr_schedule
schedule 闭包无法在 Python 3.11 反序列化。通过 custom_objects 以常量函数替换:
custom_objects = {
"clip_range": lambda _obs: 0.2,
"lr_schedule": lambda _progress_remaining: 0.001,
}
model = PPO.load(MODEL_PATH, device="npu:0", custom_objects=custom_objects)gymnasium 的 Pendulum-v1 环境在 CPU 侧运行(环境模拟不需要 NPU), 策略网络前向推理在 NPU 上执行,仅 200 步内的状态→动作映射走 NPU 算子。
seed=42)保证可复现| 指标 | NPU 实测 | 官方基线 (CPU) |
|---|---|---|
| episode mean_reward(5 幕) | -224.22 ± 122.59 | -189.25 ± 66.36 |
| episode mean_reward(3 幕自测) | -177.38 ± 56.66 | -189.25 ± 66.36 |
| 单步推理平均延迟 | 4.45 ms | - |
| 推理设备 | Ascend910_9382 @ npu:0 | - |
结论:NPU 推理结果与官方 CPU 基线同分布(|Δ| < 1σ),服务化推理端到端可用。
| 问题 | 解决方案 |
|---|---|
No module named 'decorator' | pip install decorator |
SetPrecisionMode ... error code 500001 | source /usr/local/Ascend/ascend-toolkit/set_env.sh |
code() argument 13 must be str, not int 警告 | 使用 7.3 节的 custom_objects 替换旧版闭包 |
| 多进程启动冲突 | 使用 --num_workers 0,或确保单进程持有 NPU 上下文 |
| 想切换推理卡 | export ASCEND_RT_VISIBLE_DEVICES=1 或 export PPO_DEVICE=npu:1 |
transfer_to_npu(from torch_npu.contrib import transfer_to_npu)