昇腾部署MiniMax H3 FL2VA
# MiniMax H3 FL2VA 视频生成服务部署总结
> 平台:Ascend 910B4-1 ×8(64G HBM/卡)· 单机 754G RAM
> 框架:vllm-ascend v0.26.0 + vllm-omni(Hunyuan-3D-2.0-omni)
> 用途:FL2VA 文生视频/图生视频,支持 1~3 张参考图关键帧,最长 12s
> 日期:2026-08-11
---
## 目录
1. [整体架构](#1-整体架构)
2. [硬件与软件环境](#2-硬件与软件环境)
3. [下载与准备](#3-下载与准备)
4. [容器部署](#4-容器部署)
5. [环境安装](#5-环境安装)
6. [代码改动(关键)](#6-代码改动关键)
7. [服务启动](#7-服务启动)
8. [推理调用](#8-推理调用)
9. [性能与资源数据](#9-性能与资源数据)
10. [故障排查手册](#10-故障排查手册)
11. [运维经验教训](#11-运维经验教训)
---
## 1. 整体架构
```
宿主机 (754G RAM, 8×910B4-1 64G HBM)
└─ Docker 容器 h3-vllm (quay.io/atlas-ci/vllm-ascend:v0.26.0)
├─ APIServer FastAPI 监听 :9098 (路由 /v1/videos/sync)
├─ 4×DiffusionWorker H3 50层 diffusion transformer, tp=4
│ (每 worker: ~80G RAM + ~47G HBM)
├─ 4×EngineCore VAE tile 模式解码
└─ text encoder Qwen3-VL 50层, tp=4 (replicated vision)
挂载关系:
/usr/local/Ascend/driver → /usr/local/Ascend/driver
/usr/local/Ascend/firmware → /usr/local/Ascend/firmware
/usr/local/sbin → /usr/local/sbin
/etc/ascend_install.info → /etc/ascend_install.info
/data1/fl2va → /workspace/models (模型, 135G)
/data1/h3work → /workspace (工作区, 92G)
启动参数 (tp=4, usp=4, ring=1):
--omni --task-type fl2va --num-gpus 4 --usp 4 --ring 1
--text-encoder-tp-size 4 --enable-distributed-layerwise-offload
--vae-parallel-mode tile --vae-use-tiling --vae-patch-parallel-size 4
--diffusion-attention-backend FLASH_ATTN --load-format mmap
```
**进程模型**:vllm-omni 多进程(APIServer + 4 DiffusionWorker + 4 EngineCore + orchestrator),
属于 inline 串行执行(stage_runtime 单 stage 顺序调度)。
---
## 2. 硬件与软件环境
| 项 | 值 |
|---|---|
| NPU | 华为昇腾 910B4-1 ×8,每卡 HBM 65536 MB |
| CPU/RAM | 754G 总内存 |
| 磁盘 | /data1 NVMe(2.3T 可用),/tmp 为 tmpfs(不可放大文件) |
| 容器镜像 | quay.io/atlas-ci/vllm-ascend:v0.26.0 |
| Python | 容器内 /usr/local/python3.12.13 |
| 关键依赖 | vllm 0.26.0(site-packages)、vllm-omni 0.1.dev1(editable)、mindiesd(wheel)、ffmpeg |
| 驱动 | npu-smi 25.5.2 |
**NPU 卡资源分配**(8 卡共用,注意 NPU ID 与 ASCEND_RT_VISIBLE_DEVICES 的映射):
```
npu-smi info 中 NPU 2/3/4/5 → ASCEND_RT_VISIBLE_DEVICES=0,1,2,3(服务用)
NPU 6/7 被其他进程占用 (~53.5G/卡)
```
---
## 3. 下载与准备
### 3.1 模型下载(135G)
- 位置:`/data1/fl2va/FL2VA/`(含 `model_index.json`,全套 bf16)
- 组成:Qwen3-VL text encoder(50层)+ H3 diffusion transformer(50层)+ VAE + tokenizer 等
- 注意:**模型务必放 /data1(NVMe)**,放 /tmp(tmpfs)会把 754G 内存吃掉 135G,导致服务加载时 OOM 崩溃
### 3.2 框架源码
```bash
# vllm-omni(推理管线主体,代码改动都在这)
git clone https://github.com/AIS-Hackathon/Hunyuan-3D-2.0-omni.git # → /data1/h3work/vllm-omni
# MindIE-SD wheel(VAE/算子库)
# → /data1/h3work/MindIE-SD/dist/mindiesd-*.whl
```
### 3.3 目录速查(/data1/h3work = 容器 /workspace)
| 路径 | 用途 |
|---|---|
| `start_h3.sh` | 服务启动脚本(env + vllm serve 参数) |
| `setup_env2.sh` / `setup_env2.log` | 环境安装脚本(vllm-omni editable + mindiesd + ffmpeg) |
| `h3_server.log` | 服务日志(重启前 `rm -f`) |
| `run_full.sh` | 完整 12s 视频请求脚本(curl 封装) |
| `refs/` | 参考图(分镜1.jpg / 角色1.jpg / 角色2.jpg) |
| `video_full_12s.mp4` | 生成产物 |
| `vllm-omni/` | 源码(editable 安装) |
---
## 4. 容器部署
```bash
docker run -itd --name h3-vllm --privileged --security-opt seccomp=unconfined --network host --shm-size=64g \
-v /usr/local/Ascend/driver:/usr/local/Ascend/driver \
-v /usr/local/Ascend/firmware:/usr/local/Ascend/firmware \
-v /usr/local/sbin:/usr/local/sbin \
-v /etc/ascend_install.info:/etc/ascend_install.info \
-v /data1/fl2va:/workspace/models \
-v /data1/h3work:/workspace \
quay.io/atlas-ci/vllm-ascend:v0.26.0 bash
```
> ⚠️ 必须 `--privileged`(NPU 设备访问)+ `--shm-size=64g`(进程间共享内存)+ `--network host`(9098 端口直通)
>
> ⚠️ 重建容器(docker rm -f + run)会丢失:
> - pip 安装的 vllm-omni / mindiesd(需重跑 setup_env2.sh)
> - `/vllm-workspace/vllm` 目录内容(镜像 VOLUME 为空卷,需重建占位文件,见 10.4)
> - /workspace/refs 参考图(需重新 docker cp)
---
## 5. 环境安装
容器内执行(重建容器后必跑):
```bash
cd /workspace && bash setup_env2.sh
# 内容: pip install -e vllm-omni + pip install mindiesd wheel + ffmpeg 等
```
**重要**:
- setup_env2.sh 里 `patch_vllm.py` 步骤已删除(原作用是在 vllm weight_utils.py 注入 flock 网络锁防并发加载——现已不需要,且重跑会加回锁导致问题)
- 验证:`python -c "import mindiesd"`、`pip show vllm-omni` 有版本号
---
## 6. 代码改动(关键)
> 目标:让 FL2VA 支持 **3 张参考图关键帧**(原版只允许 1~2 张首/末帧)。
> 改动文件均在 `/workspace/vllm-omni/vllm_omni/diffusion/models/minimax_h3/`
### 6.1 pipeline_minimax_h3.py —— 放开 3 图计数检查(3 处)
```python
# ① 第 ~1593 行(fl2va 分支):
if len(images) > 2:
raise OmniClientError("fl2va accepts at most first and last images")
# 改为:
if len(images) > 3:
raise OmniClientError("fl2va accepts at most 3 keyframes")
# ② 第 ~1622 行(count 分支):
if count > 2:
raise OmniClientError(...)
# 改为:
if count > 3:
raise OmniClientError(...)
# ③ 第 ~1630 行(keyframe count check):
elif len(images) > 2:
raise OmniClientError(f"... keyframe count check ...")
# 改为:
elif len(images) > 3:
raise OmniClientError(f"... keyframe count check ...")
```
> `_resolve_fl2va_keyframe_indices()`(第 ~295 行)无需改:要求
> `len(frame_indices) == 图片数` 即放行。
### 6.2 packed_sequence.py —— 关键帧布局支持中间帧
```python
# ① 修复关键帧顺序被打乱(原 sorted(set()) 会把 [0,144,-1] 排成 [-1,0,144],
# 导致参考图与帧位置错位!)
def _keyframe_cond_frame_indices(...):
...
return list(dict.fromkeys(keyframe_frame_indices)) # 保序去重
# ② 中间帧时间位置改为线性插值(原实现只支持首帧/末帧锚点)
# 在 minimax_h3_packed_sequence() 的 cond_t 循环 else 分支:
else:
denom = (frame_count - 1) if frame_count else 1
frac = pixel_index / denom
cond_t = float(text_len) + frac * (_temporal_position_span(latent_t) - _FRAME_RESCALE)
```
> `MINIMAX_H3_FL2VA_KEYFRAME_SIGNATURES` 常量((0,), (-1,), (0,-1))虽存在但未被引用,无需处理。
### 6.3 其他历史改动(已回退/不需要)
| 改动 | 状态 |
|---|---|
| weight_utils.py 注入 flock 网络锁(patch_vllm.py) | 已回退,不再需要 |
| stage_init_utils / stage_runtime mmap 注入 | 已改为启动参数 `--load-format mmap` 直传 |
| stage_runtime inline 串行执行 | 保持默认即可 |
---
## 7. 服务启动
### 7.1 启动脚本 start_h3.sh
```bash
#!/bin/bash
set -e
export ASCEND_RT_VISIBLE_DEVICES=0,1,2,3
export PORT=${PORT:-9098}
export MODEL=/workspace/models/FL2VA
export VLLM_WORKER_MULTIPROC_METHOD=spawn
export VLLM_OMNI_VIDEO_SYNC_TIMEOUT=5400 # ⚠️ 必须 ≥5400,默认1800会掐断27分钟生成
export PYTHONDONTWRITEBYTECODE=1
export HF_HUB_OFFLINE=1
export TRANSFORMERS_OFFLINE=1
export PATH=/usr/local/python3.12.13/bin:$PATH
exec vllm serve "${MODEL}" \
--load-format mmap \
--omni --task-type fl2va --num-gpus 4 --usp 4 --ring 1 \
--text-encoder-tp-size 4 --enable-distributed-layerwise-offload \
--vae-parallel-mode tile --vae-use-tiling --vae-patch-parallel-size 4 \
--diffusion-attention-backend FLASH_ATTN
```
### 7.2 启动与就绪探测
```bash
# 正确后台方式(关键!nohup & 会被 exec 会话回收,导致服务"假启动")
docker exec h3-vllm bash -c "rm -f /workspace/h3_server.log"
docker exec -d h3-vllm bash -c 'bash /workspace/start_h3.sh > /workspace/h3_server.log 2>&1'
# 就绪探测(用 /v1/models,health 有时输出异常)
curl -s -m 5 http://127.0.0.1:9098/v1/models # 返回含 "object" 即就绪
# 重启
docker exec h3-vllm bash -c "pkill -9 -f 'vllm serve'; sleep 2; rm -f /workspace/h3_server.log"
```
### 7.3 状态检查
```bash
docker exec h3-vllm bash -c "tail -20 /workspace/h3_server.log" # 日志
free -g # RAM
docker exec h3-vllm npu-smi info # HBM
docker exec h3-vllm bash -c "ps aux --sort=-rss | grep '[p]ython3'" # worker RSS
```
---
## 8. 推理调用
### 8.1 完整 12s 视频(3 张参考图关键帧)
```bash
curl -sS -m 7200 -o video_full_12s.mp4 http://127.0.0.1:9098/v1/videos/sync \
-F "prompt=<完整分镜脚本>" \
-F 'aspect_ratio=16:9' \
-F 'seconds=12' -F 'fps=24' \
-F 'num_inference_steps=25' \
-F 'flow_shift=12' \
-F 'task=fl2va' \
-F 'extra_params={"frame_indices":[0,144,-1]}' \
-F input_references=@分镜1.jpg \
-F input_references=@角色1.jpg \
-F input_references=@角色2.jpg
```
### 8.2 关键帧规则
| 图数量 | frame_indices | 含义 |
|---|---|---|
| 1 | `[0]` | 仅首帧锚定 |
| 2 | `[0,-1]` | 首帧 + 末帧 |
| 3 | `[0,N,-1]` | 首帧 + 中间帧(12s/288帧 时 N=144=8s 处)+ 末帧 |
- `-1` 表示最后一帧;中间帧必须落在 `[0, 帧数)`,各索引不得重复
- 图片顺序与索引顺序一一对应(分镜1→帧0,角色1→帧144,角色2→末帧)
### 8.3 限制与产物
- **最长 12 秒**(`seconds>12` 直接报错;脚本 16s 需裁剪为 12s)
- 产物:1376×768 / 24fps / 12.3s / H.264+AAC 音轨 / ~13MB
- 取回:`docker cp h3-vllm:/workspace/video_full_12s.mp4 <本地路径>`
---
## 9. 性能与资源数据
| 指标 | 数值 |
|---|---|
| 启动就绪 | 4 分钟(页缓存热)~ 22 分钟(冷启动) |
| 生成耗时 | ~64s/步;12s/25步 ≈ **27.5 分钟** |
| HBM 稳态 | 4×46.9G/64G(71.6%) |
| HBM 峰值 | 12s 16:9 激活 +35.2G/卡 → 临界,**偶发 OOM,重试即成功** |
| RAM 稳态 | ~665G/754G(4 worker RSS ~320G + 页缓存 ~94G) |
| RAM 加载峰值 | ~630G |
**显存/内存为什么都占着(常见疑问)**:
- 模型权重(~330G bf16 全套)**双份驻留**:
- HBM:4×47G ≈ 187G(推理执行副本)
- RAM:4 worker 各 ~80G ≈ 320G(vllm-ascend DLO 按层卸载机制的 CPU 后备副本,进程退出前不可释放)
- 另有 ~94G 可回收页缓存(mmap 读权重产生)
- 真正瓶颈是 **HBM**(激活 35G 逼近 64G),RAM 是设计冗余
---
## 10. 故障排查手册
### 10.1 服务起不来 / 启动即崩(procs=0)
```bash
docker exec h3-vllm bash -c "grep -aE 'ERROR|Traceback|corrupted|HCCL|dead|Exit code' /workspace/h3_server.log | tail"
```
- `corrupted size vs. prev_size` + `scheduler is dead (Exit -6/-11)` = HCCL/内存问题:
- 先看 `free -g`:avail < 500G 时权重加载必崩(tmpfs 被占)
- 偶发 → 重试 1~2 次
- 日志只有几行就停 = `vllm` 命令找不到 → 见 10.4
### 10.2 服务"假启动"(procs=1 但 api 不通)
- 用 `docker exec -d` 启动,**不要** `nohup bash ... &`(进程随 exec 会话被杀)
- 启动后日志无内容 → 检查 `/vllm-workspace` 占位(10.4)
### 10.3 生成报错
| 错误 | 原因 / 处理 |
|---|---|
| `at most 2 image reference frames` / `at most first and last` / `keyframe count check` | 计数检查未放开 → 改 pipeline_minimax_h3.py 3 处(6.1) |
| `packed layout only supports first/last keyframe anchors, got ...` | packed_sequence 中间帧插值未加(6.2②) |
| `frame index ... already bound` | frame_indices 有重复/越界 |
| `target.seconds must be <= 12` | seconds 超上限 |
| `NPU out of memory ... 35.21 GiB` | 12s 16:9 临界,**直接重试**(OOM 后 allocator 碎片清理,第二次常成功);仍失败则降 1:1 或 9s |
| `CancelledError` / 空错误(进度 46% 被断) | `VLLM_OMNI_VIDEO_SYNC_TIMEOUT` 太小 → 改 5400 重启 |
### 10.4 重建容器后 `vllm` 命令 No such file
- `/vllm-workspace/vllm` 是镜像 VOLUME,重建后为空 → driver.py:191 检查失败:
```bash
docker exec h3-vllm bash -c "mkdir -p /vllm-workspace/vllm/vllm/entrypoints/cli && touch /vllm-workspace/vllm/vllm/entrypoints/cli/main.py"
```
(vllm 本体在 site-packages,命令存在于 /usr/local/python3.12.13/bin/vllm)
### 10.5 内存不足
- 删除 /tmp 下大文件(模型 135G、工作区 92G、10G 日志):
```bash
rm -rf /tmp/mediamodels /tmp/h3work/setup_env.log # tmpfs 释放 → avail 回升
```
- 工作区/模型常驻 /data1(NVMe)
---
## 11. 运维经验教训
1. **tmpfs 陷阱**:/tmp 是 tmpfs(内存盘)。模型/工作区/大日志放 /tmp = 直接吃 RAM。135G 模型放 tmpfs 会让 avail 从 630G 掉到 ~120G → 服务必崩。大文件一律放 /data1。
2. **后台进程**:容器内长任务必须 `docker exec -d`,nohup 不可靠。
3. **同步超时**:`VLLM_OMNI_VIDEO_SYNC_TIMEOUT` 按生成时长设(25步 ≈ 30 分钟 → 5400s)。
4. **OOM 重试机制**:16:9 12s 的激活峰值 35.2G 是 NPU 上限边缘,首次失败重试即可;若频繁失败用 1:1(768²)或 9s。
5. **改动生效需重启**:pipeline/packed_sequence 代码在 worker 进程内加载,改完必须重启服务。
6. **保存改动源**:所有代码改动在 /data1/h3work/vllm-omni(磁盘持久),重建容器只丢 pip 安装不丢源码。
7. **就绪判断**:用 `/v1/models`(返回 object),不要用 `/health`(该环境输出有异常)。
鲲鹏昇腾开发者社区是面向全社会开放的“联接全球计算开发者,聚合华为+生态”的社区,内容涵盖鲲鹏、昇腾资源,帮助开发者快速获取所需的知识、经验、软件、工具、算力,支撑开发者易学、好用、成功,成为核心开发者。
更多推荐




所有评论(0)