Wan2.2 TI2V-5B 在 Linux 服务器上的本地部署与 HTTP 服务化实践

这篇文章记录我在一台 Linux 服务器上,从 0 开始部署 Wan2.2-TI2V-5B,到最终通过 HTTP 接口调用生成视频 的完整过程。

目标是两件事:

  1. 以后忘了流程时,可以按这篇文章重新部署成功
  2. 给后续做服务化、前端调用、自动化任务留一份可复用的基础文档

我的实际环境是:

  • Linux 服务器
  • NVIDIA RTX 4090
  • Python 3.10
  • 中国大陆网络环境
  • 最终通过 python generate.py 成功生成视频
  • 后续再封装成 FastAPI HTTP 接口

一、为什么选 TI2V-5B

Wan2.2 有多个模型,我这次选的是 TI2V-5B,原因很直接:

  • 支持 Text-to-Video
  • 也支持 Image-to-Video
  • 对消费级显卡更友好
  • 比较适合单机本地部署验证

如果目标是先把流程跑通,TI2V-5B 是更合适的起点。


二、部署前最重要的一个认知:Python 环境一定要干净

我一开始机器登录后默认是:

bash
which python
/usr/anaconda3/bin/python

也就是说,服务器默认在 conda base 里。

最开始我直接用:

bash
python -m venv /home/chenqi/venvs/wan22

这样创建出来的 venv 虽然“技术上没错”,但它底层还是基于 Anaconda 的 Python 3.13。 这就带来两个问题:

  1. 环境容易混乱
  2. torchflash-attn 这类大模型依赖对 Python 版本比较敏感,3.13 太新,不适合优先尝试

结论

不要直接用 conda base 的 python 去建这个环境。 更稳的做法是:用系统 Python 3.10 重建 venv。


三、重新创建正确的 Python 3.10 虚拟环境

1. 检查 Python 3.10 是否存在

bash
/usr/bin/python3.10 --version

如果提示没有,就安装:

bash
apt update
apt install -y python3.10 python3.10-venv python3-pip

2. 删除旧环境,重建新环境

bash
rm -rf /home/chenqi/venvs/wan22
/usr/bin/python3.10 -m venv /home/chenqi/venvs/wan22

3. 激活环境

bash
source /home/chenqi/venvs/wan22/bin/activate

4. 验证是否真的进入了正确环境

不要只看提示符,要看这些:

bash
which python
which pip
echo $VIRTUAL_ENV
python --version
python -m pip --version

理想结果应该类似:

bash
/home/chenqi/venvs/wan22/bin/python
/home/chenqi/venvs/wan22/bin/pip
/home/chenqi/venvs/wan22
Python 3.10.x

5. 升级安装工具链

bash
python -m pip install -U pip setuptools wheel packaging

这一步很重要,因为后面要装:

  • torch
  • flash-attn
  • modelscope
  • 其他编译/依赖型包

如果 pip/setuptools/wheel/packaging 太旧,很容易出奇怪错误。


四、安装 PyTorch,并验证 CUDA

1. 安装 PyTorch

我最后成功使用的是:

  • Python 3.10
  • Torch 2.6.0+cu124

安装命令是按 PyTorch 官方 CUDA wheel 路线来的,实际装的时候可以按自己机器驱动情况选对应命令。

示例:

bash
python -m pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu124

2. 验证 torch 和 CUDA 是否正常

bash
python - <<'PY'
import torch, sys
print("python:", sys.executable)
print("torch:", torch.__version__)
print("torch file:", torch.__file__)
print("cuda available:", torch.cuda.is_available())
if torch.cuda.is_available():
    print("gpu:", torch.cuda.get_device_name(0))
PY

我最终的关键输出是:

  • torch: 2.6.0+cu124
  • cuda available: True
  • gpu: NVIDIA GeForce RTX 4090

这说明:

  • Python 环境已经正确
  • PyTorch 已经能识别显卡
  • CUDA 路径没问题

五、安装系统基础工具

后面要用到:

  • git
  • ffmpeg
  • gcc/g++/make
  • ninja

先检查:

bash
command -v git
command -v ffmpeg
command -v gcc
command -v g++
command -v make
command -v ninja

如果缺了就安装:

bash
apt update
apt install -y git ffmpeg build-essential ninja-build

六、克隆 Wan2.2 仓库

第一次部署时:

bash
cd ~
git clone https://github.com/Wan-Video/Wan2.2.git
cd ~/Wan2.2

这里有一个容易误会的小点:

  • git clone 是第一次拉代码
  • git pull 是本地已经有仓库时更新代码

所以:

  • 第一次 clone 后,不需要立刻再 pull
  • 只有以后你想更新仓库时才需要 git pull

七、安装依赖时最难的坑:flash-attn

1. 先安装普通依赖,不要一上来就装 flash-attn

我最后采用的是“普通依赖先装,flash-attn 单独装”的思路。

bash
cd ~/Wan2.2
grep -v '^flash_attn$' requirements.txt > requirements.no_fa.txt
python -m pip install -r requirements.no_fa.txt -i https://pypi.tuna.tsinghua.edu.cn/simple

这样做的原因很简单:

  • flash-attn 最容易出问题
  • 单独装最方便排错

八、flash-attn 的真实踩坑过程

这是我这次部署里最典型的坑。

1. 一开始 flash-attn 导入失败

报错类似:

text
undefined symbol: ... c10::Error ...

这种错误不是“没装”,而是:

flash-attn 编译/安装时依赖的 torch 版本,和当前运行时加载的 torch 不匹配。

我当时的环境是:

  • torch 2.6.0+cu124
  • flash-attn 2.8.3

结果导入失败。

2. 解决办法

先卸载:

bash
python -m pip uninstall -y flash-attn flash_attn
python -m pip cache purge

再安装一个更稳的版本:

bash
MAX_JOBS=4 python -m pip install flash-attn==2.7.4.post1 --no-build-isolation -i https://pypi.tuna.tsinghua.edu.cn/simple

3. 验证

bash
python - <<'PY'
try:
    import flash_attn
    print("flash_attn ok")
except Exception as e:
    print("flash_attn not ready:", e)
PY

最终成功输出:

text
flash_attn ok

4. 经验总结

如果看到这种导入时的 .so undefined symbol 错误,不要纠结“是不是没装上”,更可能是:

  • torch 和 flash-attn 二进制不兼容
  • 卸载重装一个更稳的 flash-attn 版本即可

九、国内网络环境下下载模型

在中国大陆,不建议优先走 Hugging Face。 更稳的方式是:

  • 代码:GitHub
  • 模型:ModelScope
  • Python 包:清华/国内 PyPI 镜像

安装 ModelScope:

bash
python -m pip install modelscope -i https://pypi.tuna.tsinghua.edu.cn/simple

下载模型:

bash
cd ~/Wan2.2
modelscope download Wan-AI/Wan2.2-TI2V-5B --local_dir ./Wan2.2-TI2V-5B

下载完后确认目录存在:

bash
ls ~/Wan2.2/Wan2.2-TI2V-5B

十、第一次运行时又遇到的坑:requirements 不完整

模型下载完成后,我开始运行:

bash
python generate.py \
  --task ti2v-5B \
  --size 1280*704 \
  --ckpt_dir ./Wan2.2-TI2V-5B \
  --offload_model True \
  --convert_model_dtype \
  --t5_cpu \
  --prompt "一只白猫戴着墨镜坐在冲浪板上,夏日海边,电影感光影,镜头缓慢推进"

结果连续遇到了几个 ModuleNotFoundError

1. 缺 decord

安装:

bash
python -m pip install -U decord -i https://pypi.tuna.tsinghua.edu.cn/simple

验证:

bash
python - <<'PY'
import decord
print("decord ok:", decord.__version__)
PY

2. 缺 librosa

安装:

bash
python -m pip install -U librosa -i https://pypi.tuna.tsinghua.edu.cn/simple

验证:

bash
python - <<'PY'
import librosa
print("librosa ok:", librosa.__version__)
PY

3. 缺 peft

安装:

bash
python -m pip install -U peft -i https://pypi.tuna.tsinghua.edu.cn/simple

验证:

bash
python - <<'PY'
import peft
print("peft ok:", peft.__version__)
PY

4. 经验总结

这说明这份仓库在当时的依赖声明里,并不是完全齐全的。 遇到这类错误时,处理方式很固定:

  1. python -m pip show 包名
  2. 没装就 python -m pip install -U 包名
  3. import 验证

十一、第一次真正生成时,误以为程序在用 CPU

运行时我看到 top 里 Python 进程占了很多 CPU,误以为没有使用 GPU。

实际上并不是。

因为我用的是这组参数:

bash
--offload_model True
--convert_model_dtype
--t5_cpu

这意味着:

  • 一部分工作故意放到 CPU
  • 一部分工作仍然在 GPU 上
  • 这是“CPU + GPU 混合运行

真正的判断方式不是看 top,而是看:

bash
nvidia-smi

我的实际输出显示:

  • 显存占用 21GB+
  • GPU-Util 100%
  • Python 进程占着 GPU

这说明:

核心计算已经在 GPU 上,而且 GPU 已经满载。

结论: 看到 CPU 很忙,不代表没用 GPU。


十二、第一次 720P 生成失败:最后一步 OOM

第一次完整跑到结尾时,扩散采样 50/50 已经跑完了,但最后报:

text
torch.OutOfMemoryError: CUDA out of memory

而且出错点不在采样阶段,而是在 VAE decode 阶段。

这说明:

  • 主体生成已经成功
  • 最后把 latent 解码成视频时,显存差一点点

我的显卡是 4090 24GB,这种情况其实很常见。

解决办法 1:启用 PyTorch 显存碎片优化

bash
export PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True

解决办法 2:不要用有显示占用的那张卡

我的服务器有两张 4090,其中:

  • GPU 0 连着显示
  • GPU 1 几乎空闲

所以最后我改成:

bash
export CUDA_VISIBLE_DEVICES=1
export PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True

然后再跑同一条命令。

最终成功命令

bash
export CUDA_VISIBLE_DEVICES=1
export PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True

cd ~/Wan2.2
python generate.py \
  --task ti2v-5B \
  --size 1280*704 \
  --ckpt_dir ./Wan2.2-TI2V-5B \
  --offload_model True \
  --convert_model_dtype \
  --t5_cpu \
  --prompt "一只白猫戴着墨镜坐在冲浪板上,夏日海边,电影感光影,镜头缓慢推进"

经验总结

如果 4090 跑到最后一步 OOM,不要第一时间怀疑环境坏了。 更大的可能是:

  • 分辨率高
  • decode 阶段显存峰值更大
  • 显存碎片导致最后差一点
  • 当前 GPU 还承担了显示/其他进程

优先尝试:

  1. PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True
  2. 换一张更干净的 GPU
  3. 仍不行再降分辨率

十三、到这里,CLI 部署已经成功

generate.py 最终能成功输出视频时,说明以下环节都已经打通:

  • Python 环境 OK
  • torch + CUDA OK
  • flash-attn OK
  • 模型权重 OK
  • Wan2.2 本体 OK
  • 单机推理 OK

接下来进入第二阶段:HTTP 服务化


十四、为什么要封装 HTTP 接口

直接用:

bash
python generate.py ...

只能手工在服务器命令行里跑。

如果想让:

  • 前端页面调用
  • 其他程序调用
  • 内网服务调用
  • 自动化任务调用

最方便的办法就是封装成 HTTP API


十五、服务化设计思路

因为单次生成时间比较长,不适合做同步阻塞接口,所以我最后采用的是这种思路:

  • POST /generate:提交任务
  • GET /tasks/{task_id}:查询状态
  • GET /files/{filename}:下载视频

实现方式:

  • FastAPI
  • Web 进程接收请求
  • 后台线程启动一个子进程去执行 generate.py
  • 子进程结束后,把结果记录下来
  • 用户轮询任务状态

为什么不用“直接在 FastAPI 里 import 模型”

因为当前已经验证成功的是 CLI 路径。 直接包装 generate.py 是最稳的:

  • 改动最小
  • 出错边界清晰
  • 不会把模型状态污染到 Web 主进程

十六、安装 Web 依赖

bash
python -m pip install -U fastapi uvicorn[standard] python-multipart -i https://pypi.tuna.tsinghua.edu.cn/simple

其中:

  • fastapi:Web 框架
  • uvicorn:ASGI 服务
  • python-multipart:以后做图片上传用

十七、FastAPI 实现思路

核心要点:

  1. 请求进入 API
  2. 生成 task_id
  3. 开后台线程
  4. 线程里调用 subprocess.run(["python", "generate.py", ...])
  5. 任务结束后记录输出文件
  6. 提供下载接口返回 mp4

关键设计原则

  • 一次只跑一个任务
  • 不建议并发多个任务抢同一张 4090
  • 当前单次生成已经接近 24GB 显存上限
  • 并发很容易直接 OOM

十八、启动服务

在项目目录中:

bash
uvicorn app:app --host 0.0.0.0 --port 8000

十九、HTTP 调用示例

1. 文生视频

bash
curl -X POST "http://你的服务器IP:8000/generate" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "一只白猫戴着墨镜坐在冲浪板上,夏日海边,电影感光影,镜头缓慢推进",
    "size": "1280*704",
    "task": "ti2v-5B",
    "offload_model": true,
    "convert_model_dtype": true,
    "t5_cpu": true
  }'

2. 查询任务状态

bash
curl "http://你的服务器IP:8000/tasks/<task_id>"

3. 下载视频

bash
curl -O "http://你的服务器IP:8000/files/<filename>.mp4"

4. 图生视频

bash
curl -X POST "http://你的服务器IP:8000/generate-with-image" \
  -F 'prompt=夏日海边度假风,一只戴墨镜的白猫坐在冲浪板上,近景镜头' \
  -F 'size=1280*704' \
  -F 'image=@/path/to/input.jpg'

二十、这次部署的完整最终结论

成功的关键点

  1. 必须用 Python 3.10 的干净 venv
  2. 不要直接沿用 conda base 的 Python 3.13 环境
  3. PyTorch 要先装好并验证 CUDA
  4. flash-attn 要单独处理,且版本要和 torch 匹配
  5. 模型下载在大陆优先走 ModelScope
  6. Wan2.2 依赖可能不完整,缺什么补什么
  7. 4090 跑 720P 时,最后 decode 可能 OOM
  8. 用空闲 GPU + expandable_segments:True 可以提高成功率
  9. 服务化最稳的方式是 FastAPI + 子进程调用 generate.py

二十一、我最终可复现的最小成功路径

环境准备

bash
apt update
apt install -y python3.10 python3.10-venv python3-pip git ffmpeg build-essential ninja-build

rm -rf /home/chenqi/venvs/wan22
/usr/bin/python3.10 -m venv /home/chenqi/venvs/wan22
source /home/chenqi/venvs/wan22/bin/activate

python -m pip install -U pip setuptools wheel packaging

安装 torch

bash
python -m pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu124

安装 Wan2.2 代码和依赖

bash
cd ~
git clone https://github.com/Wan-Video/Wan2.2.git
cd ~/Wan2.2

grep -v '^flash_attn$' requirements.txt > requirements.no_fa.txt
python -m pip install -r requirements.no_fa.txt -i https://pypi.tuna.tsinghua.edu.cn/simple

安装 flash-attn

bash
python -m pip uninstall -y flash-attn flash_attn
python -m pip cache purge
MAX_JOBS=4 python -m pip install flash-attn==2.7.4.post1 --no-build-isolation -i https://pypi.tuna.tsinghua.edu.cn/simple

补齐额外缺失依赖

bash
python -m pip install -U decord librosa peft modelscope -i https://pypi.tuna.tsinghua.edu.cn/simple

下载模型

bash
cd ~/Wan2.2
modelscope download Wan-AI/Wan2.2-TI2V-5B --local_dir ./Wan2.2-TI2V-5B

成功运行命令

bash
export CUDA_VISIBLE_DEVICES=1
export PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True

cd ~/Wan2.2
python generate.py \
  --task ti2v-5B \
  --size 1280*704 \
  --ckpt_dir ./Wan2.2-TI2V-5B \
  --offload_model True \
  --convert_model_dtype \
  --t5_cpu \
  --prompt "一只白猫戴着墨镜坐在冲浪板上,夏日海边,电影感光影,镜头缓慢推进"

二十二、以后如果我忘了流程,按什么顺序排查

如果以后重新部署失败,我会按这个顺序检查:

第 1 层:Python 环境

bash
which python
python --version
python -m pip --version

第 2 层:torch + CUDA

bash
python - <<'PY'
import torch
print(torch.__version__)
print(torch.cuda.is_available())
print(torch.cuda.get_device_name(0))
PY

第 3 层:flash-attn

bash
python - <<'PY'
import flash_attn
print("flash_attn ok")
PY

第 4 层:模型目录

bash
ls ~/Wan2.2/Wan2.2-TI2V-5B

第 5 层:运行时显卡状态

bash
nvidia-smi

第 6 层:遇到缺包就补

  • decord
  • librosa
  • peft
  • 其他 ModuleNotFoundError 指向的包

第 7 层:最后一步 OOM

优先尝试:

bash
export PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True
export CUDA_VISIBLE_DEVICES=1

二十三、后续可以继续优化的方向

这次我先做到“能本地稳定生成 + 能 HTTP 调用”。 后面还可以继续做:

  • systemd 把 API 服务做成开机自启
  • 用 Nginx 反向代理
  • 加 API key 鉴权
  • 加任务队列,避免并发冲突
  • 把日志落盘
  • 加 Web 管理页面
  • 接 Redis / Celery 做异步任务系统

最后的总结

这次部署最核心的经验只有一句话:

Wan2.2 本地部署并不只是“装个包、跑条命令”,真正决定成败的是 Python 环境、torch/flash-attn 兼容、缺失依赖补齐,以及 24GB 显存下最后 decode 阶段的处理。

只要把这几个关键点记住,后面再重新部署,成功率就会非常高。