本教程系统讲解如何在消费级硬件(Windows 11 系统、16GB 可用内存、8GB 或 16GB 可用显存)上,通过开源推理框架 diffusers 部署图像生成模型(SDXL / SD1.5)与视频生成模型(LTX-Video / Wan2.1),并使用 Python 代码完成模型能力的调用。教程提供完整示例项目 generation-service,包含命令行工具、FastAPI 服务与客户端三种调用方式,覆盖文本生成图像、文本生成视频两大核心场景。
前置教程
如想快速开始学习本教程,你可能需要先完成以下前置教程:
- PyTorch安装与版本选择问题详解,本教程需要 CUDA 版 PyTorch 作为深度学习运行环境,是你本地部署生成模型的基础。
- Python+FastAPI在Windows环境下创建一个基础后端服务教程,本教程使用 FastAPI 构建生成服务后端,需要你掌握基础后端服务写法。
资源下载
- SDXL 底模 ModelScope 下载地址
- SD1.5 底模 ModelScope 下载地址
- LTX-Video 2B ModelScope 下载地址
- Wan2.1-T2V-1.3B(Diffusers版) ModelScope 下载地址
- 示例项目 generation-service 源码网盘下载地址
1. 图像与视频生成技术概览
1.1 什么是图像生成与视频生成
图像生成是指根据文本提示词(Prompt)自动生成符合描述的图像,代表性的技术是扩散模型(Diffusion Model)。
视频生成在图像生成的基础上增加时间维度,不仅生成单帧画面,还让画面在时间轴上连续运动,本质上是"图像生成 + 运动建模"的组合。
扩散模型的核心思想是:先学习一个从"噪声"到"图像"的逆过程。训练时模型学习如何把真实图像逐步加噪成纯噪声,推理时则从纯噪声出发,按照调度器指定的步数逐步去噪,最终还原出一张清晰图像。文本提示词通过编码器注入,引导去噪过程生成符合语义的画面。
循环 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-Video 与 Wan2.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)}")

若输出 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。国内用户推荐使用 ModelScope 或 HF 镜像 下载。使用 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。
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.py与text_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 客户端代码调用服务,演示"代码调用模型能力"
整体架构如下:
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_frames、fps、guidance 缺省时自动套用对应模型的推荐值。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")
请求参数通过 pydantic 的 BaseModel 定义并自动校验:ImageRequest 与 VideoRequest 首字段为 model(图像限 sdxl/sd15,视频限 ltx/wan),后端据此选择对应模型。
服务端每个类型同时只保留一个模型实例,切换模型时自动释放旧实例并重载,避免多个大模型同时常驻内存。
5.7 命令行工具 cli.py
命令行工具使用子命令(subparsers)组织不同操作,image 与 video 两个子命令分别对应图像、视频生成:
# 生成图像(默认 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 内部直接调用 ImageGenerator 与 VideoGenerator,不经过服务层,适合离线快速验证模型能力。
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,因此不采用全部常驻内存的方式。

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
- 图像生成:
StableDiffusionXLPipeline与StableDiffusionPipeline加载底模,pipe()直接出图 - 视频生成:
LTXPipeline与WanPipeline原生视频扩散,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.json、unet、text_encoder 等子文件。也可删除本地目录,改用 from_pretrained 在线下载(需国内镜像)。
问:无 NVIDIA 显卡如何运行?
答:跳过 CUDA torch 安装,将 config.py 的 DEVICE 改为 "cpu"。SD1.5、LTX-Video 与 Wan2.1 在 CPU 上可运行但速度很慢,仅作功能验证使用。需注意 bfloat16 在部分平台上支持有限,建议 AMD 或 NVIDIA 显卡运行。
举手提问