Article

扩散模型 Diffusers 速查文档

更新于:2026-07-20

第一部分:基础概念

第1章 Diffusers 简介与基础概念

1.1 什么是 Diffusers 库

概念名称说明注意事项
Hugging Face Diffusers一个开源库,提供预构建的扩散模型(如 Stable Diffusion)及其组件,支持文本到图像、图像到图像、视频生成等任务是 Hugging Face 生态的一部分,强调易用性和模块化设计
开源与社区驱动库由 Hugging Face 团队维护,但接受社区贡献,模型可在 Hugging Face Hub 上共享使用时应检查模型许可证,部分模型不可商用
模块化架构将扩散模型拆分为独立组件(如 UNet、VAE、Scheduler),便于替换与自定义初学者可直接使用 Pipeline 快速上手,无需理解底层细节
与 Transformers 集成共享相同的模型加载接口(from_pretrained),可无缝调用 CLIP、T5 等文本编码器需安装 transformers 库才能使用文本条件生成
支持多种后端原生基于 PyTorch,也支持 JAX 和 TensorFlow(实验性)推荐使用 PyTorch 版本以获得最佳兼容性与文档支持

1.2 扩散模型的基本原理(DDPM、DDIM、Stable Diffusion 等)

概念名称说明注意事项
正向扩散过程(Forward Process)逐步向图像添加高斯噪声,经过 T 步后将清晰图像变为纯噪声噪声调度通常固定,不参与训练
反向去噪过程(Reverse Process)模型学习从噪声中逐步恢复原始图像,每一步预测噪声或图像本身训练目标是最小化预测噪声与真实噪声的 MSE
DDPM (Denoising Diffusion Probabilistic Models)最早的扩散模型框架,使用马尔可夫链和变分推断采样速度慢(需数百步),但生成质量稳定
DDIM (Denoising Diffusion Implicit Models)非马尔可夫采样方法,允许更少步数生成高质量图像支持确定性生成,可用于图像插值
Latent Diffusion (Stable Diffusion)在低维潜在空间(latent space)进行扩散,大幅提升效率使用 VAE 编码图像,UNet 在 latent 上操作,节省显存
Score-based Generative Modeling通过估计数据分布的梯度(score function)引导生成与扩散模型数学等价,视角不同
Classifier-Free Guidance在无分类器条件下增强生成方向,通过调节 guidance_scale 控制保真度与多样性常用于文本到图像生成,提升提示词相关性

1.3 Diffusers 的核心组件概览(Pipeline、UNet、VAE、Scheduler 等)

组件名称说明注意事项
Pipeline高层接口,封装完整生成流程(文本编码 → 噪声生成 → 去噪 → 解码)推荐初学者使用,如 StableDiffusionPipeline
UNet主干网络,负责在每一步预测噪声输入包括噪声图像、timestep、条件嵌入;输出为噪声残差
VAE (Variational Autoencoder)编码器将图像压缩至 latent 空间,解码器还原为图像解码时可能出现数值溢出,需使用 clampsample 方法处理
Scheduler控制噪声添加与去除的策略,决定采样步骤和噪声调度不同 scheduler 影响生成速度与质量,可热替换
Text Encoder (e.g., CLIP)将输入文本转换为嵌入向量,作为生成条件通常来自 transformers 库,如 CLIPTextModel
Tokenizer将文本字符串转换为模型可处理的 token ID 序列必须与 text encoder 匹配使用
AutoencoderKLDiffusers 中 VAE 的实现类,使用 KL 正则化解码前需调用 .decode() 并后处理为像素范围 [0,1][0,255]

1.4 与其他库的对比(如 PyTorch Lightning、Keras、Transformers)

对比项DiffusersPyTorch LightningKerasTransformers
主要用途扩散模型推理与训练简化 PyTorch 训练流程高级神经网络 API(TensorFlow 后端)自然语言处理模型
模型类型支持扩散模型为主(图像、音频、视频)通用深度学习模型通用模型,侧重 CNN/RNNTransformer 架构(BERT、GPT、T5 等)
易用性高层 Pipeline 简单易用,底层组件灵活封装训练循环,降低工程复杂度API 简洁,适合快速原型提供 from_pretrained 标准接口
与 Diffusers 关系核心库可用于训练 Diffusers 模型不直接兼容深度集成,共享 tokenizer 和 text encoder
是否需要手动写训练循环否(Pipeline 自动完成)是(但结构清晰)否(提供 Trainer 类)
典型应用场景文本生成图像、图像编辑训练扩散模型快速搭建 CNN 分类器文本生成、翻译、摘要
注意事项依赖 transformers 处理文本可与 Diffusers 结合实现分布式训练不推荐用于扩散模型开发必须安装以使用 Stable Diffusion

第二部分:环境搭建与快速上手

第2章 环境搭建与快速上手

2.1 安装 Diffusers 与依赖库

操作名称操作细节注意事项
安装 diffuserspip install diffusers默认安装最新稳定版
安装 transformerspip install transformers必需,用于文本编码
安装 torchpip install torch torchvision torchaudio推荐使用 GPU 版本(见官网)
安装 xformers(可选)pip install xformers加速注意力计算,节省显存,但可能不稳定
从源码安装最新版pip install git+https://github.com/huggingface/diffusers获取未发布的新功能或修复
安装特定版本pip install diffusers==0.26.0用于复现论文或项目依赖
安装依赖(开发模式)git clone https://github.com/huggingface/diffusers
cd diffusers
pip install -e ".[dev]"
贡献代码或调试源码时使用

2.2 使用预训练模型进行图像生成(文本到图像)

方法名称语法用途代码示例注意事项
from_pretrainedStableDiffusionPipeline.from_pretrained("runwayml/stable-diffusion-v1-5")加载预训练 pipelinefrom diffusers import StableDiffusionPipeline
pipe = StableDiffusionPipeline.from_pretrained("runwayml/stable-diffusion-v1-5")
pipe = pipe.to("cuda")
首次运行会下载模型(约 4-7GB)
call (pipe())pipe(prompt, num_inference_steps=50, guidance_scale=7.5)生成图像image = pipe("a photo of a cat", num_inference_steps=30).images[0]
image.save("cat.png")
输出为 PIL.Image 对象列表,取 [0] 获取第一张
topipe.to(device)移动模型到指定设备pipe = pipe.to("cuda") # 使用 GPU
pipe = pipe.to("cpu") # 使用 CPU
GPU 显存不足时可尝试 fp16
enable_attention_slicingpipe.enable_attention_slicing()降低显存占用pipe.enable_attention_slicing()
image = pipe("a dog").images[0]
会轻微降低速度,但可运行更大 batch
disable_attention_slicingpipe.disable_attention_slicing()恢复默认注意力计算pipe.disable_attention_slicing()在不需要节省显存时关闭

2.3 使用预训练模型进行图像到图像生成

方法名称语法用途代码示例注意事项
StableDiffusionImg2ImgPipeline.from_pretrainedfrom_pretrained(model_id)加载图像到图像 pipelinefrom diffusers import StableDiffusionImg2ImgPipeline
pipe = StableDiffusionImg2ImgPipeline.from_pretrained("runwayml/stable-diffusion-v1-5").to("cuda")
与文本到图像 pipeline 不同
callpipe(prompt, image, strength, guidance_scale)执行图像到图像生成from PIL import Image
init_image = Image.open("cat.jpg")
result = pipe(prompt="a sketched cat", image=init_image, strength=0.7, guidance_scale=9.0)
result.images[0].save("sketch.png")
strength 控制变化程度(0~1),越大越偏离原图
strength 参数float in [0, 1]控制噪声添加强度,决定输出与输入的相似度strength=0.3:轻微修改
strength=0.8:大幅重构
strength 可能丢失原图结构
image 输入格式PIL.Imagetorch.Tensor提供初始图像图像应为 RGB,尺寸建议 512x512自动调整大小可能导致变形

2.4 使用不同调度器(Scheduler)生成图像

方法名称语法用途代码示例注意事项
from_pretrainedDPMSolverMultistepScheduler.from_pretrained("runwayml/stable-diffusion-v1-5", subfolder="scheduler")加载调度器from diffusers import DPMSolverMultistepScheduler
scheduler = DPMSolverMultistepScheduler.from_pretrained("runwayml/stable-diffusion-v1-5", subfolder="scheduler")
需指定 subfolder="scheduler"
set_schedulerpipe.scheduler = scheduler替换 pipeline 中的调度器pipe.scheduler = scheduler可动态切换,无需重新加载模型
常用调度器DDIMScheduler, LMSDiscreteScheduler, EulerDiscreteScheduler, DPMSolverMultistepScheduler不同采样策略DPM++ 和 Euler 在 20-30 步内效果好DPMSolver 速度快,适合交互式应用
num_inference_stepspipe(prompt, num_inference_steps=N)设置采样步数较新 scheduler 如 DPM 可用 20-25 步传统 DDPM 需 1000 步,不实用
guidance_scalepipe(guidance_scale=7.5)控制条件引导强度值越高越贴近提示词,过高会导致过饱和一般 7~12 为合理范围

2.5 快速推理的硬件加速(CPU/GPU/TPU)

方法名称语法用途代码示例注意事项
to("cuda")pipe.to("cuda")将模型移动到 GPUpipe = pipe.to("cuda")需安装 CUDA 版 PyTorch
to("cpu")pipe.to("cpu")强制使用 CPU 推理pipe = pipe.to("cpu")速度慢,显存不足时备用
half()pipe.unet.half(), pipe.vae.half(), etc.转为 FP16 半精度pipe.unet = pipe.unet.half()
pipe.vae = pipe.vae.half()
pipe.to("cuda")
可减少显存占用近半,几乎无质量损失
enable_xformers_memory_efficient_attentionpipe.enable_xformers_memory_efficient_attention()使用 xformers 优化注意力pipe.enable_xformers_memory_efficient_attention()需安装 xformers,某些平台可能编译失败
混合精度 (AMP)with torch.autocast("cuda"): ...自动混合精度推理with torch.autocast("cuda"):
    image = pipe(prompt).images[0]
PyTorch 原生支持,推荐与 half() 结合
TPU 支持使用 JAX 版本 Diffusers在 Google Cloud TPU 上运行需使用 diffusers[pipeline-jax]配置复杂,适合大规模部署

第三部分:Diffusion Pipeline 详解

第3章 Diffusion Pipeline 详解

3.1 Pipeline 的基本结构与工作流程

组件/阶段说明注意事项
Tokenizer将输入文本转换为 token ID 序列必须与 text_encoder 匹配,如 CLIP tokenizer
Text Encoder将 tokens 编码为嵌入向量(text embeddings)输出为 [batch_size, sequence_length, hidden_size]
VAE Encoder将输入图像编码为 latent 表示(用于 img2img/inpainting)latent 形状通常为 [batch_size, 4, 64, 64](Stable Diffusion)
Latent 初始化随机生成噪声 latent(形状同上)在文生图任务中使用
UNet + Scheduler在每个 timestep 上,UNet 预测噪声,Scheduler 执行去噪步骤核心循环,执行 num_inference_steps
VAE Decoder将去噪后的 latent 解码为像素图像输出为 [0, 1] 范围的 RGB 图像
后处理将 tensor 转换为 PIL.Image 对象自动完成,可通过 output_type 控制
工作流程顺序文本 → Tokenizer → Text Encoder → Context
随机噪声 → Latent → UNet+Scheduler(T 步)→ Decoded Image
整个过程由 Pipeline 封装

3.2 常用 Pipeline 类型对比(StableDiffusionPipeline、DDPMPipeline、LatentConsistencyModelPipeline 等)

Pipeline 类名用途输入要求典型应用场景注意事项
StableDiffusionPipeline文本到图像生成prompt (str/List)通用图像生成最常用,支持 fp16 和 xformers
StableDiffusionImg2ImgPipeline图像到图像生成prompt, image, strength风格迁移、图像增强strength 控制变化程度
StableDiffusionInpaintPipeline图像修复(inpainting)prompt, image, mask局部编辑、物体移除mask 指定需重绘区域
DDPMPipeline基础 DDPM 模型采样num_inference_steps教学、研究基础扩散模型不依赖文本条件,仅生成随机图像
DDIMPipeline使用 DDIM 采样的非马尔可夫模型num_inference_steps, eta快速采样、图像插值eta=0 为确定性生成
PNDMPipeline使用 PNDM(Pseudo Numerical Methods)调度num_inference_steps加速 DDPM 采样兼容旧版模型
KarrasVePipeline基于能量函数的扩散模型num_inference_steps特定研究模型使用不同的数学框架
LDMPipelineLatent Diffusion Model 基础 pipelinelatent noise早期潜在扩散模型现已被 StableDiffusion 替代
LatentConsistencyModelPipeline一致性模型,极快采样(1-4 步)prompt, num_inference_steps=1~4实时生成、低延迟应用新兴技术,质量略低于标准 diffusion
AudioLDM2Pipeline文本到音频生成prompt音频合成支持音乐、语音等生成
CycleDiffusionPipeline图像间双向变换source_prompt, target_prompt, image图像风格渐变实验性功能

3.3 Pipeline 的输入输出参数详解

参数名类型用途默认值注意事项
promptstrList[str]输入的文本提示"a photo of a cat"支持多提示批量生成
negative_promptstrList[str]不希望出现的内容""提升生成质量,避免不相关内容
num_inference_stepsint去噪迭代次数50较新 scheduler 可减少至 20~30
guidance_scalefloat分类器无关引导强度7.5>1.0 增强提示相关性,过高导致过饱和
height, widthint输出图像尺寸512应为 8 的倍数,否则可能报错
batch_sizeint批量生成数量1受显存限制,fp16 下可增大
output_typestr输出格式"pil"可选 "numpy", "latent"
return_dictbool是否返回字典True设为 False 可只返回图像列表
generatortorch.Generator随机种子控制None用于复现结果,如 torch.Generator("cuda").manual_seed(42)
latentstorch.Tensor自定义初始噪声自动生成形状应为 (batch_size, 4, height//8, width//8)
callbackfunction每步调用的回调函数None用于进度监控或中断
callback_stepsint回调触发间隔1每 N 步调用一次 callback
cross_attention_kwargsdict传递给注意力层的参数None如用于 ControlNet

3.4 自定义 Pipeline 的加载与调用方式

方法名称语法用途代码示例注意事项
from_pretrainedMyPipeline.from_pretrained(model_id)加载自定义 pipeline 类class MyPipeline(DiffusionPipeline):
    ...
pipe = MyPipeline.from_pretrained("runwayml/stable-diffusion-v1-5")
需继承 DiffusionPipeline
register_modulespipe.register_modules(**kwargs)动态注册组件unet = UNet2DConditionModel.from_pretrained(...)
scheduler = DDIMScheduler.from_pretrained(...)
pipe.register_modules(unet=unet, scheduler=scheduler)
用于组合不同来源的模块
save_pretrainedpipe.save_pretrained(save_dir)保存自定义 pipelinepipe.save_pretrained("./my_pipeline")可重新加载
加载 LoRA 权重pipe.load_lora_weights(lora_model_id)加载 LoRA 微调权重pipe.load_lora_weights("latent-consistency/lcm-lora-sdv1-5")
image = pipe(prompt, num_inference_steps=4).images[0]
支持热插拔
使用子文件夹加载SomePipeline.from_pretrained("model_id", subfolder="unet")从特定子目录加载组件from diffusers import UNet2DConditionModel
unet = UNet2DConditionModel.from_pretrained("runwayml/stable-diffusion-v1-5", subfolder="unet")
适用于分体式模型结构

3.5 Pipeline 的保存与加载

操作名称操作细节代码示例注意事项
保存完整 pipelinepipe.save_pretrained(save_directory)pipe.save_pretrained("./my_sd_model")会保存所有组件(tokenizer, text_encoder, unet, vae, scheduler)
加载保存的 pipelineSomePipeline.from_pretrained(save_directory)from diffusers import StableDiffusionPipeline
pipe = StableDiffusionPipeline.from_pretrained("./my_sd_model")
自动识别组件类型
仅保存部分组件unet.save_pretrained("./unet_only")pipe.unet.save_pretrained("./unet_weights")可单独保存 UNet 或 VAE
加载部分权重pipe.unet = UNet2DConditionModel.from_pretrained("./unet_weights")pipe.unet = UNet2DConditionModel.from_pretrained("./unet_weights")用于微调后替换
保存 FP16 模型先转换再保存pipe.unet.half()
pipe.save_pretrained("./sd_fp16")
减少存储空间和加载时间
安全保存(无 pickle)使用 safetensors 格式确保安装 safetensors,自动使用安全格式保存更安全,防止恶意代码执行
跨设备加载支持 CPU/GPU 互转pipe = pipe.to("cuda") # 从 CPU 加载后移到 GPU权重自动转移,无需额外操作

第四部分:噪声调度器(Scheduler)深入解析

第4章 噪声调度器(Scheduler)深入解析

4.1 调度器的作用与分类(DDPM、DDIM、PNDM、K-LMS、Euler 等)

调度器名称类名作用采样速度注意事项
DDPMDDPMScheduler基础马尔可夫扩散过程慢(需 1000 步)用于教学,实际生成不推荐
DDIMDDIMScheduler非马尔可夫采样,允许少步生成快(20~50 步)支持确定性生成(eta=0
PNDMPNDMScheduler伪数值方法加速 DDPM中等(50~100 步)旧版兼容,现较少使用
K-LMS (LMS)LMSDiscreteScheduler基于 Langevin 动力学快(20~50 步)对噪声敏感,可能不稳定
EulerEulerDiscreteScheduler一阶欧拉积分快(30~50 步)简单稳定,适合初学者
Euler AncestralEulerAncestralDiscreteScheduler添加随机性的 Euler中等引入随机性,增加多样性
DPMSolver++DPMSolverMultistepScheduler高阶求解器,支持半隐式极快(10~25 步)当前主流,推荐使用
DPMSolverSinglestepDPMSolverSinglestepScheduler单步高阶求解极快(10~15 步)适合极低步数场景
UniPCUniPCMultistepScheduler统一预测器-校正器极快(10~15 步)新兴算法,性能优异
KDPM2KDPM2DiscreteScheduler二阶 Karras 算法少见,特定模型使用

4.2 各调度器的数学原理与采样策略

调度器数学原理采样策略注意事项
DDPM基于变分推断,学习反向过程的均值和方差每步添加噪声再预测去除需大量步数,采样效率低
DDIM将扩散过程视为常微分方程(ODE)使用 ODE 求解器跳步采样支持任意步数,可插值
PNDM将扩散视为数值微分方程求解使用多步法(如 Adams-Bashforth)近似方法,可能偏离真实路径
K-LMS基于 Langevin dynamics,引入梯度指导使用离散化 Langevin 方程对梯度敏感,需调节
Euler一阶显式欧拉法求解 ODEx_{t-1} = x_t - Δt · f(x_t, t)简单但精度较低
Euler Ancestral在 Euler 基础上添加随机扰动引入祖先采样机制增加多样性,但不可复现
DPMSolver使用高阶 ODE 求解器(如 Runge-Kutta)多步预测与校正收敛快,适合低步数
DPMSolver++半隐式求解,结合预测与历史信息结合 backward 和 forward 求解稳定性优于显式方法
UniPC统一预测器-校正器框架通用框架,适配多种扩散形式理论统一,实现复杂
KDPM2二阶 Karras 采样器使用二阶导数信息精度高,但计算开销略大

4.3 调度器的通用接口与参数配置

方法/属性语法用途代码示例注意事项
configscheduler.config获取调度器配置字典print(scheduler.config)包含 beta_schedule, steps_offset
set_timestepsscheduler.set_timesteps(num_inference_steps)设置总采样步数scheduler.set_timesteps(30)必须在采样前调用
timestepsscheduler.timesteps获取离散的时间步序列print(scheduler.timesteps)长度等于 num_inference_steps
stepscheduler.step(model_output, t, sample, **kwargs)执行单步去噪latents = scheduler.step(noise_pred, t, latents).prev_sample核心方法,返回下一步样本
add_noisescheduler.add_noise(original_samples, noise, timesteps)正向过程加噪声noisy_latents = scheduler.add_noise(latents, noise, t)用于训练或 img2img
init_noise_sigmascheduler.init_noise_sigma初始噪声标准差sigma = scheduler.init_noise_sigma用于 img2img 中调整噪声强度
scale_model_inputscheduler.scale_model_input(sample, t)缩放输入以适应模型input_tensor = scheduler.scale_model_input(latents, t)某些 scheduler 需要此操作
betas, alphas_cumprodscheduler.betas, scheduler.alphas_cumprod噪声调度参数用于调试或自定义逻辑一般不直接修改

4.4 不同调度器的生成效果对比

调度器推荐步数生成质量速度确定性适用场景注意事项
DDPM1000教学演示不实用
DDIM50是(eta=0通用生成、插值平衡好
PNDM50兼容旧模型已过时
K-LMS50快速生成可能不稳定
Euler50稳定生成推荐初学者
Euler Ancestral50中高多样性生成每次结果不同
DPM++ 2M20~25极快主流应用当前最佳选择之一
DPM++ SDE20~25高(更自然)艺术生成引入随机性
UniPC10~15极快实时生成新兴优秀方案
LCM4~8中高极快是/否超快推理配合 LoRA 使用

4.5 自定义调度器的实现与替换

操作名称操作细节代码示例注意事项
继承 SchedulerMixin创建类继承 SchedulerMixinfrom diffusers import SchedulerMixin
class MyScheduler(SchedulerMixin):
    def step(...): ...
必须实现核心方法
实现 step 方法定义单步去噪逻辑def step(self, model_output, timestep, sample, **kwargs):
    # 自定义去噪公式
    prev_sample = ...
    return {"prev_sample": prev_sample}
返回字典格式
实现 add_noise定义正向加噪过程def add_noise(self, original_samples, noise, timesteps):
    coeff = self.alphas_cumprod[timesteps] ** 0.5
    return coeff * original_samples + (1 - coeff) ** 0.5 * noise
保持与反向一致
注册为配置文件创建 scheduler_config.json{"_class_name": "MyScheduler", "beta_schedule": "linear"}放入模型目录
加载自定义调度器使用 from_configsched = MyScheduler.from_config("./my_scheduler/scheduler_config.json")需正确配置
替换 pipeline 中调度器直接赋值pipe.scheduler = my_scheduler无需重新加载模型
测试调度器在 pipeline 中运行image = pipe("test", num_inference_steps=20).images[0]验证是否正常工作

第五部分:UNet 模型结构与使用

第5章 UNet 模型结构与使用

5.1 UNet 在扩散模型中的角色

概念名称说明注意事项
噪声预测器UNet 的核心任务是预测当前 latent 状态中的噪声成分输入为加噪后的 latent 和 timestep,输出为噪声残差
时间步嵌入(timestep embedding)将离散 timestep 编码为向量,作为条件输入使用正弦位置编码或 MLP 实现
条件生成支持接收文本嵌入(text embeddings)作为条件,实现文本到图像控制通过 cross-attention 层融合文本信息
多尺度特征处理利用编码器-解码器结构捕获局部与全局图像特征中间通过 skip-connections 保留细节
可替换性UNet 是 Diffusers Pipeline 中可独立替换的模块可加载微调后的 UNet 或不同架构(如 3D UNet)
训练与推理一致性训练目标为最小化预测噪声与真实噪声的 MSE推理时通过 scheduler 多次调用完成去噪

5.2 UNet 的网络结构与前向传播机制

结构组件说明注意事项
Encoder(下采样路径)多个 ResNet 块 + Attention 层 + Downsample逐步降低空间分辨率,增加通道数
Bottleneck中间连接层,包含 ResNet 和 Attention 模块处理最抽象的特征表示
Decoder(上采样路径)多个 ResNet 块 + Attention 层 + Upsample逐步恢复空间分辨率
Skip Connections将 encoder 的输出直接传给 decoder 对应层保留细节信息,缓解梯度消失
Cross-Attention 层在 decoder 中融合文本条件(text embeddings)每个 attention head 关注不同文本 token
Timestep Embedding将 timestep 映射为向量,加入到每个 ResNet 块实现时间感知的去噪
ResNet Block with Attention基本构建单元,包含卷积、归一化、注意力支持条件输入
GroupNorm & SiLU常用归一化和激活函数稳定训练,适合扩散模型
前向传播流程latent → encoder → bottleneck → decoder(融合 skip 和 text cond)→ noise prediction每一步调用一次 UNet
输入拼接方式timestep 和 text embeddings 通过 modulation 或 attention 注入不同实现方式影响性能

5.3 UNet 的输入输出格式(噪声、timestep、条件嵌入等)

输入/输出类型形状用途注意事项
sample (noisy latent)torch.Tensor(B, C, H//8, W//8)当前加噪的 latent 状态Stable Diffusion 中 C=4, H=W=512 → (B,4,64,64)
timesteptorch.Tensorintscalar 或 (B,)当前去噪步数自动广播为 batch 维度
encoder_hidden_statestorch.Tensor(B, Seq_Len, Hidden_Size)文本编码器输出(如 CLIP)Seq_Len=77, Hidden_Size=768
return_dictbool-是否返回字典默认 True,返回 {"sample": pred_noise}
输出:预测噪声torch.Tensor同输入 sample模型预测的噪声残差用于 scheduler 计算下一步
可选输入:class_labelstorch.Tensor(B,)类条件扩散模型使用如 ImageNet 类别
可选输入:cross_attention_kwargsdict-传递额外注意力参数如用于 ControlNet 的控制信号
设备一致性所有输入必须在同一设备(CPU/GPU)--否则会报错
数据类型推荐 torch.float16(GPU)或 torch.float32--混合精度训练需注意

5.4 冻结与微调 UNet 层

方法名称语法用途代码示例注意事项
freeze()module.requires_grad_(False)冻结指定层# 冻结 attention 层
for attn in pipe.unet.attn_processors:
    attn.requires_grad_(False)
减少训练参数量
unfreeze()module.requires_grad_(True)解冻层用于训练pipe.unet.conv_out.requires_grad_(True)通常只训练部分层
只训练 attention使用 PEFT 或手动选择微调 adapterfor name, param in pipe.unet.named_parameters():
    if "attn" in name:
        param.requires_grad = True
LoRA 常用策略
使用 LoRA 微调配合 peft 库插入低秩矩阵高效微调from peft import LoraConfig, get_peft_model
config = LoraConfig(r=4, lora_alpha=32, target_modules=["to_q", "to_v"])
unet_lora = get_peft_model(pipe.unet, config)
显存占用低,适合消费级 GPU
optimizer 设置只传入 requires_grad 的参数节省内存optimizer = torch.optim.AdamW(filter(lambda p: p.requires_grad, unet.parameters()), lr=1e-4)避免优化冻结层
查看可训练参数sum(p.numel() for p in model.parameters() if p.requires_grad)监控训练规模print(f"Trainable params: {num_trainable:,}")确保只训练目标层
gradient checkpointingpipe.unet.enable_gradient_checkpointing()降低显存占用pipe.unet.enable_gradient_checkpointing()会轻微降低速度

5.5 使用自定义 UNet 替换预训练模型中的 UNet

方法名称语法用途代码示例注意事项
from_pretrainedUNet2DConditionModel.from_pretrained(...)加载 UNet 权重from diffusers import UNet2DConditionModel
custom_unet = UNet2DConditionModel.from_pretrained("path/to/unet")
必须匹配架构
替换 pipeline 中的 UNetpipe.unet = new_unet更新模型组件pipe.unet = custom_unet
pipe.unet.to("cuda")
替换后需移动到相同设备
修改架构后加载部分权重使用 ignore_mismatched_sizes兼容尺寸变化unet = UNet2DConditionModel.from_pretrained("runwayml/stable-diffusion-v1-5", subfolder="unet", ignore_mismatched_sizes=True)仅加载匹配层
保存自定义 UNetunet.save_pretrained(save_dir)持久化模型custom_unet.save_pretrained("./my_unet")可重新加载
从 checkpoint 加载torch.load + load_state_dict加载非标准格式state_dict = torch.load("unet.ckpt")
pipe.unet.load_state_dict(state_dict)
需匹配 key 名称
验证替换后功能运行一次推理确保无报错image = pipe("test", num_inference_steps=20).images[0]检查输出是否合理
架构兼容性要求输入输出通道、条件接口必须一致--否则无法集成到 pipeline

第六部分:变分自编码器(VAE)详解

第6章 变分自编码器(VAE)详解

6.1 VAE 的编码与解码过程

过程说明注意事项
编码(Encode)将 RGB 图像压缩为低维 latent 表示输入为 [0,1] 归一化的 tensor
解码(Decode)将 latent 表示还原为 RGB 图像输出为 [0,1] 范围的图像
Encoder 网络结构多个卷积层 + Downsampling + 激活函数输出 latent shape 通常为 (4,64,64)
Decoder 网络结构多个卷积层 + Upsampling + 激活函数对称结构,逐步恢复分辨率
Latent Normalizationlatent 值通常分布在 [-3,3]非标准正态,注意调度器适配
输入预处理图像需缩放到 512x512 并归一化到 [0,1]使用 torchvision.transforms
输出后处理解码后使用 clampsigmoid 确保范围防止数值溢出
推理模式使用通常只使用 decode 方法生成图像encode 多用于 img2img 或训练
KL-Divergence 层在 latent 空间引入正则化(训练时)推理时忽略,直接使用均值

6.2 Latent Space 的理解与操作

概念名称说明注意事项
Latent Vector图像在 VAE 编码后的低维表示通常为 (B,4,64,64),比原图小 64 倍
潜在空间维度通道数代表特征维度,空间尺寸为压缩后分辨率Stable Diffusion 中为 4x64x64
连续性相似图像在 latent 空间中距离较近支持插值和语义编辑
线性可分性不同语义概念可能在 latent 空间中线性可分Textual Inversion 利用此特性
操作方式可对 latent 进行加减、插值、掩码等操作latents += direction * alpha
插值(Interpolation)两个 latent 向量之间线性或球面插值生成过渡图像序列
潜在空间正则化训练时通过 KL loss 约束 latent 分布推理时可忽略
潜在空间攻击对 latent 添加扰动可改变生成结果用于对抗样本研究
可视化无法直接可视化,需通过 VAE 解码所有操作最终需解码观察效果

6.3 VAE 的推理与训练模式差异

模式行为差异代码控制注意事项
训练模式(train)启用 dropout、batchnorm 更新、输出均值和方差vae.train()用于微调 VAE
推理模式(eval)固定归一化统计量,不使用 dropoutvae.eval()生成时必须使用
编码输出训练时输出 latent_meanlatent_logvarz = vae.encode(x).latent_dist.sample()推理时直接采样
重参数化技巧仅在训练时使用 reparameterizez = mean + eps * exp(0.5 * logvar)推理时可直接用均值
KL Loss仅在训练时计算并加入总损失loss = recon_loss + kl_weight * kl_loss推理时不计算
数值稳定性训练时需防止 logvar 过小logvar = torch.clamp(logvar, -30.0, 20.0)避免 exp(0.5*logvar) 溢出
梯度计算训练时保留梯度requires_grad=True推理时可禁用 torch.no_grad()
批量处理训练时使用大 batchdataloader + loop推理时通常 batch=1

6.4 使用 VAE 进行图像压缩与重建

方法名称语法用途代码示例注意事项
encodevae.encode(image).latent_dist.sample()图像压缩为 latentfrom torchvision import transforms
transform = transforms.ToTensor()
image_tensor = transform(image).unsqueeze(0).to("cuda")
image_tensor = 2 * image_tensor - 1 # 归一化到 [-1,1]
latents = vae.encode(image_tensor).latent_dist.sample()
latents = latents * 0.18215 # 缩放因子
必须归一化并缩放
decodevae.decode(latents / 0.18215).samplelatent 解码为图像latents = torch.randn(1, 4, 64, 64).to("cuda")
latents = latents / 0.18215
image_tensor = vae.decode(latents).sample
image_tensor = (image_tensor / 2 + 0.5).clamp(0, 1) # 转回 [0,1]
image = transforms.ToPILImage()(image_tensor[0])
注意缩放和 clamp
缩放因子0.18215Stable Diffusion VAE 特有来自训练时的统计值必须匹配,否则图像失真
重建误差MSE 或 L1 损失评估 VAE 质量recon_loss = F.mse_loss(decoded, original)通常存在细节丢失
批量编码支持 batch 处理vae.encode(img_batch).latent_dist.sample()提高处理效率
设备一致性图像和 VAE 必须在同一设备.to("cuda")否则报错
输入范围必须为 [-1,1]使用 (x * 2 - 1) 转换原始图像为 [0,1]

6.5 处理 VAE 的数值溢出与后处理技巧

技巧/方法操作细节代码示例注意事项
解码后 clamp限制像素值在 [0,1] 范围decoded = torch.clamp(decoded, 0, 1)防止生成无效颜色
使用 sample 而非 latent_dist.mode推荐采样而非取众数latents = vae.encode(x).latent_dist.sample()更稳定
输出后处理(+0.5[-1,1] 转为 [0,1]image = (decoded / 2 + 0.5).clamp(0, 1)标准做法
处理 NaN/Inf检查并替换异常值if torch.isnan(decoded).any():
    decoded = torch.nan_to_num(decoded)
避免图像全黑或花屏
缩放 latent 输入使用预定义缩放因子latents = latents / 0.18215 # for SD不同模型因子不同
启用 vae.slicing降低显存占用pipe.enable_vae_slicing()适用于大 batch 或高分辨率
启用 vae.tiling分块处理大图像pipe.enable_vae_tiling()用于 >1024x1024 图像
使用 half 精度减少显存vae.decoder = vae.decoder.half()
latents = latents.half()
需 GPU 支持 FP16
异常捕获包裹解码过程try:
    image = vae.decode(latents).sample
except RuntimeError as e:
    print("VAE error:", e)
提高鲁棒性

第七部分:文本编码器与条件生成

第7章 文本编码器与条件生成

7.1 CLIP 文本编码器的作用

概念名称说明注意事项
多模态对齐CLIP(Contrastive Language-Image Pretraining)通过对比学习将文本和图像映射到同一语义空间是 Stable Diffusion 实现文本控制的关键
文本编码功能将输入提示词(prompt)转换为固定维度的嵌入向量(text embeddings)输出维度通常为 768 或 1024
双塔结构包含独立的图像编码器和文本编码器,在训练时进行对比损失优化推理时仅使用文本编码器
Tokenization使用 BPE(Byte Pair Encoding)分词,支持开放词汇最大长度为 77 tokens(含起止符)
Embedding Pooling对 token embeddings 进行池化或直接使用序列输出Diffusers 中通常保留完整序列
与 UNet 集成text embeddings 通过 cross-attention 注入 UNet 的 decoder 层实现文本条件去噪
模型来源通常来自 transformers 库,如 CLIPTextModel需与 tokenizer 配套使用
开源实现Hugging Face 提供多种 CLIP 模型(openai/clip-vit-base-patch32 等)可替换不同版本以优化效果

7.2 文本嵌入(text embeddings)的生成与使用

方法名称语法用途代码示例注意事项
Tokenizer 编码tokenizer(prompt, return_tensors="pt", padding=True, truncation=True)将文本转为 token IDsfrom transformers import CLIPTokenizer
tokenizer = CLIPTokenizer.from_pretrained("openai/clip-vit-large-patch14")
inputs = tokenizer("a cat", max_length=77, return_tensors="pt", padding="max_length", truncation=True)
必须 padding="max_length" 以支持 batch
Text Encoder 推理text_encoder(inputs.input_ids.to(device))生成文本嵌入from transformers import CLIPTextModel
text_encoder = CLIPTextModel.from_pretrained("openai/clip-vit-large-patch14").to(device)
embeddings = text_encoder(inputs.input_ids.to(device))[0] # [last_hidden_state]
输出为 [batch, seq_len, hidden_size]
负提示嵌入分别编码正负提示实现 classifier-free guidancepos_inputs = tokenizer("cat", ...)
neg_inputs = tokenizer("", ...) # 空或"low quality"
pos_emb = text_encoder(pos_inputs.input_ids)
neg_emb = text_encoder(neg_inputs.input_ids)
负提示常为空或负面描述
嵌入拼接torch.cat([neg_emb, pos_emb])用于 CFGcond_inputs = torch.cat([neg_emb, pos_emb])
noise_pred = unet(latents, t, encoder_hidden_states=cond_inputs)
batch 维度拼接
自定义嵌入输入直接传入 pipeline绕过内置 tokenizerpipe(prompt=None, text_embeddings=custom_emb, ...)需手动实现
截断与填充max_length=77适配模型输入超长文本会被截断建议控制在 75 词以内
设备一致性所有张量需在相同设备.to("cuda")否则报错

7.3 支持长文本与负提示(negative prompt)的机制

机制说明注意事项
Classifier-Free Guidance (CFG)同时预测有条件和无条件的噪声,通过加权差值增强提示相关性公式:$\epsilon_{guided} = \epsilon_{uncond} + w \cdot (\epsilon_{cond} - \epsilon_{uncond})$
Guidance Scale (w)控制条件引导强度通常 7~12,过高导致过饱和或伪影
Negative Prompt用户指定不希望出现的内容如 “blurry, low quality, text”
内部实现pipeline 自动编码正负提示并拼接调用 UNet 时 batch size 翻倍
空字符串作为负条件若未提供 negative_prompt,常使用空字符串 ""代表”无文本条件”
批量处理支持 per-sample 正负提示可为每张图像设置不同负提示
长文本截断超过 77 tokens 的文本会被截断可使用文本重写或分块策略缓解
组合提示使用逗号分隔多个描述如 “a red cat, sitting on a chair, sunlight”

7.4 使用自定义文本编码器

方法名称语法用途代码示例注意事项
加载自定义模型CLIPTextModel.from_pretrained("path/to/model")使用微调后的文本编码器custom_text_encoder = CLIPTextModel.from_pretrained("./my_clip")架构需兼容
替换 pipeline 组件pipe.text_encoder = new_encoder集成到 pipelinepipe.text_encoder = custom_text_encoder
pipe.text_encoder.to("cuda")
需移动到相同设备
使用不同 tokenizerCLIPTokenizer.from_pretrained("new_tokenizer")支持新词汇custom_tokenizer = CLIPTokenizer.from_pretrained("./my_tokenizer")
pipe.tokenizer = custom_tokenizer
必须匹配
注册新模块pipe.register_modules(text_encoder=encoder, tokenizer=tokenizer)动态替换多个组件pipe.register_modules(
    text_encoder=custom_text_encoder,
    tokenizer=custom_tokenizer
)
推荐方式
保存自定义 pipelinepipe.save_pretrained("./custom_pipe")持久化pipe.save_pretrained("./custom_pipe")可重新加载
验证替换效果生成图像测试确保功能正常image = pipe("test").images[0]检查是否崩溃或输出异常
架构兼容性输入输出维度必须匹配hidden_size=768, max_length=77否则无法集成

7.5 多条件生成(如文本+图像)

条件类型实现方式用途注意事项
文本 + 图像(img2img)使用 StableDiffusionImg2ImgPipeline基于原图生成新图通过 strength 控制变化程度
文本 + 深度图使用 StableDiffusionDepth2ImgPipeline保持几何结构需预估深度图
文本 + 边缘图使用 Canny Edge + ControlNet精确控制轮廓见 8.5 节
文本 + 姿势图使用 OpenPose + ControlNet控制人物姿态适用于角色生成
文本 + 语义分割图使用 segmentation mask控制布局如建筑物、天空位置
多模态嵌入拼接将图像特征与文本嵌入拼接实验性方法需对齐维度
Cross-Attention 注入在 UNet 中添加额外 attention 层融合多条件ControlNet 的实现方式
Timestep 调制根据条件调整时间步动态控制生成过程高级技巧
条件权重控制为不同条件设置权重平衡影响controlnet_conditioning_scale
Pipeline 选择根据任务选择专用 pipelineTextToImagePipeline, ImageToImagePipeline官方支持有限,需扩展

第八部分:图像生成高级技巧

第8章 图像生成高级技巧

8.1 提示词工程(Prompt Engineering)最佳实践

技巧说明示例注意事项
明确主体清晰描述主体对象”a golden retriever”避免模糊词汇
添加风格指定艺术风格或媒介”oil painting”, “photorealistic”, “anime style”显著影响视觉效果
描述环境包含场景和背景”in a sunny park”, “on Mars”增强画面丰富度
光照条件指定光源类型”soft lighting”, “dramatic shadows”, “backlit”影响氛围
构图与视角描述镜头和角度”wide-angle shot”, “close-up”, “from above”控制画面布局
质量词提升图像质量”high resolution”, “8K”, “sharp focus”减少模糊或伪影
避免负面词显式排除不希望的内容negative prompt: “blurry, deformed, text”提升整体质量
使用逗号分隔结构化提示”a cat, sitting on a windowsill, sunlight, detailed fur”更易解析
权重语法强调关键元素(cat:1.2), [cat](降低)Diffusers 支持 (word:weight)
迭代优化多次生成并调整提示逐步细化描述实践中最重要的技巧

8.2 使用引导(guidance scale)控制生成质量

参数名说明推荐值注意事项
guidance_scale控制文本条件引导强度7.0 ~ 12.0默认 7.5
低值(<5)生成更随机,多样性高,但可能偏离提示3~5适合创意探索
中值(7~9)平衡保真度与多样性7.5(默认)大多数场景适用
高值(10~15)更贴近提示,细节更丰富10~12可能出现过饱和或伪影
极高值(>15)可能导致图像失真或崩溃不推荐特别在低步数时
与步数关系低步数采样需降低 guidance_scale如 DPM++ 25 步 → scale=7~9避免过度引导
动态调节在生成过程中变化 scale实验性可结合 callback 实现
负面提示协同guidance_scale 配合负面提示效果更好如 “low quality, blurry”提升整体质量
数值稳定性过高可能导致 latent 溢出观察解码是否报错可尝试降低或使用 clamp

8.3 多步生成与图像插值(image interpolation)

方法名称语法用途代码示例注意事项
固定初始噪声设置 generator 和 seed复现生成结果g = torch.Generator("cuda").manual_seed(42)
image = pipe("cat", generator=g).images[0]
相同 seed 产生相同图像
图像插值(Latent Space)线性插值两个 latent 向量生成过渡图像latents_a = torch.randn(1,4,64,64)
latents_b = torch.randn(1,4,64,64)
for i in range(5):
    alpha = i / 4.0
    inter_latents = latents_a * (1-alpha) + latents_b * alpha
    image = pipe(prompt, latents=inter_latents).images[0]
需禁用随机噪声
球面插值(Slerp)更自然的插值方式避免中间模糊def slerp(t, v0, v1):
    ... # 实现球面插值
inter = slerp(alpha, latents_a, latents_b)
数学上更合理
Prompt Interpolation插值两个文本嵌入语义过渡emb1 = encode("cat")
emb2 = encode("dog")
inter_emb = emb1 * (1-alpha) + emb2 * alpha
image = pipe(prompt=None, text_embeddings=inter_emb).images[0]
需手动编码
多阶段生成分步生成,逐步细化如先生成草图再细化先用低分辨率生成,再用 upscaler需多 pipeline 协作
使用 DDIM 进行确定性插值DDIM 支持任意起点终点图像混合使用 DDIMScheduler 和固定噪声可实现图像 morphing

8.4 图像修复(inpainting)与局部编辑

方法名称语法用途代码示例注意事项
StableDiffusionInpaintPipelinefrom_pretrained("runwayml/stable-diffusion-inpainting")专用修复 pipelinefrom diffusers import StableDiffusionInpaintPipeline
pipe = StableDiffusionInpaintPipeline.from_pretrained("runwayml/stable-diffusion-inpainting").to("cuda")
模型专门训练
mask 输入PIL.Image 或 tensor指定需编辑区域白色(255)为重绘区,黑色为保留区形状与图像相同
image + mask 输入pipe(image=image, mask_image=mask, prompt=new_prompt)局部重绘result = pipe(
    prompt="a man with sunglasses",
    image=init_image,
    mask_image=mask,
    num_inference_steps=50
)
保持上下文一致性
边缘对齐mask 边缘应柔和或扩展避免明显边界可用高斯模糊处理 mask减少接缝
多次修复分区域逐步编辑复杂场景修改每次修复一小块避免全局失真
prompt 设计新提示应与原图协调如只改衣服颜色”red shirt” 而非完整描述保持其他元素不变
尺寸要求图像和 mask 必须为 512x512 或 8 的倍数否则自动 resize 可能变形建议预处理

8.5 控制生成(ControlNet 集成)

方法名称语法用途代码示例注意事项
加载 ControlNetControlNetModel.from_pretrained("lllyasviel/control_v11p_sd15_canny")加载控制模块from diffusers import ControlNetModel
controlnet = ControlNetModel.from_pretrained("lllyasviel/control_v11p_sd15_canny", torch_dtype=torch.float16)
多种类型可选
使用 ControlNetPipelineStableDiffusionControlNetPipeline集成 ControlNetfrom diffusers import StableDiffusionControlNetPipeline
pipe = StableDiffusionControlNetPipeline.from_pretrained(..., controlnet=controlnet).to("cuda")
需传入 controlnet
条件图像输入canny_map, depth_map, pose_map提供结构控制pipe(image=canny_map, prompt="house", controlnet_conditioning_scale=0.8)图像需预处理
多 ControlNet列表传入多个 controlnet组合控制pipe = StableDiffusionControlNetPipeline(..., controlnet=[canny, depth])
images = pipe(image=[canny_img, depth_img], ...).images
支持多条件
conditioning_scalefloatList[float]控制影响强度scale=0.5~1.0过高导致僵硬
预处理工具使用 OpenCV、Hough 等生成控制图如 Canny 边缘import cv2
edges = cv2.Canny(image, 100, 200)
需转换为 PIL
支持的 ControlNet 类型canny, depth, hed, normal, pose, scribble 等不同控制信号根据任务选择模型需匹配
训练自己的 ControlNet微调 controlnet 权重适配特定数据使用 train_controlnet.py 脚本需大量标注数据

第九部分:模型微调(Fine-tuning)技术

第9章 模型微调(Fine-tuning)技术

9.1 DreamBooth 微调原理与实现

概念/方法说明代码示例注意事项
核心思想通过少量图像(3~5 张)微调整个扩散模型,将新概念(如特定人物或物体)注入模型使用唯一标识符(如 sks)绑定新概念-
唯一标识符(Identifier)一个罕见词(如 sks)用于代表新概念在提示中使用 sks dog 表示微调后的对象避免常用词,防止语义冲突
先验保留损失(Prior Preservation Loss)防止语言漂移,同时训练新概念和类别先验(如 “dog”)鼓励模型保留原始语义必须使用 class_promptnum_class_images
训练流程冻结 VAE 和 UNet 大部分层,仅微调 UNet,可选使用 LoRA通常训练 800~2000 步需要较高显存
输入数据每张图像需对应一个文本描述,格式为 "a [identifier] [class]""a sks dog"描述应一致
超参数设置学习率 1e-6 ~ 2e-6,AdamW 优化器,batch size 1~2使用梯度累积显存不足时降低 batch
代码实现(Hugging Face)使用 train_dreambooth.py 脚本官方提供训练脚本accelerate launch train_dreambooth.py --pretrained_model_name_or_path="runwayml/stable-diffusion-v1-5" ...
输出结果微调后的模型可生成 sks dog in space 等新场景概念泛化能力强可能过拟合若数据太少

9.2 Textual Inversion 概念与训练流程

概念/方法说明代码示例注意事项
核心思想不修改模型权重,而是学习一个新词的嵌入向量(embedding)来表示新概念将新概念编码为 token embedding-
嵌入空间学习在 CLIP 文本编码器的 token embedding 空间中优化一个新向量新 token 如 <my-concept>维度为 768
训练目标最小化重建损失,使生成图像匹配输入图像使用先验保留损失防止漂移与 DreamBooth 类似
Token 初始化可随机初始化,或基于类别词(如 “dog”)的 embedding 微调initializer_token="dog"更快收敛
训练流程固定扩散模型,仅优化一个 embedding 向量显存占用极低(<5GB)适合消费级 GPU
代码实现使用 textual_inversion.py 脚本accelerate launch textual_inversion.py --learnable_property="object" ...支持 object/style 学习
使用方式训练后保存 .bin 文件,在推理时加载pipe.load_textual_inversion("my_concept.bin")可组合多个概念
局限性表达能力弱于 DreamBooth 或 LoRA仅学习 embedding,不调整模型结构复杂概念可能学不准

9.3 LoRA(Low-Rank Adaptation)微调方法

概念/方法说明代码示例注意事项
核心思想在原始权重旁添加低秩矩阵($A \cdot B$),仅训练 A 和 B参数量减少 90%+,高效微调-
数学原理$\Delta W = A \times B$,其中 $A \in \mathbb{R}^{d \times r}, B \in \mathbb{R}^{r \times k}, r \ll d,k$$r$ 为秩(rank),通常 4~64显著减少训练参数
注入位置通常应用于 UNet 中的 to_q, to_v, to_k, to_out 等 attention 层也可用于 FFN 层可配置 target_modules
训练过程冻结原始模型,仅训练 LoRA 参数显存占用低,支持消费级 GPU可结合梯度检查点
保存与加载仅保存 LoRA 权重(几 MB~100MB),而非完整模型lora.save_pretrained("my_lora")可跨基础模型使用
推理集成加载 LoRA 权重后,自动注入到 UNetpipe.unet.load_attn_procs("my_lora")无需修改 pipeline
多 LoRA 组合可叠加多个 LoRA 模块如风格 + 人物使用 alpha 控制权重
代码实现使用 peftfrom peft import LoraConfig, get_peft_modelHugging Face 原生支持

9.4 使用 PEFT 进行高效微调

方法名称语法用途代码示例注意事项
LoraConfigLoraConfig(..., r=4, lora_alpha=32, target_modules=["to_q", "to_v"])定义 LoRA 配置from peft import LoraConfig
config = LoraConfig(
    r=4,
    lora_alpha=32,
    target_modules=["to_q", "to_v"],
    lora_dropout=0.0,
    bias="none"
)
r 越大表达能力越强
get_peft_modelget_peft_model(model, config)包装模型以支持 PEFTunet_lora = get_peft_model(pipe.unet, config)返回可训练的 PEFT 模型
print_trainable_parameters打印可训练参数数量监控训练规模def print_trainable_parameters(model):
    trainable = sum(p.numel() for p in model.parameters() if p.requires_grad)
    total = sum(p.numel() for p in model.parameters())
    print(f"Trainable: {trainable}, %: {100 * trainable / total:.2f}")
确保只训练 LoRA
save_pretrainedmodel.save_pretrained(save_dir)保存 PEFT 模型unet_lora.save_pretrained("./lora_weights")仅保存适配器
load_peft_modelPeftModel.from_pretrained(model, "./lora_weights")加载 PEFT 模型unet_loaded = PeftModel.from_pretrained(pipe.unet, "./lora_weights")需原始模型
enable_gradient_checkpointingmodel.enable_gradient_checkpointing()降低显存unet_lora.enable_gradient_checkpointing()训练时使用
支持的 PEFT 方法LoRA, IA³, AdaLora, Prefix Tuning 等不同高效微调方法PEFT 支持多种LoRA 最常用

9.5 微调过程中的数据准备与训练配置

项目说明推荐配置注意事项
图像数量DreamBooth: 310 张;Textual Inversion: 35 张;LoRA: 10~50 张质量优于数量避免重复或低质图像
图像质量高分辨率(512x512),清晰,主体居中JPG/PNG 格式可缩放但避免模糊
文本标注每张图像对应一个 prompt,格式 "a [identifier] [class]""a sks dog"保持一致性
类别先验图像用于 prior preservation loss自动生成 200~300 张同类图像如 “dog” 的通用图像
训练轮数(Steps)DreamBooth: 8002000;LoRA: 10005000根据数据量调整过多导致过拟合
学习率AdamW: 1e-6 (DreamBooth), 1e-4 (LoRA)使用线性衰减或 cosine初始值敏感
Batch Size1~4,取决于显存使用梯度累积模拟大 batchgradient_accumulation_steps=4
优化器AdamW 或 AdamW8bit(节省显存)bitsandbytes 支持 8-bit 优化器推荐使用
数据增强一般不推荐可能破坏概念一致性保持原始视角和光照
验证方式定期生成图像检查效果如每 100 步生成 sks dog in space观察是否过拟合或漂移

第十部分:模型部署与优化

第10章 模型部署与优化

10.1 将 Diffusers 模型导出为 ONNX 或 TorchScript

方法名称语法用途代码示例注意事项
ONNX Exportdiffusers.onnx_export导出为 ONNX 格式from diffusers import OnnxStableDiffusionPipeline
OnnxStableDiffusionPipeline.from_pretrained("runwayml/stable-diffusion-v1-5", provider="CPUExecutionProvider").save_pretrained("onnx/")
支持 CPU/GPU 推理
TorchScripttorch.jit.tracescript导出为 TorchScripttraced_model = torch.jit.trace(unet, example_inputs)
torch.jit.save(traced_model, "unet.pt")
需固定输入形状
动态轴处理ONNX 中设置 dynamic_axes支持变长输入dynamic_axes={"sample": {0: "batch", 2: "height", 3: "width"}}否则输入固定
子模块导出可分别导出 VAE、UNet、Text Encoder灵活部署逐个模块导出并组合注意接口对齐
依赖安装onnx, onnxruntime运行 ONNX 模型pip install onnx onnxruntimeGPU 需 onnxruntime-gpu
精度问题FP16 可能导致数值误差导出时指定 torch.float16测试输出一致性
不支持操作某些 PyTorch 操作无法导出如部分 control flow需重写或替换
验证导出模型加载并运行推理确保输出合理与原始模型对比

10.2 使用 Diffusers + Gradio 构建 Web 演示

方法名称语法用途代码示例注意事项
Gradio Interfacegr.Interface(fn, inputs, outputs)创建交互界面import gradio as gr
def generate(prompt):
    image = pipe(prompt).images[0]
    return image
gr.Interface(fn=generate, inputs="text", outputs="image").launch()
快速原型
自定义组件gr.Textbox, gr.Slider, gr.Image精细化控制inputs = [
    gr.Textbox(label="Prompt"),
    gr.Slider(minimum=1, maximum=50, value=20, label="Steps")
]
提升用户体验
并发控制concurrency_count限制同时请求数.launch(concurrency_count=2)防止显存溢出
队列机制queue()异步处理请求.launch().queue()适合高延迟模型
加载模型缓存全局加载一次避免重复加载pipe = DiffusionPipeline.from_pretrained(...).to("cuda")放在函数外
错误处理try-except 包裹生成函数提升鲁棒性try: ... except Exception as e: return str(e)避免崩溃
部署到 Spaces推送到 Hugging Face免费托管git push 到 Spaces 仓库支持 Docker
性能优化启用 fp16, xformers加快生成速度pipe.enable_attention_slicing()
pipe.enable_xformers_memory_efficient_attention()
必要时使用

10.3 模型量化与推理加速(FP16, INT8)

技术说明代码示例注意事项
FP16 推理使用半精度浮点数显存减半,速度提升pipe = pipe.to(torch.float16)
pipe.unet.half() # 确保所有模块为 fp16
xFormers内存高效注意力降低显存占用pipe.enable_xformers_memory_efficient_attention()
Attention Slicing分块计算注意力降低峰值显存pipe.enable_attention_slicing()
VAE Slicing分块解码处理大 batchpipe.enable_vae_slicing()
VAE Tiling分块处理超大图像支持 >1024x1024pipe.enable_vae_tiling()
INT8 量化使用 8 位整数极大降低显存使用 transformersload_in_8bit=True
模型剪枝移除冗余权重实验性需重新训练或微调
TensorRTNVIDIA 高性能推理极致优化使用 torch2trt 或官方工具

10.4 分布式推理与批量生成优化

方法说明代码示例注意事项
批量生成一次生成多张图像提高吞吐量prompts = ["cat", "dog", "bird"]
images = pipe(prompts).images
动态批处理服务器端合并请求提升 GPU 利用率需自定义服务框架
模型并行将模型分片到多 GPU处理大模型pipe.to("cuda:0"), unet.to("cuda:1")
数据并行多 GPU 同时处理不同 batch常用于训练推理中较少用
异步生成使用线程或协程提高响应速度async def generate(...)
内存优化启用 slicing, tiling, fp16降低单次消耗组合使用
缓存机制缓存常用 prompt 的 latent加快响应适用于固定内容生成
负载均衡多实例部署 + 负载均衡器支持高并发如 Nginx + 多个 Gradio 实例

10.5 部署到 Hugging Face Spaces 或云平台

平台部署方式优点注意事项
Hugging Face SpacesGit 推送代码(Gradio/Streamlit)免费,集成模型仓库免费实例有休眠限制
GitHub + Docker编写 Dockerfile 并部署灵活控制环境需自行托管
AWS SageMaker使用 Hugging Face DLC 镜像企业级,可扩展成本较高
Google Cloud Run容器化部署自动扩缩容适合轻量服务
Azure ML集成 MLOps企业支持复杂配置
Replicate上传模型即服务简单,按调用付费平台抽成
配置文件app.py, requirements.txt, Dockerfile, README.md标准化部署必须包含依赖
环境变量设置 HF_TOKEN用于下载私有模型安全存储
冷启动优化预加载模型减少首次延迟app.py 中全局加载
监控与日志添加日志输出便于调试记录生成时间、错误等

第十一部分:自定义扩散模型开发

第11章 自定义扩散模型开发

11.1 从零构建一个简单的 DDPM 模型

概念/组件说明注意事项
UNet 去噪网络主干网络,预测噪声输入:$x_t$, $t$;输出:噪声残差
时间步嵌入(Timestep Embedding)将时间步 $t$ 编码为向量使用正弦位置编码或 MLP
正向扩散过程固定过程:逐步添加高斯噪声$x_t = \sqrt{\bar{\alpha}_t} x_0 + \sqrt{1 - \bar{\alpha}_t} \epsilon$,$\alpha_t$ 预定义
反向去噪过程学习从 $x_t$ 恢复 $x_{t-1}$UNet 预测噪声 $\epsilon_\theta(x_t, t)$
模型定义自定义 DDPMUNet继承 nn.Module,支持时间步输入
输入输出$x$: [B,C,H,W], $t$: [B],输出预测噪声归一化输入到 [-1,1]
损失函数均方误差(MSE)$F.mse_loss(noise_pred, noise_true)$

简单 DDPM UNet 示例:

import torch
import torch.nn as nn

class DDPMUNet(nn.Module):
    def __init__(self):
        super().__init__()
        self.conv1 = nn.Conv2d(3, 64, 3, padding=1)
        self.time_embed = nn.Embedding(1000, 64)
        self.relu = nn.ReLU()
        self.conv2 = nn.Conv2d(64, 3, 3, padding=1)

    def forward(self, x, t):
        h = self.relu(self.conv1(x))
        t_emb = self.time_embed(t).view(-1, 64, 1, 1)
        h = h + t_emb  # 简单融合
        return self.conv2(h)

11.2 自定义训练循环与损失函数

方法名称语法用途注意事项
训练循环结构for epoch in range(epochs):
    for batch in dataloader:
控制训练流程实现完整训练流程
噪声调度预计算 $\alpha_t$, $\bar{\alpha}_t$用于正向扩散betas = torch.linspace(1e-4, 0.02, T)
损失变体L1、Huber、VLB替代 MSEloss = F.smooth_l1_loss(...),Huber 更鲁棒
梯度裁剪torch.nn.utils.clip_grad_norm_稳定训练防止梯度爆炸
学习率调度torch.optim.lr_scheduler动态调整 LRscheduler = StepLR(optimizer, step_size=10, gamma=0.9)
模型保存torch.save(model.state_dict(), path)持久化训练结果包含 model, optimizer, epoch
验证与可视化定期生成图像监控训练效果使用 no_grad()

训练循环示例:

betas = torch.linspace(1e-4, 0.02, T)  # 常用线性或余弦调度
alphas = 1 - betas
alpha_bars = torch.cumprod(alphas, dim=0)

model.train()
for x, _ in train_loader:
    x = x.to(device) * 2.0 - 1.0  # [0,1] -> [-1,1]
    t = torch.randint(0, T, (x.size(0),), device=device)
    noise = torch.randn_like(x)
    x_t = sqrt_alpha_bar[t] * x + sqrt_one_minus_alpha_bar[t] * noise
    noise_pred = model(x_t, t)
    loss = F.mse_loss(noise_pred, noise)
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

11.3 使用 Diffusers 训练自定义数据集

方法名称语法用途代码示例注意事项
数据加载torchvision.datasets.ImageFolder加载本地图像from torchvision import transforms
dataset = ImageFolder("path/to/data",
    transform=transforms.Compose([
        transforms.Resize((512, 512)),
        transforms.ToTensor()
    ])
)
dataloader = DataLoader(dataset, batch_size=4, shuffle=True)
图像需为 .jpg.png
Diffusers 训练脚本train_text_to_image.py官方训练脚本accelerate launch train_text_to_image.py --dataset_name "my_dataset" ...支持多种任务
文本标注使用 caption.txtmetadata.jsonl提供 prompt每张图像对应一行文本格式必须正确
Tokenizer 编码tokenizer(prompt, padding="max_length")批量编码文本input_ids = tokenizer(prompts, max_length=77, padding="max_length", return_tensors="pt").input_ids与模型匹配
训练配置TrainingArguments设置超参数args = TrainingArguments(
    output_dir="output",
    per_device_train_batch_size=4,
    num_train_epochs=10,
    learning_rate=1e-4,
    report_to="tensorboard"
)
使用 accelerate 配置分布式
模型初始化UNet2DModelUNet2DConditionModel根据任务选择unet = UNet2DConditionModel.from_pretrained("runwayml/stable-diffusion-v1-5", subfolder="unet")可加载预训练权重
分布式训练Accelerator多 GPU/TPU 训练from accelerate import Accelerator
accelerator = Accelerator(mixed_precision="fp16")
unet, optimizer, dataloader = accelerator.prepare(unet, optimizer, dataloader)
推荐使用
日志与监控TensorBoard, WandB跟踪训练过程accelerator.log({"loss": loss})便于调试

11.4 实现新的调度算法

调度算法说明代码示例(关键逻辑)注意事项
继承 SchedulerMixin所有调度器需继承该类from diffusers import SchedulerMixin实现必要接口
关键方法step(), add_noise(), set_timesteps()定义扩散行为-
自定义调度器MyCustomScheduler实现所有抽象方法-
注册调度器添加到 configuration.json使其可被 from_pretrained 加载或手动传入 pipeline
数值稳定性避免除零或溢出使用 clamp 或 log 技巧特别在计算 $\sigma$ 时
测试新调度器在 pipeline 中替换pipe.scheduler = MyCustomScheduler()验证生成效果
支持动态步数set_timesteps 应支持任意 num_inference_steps用于不同采样步数提升灵活性

自定义调度器示例:

class MyCustomScheduler(SchedulerMixin):
    def __init__(self, num_train_timesteps=1000):
        super().__init__()
        self.num_train_timesteps = num_train_timesteps
        # 定义 beta, alpha, etc.

    def add_noise(self, original_samples, noise, timesteps):
        # 实现正向扩散
        return noisy_samples

    def step(self, model_output, timestep, sample):
        # 实现单步去噪
        prev_sample = ...
        return prev_sample

    def set_timesteps(self, num_inference_steps):
        # 设置推理时间步
        self.timesteps = torch.linspace(0, self.num_train_timesteps - 1, num_inference_steps).long()

11.5 扩展 Pipeline 支持新任务(如超分、去噪)

任务类型实现方式代码示例注意事项
超分辨率(Super-Resolution)使用 DDPMSuperResPipeline 或自定义from diffusers import DDPMSuperResPipeline
pipe = DDPMSuperResPipeline.from_pretrained("google/ddpm-cifar10-32")
low_res_img = Image.open("low_res.png")
high_res_img = pipe(image=low_res_img).images[0]
需训练超分扩散模型
图像去噪(Denoising)将噪声图作为输入,反向生成干净图类似 DDPM 推理假设噪声水平已知
自定义 Pipeline 类继承 DiffusionPipeline必须调用 register_modules-
注册模块register_modules(**kwargs)管理可序列化组件便于 save_pretrained
保存与加载save_pretrained(), from_pretrained()持久化 pipeline所有模块需支持
输入输出设计明确定义 __call__ 接口image, mask, condition提升易用性
与现有组件集成复用 UNet、VAE、Scheduler避免重复造轮子推荐方式

自定义 Pipeline 类示例:

from diffusers import DiffusionPipeline

class MyTaskPipeline(DiffusionPipeline):
    def __init__(self, unet, vae, scheduler):
        super().__init__()
        self.register_modules(unet=unet, vae=vae, scheduler=scheduler)

    def __call__(self, input_data, num_inference_steps=50):
        self.scheduler.set_timesteps(num_inference_steps)
        sample = input_data
        for t in self.scheduler.timesteps:
            ...  # 去噪循环
        return sample

第十二部分:生态集成与扩展

第12章 生态集成与扩展

12.1 与 Transformers 库的无缝集成

集成方式说明代码示例注意事项
共享 tokenizer使用 CLIPTokenizerfrom transformers import CLIPTokenizerDiffusers 内部使用相同实现
文本编码器CLIPTextModeltext_encoder = CLIPTextModel.from_pretrained("openai/clip-vit-large-patch14")可替换为其他文本模型
跨库模型加载直接传入 pipelinepipe = StableDiffusionPipeline.from_pretrained("runwayml/stable-diffusion-v1-5", text_encoder=text_encoder)架构需兼容
多模态任务结合 NLP 模型生成 prompt如使用 T5 或 BART 生成描述实现文本到图像的端到端
特征提取使用 transformers 模型提取图像/文本特征用于损失计算或条件输入如 CLIP score
分词一致性确保 tokenizer 配对clip-vit 配 clip tokenizer避免编码错误
设备同步所有模型在同一设备.to("cuda")否则报错
保存统一模型save_pretrained 保存整个 pipeline包含所有组件便于共享

12.2 与 Accelerate 库协同进行分布式训练

方法名称语法用途代码示例注意事项
初始化 AcceleratorAccelerator()管理分布式状态from accelerate import Accelerator
accelerator = Accelerator(mixed_precision="fp16", gradient_accumulation_steps=2)
自动处理设备、精度、分布式
准备模型与优化器accelerator.prepare()包装并分发model, optimizer, dataloader = accelerator.prepare(model, optimizer, dataloader)必须使用返回对象
梯度累积内置支持模拟大 batch设置 gradient_accumulation_steps减少 optimizer.step() 频率
混合精度训练mixed_precision="fp16"加速并省显存Accelerator 中启用自动处理缩放
模型保存accelerator.save()正确保存模型accelerator.save(model.state_dict(), "model.pth")避免多卡重复保存
日志记录accelerator.log()统一记录accelerator.log({"loss": loss}, step=global_step)支持 TensorBoard/WandB
分布式数据加载accelerator.prepare(dataloader)自动分片数据每个进程获取子集无需手动 DistributedSampler
多节点训练使用 accelerate launch跨多台机器accelerate launch --num_machines=2 train.py需配置网络

12.3 使用 Diffusers Hub 模型与上传自定义模型

操作语法用途代码示例注意事项
下载模型from_pretrained()加载 Hub 模型pipe = StableDiffusionPipeline.from_pretrained("runwayml/stable-diffusion-v1-5")需登录 huggingface-cli login
上传模型push_to_hub()发布模型pipe.push_to_hub("my-sd-model", commit_message="Initial release")需有仓库写权限
创建仓库create_repo()初始化远程仓库from huggingface_hub import create_repo
create_repo("my-sd-model", private=False)
可设为私有
上传配置文件save_pretrained()保存并上传pipe.save_pretrained("./my_model")
pipe.push_to_hub("my-sd-model")
自动上传 config.json
私有模型private=True限制访问pipe.push_to_hub("my-secret-model", private=True)仅自己可见
模型版本控制Git 提交历史管理迭代每次 push 生成新 commit支持 revert
缓存管理--local_files_only强制使用本地缓存from_pretrained(..., local_files_only=True)离线环境使用
安全令牌use_auth_token访问私有模型from_pretrained(..., use_auth_token=True)或设置 HF_TOKEN 环境变量

12.4 社区模型与第三方扩展(如 ControlNet, T2I-Adapter)

扩展名称用途加载方式注意事项
ControlNet条件控制(边缘、深度、姿态等)ControlNetModel.from_pretrained("lllyasviel/control_v11p_sd15_canny")需与 pipeline 集成
T2I-Adapter轻量级条件适配器T2IAdapter.from_pretrained("TencentARC/t2i-adapter-style-sketch-sd15v1")参数量小,易训练
IP-Adapter图像提示控制IPAdapter.from_pretrained(pipe, "h94/IP-Adapter", subfolder="models")实现图像到图像的语义控制
DeepFloyd IF分阶段文本到图像使用 IFPipeline支持超高分辨率
Kandinsky多模态扩散模型KandinskyPipeline支持潜在插值
AnimateDiff生成视频结合 UNet 时序层用于动画生成
LCM-LoRA轻量级蒸馏 LoRA加速推理至 4 步内load_lora_weights
社区模型来源Hugging Face Hub搜索 “stable-diffusion”, “controlnet” 等注意许可证(如 NSFW)
兼容性检查基础模型版本如 SD 1.5 vs SDXL权重不通用

12.5 最佳实践与常见问题汇总

类别最佳实践 / 常见问题解决方案注意事项
显存不足OOM 错误使用 fp16, xformers, attention_slicing, batch_size=1组合使用更有效
生成质量差图像模糊、畸形检查 prompt、增加步数、调整 guidance_scale、使用 better checkpoint数据质量是关键
文本不相关忽略 prompt提高 guidance_scale(7~12),优化 prompt 描述避免模糊词汇
训练过拟合生成图像与训练集几乎相同减少训练步数,增加先验保留损失,使用 LoRA 而非 DreamBooth监控验证集
负面提示无效不期望内容仍出现显式添加负面词,提高 guidance_scale如 “blurry, text, deformed”
模型加载慢from_pretrained 耗时使用 local_files_only,或缓存到本地Hub 下载受网络影响
ONNX 导出失败不支持操作使用 diffusers 官方导出脚本,或改用 TorchScript检查动态轴设置
分布式训练错误进程通信失败使用 accelerate launch 而非直接运行正确配置 config.yaml
推理速度慢生成时间过长使用 fp16, xformers, DDIM 或 DPM-Solver++, LoRA避免 PNDM
模型上传失败权限或网络问题检查 huggingface-cli login,使用 HF_TOKEN,重试大文件建议使用 git lfs