在海光 DCU 上部署 Wan2.1:打造一套可落地的 AI 短剧生产流水线
随着视频生成模型逐渐成熟,AI 短剧的生产方式正在从"逐镜头拍摄"转向"剧本驱动、角色参考图约束、模型批量生成、后期自动合成"。Wan2.1 提供了文生视频、图生视频、首尾帧生成和视频编辑等能力,非常适合构建本地化的 AI 短剧生产平台。
本文介绍如何在海光 DCU 环境中部署 Wan2.1,并围绕角色一致性、分镜生成、显存优化、多卡推理和后期合成,搭建一条完整的 AI 短剧生产流水线。
说明:海光 DCU 的驱动、DTK、PyTorch 软件包通常需要与具体 DCU 型号及服务器镜像严格匹配。本文中的安装命令是工程模板,实际部署时应优先使用海光提供的 DTK 镜像或经过验证的 PyTorch 环境,不要直接安装 CUDA 版本的 PyTorch。
一、为什么选择 Wan2.1 制作 AI 短剧
Wan2.1 是一套开源视频生成模型,主要包含以下能力:
| 模型 | 能力 | 推荐用途 |
|---|---|---|
| Wan2.1-T2V-1.3B | 文生视频,主要面向 480P | 环境验证、分镜预览、批量草稿 |
| Wan2.1-T2V-14B | 480P/720P 文生视频 | 空镜、转场、特效镜头 |
| Wan2.1-I2V-14B-480P | 480P 图生视频 | 低成本角色镜头 |
| Wan2.1-I2V-14B-720P | 720P 图生视频 | 正式成片、角色一致性镜头 |
| Wan2.1-FLF2V-14B | 首尾帧生成视频 | 镜头衔接、动作过渡 |
| Wan2.1-VACE | 视频生成与编辑 | 局部重绘、姿态控制、背景替换 |
官方说明中,T2V-14B 同时支持480P和720P,T2V-1.3B主要推荐480P;I2V则提供单独的480P与720P模型。虽然1.3B模型也能尝试720P,但稳定性不如480P。

对AI短剧来说,Wan2.1最大的价值并不是"一次生成完整短剧",而是按镜头生成数秒视频,再通过剪辑、配音、字幕和音效合成为完整剧集。
二、整体技术架构
一套实用的AI短剧平台可以划分为五层:
#mermaid-svg-qqb9mnWN2KOakss5{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-qqb9mnWN2KOakss5 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-qqb9mnWN2KOakss5 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-qqb9mnWN2KOakss5 .error-icon{fill:#552222;}#mermaid-svg-qqb9mnWN2KOakss5 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-qqb9mnWN2KOakss5 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-qqb9mnWN2KOakss5 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-qqb9mnWN2KOakss5 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-qqb9mnWN2KOakss5 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-qqb9mnWN2KOakss5 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-qqb9mnWN2KOakss5 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-qqb9mnWN2KOakss5 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-qqb9mnWN2KOakss5 .marker.cross{stroke:#333333;}#mermaid-svg-qqb9mnWN2KOakss5 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-qqb9mnWN2KOakss5 p{margin:0;}#mermaid-svg-qqb9mnWN2KOakss5 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-qqb9mnWN2KOakss5 .cluster-label text{fill:#333;}#mermaid-svg-qqb9mnWN2KOakss5 .cluster-label span{color:#333;}#mermaid-svg-qqb9mnWN2KOakss5 .cluster-label span p{background-color:transparent;}#mermaid-svg-qqb9mnWN2KOakss5 .label text,#mermaid-svg-qqb9mnWN2KOakss5 span{fill:#333;color:#333;}#mermaid-svg-qqb9mnWN2KOakss5 .node rect,#mermaid-svg-qqb9mnWN2KOakss5 .node circle,#mermaid-svg-qqb9mnWN2KOakss5 .node ellipse,#mermaid-svg-qqb9mnWN2KOakss5 .node polygon,#mermaid-svg-qqb9mnWN2KOakss5 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-qqb9mnWN2KOakss5 .rough-node .label text,#mermaid-svg-qqb9mnWN2KOakss5 .node .label text,#mermaid-svg-qqb9mnWN2KOakss5 .image-shape .label,#mermaid-svg-qqb9mnWN2KOakss5 .icon-shape .label{text-anchor:middle;}#mermaid-svg-qqb9mnWN2KOakss5 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-qqb9mnWN2KOakss5 .rough-node .label,#mermaid-svg-qqb9mnWN2KOakss5 .node .label,#mermaid-svg-qqb9mnWN2KOakss5 .image-shape .label,#mermaid-svg-qqb9mnWN2KOakss5 .icon-shape .label{text-align:center;}#mermaid-svg-qqb9mnWN2KOakss5 .node.clickable{cursor:pointer;}#mermaid-svg-qqb9mnWN2KOakss5 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-qqb9mnWN2KOakss5 .arrowheadPath{fill:#333333;}#mermaid-svg-qqb9mnWN2KOakss5 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-qqb9mnWN2KOakss5 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-qqb9mnWN2KOakss5 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-qqb9mnWN2KOakss5 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-qqb9mnWN2KOakss5 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-qqb9mnWN2KOakss5 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-qqb9mnWN2KOakss5 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-qqb9mnWN2KOakss5 .cluster text{fill:#333;}#mermaid-svg-qqb9mnWN2KOakss5 .cluster span{color:#333;}#mermaid-svg-qqb9mnWN2KOakss5 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-qqb9mnWN2KOakss5 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-qqb9mnWN2KOakss5 rect.text{fill:none;stroke-width:0;}#mermaid-svg-qqb9mnWN2KOakss5 .icon-shape,#mermaid-svg-qqb9mnWN2KOakss5 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-qqb9mnWN2KOakss5 .icon-shape p,#mermaid-svg-qqb9mnWN2KOakss5 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-qqb9mnWN2KOakss5 .icon-shape .label rect,#mermaid-svg-qqb9mnWN2KOakss5 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-qqb9mnWN2KOakss5 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-qqb9mnWN2KOakss5 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-qqb9mnWN2KOakss5 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 剧本与角色设定
分镜及提示词生成
角色参考图生成
DCU 上运行 Wan2.1
配音、字幕与后期合成
具体流程如下:
- 使用大语言模型生成故事大纲、对白和分镜。
- 为主要角色制作固定参考图和角色设定表。
- 将每个分镜转换为Wan2.1提示词。
- 使用T2V生成空镜,使用I2V生成角色镜头。
- 使用FLF2V或VACE处理镜头衔接与局部修复。
- 生成对白、旁白、环境音和背景音乐。
- 使用FFmpeg合成视频、音频和字幕。
- 对结果进行质量检测,不合格镜头自动重新生成。
生产环境中,建议将"剧本生成"和"视频生成"解耦。Wan2.1只负责一个个独立镜头,不负责理解整集剧情。
三、海光 DCU 环境准备
3.1 软件栈
典型的软件栈包括:
- Linux操作系统;
- 海光DCU驱动;
- DTK运行环境;
- 与DTK匹配的PyTorch;
- Python 3.10或项目镜像指定版本;
- FFmpeg;
- Wan2.1源码及模型权重。
海光DCU的软件生态与ROCm体系具有一定兼容性。公开的飞桨部署资料也展示了通过/dev/kfd、/dev/dri向容器映射DCU设备,并使用rocm-smi检查设备状态的方式。Paddle Inference 海光 DCU 部署文档
但需要注意:不同型号DCU对应的驱动、DTK和框架版本可能不同,不能仅根据ROCm版本号判断兼容性。
3.2 检查设备状态
首先检查DCU是否正常识别:
bash
rocm-smi
继续检查PyTorch能否识别设备:
bash
python - <<'PY'
import torch
print("PyTorch:", torch.__version__)
print("设备可用:", torch.cuda.is_available())
print("设备数量:", torch.cuda.device_count())
for i in range(torch.cuda.device_count()):
print(i, torch.cuda.get_device_name(i))
PY
在基于ROCm或DTK适配的PyTorch中,设备接口仍可能表现为torch.cuda。这只是框架API命名,不代表程序实际运行在NVIDIA CUDA设备上。
再执行一个简单矩阵运算:
bash
python - <<'PY'
import torch
device = "cuda"
a = torch.randn(4096, 4096, device=device, dtype=torch.float16)
b = torch.randn(4096, 4096, device=device, dtype=torch.float16)
c = a @ b
torch.cuda.synchronize()
print(c.shape, c.device, c.dtype)
PY
如果设备识别正常,但矩阵运算失败,通常是DTK、PyTorch或者算子库版本不匹配。
3.3 容器启动示例
应优先使用海光或服务器供应商提供的基础镜像:
bash
docker run -it \
--name wan21-dcu \
--network host \
--shm-size 64g \
--device=/dev/kfd \
--device=/dev/dri \
--group-add video \
--cap-add SYS_PTRACE \
--security-opt seccomp=unconfined \
-v /data/models:/models \
-v /data/wan-workspace:/workspace \
harbor.sourcefind.cn:5443/dcu/admin/base/vllm:0.18.1-ubuntu22.04-dtk26.04-py3.10 \
/bin/bash
其中:
/models保存模型,最好位于NVMe磁盘;/workspace保存源码、参考图片和生成结果;--shm-size需要适当增大,避免多进程数据交换失败;- 不建议直接套用普通NVIDIA容器的启动参数。
四、安装 Wan2.1
4.1 下载源码
bash
cd /workspace
git clone https://developer.sourcefind.cn/codes/modelzoo/wan2.1_pytorch.git
cd Wan2.1
官方项目要求PyTorch不低于2.4,但在DCU环境中不能为了满足版本号而覆盖厂商适配的PyTorch。正确做法是保留DTK镜像中的PyTorch,然后安装其余依赖。Wan2.1 模型说明
建议先备份并检查依赖文件:
bash
python -m pip freeze > dcu-base-requirements.txt
grep -nE 'torch|flash|triton|xformers' requirements.txt
然后避免重新安装CUDA版torch:
bash
grep -vE '^(torch|torchvision|torchaudio)' requirements.txt \
> requirements-dcu.txt
pip install -r requirements-dcu.txt
安装完成后执行:
bash
python -c "import torch; print(torch.__version__, torch.cuda.is_available())"
4.2 算子兼容性处理
Wan2.1的部分依赖可能默认面向CUDA环境,例如:
- FlashAttention;
- xFormers;
- Triton自定义算子;
- fused layer norm;
- CUDA专用混合精度实现。
DCU适配建议遵循以下顺序:
- 优先使用DTK镜像内已经适配的算子。
- 尝试PyTorch原生SDPA实现。
- 关闭可选的FlashAttention或xFormers。
- 使用普通PyTorch算子替代融合算子。
- 最后才考虑修改或重写HIP算子。
如果代码支持PyTorch原生注意力,可优先选择:
python
import torch.nn.functional as F
output = F.scaled_dot_product_attention(
query,
key,
value,
dropout_p=0.0,
is_causal=False,
)
替换后性能可能有所下降,但更适合作为DCU首轮功能验证方案。
五、下载模型
内网或国内环境可以使用ModelScope,能够访问Hugging Face时也可以直接下载。
5.1 下载1.3B模型
bash
pip install modelscope
modelscope download Wan-AI/Wan2.1-T2V-1.3B \
--local_dir /models/Wan2.1-T2V-1.3B
1.3B模型适合验证软件栈、批量生成分镜草稿和测试提示词。
5.2 下载14B图生视频模型
bash
modelscope download Wan-AI/Wan2.1-I2V-14B-720P \
--local_dir /models/Wan2.1-I2V-14B-720P
如果主要制作竖屏短剧,可先使用480P版本验证流程,再根据成片要求切换到720P。
5.3 模型选择原则
| 场景 | 推荐模型 |
|---|---|
| 验证DCU兼容性 | T2V-1.3B |
| 快速制作分镜样片 | T2V-1.3B、480P |
| 角色一致性镜头 | I2V-14B |
| 风景、空镜、特效 | T2V-14B |
| 指定镜头起点和终点 | FLF2V-14B |
| 修改已有视频 | VACE |
| 正式成片 | I2V-14B-720P |
六、运行第一个视频生成任务
6.1 文生视频
首先使用1.3B模型生成一个480P测试视频:
bash
python generate.py \
--task t2v-1.3B \
--size 832*480 \
--ckpt_dir /models/Wan2.1-T2V-1.3B \
--offload_model True \
--t5_cpu \
--sample_shift 8 \
--sample_guide_scale 6 \
--prompt "夜晚的现代都市天台,一名穿黑色风衣的年轻侦探缓慢转身,远处霓虹灯闪烁,中景,缓慢推进镜头,电影级光影,悬疑氛围"
官方针对1.3B模型建议将sample_guide_scale设置为6,并将sample_shift控制在8~12之间;显存不足时可以启用--offload_model True和--t5_cpu。Wan2.1 官方运行说明
6.2 图生视频
AI短剧中的人物镜头更适合使用I2V。先生成并审核一张角色定妆图,再将其作为视频首帧:
bash
python generate.py \
--task i2v-14B \
--size 1280*720 \
--ckpt_dir /models/Wan2.1-I2V-14B-720P \
--image assets/characters/detective.png \
--offload_model True \
--t5_cpu \
--prompt "年轻男侦探站在天台上,保持人物面部、发型和服装不变。他听见身后的脚步声,先停顿,然后缓慢回头。中景,镜头轻微推进,夜晚霓虹灯,电影级写实风格,动作自然稳定。"
图生视频能够保留参考图片中的外貌和服装特征,因此比纯文生视频更适合连续剧情。Wan2.1官方提供独立的I2V-14B-480P和I2V-14B-720P权重。Wan2.1 I2V-14B-720P
七、短剧分镜设计
不要向模型输入整段剧情,而应将剧本拆解为3~6秒的独立镜头。
一个结构化分镜可以采用以下格式:
json
{
"shot_id": "EP01_S003",
"duration": 5,
"shot_type": "medium_close_up",
"character": "林默",
"location": "夜晚天台",
"action": "听见脚步声后缓慢回头",
"camera": "镜头缓慢推进",
"lighting": "蓝紫色霓虹侧光",
"dialogue": "你终于来了。",
"reference_image": "characters/linmo_front.png"
}
再通过模板转换为视频提示词:
text
{角色固定描述},
位于{场景},
{动作描述},
{景别},
{运镜方式},
{光线与时间},
{画面风格},
人物面部稳定,服装保持一致,动作连贯自然。
推荐提示词顺序为:
text
主体 → 场景 → 动作 → 景别 → 运镜 → 光照 → 风格 → 一致性约束
例如:
text
28岁的中国男性侦探,短黑发,轮廓分明,穿黑色长款风衣和深灰色衬衫。
他站在雨后的城市天台,听见身后的脚步声,身体停顿一秒,然后缓慢回头。
中近景,镜头缓慢向前推进,蓝紫色霓虹侧光,写实电影质感。
保持人物面部、发型和服装不变,动作自然,背景稳定。
提示词中不要同时描述太多动作。一个镜头只表达一个主要动作,通常比"走进房间、拿起手机、转身说话、坐下思考"更加稳定。
在这里插入图片描述


八、解决角色一致性问题
角色一致性是AI短剧最重要、也最容易失败的环节。
8.1 建立角色资产包
每个主要角色都应建立独立目录:
text
characters/
└── linmo/
├── profile.json
├── front.png
├── left.png
├── right.png
├── full_body.png
└── costume_01.png
profile.json保存不可随意改变的特征:
json
{
"name": "林默",
"age": 28,
"gender": "male",
"face": "轮廓分明,单眼皮,高鼻梁",
"hair": "短黑发,侧分",
"costume": "黑色长款风衣,深灰衬衫",
"accessory": "左手佩戴黑色机械表",
"style": "写实电影风格"
}
8.2 优先使用图生视频
不同镜头应尽可能复用相同角色参考图,不要每次用文本重新生成角色。
建议:
- 正面对白使用正面参考图;
- 侧面镜头使用侧面参考图;
- 全身动作使用全身参考图;
- 服装发生变化时创建新的角色版本;
- 同一场戏保持相同提示词前缀。
8.3 使用首尾帧控制转场
对于连续动作,可以把上一镜头最后一帧作为下一镜头起点,或者使用FLF2V指定首尾帧。
官方说明FLF2V模型主要支持720P,并建议使用中文提示词以获得更好的首尾帧生成效果。Wan2.1 模型https://developer.sourcefind.cn/codes/modelzoo/wan2.1_pytorch.git
提取上一镜头最后一帧:
bash
ffmpeg -sseof -0.1 \
-i EP01_S003.mp4 \
-frames:v 1 \
EP01_S003_last.png
然后将这张图片作为下一个镜头的视觉参考,可以显著降低场景、服装和构图跳变。
九、DCU显存和性能优化
视频扩散模型的显存占用同时受以下因素影响:
- 模型参数量;
- 分辨率;
- 视频帧数;
- 注意力序列长度;
- 数据精度;
- 文本编码器是否常驻设备;
- VAE是否分块处理;
- 是否启用模型卸载;
- 单卡或多卡并行策略。
9.1 推荐优化顺序
出现显存不足时,按以下顺序处理:
- 将720P降为480P。
- 减少生成帧数。
- 启用
--offload_model True。 - 启用
--t5_cpu。 - 使用1.3B模型验证。
- 对VAE启用切片或分块。
- 使用多卡FSDP或序列并行。
- 最后再考虑量化。
CPU卸载会降低显存占用,但会增加主机内存和PCIe传输压力。因此建议服务器配置足够的系统内存,并将模型放在本地NVMe磁盘。
9.2 混合精度
首先测试BF16:
python
dtype = torch.bfloat16
如果当前DCU或算子对BF16支持不完整,再退回FP16:
python
dtype = torch.float16
不能仅判断设备是否支持BF16,还需要验证Wan2.1完整推理链路中的注意力、归一化和VAE算子。
十、批量生成与任务调度
生产系统不应直接让业务接口同步调用generate.py,建议构建任务队列:
#mermaid-svg-6a39EdSt8aRbGNIn{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-6a39EdSt8aRbGNIn .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-6a39EdSt8aRbGNIn .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-6a39EdSt8aRbGNIn .error-icon{fill:#552222;}#mermaid-svg-6a39EdSt8aRbGNIn .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-6a39EdSt8aRbGNIn .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-6a39EdSt8aRbGNIn .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-6a39EdSt8aRbGNIn .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-6a39EdSt8aRbGNIn .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-6a39EdSt8aRbGNIn .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-6a39EdSt8aRbGNIn .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-6a39EdSt8aRbGNIn .marker{fill:#333333;stroke:#333333;}#mermaid-svg-6a39EdSt8aRbGNIn .marker.cross{stroke:#333333;}#mermaid-svg-6a39EdSt8aRbGNIn svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-6a39EdSt8aRbGNIn p{margin:0;}#mermaid-svg-6a39EdSt8aRbGNIn .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-6a39EdSt8aRbGNIn .cluster-label text{fill:#333;}#mermaid-svg-6a39EdSt8aRbGNIn .cluster-label span{color:#333;}#mermaid-svg-6a39EdSt8aRbGNIn .cluster-label span p{background-color:transparent;}#mermaid-svg-6a39EdSt8aRbGNIn .label text,#mermaid-svg-6a39EdSt8aRbGNIn span{fill:#333;color:#333;}#mermaid-svg-6a39EdSt8aRbGNIn .node rect,#mermaid-svg-6a39EdSt8aRbGNIn .node circle,#mermaid-svg-6a39EdSt8aRbGNIn .node ellipse,#mermaid-svg-6a39EdSt8aRbGNIn .node polygon,#mermaid-svg-6a39EdSt8aRbGNIn .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-6a39EdSt8aRbGNIn .rough-node .label text,#mermaid-svg-6a39EdSt8aRbGNIn .node .label text,#mermaid-svg-6a39EdSt8aRbGNIn .image-shape .label,#mermaid-svg-6a39EdSt8aRbGNIn .icon-shape .label{text-anchor:middle;}#mermaid-svg-6a39EdSt8aRbGNIn .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-6a39EdSt8aRbGNIn .rough-node .label,#mermaid-svg-6a39EdSt8aRbGNIn .node .label,#mermaid-svg-6a39EdSt8aRbGNIn .image-shape .label,#mermaid-svg-6a39EdSt8aRbGNIn .icon-shape .label{text-align:center;}#mermaid-svg-6a39EdSt8aRbGNIn .node.clickable{cursor:pointer;}#mermaid-svg-6a39EdSt8aRbGNIn .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-6a39EdSt8aRbGNIn .arrowheadPath{fill:#333333;}#mermaid-svg-6a39EdSt8aRbGNIn .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-6a39EdSt8aRbGNIn .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-6a39EdSt8aRbGNIn .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-6a39EdSt8aRbGNIn .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-6a39EdSt8aRbGNIn .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-6a39EdSt8aRbGNIn .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-6a39EdSt8aRbGNIn .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-6a39EdSt8aRbGNIn .cluster text{fill:#333;}#mermaid-svg-6a39EdSt8aRbGNIn .cluster span{color:#333;}#mermaid-svg-6a39EdSt8aRbGNIn div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-6a39EdSt8aRbGNIn .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-6a39EdSt8aRbGNIn rect.text{fill:none;stroke-width:0;}#mermaid-svg-6a39EdSt8aRbGNIn .icon-shape,#mermaid-svg-6a39EdSt8aRbGNIn .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-6a39EdSt8aRbGNIn .icon-shape p,#mermaid-svg-6a39EdSt8aRbGNIn .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-6a39EdSt8aRbGNIn .icon-shape .label rect,#mermaid-svg-6a39EdSt8aRbGNIn .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-6a39EdSt8aRbGNIn .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-6a39EdSt8aRbGNIn .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-6a39EdSt8aRbGNIn :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 通过
失败
短剧项目
分镜任务队列
DCU 推理 Worker
质量检测
成片素材库
每个任务至少记录:
json
{
"task_id": "EP01_S003_V02",
"model": "Wan2.1-I2V-14B-720P",
"device_id": 0,
"prompt": "...",
"image": "linmo_front.png",
"seed": 382947,
"resolution": "1280x720",
"status": "running",
"retry_count": 1
}
推荐保存以下信息,以便复现镜头:
- 模型名称和权重版本;
- Git提交号;
- Prompt与负面约束;
- 随机种子;
- 推理步数;
- 分辨率与帧数;
- 精度类型;
- DCU型号;
- DTK与PyTorch版本;
- 生成耗时和峰值显存。
十一、配音、字幕和视频合成
Wan2.1负责视觉镜头,完整短剧还需要配音和后期。
可以将每段对白生成独立音频:
text
audio/
├── EP01_S001.wav
├── EP01_S002.wav
└── EP01_S003.wav
使用FFmpeg拼接镜头:
bash
ffmpeg -f concat -safe 0 \
-i shots.txt \
-c:v libx264 \
-pix_fmt yuv420p \
episode_video.mp4
加入对白和背景音乐:
bash
ffmpeg \
-i episode_video.mp4 \
-i dialogue.wav \
-i bgm.mp3 \
-filter_complex \
"[1:a]volume=1.2[voice];[2:a]volume=0.18[bgm];[voice][bgm]amix=inputs=2:duration=longest[a]" \
-map 0:v \
-map "[a]" \
-c:v copy \
-c:a aac \
-shortest \
episode_audio.mp4
烧录字幕:
bash
ffmpeg \
-i episode_audio.mp4 \
-vf "subtitles=episode.srt" \
-c:v libx264 \
-c:a copy \
episode_final.mp4
为避免口型不匹配,可以采用以下方案:
- 将对白放在背影、侧脸或远景镜头;
- 使用旁白推动剧情;
- 单独引入口型同步模型;
- 先生成音频,再根据音频时长设计镜头;
- 对特写对白镜头进行专项生成和人工筛选。
十二、常见问题排查
1. torch.cuda.is_available()返回False
检查:
bash
ls -l /dev/kfd /dev/dri
rocm-smi
groups
python -c "import torch; print(torch.__version__)"
常见原因包括设备未映射进容器、用户不在video组、驱动与容器不匹配,或者误装了普通CPU版PyTorch。
2. 出现hipErrorNoBinaryForGpu
说明当前算子没有为目标DCU架构编译。需要:
- 使用海光提供的预编译软件包;
- 重新编译对应算子;
- 删除CUDA专用扩展;
- 使用PyTorch原生实现替代。
3. 安装依赖后DCU突然不可用
通常是pip install -r requirements.txt覆盖了DTK适配版PyTorch。重新安装厂商PyTorch,并在依赖文件中排除:
text
torch
torchvision
torchaudio
4. 生成到一半显存不足
优先启用:
bash
--offload_model True --t5_cpu
仍然不足时,降低分辨率、帧数或改用1.3B模型。
5. 生成速度很慢
检查DCU利用率:
bash
watch -n 1 rocm-smi
如果DCU利用率周期性降至零,可能存在:
- CPU卸载过多;
- 模型从机械盘反复加载;
- 系统内存不足;
- PCIe传输成为瓶颈;
- 多卡通信效率过低;
- 视频编码阻塞推理任务。
6. 角色每个镜头都不一样
解决方法不是简单增加提示词,而是:
- 固定角色参考图;
- 使用I2V代替T2V;
- 固定角色描述和随机种子;
- 一个场景固定一套光照和服装;
- 将上一镜头末帧用于下一镜头;
- 对脸部特写单独生成。
十三、推荐的落地路线
建议分三个阶段建设。
第一阶段:完成兼容性验证
目标:
- DCU可以运行PyTorch;
- T2V-1.3B能够生成480P视频;
- 验证FP16或BF16;
- 记录峰值显存和生成时间;
- 找出不兼容算子。
这一阶段不要直接部署14B,也不要急于上多卡。
第二阶段:构建短剧流水线
目标:
- 建立角色资产库;
- 实现结构化分镜;
- 部署I2V-14B;
- 实现任务队列;
- 自动拼接、配音和字幕;
- 保存随机种子与推理参数。
第三阶段:优化生产效率
目标:
- 多卡并行;
- 模型常驻;
- VAE分块;
- 批量任务调度;
- 镜头质量自动评分;
- 失败任务自动重试;
- 建立每分钟视频的成本指标。
结语
在海光DCU上部署Wan2.1,真正的难点并不只是让模型"跑起来",而是解决三类工程问题:
第一,处理DTK、PyTorch和视频生成算子之间的兼容关系;第二,通过参考图、分镜模板和首尾帧控制提高角色及场景一致性;第三,把单次模型推理改造成可追踪、可重试、可批量调度的内容生产流水线。
在实际项目中,推荐先以Wan2.1-T2V-1.3B和480P完成DCU适配,再引入I2V-14B制作正式角色镜头。短剧生产则应坚持"一个镜头一个任务、图生视频优先、统一角色资产、后期集中合成"的原则。这样既能降低DCU适配风险,也能明显提高成片稳定性和生产效率。