本教程系统讲解如何在消费级硬件(Windows 11 系统、16GB 可用内存、8GB 或 16GB 可用显存)上,通过开源推理框架 diffusers 部署图像生成模型(SDXL / SD1.5)与视频生成模型(LTX-Video / Wan2.1),并使用 Python 代码完成模型能力的调用。教程提供完整示例项目 generation-service,包含命令行工具、FastAPI 服务与客户端三种调用方式,覆盖文本生成图像、文本生成视频两大核心场景。

前置教程

如想快速开始学习本教程,你可能需要先完成以下前置教程:

资源下载

1. 图像与视频生成技术概览

1.1 什么是图像生成与视频生成

图像生成是指根据文本提示词(Prompt)自动生成符合描述的图像,代表性的技术是扩散模型(Diffusion Model)

视频生成在图像生成的基础上增加时间维度,不仅生成单帧画面,还让画面在时间轴上连续运动,本质上是"图像生成 + 运动建模"的组合。

扩散模型的核心思想是:先学习一个从"噪声"到"图像"的逆过程。训练时模型学习如何把真实图像逐步加噪成纯噪声,推理时则从纯噪声出发,按照调度器指定的步数逐步去噪,最终还原出一张清晰图像。文本提示词通过编码器注入,引导去噪过程生成符合语义的画面。

graph LR A[随机噪声] --> B[扩散模型逐次去噪
循环 N 步] B --> C[中间图像] B --> D[文本提示词编码
引导去噪方向] C --> E[最终图像] D --> B classDef input fill:#d6eaf8,stroke:#1a6b8a,stroke-width:2px classDef process fill:#d5f5e3,stroke:#1e8449,stroke-width:2px classDef guide fill:#ffecd6,stroke:#ca6f1e,stroke-width:2px classDef output fill:#ebdef0,stroke:#6c3483,stroke-width:2px class A input class B process class C output class D guide class E output

视频生成则在每一帧上执行类似的去噪,同时引入时空建模保证相邻帧之间的内容连贯。当前主流的视频生成模型采用原生视频扩散架构,直接端到端建模空间与时间两个维度,而非在图像模型上"打补丁"。本教程选用的 LTX-VideoWan2.1 即属于此类。

1.2 本地部署与云端 API 的对比

调用图像与视频生成能力有两条主流路线:调用在线生成服务(如各类文生图/文生视频 API)与 本地部署生成模型。两者的对比如下:

对比项 在线生成服务 本地部署生成模型
联网要求 需要联网调用云端服务 无需联网,完全离线可用
调用成本 按生成张数/时长计费 模型开源免费,需自备硬件
数据隐私 提示词与图片上传至云端 数据不出本地,隐私可控
生成数量 受额度与并发限制 无限制,可无限次生成
可控性 参数受服务商限制 步数、种子、模型可完全自定义
部署门槛 低,注册即可调用 较高,需配置深度学习环境
硬件要求 无,云端算力 需要一定显存与内存

1.3 消费级硬件约束与模型选型

本教程针对的目标硬件为:Windows 11 系统、约 16GB 可用内存、8GB 或 16GB 可用显存。受显存限制,并非所有生成模型都能流畅运行,需要合理选型:

硬件方案 图像模型 推荐分辨率 视频模型 推荐帧数
8GB 显存 + 16GB 内存 SD1.5 512×512 LTX-Video 2B 121 帧
16GB 显存 + 16GB 内存 SDXL 1024×1024 Wan2.1-T2V-1.3B 81 帧

选型原则:

  • 图像模型:8GB 显存推荐 SD1.5(512px,占用约 4GB);16GB 显存推荐 SDXL(1024px,占用约 7GB),画面细节与构图显著更好。
  • 视频模型LTX-Video 2B 是 Lightricks 开源的轻量视频扩散模型,参数量仅约 20 亿,专为消费级显卡设计,8GB 显存即可流畅生成 121 帧 720p 视频;Wan2.1-T2V-1.3B 是阿里开源的文生视频模型,中文理解好,体积同样轻量,显存更充裕时推荐使用。

本教程示例项目通过 config.py 一键切换图像与视频底模。

1.4 为什么选择 diffusers 而非 ComfyUI

目前主流教程常推荐 ComfyUI(节点式图像/视频生成工具)。本教程选用 Hugging Face 官方的 diffusers 库,原因如下:

对比项 diffusers ComfyUI
使用方式 纯 Python 代码,可编程 图形化节点拖拽
二次开发 直接嵌入自己的程序 需通过 API 或自定义节点
运行方式 作为库引入,轻量 独立 GUI 应用,需启动界面
自动化 天然适合批处理与服务化 需借助工作流 JSON
学习价值 理解模型原理与参数 偏工具操作

本教程全部示例均基于 diffusers。若你未来需要工作流式的可视化操作,可在此基础上学习 ComfyUI,两者并不冲突。

2. 环境准备

2.1 确认硬件与驱动

开始前先确认显卡型号、显存大小以及驱动是否满足条件。在 PowerShell 中运行:

nvidia-smi

nvidia-smi 会显示显卡型号、驱动版本与显存总量。确认你的 NVIDIA 显卡显存为 8GB 或 16GB+,且驱动版本较新(支持 CUDA 12.x)。PyTorch 安装包自带 CUDA 运行时库,无需单独安装系统级 CUDA Toolkit,只要显卡驱动支持即可。

nvidia-smi 无输出,说明显卡驱动未安装或不是 NVIDIA 显卡,需先安装驱动。

2.2 创建 conda 环境

生成模型依赖较多,使用独立的 conda 环境管理。命令行工具与服务统一使用 uv 安装依赖:

# 创建并激活 conda 环境
conda create -n generation python=3.10 -y
conda activate generation

# 安装 uv(Python 包管理工具)
pip install uv

环境名 generation 对应本教程示例项目,依赖隔离避免与系统 Python 冲突。

2.3 安装 CUDA 版 PyTorch

先安装 CUDA 版 PyTorch,国内推荐从阿里云镜像直链下载 cu128 的 wheel(速度快);网络好的话可改用官方源。注意一定要先装 torch,再装其他依赖,避免 diffusers 把 torch 解析成 CPU 版:

# 方法一:阿里云镜像直链(国内推荐)
uv pip install "https://mirrors.aliyun.com/pytorch-wheels/cu128/torch-2.8.0%2Bcu128-cp310-cp310-win_amd64.whl" "https://mirrors.aliyun.com/pytorch-wheels/cu128/torchvision-0.23.0%2Bcu128-cp310-cp310-win_amd64.whl"

# 方法二:PyTorch 官方源
uv pip install torch==2.8.0 torchvision --index-url https://download.pytorch.org/whl/cu128

验证 PyTorch 是否正确识别 GPU:

import torch
print(torch.__version__)
print(f"CUDA available: {torch.cuda.is_available()}")
print(f"Device name: {torch.cuda.get_device_name(0)}")

方法二:PyTorch 官方源示意图

若输出 CUDA available: True 并显示你的显卡型号,说明 CUDA 版 PyTorch 安装成功。

2.4 安装 diffusers 等依赖

进入示例项目目录,安装生成模型与服务的其余依赖:

cd generation-service
uv pip install -r requirements.txt --index-url https://pypi.tuna.tsinghua.edu.cn/simple
依赖包 用途
diffusers Hugging Face 官方扩散模型推理库
transformers 文本编码器(CLIP/T5/umt5)支持
accelerate 显存优化,支持 model_cpu_offload
safetensors 安全加载模型权重
sentencepiece 文本编码器分词支持
protobuf 文本编码器配置解析
pillow 图像与视频帧(PIL 图像)处理
imageio GIF 视频导出
fastapi / uvicorn 构建生成服务后端
pydantic 请求参数校验
requests 客户端调用服务

2.5 下载模型权重

本教程需要四份模型权重:图像用到 SDXL 与 SD1.5,视频用到 LTX-Video 与 Wan2.1。国内用户推荐使用 ModelScopeHF 镜像 下载。使用 ModelScope 前,需先在 generation 环境中安装其命令行工具:

# 安装 modelscope 命令行工具(用于下载模型权重)
uv pip install modelscope --index-url https://pypi.tuna.tsinghua.edu.cn/simple

若改用 HuggingFace 官方源下载,使用前先设置国内镜像环境变量:

# Windows PowerShell 设置 HF 镜像
$env:HF_ENDPOINT = "https://hf-mirror.com"

SDXL 底模(约 7GB,16GB 显存用户使用):

modelscope download --model AI-ModelScope/stable-diffusion-xl-base-1.0 --local_dir C:/models/sdxl-base

SD1.5 底模(约 4GB,8GB 显存用户使用):

modelscope download --model AI-ModelScope/stable-diffusion-v1-5 --local_dir C:/models/sd15

LTX-Video 2B 视频模型(约 9GB,8GB 显存用户使用):

modelscope download --model AI-ModelScope/LTX-Video --local_dir C:/models/ltx-video

Wan2.1-T2V-1.3B 视频模型(约 11GB,16GB 显存用户使用):

注意:需下载 Diffusers 格式 的版本(-Diffusers 后缀),原始格式不含 diffusers 需要的 model_index.json,无法直接加载。

modelscope download --model Wan-AI/Wan2.1-T2V-1.3B-Diffusers --local_dir C:/models/wan-t2v-1.3b

提示:diffusers 的 from_pretrained 支持直接传入本地目录。按上述命令将模型下载到 C:/models/ 下对应目录后,示例项目即可离线加载。首次 from_pretrained 若不指定本地目录,会自动联网下载到 HuggingFace 缓存,国内建议优先使用本地目录方式。

3. 图像生成模型部署与调用

3.1 SDXL 与 SD1.5 模型对比

SD1.5(Stable Diffusion 1.5) 是经典的开源文生图模型,参数量约 9.6 亿,原生分辨率 512×512,显存友好,社区生态成熟。SDXL(Stable Diffusion XL) 是 Stability AI 发布的升级版本,参数量约 35 亿,原生分辨率 1024×1024,画面细节、构图与文字渲染能力显著提升,但显存占用更高。

对比项 SD1.5 SDXL
参数量 约 9.6 亿 约 35 亿
原生分辨率 512×512 1024×1024
显存占用 约 4GB 约 7GB
画面质量 一般 显著更好
推理速度 较快 较慢
适用硬件 8GB 显存 16GB 显存

3.2 文本生成图像(txt2img)

使用 diffusers 生成图像,只需加载对应管线并传入提示词。以 SDXL 为例:

from diffusers import StableDiffusionXLPipeline
import torch

# 加载 SDXL 底模(本地目录 C:/models/sdxl-base)
pipe = StableDiffusionXLPipeline.from_pretrained(
    "C:/models/sdxl-base",
    torch_dtype=torch.float16,   # 半精度推理,节省显存
    use_safetensors=True,
)
pipe.enable_model_cpu_offload()  # 显存不足时自动卸载部分层到内存

image = pipe(
    prompt="a shiba inu wearing an astronaut helmet, high quality, photorealistic",   # 中文:一只戴着宇航员头盔的柴犬,高质量,写实风格
    negative_prompt="blurry, low quality, deformed",   # 中文:模糊,低质量,变形
    num_inference_steps=30,
    guidance_scale=7.5,
).images[0]

image.save("sdxl_dog.png")

8GB 显存的用户改用 SD1.5,代码几乎一致,仅换用 StableDiffusionPipeline 与对应模型目录:

from diffusers import StableDiffusionPipeline
import torch

pipe = StableDiffusionPipeline.from_pretrained(
    "C:/models/sd15",
    torch_dtype=torch.float16,
    use_safetensors=True,
)
pipe.enable_model_cpu_offload()

image = pipe(prompt="a shiba inu, high quality", num_inference_steps=30).images[0]   # 中文:一只柴犬,高质量
image.save("sd15_dog.png")

提示images[0] 取回一张 PIL.Image 对象,可直接 save() 保存,也可后续做图像处理。torch_dtype=torch.float16 使用半精度,是生成模型节省显存的关键。

提示词语言:SD1.5 与 SDXL 使用 CLIP 系文本编码器,训练数据以英文为主,中文提示词理解较弱,出图质量可能下降。建议使用英文提示词,例如中文"一只戴着宇航员头盔的柴犬,写实风格"可写成 a shiba inu wearing an astronaut helmet, high quality, photorealistic。若坚持用中文,需在提示词中补充具体描述(但仍然不建议使用中文)。

3.3 关键生成参数详解

调用生成接口时,几个核心参数直接影响出图效果:

参数 说明 建议值
prompt 正向提示词,描述你想要的内容 描述越具体越好
negative_prompt 负向提示词,描述你不想要的内容 blurry, low quality(模糊、低质量)
num_inference_steps 去噪步数,越多越精细但越慢 20-30
guidance_scale 提示词引导强度,越大越贴合提示词 7.5 左右
seed 随机种子,固定后结果可复现 同一种子出图一致
width / height 输出分辨率 与底模原生分辨率一致

技巧:使用固定 seed 可以复现同一画面,便于对比参数调整效果;guidance_scale 过高会使画面生硬、失真,过低则画面游离于提示词。

3.4 显存优化技巧

消费级硬件显存有限,diffusers 提供了多种优化手段:

优化手段 作用 适用场景
enable_model_cpu_offload() 将部分层卸载到 CPU 内存,按需换入 GPU 8GB 显存跑 SDXL
enable_attention_slicing() 分块计算注意力,降低峰值显存 显存紧张时
torch_dtype=torch.float16 半精度推理,显存占用减半 通用
降低分辨率 512px 比 1024px 省显存 显存不足时

model_cpu_offload 是最实用的手段:它把模型中未参与当前计算的层暂存到内存(本教程硬件有 16GB 内存),计算出该层时再载入 GPU,从而在较小显存上运行大模型,代价是速度略有下降。

4. 视频生成模型部署与调用

4.1 LTX-Video 与 Wan2.1 技术原理

LTX-Video 是 Lightricks 开源的原生视频扩散模型,采用视频 DiT(Diffusion Transformer)架构,直接对"空间 + 时间"联合建模,参数量仅约 20 亿,专为单张消费级显卡优化,是当前轻量视频生成的代表。

Wan2.1 是阿里开源的视频生成系列,其中 T2V-1.3B 为轻量文生视频版本,中文理解能力强,同样兼容 diffusers。

graph LR A[文本提示词] --> B[文本编码器
T5 / umt5] B --> C[视频 DiT 主干
空间+时间联合去噪] C --> D[视频 VAE 解码
还原像素帧] D --> E[连续帧序列
导出 GIF 视频] classDef input fill:#d6eaf8,stroke:#1a6b8a,stroke-width:2px classDef model fill:#ffecd6,stroke:#ca6f1e,stroke-width:2px classDef process fill:#d5f5e3,stroke:#1e8449,stroke-width:2px classDef output fill:#ebdef0,stroke:#6c3483,stroke-width:2px class A input class B model class C model class D process class E output

两款模型的训练原生精度均为 bfloat16(bf16),配合 model_cpu_offload 即可在消费级显存上运行。

4.2 使用 LTX-Video 生成视频

使用 diffusers 的 LTXPipeline 文生视频,只需加载模型并传入提示词:

from diffusers import LTXPipeline
import torch

# 加载 LTX-Video 2B(本地目录 C:/models/ltx-video)
pipe = LTXPipeline.from_pretrained(
    "C:/models/ltx-video",
    torch_dtype=torch.bfloat16,   # 训练原生精度 bf16(RTX 20 系列改 fp16,见 4.3 提示)
)
pipe.enable_model_cpu_offload()  # 适配 8GB 显存

output = pipe(
    prompt="a golden retriever running on the grass",   # 中文:一只在草地上奔跑的金毛犬
    negative_prompt="blurry, low quality, broken motion",   # 中文:模糊,低质量,动作不连贯
    num_frames=121,          # LTX-Video 原生 121 帧
    guidance_scale=3.0,      # LTX 引导强度取值通常较小
    num_inference_steps=50,
    output_type="pil",       # 直接返回 PIL 帧列表,便于后续导出 GIF
)
frames = output.frames[0]   # 取第 0 组视频帧

4.3 使用 Wan2.1 生成视频

使用 Wan2.1 时方法几乎一致,仅换用 WanPipeline 与对应模型目录:

from diffusers import WanPipeline
import torch

pipe = WanPipeline.from_pretrained(
    "C:/models/wan-t2v-1.3b",
    torch_dtype=torch.bfloat16,
)
pipe.enable_model_cpu_offload()

output = pipe(
    prompt="一只在草地上奔跑的金毛犬",
    negative_prompt="模糊,低质量,动作不连贯",
    num_frames=81,           # Wan2.1 默认 81 帧
    guidance_scale=5.0,
    num_inference_steps=50,
    output_type="pil",       # Wan 需显式指定返回 PIL 帧列表(LTX 默认即为 pil)
)
frames = output.frames[0]

提示:Wan2.1 使用多语言 umt5 编码器,中文理解好,故示例直接使用中文提示词;本教程中 SD1.5、SDXL 与 LTX-Video 的示例提示词统一使用英文并附中文翻译,各模型的语言支持差异见 4.6 节。

RTX 20 系列(Turing)显卡注意:PyTorch 的 FlashAttention 需要 Ampere 及以上架构,memory-efficient attention 内核在 Turing 上也不支持 bf16。若在 RTX 20 系列上按上面的代码用 bfloat16 推理,SDPA 会回退到 math 后端,一次性物化完整 attention 矩阵,生成 Wan 视频时可能报 CUDA out of memory。Turing 显卡需改用 fp16 并强制 memory-efficient 后端:

torch.backends.cuda.enable_flash_sdp(False)
torch.backends.cuda.enable_math_sdp(False)
pipe = WanPipeline.from_pretrained("C:/models/wan-t2v-1.3b", torch_dtype=torch.float16)

LTX-Video 序列较短,在 RTX 20 系列上相对不易爆显存,但同样建议改用 fp16。示例项目 video_gen.py按显卡架构自动选择精度,无需手动修改

4.4 视频输出与帧率控制

output.frames[0] 是一组 PIL 图像帧(数量等于 num_frames),需要合成为可播放的视频文件。diffusers 提供 export_to_gif 工具,将帧序列导出为 GIF:

from diffusers.utils import export_to_gif

# 导出为 GIF,fps 控制每秒播放帧数
export_to_gif(frames, "output_video.gif", fps=24)
print(f"已生成 {len(frames)} 帧视频")
参数 LTX-Video Wan2.1 说明
num_frames 121 81 各模型的原生帧数
fps 24 16 各模型训练时的帧率
num_inference_steps 50 50 去噪步数,越多越精细但越慢
guidance_scale 3.0 5.0 提示词引导强度

提示:121 帧 @ 24fps 约等于 5 秒视频。帧数越大显存占用越高,8GB 显存若爆显存可降低 num_frames(如 LTX 降到 97、Wan 降到 65)。GIF 是最简单的导出格式,如需 MP4 可后续用 ffmpeg 对帧序列转码。

4.5 帧数取值约束与时长换算

num_frames 并非任意整数,而是有硬性约束:视频 VAE 会在时间维对画面做下采样压缩,要求 num_frames - 1 能被时间压缩倍数整除。Wan2.1 的时间压缩倍数为 4,LTX-Video 为 8,合法帧数分别为:

模型 合法帧数(k 取整数) 常用档位
Wan2.1 4k + 1,即 1, 5, 9, 13, 17, ..., 81 17 / 33 / 49 / 65 / 81
LTX-Video 8k + 1,即 1, 9, 17, 25, ..., 121 17 / 33 / 49 / 65 / 97 / 121

若传入不满足约束的数值,diffusers 不会报错,而是自动调整为合法帧数并打印一条 warning,例如 Wan 传 --frames 50 实际生成 49 帧、传 --frames 80 生成 81 帧。常用档位对应时长如下(Wan 按 16fps、LTX 按 24fps):

Wan 帧数 时长 LTX 帧数 时长
17 约 1 秒 17 约 0.7 秒
33 约 2 秒 33 约 1.4 秒
49 约 3 秒 49 约 2 秒
65 约 4 秒 65 约 2.7 秒
81 约 5 秒 97 约 4 秒
121 约 5 秒

提示:1 帧等价于一张静态图像,5/9/13 帧只有零点几秒,实际意义不大。视频生成建议从 17 帧(约 1 秒)起步;各模型默认档位(Wan 81 帧、LTX 121 帧)即约为 5 秒视频。

4.6 提示词长度与语言限制

提示词进入模型前要经过文本编码器转成向量,编码器决定了模型对提示词的语言支持与长度上限。token 是文本编码器的最小处理单元(英文约一个单词、中文约一个字),提示词超过上限后,多出的部分会被直接截断丢弃,不会报错:

模型 文本编码器 语言支持 长度上限
SD1.5 CLIP ViT-L/14 英文为主,中文较弱 77 token,硬上限
SDXL CLIP ViT-L + OpenCLIP ViT-bigG(双编码器) 英文为主,中文较弱 77 token,硬上限
LTX-Video T5 英文为主 默认 128 token,可调大
Wan2.1 umt5(多语言 T5) 中英文均好 默认 512 token,可调大

SD1.5 / SDXL 的 77 token 是硬性限制:CLIP 编码器的位置编码固定在 77 个位置,无法通过参数调大。超过约 60 个英文单词(或 50~70 个中文字)的提示词,超出部分不生效。这也是中文提示词在 SD 系模型上效果差的另一原因——中文按字切分后 token 消耗更快,长句更容易触顶被截断。

LTX-Video / Wan2.1 无硬上限:T5 与 umt5 使用相对位置编码,只是 diffusers 管线默认截断到 max_sequence_length(LTX 默认 128、Wan 默认 512)。需要更长提示词时,可在 pipe() 调用中传入 max_sequence_length 调大:

# 仅 LTX / Wan 支持调大提示词长度
output = pipe(prompt=prompt, ..., max_sequence_length=1024)

Wan2.1 的默认 512 token 足以容纳中文的详细场景、镜头与风格描述;LTX 默认偏短,写长提示词时容易被截断。

提示:示例项目的 cli.pytext_to_video 目前未暴露 max_sequence_length 参数,默认使用各模型的缺省值(Wan 512、LTX 128)。如需更长提示词,需在代码中补传该参数。

5. 综合示例项目:generation-service

5.1 项目目标与架构

示例项目 generation-service 将图像生成(SDXL / SD1.5)与视频生成(LTX-Video / Wan2.1)封装为完整的生成服务,实现以下目标:

  • 通过命令行工具直接生成图像与视频
  • 通过 FastAPI 服务对外暴露图像、视频生成接口
  • 通过 Python 客户端代码调用服务,演示"代码调用模型能力"

整体架构如下:

graph LR U[调用方
CLI / client.py / curl] -->|POST 请求| A[FastAPI 后端
main.py] A --> B[img_gen.py
SDXL / SD1.5 图像管线] A --> C[video_gen.py
LTX-Video / Wan2.1 视频管线] B --> M1[本地模型
C:/models/sdxl-base 或 sd15] C --> M2[本地模型
ltx-video 或 wan-t2v-1.3b] B -->|图像| U C -->|GIF 视频| U classDef frontend fill:#d6eaf8,stroke:#1a6b8a,stroke-width:2px classDef backend fill:#d5f5e3,stroke:#1e8449,stroke-width:2px classDef engine fill:#ebdef0,stroke:#6c3483,stroke-width:2px classDef model fill:#ffecd6,stroke:#ca6f1e,stroke-width:2px class U frontend class A backend class B,C engine class M1,M2 model

5.2 项目结构

generation-service/
├── config.py                  # 服务配置(端口、模型路径、默认参数)
├── img_gen.py                 # 图像生成服务(SDXL / SD1.5 封装)
├── video_gen.py               # 视频生成服务(LTX-Video / Wan2.1 封装)
├── main.py                    # FastAPI 后端,生成接口
├── cli.py                     # 命令行工具(子命令)
├── client.py                  # 客户端调用示例
├── requirements.txt           # 依赖管理
├── README.md                  # 项目说明
└── static/
    └── index.html             # 前端验证页面(浏览器访问 /)

5.3 配置文件 config.py

所有配置统一在 config.py 中修改,包括监听端口、模型目录、推理设备与默认生成参数:

# config.py(核心片段,完整代码请查看 generation-service/config.py)
PORT = 8000
DEVICE = "cuda"                # 推理设备:cuda / cpu

# 图像模型类型:sdxl(16GB 显存推荐)/ sd15(8GB 显存推荐)
IMG_MODEL_TYPE = "sdxl"

# 视频模型类型:ltx(LTX-Video 2B,8GB 显存即可)/ wan(Wan2.1-T2V-1.3B,16GB 推荐)
VIDEO_MODEL_TYPE = "ltx"

# 模型本地目录
IMG_SDXL_DIR = "C:/models/sdxl-base"         # SDXL 底模
IMG_SD15_DIR = "C:/models/sd15"              # SD1.5 底模
LTX_MODEL_DIR = "C:/models/ltx-video"        # LTX-Video 2B
WAN_MODEL_DIR = "C:/models/wan-t2v-1.3b"     # Wan2.1-T2V-1.3B

DEFAULT_STEPS = 30
DEFAULT_GUIDANCE = 7.5

8GB 显存用户将图像 IMG_MODEL_TYPE 改为 "sd15"、视频保留 VIDEO_MODEL_TYPE = "ltx";16GB 显存用户可将图像用 "sdxl"、视频将 VIDEO_MODEL_TYPE 改为 "wan" 以获得更好的中文生成效果。

5.4 图像生成服务 img_gen.py

img_gen.py 封装了 ImageGenerator 类,根据 model_type 加载 SDXL 或 SD1.5 管线,提供统一的 text_to_image 方法。考虑到模型加载耗时,采用懒加载方式在首次调用时才加载模型,并启用 model_cpu_offload 适配低显存:

# img_gen.py(核心片段,完整代码请查看 generation-service/img_gen.py)
class ImageGenerator:
    def __init__(self, model_type="sdxl", device=DEVICE):
        self.model_type = model_type
        self.device = device
        self.pipe = None

    def load(self):
        """首次调用时加载对应底模管线。"""
        dtype = torch.float16 if self.device == "cuda" else torch.float32
        if self.model_type == "sdxl":
            self.pipe = StableDiffusionXLPipeline.from_pretrained(
                IMG_SDXL_DIR, torch_dtype=dtype, use_safetensors=True)
        else:
            self.pipe = StableDiffusionPipeline.from_pretrained(
                IMG_SD15_DIR, torch_dtype=dtype, use_safetensors=True)
        if self.device == "cuda":
            self.pipe.enable_model_cpu_offload()
        else:
            self.pipe.to(self.device)
        return self

    def text_to_image(self, prompt, negative_prompt="", steps=DEFAULT_STEPS,
                      guidance=DEFAULT_GUIDANCE, width=None, height=None, seed=None):
        """文本生成图像,返回 PIL.Image 对象。"""
        ...

通过 IMG_MODEL_TYPE 实现 SDXL 与 SD1.5 之间切换,适配 8GB / 16GB 两种显存。

5.5 视频生成服务 video_gen.py

video_gen.py 封装了 VideoGenerator 类,根据 model_type 加载 LTX-Video 或 Wan2.1 管线,提供 text_to_video 方法,生成后直接导出 GIF。不同视频模型的原生帧数、帧率与引导强度不同,通过 MODEL_DEFAULTS 映射统一处理:

# video_gen.py(核心片段,完整代码请查看 generation-service/video_gen.py)
# 各视频模型的推荐帧数、帧率与引导强度
MODEL_DEFAULTS = {
    "ltx": {"frames": 121, "fps": 24, "guidance": 3.0},   # LTX-Video 原生 24fps
    "wan": {"frames": 81, "fps": 16, "guidance": 5.0},    # Wan2.1 原生 16fps
}

class VideoGenerator:
    def load(self):
        """首次调用时加载对应视频管线。"""
        if self.device == "cuda":
            # RTX 20 系列(Turing)无 FlashAttention,且 memory-efficient 内核
            # 在 Turing 上不支持 bf16,bf16 会让 SDPA 回退到 math 后端物化完整
            # attention 矩阵,Wan 视频序列较长时极易 OOM,需改用 fp16 并强制
            # memory-efficient 后端;更新的显卡保持 bf16(flash 自动生效)。
            if torch.cuda.get_device_capability(0)[0] < 8:
                dtype = torch.float16
                torch.backends.cuda.enable_flash_sdp(False)
                torch.backends.cuda.enable_math_sdp(False)
            else:
                dtype = torch.bfloat16
        else:
            dtype = torch.bfloat16
        if self.model_type == "ltx":
            self.pipe = LTXPipeline.from_pretrained(LTX_MODEL_DIR, torch_dtype=dtype)
        else:
            self.pipe = WanPipeline.from_pretrained(WAN_MODEL_DIR, torch_dtype=dtype)
        if self.device == "cuda":
            self.pipe.enable_model_cpu_offload()
            # VAE 解码切片 + 分块,降低视频解码阶段显存峰值
            self.pipe.vae.enable_slicing()
            self.pipe.vae.enable_tiling()
        else:
            self.pipe.to(self.device)
        return self

    def text_to_video(self, prompt, negative_prompt="", num_frames=None, steps=DEFAULT_STEPS,
                      guidance=None, fps=None, seed=None, output="output_video.gif"):
        """文本生成视频,返回 GIF 文件路径。"""
        ...
        result = self.pipe(
            prompt=prompt,
            negative_prompt=negative_prompt,
            num_frames=num_frames,
            num_inference_steps=steps,
            guidance_scale=guidance,
            generator=gen,
            output_type="pil",   # 直接返回 PIL 帧列表,供 export_to_gif 导出
        )
        frames = result.frames[0]
        ...   # 兜底:旧版 diffusers 可能返回 numpy/Tensor 帧,转成 PIL
        export_to_gif(frames, output, fps=fps)
        return output

通过 VIDEO_MODEL_TYPE 实现 LTX-Video 与 Wan2.1 之间切换;num_framesfpsguidance 缺省时自动套用对应模型的推荐值。load() 会根据显卡架构自动选择推理精度(RTX 20 系列用 fp16、其余用 bf16),--output 参数会传递给 text_to_video 控制输出文件名。

5.6 后端接口 main.py

main.py 是服务的核心入口,使用 FastAPI 提供图像与视频两个生成接口。模型通过全局变量懒加载,首次请求时才加载。完整的接口定义:

接口 方法 说明
/api/image/generate POST 传入 {"model": "sdxl", "prompt": "..."},返回一张 PNG 图像
/api/video/generate POST 传入 {"model": "ltx", "prompt": "..."},返回一段 GIF 视频
# main.py(核心片段,完整代码请查看 generation-service/main.py)
@app.post("/api/image/generate")
async def generate_image(req: ImageRequest):
    """接收提示词,按 model 选择底模,生成并返回一张图像。"""
    gen = get_image_gen(req.model)
    img = gen.text_to_image(
        req.prompt, req.negative_prompt, req.steps, req.guidance,
        req.width, req.height, req.seed,
    )
    path = os.path.join(tempfile.gettempdir(), "generated_image.png")
    img.save(path)
    return FileResponse(path, media_type="image/png")

@app.post("/api/video/generate")
async def generate_video(req: VideoRequest):
    """接收提示词,按 model 选择视频模型,生成并返回一段 GIF 视频。"""
    gen = get_video_gen(req.model)
    path = gen.text_to_video(
        req.prompt, req.negative_prompt, req.num_frames,
        req.steps, req.guidance, req.fps, req.seed,
    )
    return FileResponse(path, media_type="image/gif")

请求参数通过 pydanticBaseModel 定义并自动校验:ImageRequestVideoRequest 首字段为 model(图像限 sdxl/sd15,视频限 ltx/wan),后端据此选择对应模型。

服务端每个类型同时只保留一个模型实例,切换模型时自动释放旧实例并重载,避免多个大模型同时常驻内存。

5.7 命令行工具 cli.py

命令行工具使用子命令(subparsers)组织不同操作,imagevideo 两个子命令分别对应图像、视频生成:

# 生成图像(默认 SDXL,16GB 显存)—— 中文:一只柴犬,写实风格
python cli.py image --prompt "a shiba inu, photorealistic" --output dog.png

# 8GB 显存改用 SD1.5 —— 中文:一只柴犬
python cli.py image --prompt "a shiba inu" --model sd15

# 生成视频(默认 LTX-Video)—— 中文:一只在草地上奔跑的金毛犬
python cli.py video --prompt "a golden retriever running on the grass"

# 16GB 显存改用 Wan2.1 —— Wan 支持中文提示词,无需翻译
python cli.py video --prompt "一只在草地上奔跑的金毛犬" --model wan --fps 30

cli.py 内部直接调用 ImageGeneratorVideoGenerator,不经过服务层,适合离线快速验证模型能力。

5.8 客户端调用 client.py

client.py 演示如何通过 Python 代码调用已启动的生成服务,使用 requests 发送 POST 请求并保存返回的图片与视频:

# client.py(核心片段,完整代码请查看 generation-service/client.py)
def generate_image(prompt, out="client_image.png"):
    """调用图像生成接口并保存结果。"""
    resp = requests.post(f"{BASE_URL}/api/image/generate", json={"prompt": prompt})
    resp.raise_for_status()
    with open(out, "wb") as f:
        f.write(resp.content)
    print(f"图像已保存: {out}")

def generate_video(prompt, out="client_video.gif"):
    """调用视频生成接口并保存结果。"""
    resp = requests.post(f"{BASE_URL}/api/video/generate", json={"prompt": prompt})
    resp.raise_for_status()
    with open(out, "wb") as f:
        f.write(resp.content)
    print(f"视频已保存: {out}")

client.py 展示了"代码调用模型能力"的完整链路:客户端发送提示词到服务,服务内部加载模型推理,返回生成结果。这与你接入任意本地生成服务的方式一致。

5.9 运行与测试

第一步:创建环境并安装依赖

若已按第 2 章完成环境准备(generation 环境已创建),直接激活即可;否则先按第 2 章创建环境并安装 CUDA torch 与依赖。

conda activate generation
cd generation-service
uv pip install -r requirements.txt --index-url https://pypi.tuna.tsinghua.edu.cn/simple

第二步:确认模型位置

确保模型已按第 2.5 节下载到 C:/models/ 对应目录。如需自定义路径,修改 config.py

第三步:命令行验证模型能力

先用 CLI 验证图像生成是否正常(首次会加载模型,耗时较长):

python cli.py image --prompt "a shiba inu, photorealistic" --output dog.png   # 中文:一只柴犬,写实风格

dog.png 正常生成,再验证视频生成(默认 LTX-Video,首次加载模型耗时较长):

python cli.py video --prompt "a golden retriever running on the grass"   # 中文:一只在草地上奔跑的金毛犬

第四步:启动服务

python main.py

服务启动于 http://127.0.0.1:8000。浏览器打开该地址即可进入前端验证页面(见 5.10),在四个模型模块中分别输入提示词验证生成效果;也可继续用下面的 client.py 或 curl 调用接口。

第五步:通过代码调用服务

另开一个终端,运行客户端调用服务:

python client.py

也可使用 curl 直接验证接口:

curl.exe -X POST http://127.0.0.1:8000/api/image/generate -H "Content-Type: application/json" -d "{\"model\":\"sdxl\",\"prompt\":\"a cat, high quality\"}" --output cat.png   # 中文:一只猫,高清

5.10 前端验证页面 index.html

命令行与接口适合程序调用,直接演示时更推荐浏览器页面。项目在 static/index.html 提供了一套模型能力验证页面,每个模型一个独立模块,支持在线调整参数并直接预览生成结果:

模块 模型 可调参数
图像生成 SDXL / SD1.5 提示词、负向提示词、步数、引导强度、种子
视频生成 LTX-Video / Wan2.1 提示词、负向提示词、步数、帧数、帧率、引导强度、种子

提示:视频生成耗时较长(Wan 81 帧约 10 分钟),页面会显示等待状态。服务端每个类型同时只保留一个模型实例,切换模型(如 SDXL 换 SD1.5)时会重新加载权重、首次较慢;四个模型权重合计超过 30GB,因此不采用全部常驻内存的方式。

前端验证页面 index.html示意图

6. 常见问题与优化建议

6.1 显存不足(OOM)

生成时报 CUDA out of memory 属于显存不足:

处理方法 说明
启用 enable_model_cpu_offload() 将部分层卸载到内存,示例项目已默认启用
RTX 20 系列改用 fp16 推理 Turing 显卡 bf16 无快速 attention 内核,示例项目已按架构自动处理
降低视频帧数 LTX 降到 97 帧、Wan 降到 65 帧,减少显存占用
图像用 SD1.5、视频用 LTX-Video 8GB 显存最稳的组合,SDXL / Wan2.1 在 8GB 上易爆显存

6.2 生成速度慢

生成速度取决于显存、步数与分辨率。提速手段:

  • 减少 num_inference_steps(如图像从 30 降到 20,视频从 50 降到 30),质量损失较小
  • 使用 16GB 显存或降低分辨率
  • 关闭 model_cpu_offload(但需要显存足够),减少层换入换出开销
  • 固定 seed 便于对比,避免重复探索

6.3 质量提升技巧

  • 写具体的提示词:描述主体、风格、光线、镜头,如 a shiba inu wearing an astronaut helmet, close-up, soft lighting, photorealistic(中文:一只戴着宇航员头盔的柴犬,特写,柔和光线,写实风格)
  • 善用负向提示词:添加 blurry, low quality, deformed, extra limbs(中文:模糊、低质量、畸形、多余肢体)可显著提升成片率
  • 选对底模:16GB 显存优先 SDXL、视频用 Wan2.1,细节明显更好
  • 多次生成挑选:固定步数与引导值,切换 seed 多生成几张择优

7. 总结

7.1 核心内容回顾

  • 生成技术:图像与视频生成基于扩散模型,从噪声逐步去噪还原画面,视频叠加时空建模
  • diffusers 选型:纯代码调用、理解原理、生态统一,替代 ComfyUI 的节点式操作
  • 消费级选型:8GB 显存走 SD1.5 + LTX-Video,16GB 显存图像升级 SDXL、视频用 Wan2.1
  • 图像生成StableDiffusionXLPipelineStableDiffusionPipeline 加载底模,pipe() 直接出图
  • 视频生成LTXPipelineWanPipeline 原生视频扩散,export_to_gif 导出 GIF
  • 服务封装:generation-service 提供浏览器前端页面、CLI、FastAPI 服务与客户端四种调用方式
  • 显存优化model_cpu_offload、半精度、按显卡架构选择 attention 后端与降低帧数

7.2 常见问题与解答

问:首次生成非常慢怎么办?

答:首次调用需加载模型权重,耗时较长,属正常现象。之后生成会快很多。也可先用 CLI 生成一次预热模型,再启动服务。

问:8GB 显存能否运行 SDXL?

答:可以,但需开启 model_cpu_offload 并降低分辨率,速度较慢且仍可能爆显存。8GB 显存更推荐使用 SD1.5,体验更稳定。

问:视频生成很卡或爆显存?

答:减少 num_frames(LTX 降到 97、Wan 降到 65),或降低分辨率。RTX 20 系列(Turing)显卡还需改用 fp16 推理,否则 bf16 因缺少快速 attention 内核会物化完整矩阵导致爆显存,示例项目已自动处理。视频帧数直接决定显存占用,8GB 显存建议用 LTX-Video 并保持默认参数。

问:视频模型报错缺少文本编码器或分词器?

答:LTX-Video 与 Wan2.1 依赖 T5 / umt5 文本编码器。若未随模型一并下载,需联网拉取。国内用户设置 $env:HF_ENDPOINT = "https://hf-mirror.com" 后重新加载即可,或手动下载编码器权重到模型目录。

问:找不到模型文件或加载报错?

答:确认模型已下载到 config.py 中指定的本地目录,且目录内包含 model_index.jsonunettext_encoder 等子文件。也可删除本地目录,改用 from_pretrained 在线下载(需国内镜像)。

问:无 NVIDIA 显卡如何运行?

答:跳过 CUDA torch 安装,将 config.pyDEVICE 改为 "cpu"。SD1.5、LTX-Video 与 Wan2.1 在 CPU 上可运行但速度很慢,仅作功能验证使用。需注意 bfloat16 在部分平台上支持有限,建议 AMD 或 NVIDIA 显卡运行。