news 2026/10/7 10:18:24

扩散模型原理详解:从加噪去噪到图像与视频生成

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
扩散模型原理详解:从加噪去噪到图像与视频生成

在生成图片、生成视频的 AI 工具集中爆发的 2023-2025 年,扩散模型(Diffusion Model)几乎成了所有主流图像生成产品的共同底座。从 Midjourney 的绘图质量,到 Stable Diffusion 的开源生态,再到各类可控视频生成工具的帧间一致性,背后都离不开“加噪-去噪”这套核心机制。

本文将作为扩散模型专题的“上篇”,重点拆解 AI 图像与视频生成的底层原理:扩散模型为什么能生成图、图像生成和视频生成的架构差异在哪里、一个最小可运行的扩散模型究竟怎么写。文章不要求读者有扎实的数学基础,只需要了解基本的 Python 和 PyTorch 操作即可。学完后,你会对 “Stable Diffusion 为什么叫 Diffusion”“视频生成为什么比图像生成难这么多” 这类问题有清晰的答案。

1. 为什么我们需要扩散模型

1.1 生成模型的老问题是“既要像、又要多样”

在扩散模型成为主流之前,图像生成领域主要由两类模型承担:生成对抗网络(GAN)和变分自编码器(VAE)。

GAN 的思路是让生成器和判别器相互博弈。生成器负责把随机噪声变成图片,判别器负责判断图片是真是假。训练到理想状态时,生成器造出的图片连判别器都分不出真假。GAN 的优点是生成速度快、图像风格清晰,但短板同样明显:训练不稳定,容易出现模式坍塌,也就是生成器只学会了少数几种看起来不错的图,多样性不够。

VAE 的思路则偏向“编码-解码”。输入图片先被编码成潜在向量,再被解码回图片,训练时要求潜在向量服从某种先验分布。VAE 训练稳定、潜在空间连续,但生成的图片往往偏模糊,细节不足。

扩散模型换了一个角度:与其一开始就尝试“无中生有”,不如学习“逆着破坏过程还原”。它先把一张真实图片逐步加噪声,直到变成近乎纯噪声;然后训练一个网络,学会从噪声中一步步把图片恢复出来。这个思路看起来简单,却同时解决了 GAN 的训练不稳定问题和 VAE 的细节模糊问题,因此迅速成为图像生成的主流方案。

1.2 扩散模型解决的核心问题

从宏观视角看,扩散模型解决的核心问题是:

  • 从噪声分布到数据分布的映射。训练完成后,任意采样一组高斯噪声,经过多次迭代去噪,就能得到一张符合训练数据风格的图像。
  • 细粒度控制。通过在去噪过程中注入条件信息,可以让模型生成指定类别、指定文本描述的图片,甚至控制姿态、构图和景深。
  • 高保真度与高多样性平衡。扩散模型不依赖对抗博弈,生成结果天然具有更好的多样性;配合大模型容量和海量训练数据,细节保真度也远超早期生成模型。

1.3 扩散模型与 GAN、VAE 的直观对比

维度GANVAE扩散模型
训练稳定性容易模式坍塌较稳定稳定
图像细节好偏模糊最好
生成速度快快慢(需多步采样)
模式覆盖容易窄化较宽宽
可控条件注入较难一般灵活(文本、掩码、深度图)

需要注意的是,速度是扩散模型的主要短板。一张 512x512 图片在普通显卡上可能需要几秒到几十秒,而 GAN 可以做到实时。这也是后来“加速采样器”“蒸馏模型”等优化方向要解决的核心矛盾。

2. 扩散模型的两条路:加噪与去噪

2.1 前向扩散过程:把图片一点点毁掉

扩散模型里有两个相反过程,第一个叫前向过程(Forward Process),也叫扩散过程。

假设我们有一张原始图片 ( x_0 ),前向过程会在一系列时间步 ( t = 1, 2, ..., T ) 上,逐步往图片里加入高斯噪声。时间步越大,噪声越强,图片越模糊,最后近似变成一张纯高斯噪声图。

每一步的数学描述可以概括为:

[ x_t = \sqrt{\bar{\alpha}_t} \cdot x_0 + \sqrt{1 - \bar{\alpha}_t} \cdot \epsilon ]

其中 ( \epsilon ) 是从标准正态分布中采样的噪声,( \bar{\alpha}_t ) 是由噪声调度表计算出的衰减系数。直观理解是:原始信号占比随着 ( t ) 增大而下降,噪声占比上升。

在代码实现里,前向过程往往不是真的循环 T 次,而是利用公式一步直接得到任意时间步 ( t ) 下的加噪图片。这样训练时会非常高效。

2.2 逆向去噪过程:训练一个“噪声预测器”

有了被破坏的图片,我们希望还原。但我们并不知道破坏过程中每一步具体用的是哪个噪声,所以需要训练一个神经网络去预测它。

这个网络通常写作 ( \epsilon_\theta(x_t, t) ),输入是“加噪后的图片”和“时间步信息”,输出是“模型预测的噪声”。网络训练好之后,就可以从纯噪声开始,不断执行:

[ x_{t-1} = \text{根据} x_t \text{和预测噪声} \epsilon_\theta \text{反推得到的上一时间步状态} ]

多步迭代,最终得到清晰的图片。

这里有个初学者容易困惑的点:网络究竟学习的是什么?它学习的不是“如何画一只猫”,而是一个更小的任务——“从加了噪声的猫图里,把噪声分量分离出来”。当模型能准确预测噪声时,它实际上就隐式学会了猫的长相、纹理、颜色分布等数据规律。正如一句话所说:要预测“什么是噪声”,首先得知道“什么是信号”。

2.3 噪声调度与训练目标

噪声调度(Noise Schedule)决定了每个时间步加入多少噪声。常见的调度有:

  • 线性调度:从较小的 beta 值线性增加到较大的 beta 值。早期 DDPM 使用这种方式。
  • 余弦调度:噪声变化更平滑,训练更稳定,在很多开源模型中被广泛采用。
  • 缩放调度:根据数据分布调整噪声水平,常用于潜在扩散模型。

训练目标最简洁的形式是:

[ L = ||\epsilon - \epsilon_\theta(x_t, t)||^2 ]

也就是让模型预测的噪声与真实噪声之间的均方误差越小越好。这个损失函数写法简单,却非常有效,是扩散模型训练中最常见的损失形式。

2.4 采样节奏:从 DDPM 到 DDIM

训练时我们往往使用 1000 个时间步,但在推理时如果也迭代 1000 次,生成速度会非常慢。于是出现了很多采样加速方法:

  • DDPM 采样:按原始时间步逐级反向去噪,质量高但速度慢。
  • DDIM(Denoising Diffusion Implicit Models):允许跳步采样,可以用 20-50 步生成质量不错的图片。它把采样过程从“随机过程”改成“确定性过程”,还带来了潜在空间的插值能力。
  • DPM-Solver、DPM++ 等现代采样器:基于微分方程数值求解的思路,用更少的步数获得高质量结果。ComfyUI、Stable Diffusion WebUI 里的采样器选项,本质就是这一层算法选择。

理解采样器的意义后,再回头看“为什么不同采样器出图效果不一样”“步数设多少合适”这些问题,就会清楚很多。

3. 图像生成中的三大设计

3.1 从像素空间到潜在空间

纯粹在像素空间做扩散,计算量非常巨大。一张 1024x1024 的 RGB 图片,意味着网络要处理百万级像素的每一位。为了降低计算成本,Stable Diffusion 等模型的思路是先做一个VAE 编码器,把 512x512 的图片压缩成 64x64 的潜在特征图,再在潜在特征空间做扩散,最后用 VAE 解码器恢复成像素图片。

这就是潜在扩散模型(Latent Diffusion Model,LDM)的核心思想:扩散过程不直接发生在像素空间,而是发生在低维潜在空间。这也是为什么很多人说“Stable Diffusion 的王牌一半来自 VAE”。

这样做的好处非常明显:

  • 计算量大幅下降,普通消费级显卡可以运行;
  • 潜在空间更容易表达高层的语义特征;
  • 解码器能把潜在特征还原成细节丰富的图像。

3.2 条件控制:文本、类别与无分类器引导

扩散模型真正走进大众视野,靠的是“文本生成图像”能力。怎么把文本信息输入到去噪网络?

目前主流的做法是Cross-Attention(交叉注意力)。文本先经过文本编码器(比如 CLIP 的文本编码器)得到文本向量,然后在 UNet 的每个注意力层中与图像特征做交叉注意力,让每一层去噪过程都能参考文本提示(Prompt)。

同时,为了让模型对文本提示更“听话”,研究者提出了无分类器引导(Classifier-Free Guidance,CFG)。具体方式是:训练时同时让网络学习“带条件的去噪”和“不带条件的去噪”,推理时按下式组合:

[ \epsilon_{\text{final}} = \epsilon_{\text{uncond}} + \text{guidance_scale} \cdot (\epsilon_{\text{cond}} - \epsilon_{\text{uncond}}) ]

当 guidance_scale 大于 1 时,模型会更贴合文本条件;但设置过大也会导致色彩过饱和、构图失真。这就是 WebUI 里“提示词相关性(CFG Scale)”参数背后的原理。

3.3 采样器与步数权衡

图像生成不是“步数越多越好”。步数过多时,采样器可能引入额外噪声,也可能让画面产生不自然纹理。实际项目中:

  • 低步数(10-20 步)适合快速草稿、实时交互;
  • 中步数(20-30 步)是大多数高质量出图的常用范围;
  • 高步数(50 步以上)对部分采样器收益不大。

具体最优步数要结合采样器类型和模型训练配置来测,不能简单照搬别人的参数。

4. 视频生成:多了一维时间

4.1 视频生成与图像生成的本质差异

视频生成可以看作“图像生成 + 时间一致性”。每一帧都需要清晰合理,同时帧与帧之间还要保证物体运动连续、人物身份一致、场景光照一致。

这是视频生成远比图像生成困难的核心原因。对图像生成来说,模型只需要生成静态分布;对视频生成来说,模型必须在更高维的“图像序列空间”中保持时间和空间的双重一致性。

4.2 时空联合扩散

一类主流方案是直接把扩散模型扩展到三维时空:

  • 输入不再是单张潜在特征图,而是多帧图像堆叠成的视频潜在张量;
  • 网络结构在原有 UNet 基础上增加时间注意力(Temporal Attention)或3D 卷积,让模型同时建模空间结构信息与时间运动信息;
  • 训练数据从“单张图片”换成“视频片段”。

这种方案的优点是端到端、语义一致性强,缺点是对显存和训练数据要求极高。为了让普通设备也能运行,很多视频模型会把空间生成和时间建模拆开,先做空间生成,再做时间对齐。

4.3 先图像后视频的两阶段方案

另一种常见思路是把“文本到视频”拆成两步:

  1. 首先生成关键帧或首帧。用图像生成模型确定画面的主体、风格、构图。
  2. 再补全中间帧或生成运动序列。用一个条件模型,在已有帧的基础上生成后续帧,保持内容一致。

这个思路对应很多实际工具里的“图生视频”“帧插值”功能。它最大的优点是复用成熟的图像生成模型,计算成本相对可控;缺点是长视频累积误差明显,画面可能逐渐漂移。

4.4 一致性与资源开销问题

视频生成需要额外关注几个工程问题:

  • 上下文长度:视频是连续帧序列,模型需要足够的“时间上下文”才能理解运动规律。
  • 首尾循环:很多模型默认生成循环视频,训练数据如果不支持首尾衔接,就会在闭环处出现跳变。
  • 显存瓶颈:视频张量比图像张量大一个数量级,通常需要使用上下文并行、模型并行、混合精度训练等手段。

从趋势上看,视频生成正在从“贴片式拼接”走向“原生时空联合建模”,但距离图像生成那么成熟的生态还有一段路。

5. 最小可运行的扩散模型实战

下面我们用 PyTorch 实现一个极简扩散模型。为了便于理解,这里不生成图片,而是让模型学会从一个形变的二维高斯分布中采样。麻雀虽小,但加噪、去噪网络、训练、采样四个环节全部保留。

5.1 示例目标与网络选型

在 2D 数据点上做扩散,去噪网络只需要一个带时间嵌入的多层感知机(MLP)。这个结构和图像领域的 UNet 在思想上完全一致:输入时间步编码和带噪样本,输出预测噪声。

完整代码逻辑如下。

5.2 数据准备与加噪

import numpy as np import torch import torch.nn as nn import torch.nn.functional as F from torch.utils.data import DataLoader, TensorDataset # 生成一个经过线性变换的二维高斯分布,共 20000 个样本 np.random.seed(0) data = np.random.randn(20000, 2) @ np.array([[2.0, 0.5], [0.5, 1.0]]) dataset = TensorDataset(torch.from_numpy(data).float()) loader = DataLoader(dataset, batch_size=256, shuffle=True) # 线性噪声调度 def linear_beta_schedule(timesteps=500, beta_start=1e-4, beta_end=0.02): return torch.linspace(beta_start, beta_end, timesteps) betas = linear_beta_schedule() alphas = 1.0 - betas alpha_bars = torch.cumprod(alphas, dim=0)

前向加噪函数q_sample接收原始样本和时间步索引,直接返回加噪结果和真实噪声。

def q_sample(x_start, t): noise = torch.randn_like(x_start) sqrt_alpha_bar = torch.sqrt(alpha_bars[t])[:, None] sqrt_one_minus_alpha_bar = torch.sqrt(1.0 - alpha_bars[t])[:, None] x_t = sqrt_alpha_bar * x_start + sqrt_one_minus_alpha_bar * noise return x_t, noise

这里的关键是理解alpha_bars[t]:它表示直到第 t 步时,原始信号保留的比例系数。

5.3 搭建去噪网络

网络包含两部分:时间步编码模块(TimeEmbedding)和主体 MLP。时间步编码让同一个网络能够感知“当前噪声有多重”,从而调整去噪策略。

class TimeEmbedding(nn.Module): def __init__(self, dim=16): super().__init__() self.dim = dim def forward(self, t): half = self.dim // 2 freqs = torch.exp( -np.log(10000) * torch.arange(half, dtype=torch.float32) / half ) args = t[:, None].float() * freqs[None, :] return torch.cat([torch.cos(args), torch.sin(args)], dim=-1) class SimpleDenoiser(nn.Module): def __init__(self, input_dim=2, hidden_dim=128, time_dim=16): super().__init__() self.time_embed = TimeEmbedding(time_dim) self.net = nn.Sequential( nn.Linear(input_dim + time_dim, hidden_dim), nn.ReLU(), nn.Linear(hidden_dim, hidden_dim), nn.ReLU(), nn.Linear(hidden_dim, input_dim), ) def forward(self, x, t): te = self.time_embed(t) h = torch.cat([x, te], dim=-1) return self.net(h)

5.4 训练

训练时随机抽取时间步 ( t ),对样本加噪,再让模型预测噪声,用均方误差计算损失。

model = SimpleDenoiser() optimizer = torch.optim.Adam(model.parameters(), lr=1e-3) epochs = 200 for epoch in range(epochs): total_loss = 0.0 for (xb,) in loader: t = torch.randint(0, len(betas), (xb.shape[0],), dtype=torch.long) x_t, noise = q_sample(xb, t) pred_noise = model(x_t, t) loss = F.mse_loss(pred_noise, noise) optimizer.zero_grad() loss.backward() optimizer.step() total_loss += loss.item() * xb.shape[0] if (epoch + 1) % 50 == 0: print(f"Epoch {epoch + 1}/{epochs}, Loss: {total_loss / len(dataset):.6f}")

5.5 采样生成

训练完成后,从纯噪声出发,按时间步从后往前逐步去噪。为了方便理解,代码直接实现了 DDPM 采样过程。

def p_sample(model, num_samples=16, device="cpu"): model.eval() x = torch.randn(num_samples, 2, device=device) for i in reversed(range(len(betas))): t = torch.full((num_samples,), i, dtype=torch.long, device=device) with torch.no_grad(): pred_noise = model(x, t) alpha = alphas[i] alpha_bar = alpha_bars[i] if i > 0: z = torch.randn_like(x) else: z = 0 # DDPM 反向传播更新公式 mean = (x - (1.0 - alpha) / torch.sqrt(1.0 - alpha_bar) * pred_noise) / torch.sqrt(alpha) x = mean + torch.sqrt(betas[i]) * z return x samples = p_sample(model, num_samples=16) samples_np = samples.numpy() print("生成的 16 个样本点如下:") print(samples_np)

5.6 运行提示与预期结果

  • 训练 200 个 epoch 后,损失会从几十降低到零点几甚至更低。
  • 采样得到的 16 个点应该大致符合原始数据分布的形状:整体呈椭圆形分布,主要方位沿 (2,0.5) 方向拉伸。
  • 如果损失不下降或采样点分布异常,优先检查学习率、训练步数和噪声调度。

代码里的网络、函数都是完整可运行的。你也可以把data替换成 MNIST 图像数据,把 MLP 换成一个简单的 UNet,就得到标准的 DDPM 图像生成流程了。

6. 常见问题与排查思路

问题现象常见原因解决思路
训练损失不下降学习率过大或过小;时间步编码维度不足降低学习率到 1e-4 量级,增加时间嵌入维度
采样结果全是噪声采样公式写错;时间步传入方向错误检查反向循环是否从大到小逐时间步执行,核对 alpha_bar 索引
生成结果多样性差训练数据太少或噪声调度范围不合适增加数据量,尝试余弦噪声调度
图像生成显存不足直接在像素空间做扩散,分辨率太高改用潜在扩散模型,或降低批量大小、开启梯度检查点
视频生成出现闪烁和漂移模型缺少时间注意力;上下文帧数不足增加帧间注意力模块,扩大时序上下文窗口
文本条件不生效条件特征没有正确注入网络;CFG 权重过低检查 Cross-Attention 输入,调高 CFG Scale
采样速度慢推理步数过高使用 DDIM 或 DPM++ 等加速采样器,降低到 20-30 步

7. 最佳实践与工程建议

7.1 技术选型与调参

实际项目中,不建议从零训练扩散模型,因为数据量和算力要求都非常高。更合理的路径是使用成熟的开源模型底座,再针对业务数据做微调:

  • 图像生成优先考虑 Stable Diffusion 生态,社区资源多,插件丰富。
  • 视频生成优先选择开源视频模型或商业 API,先验证效果再投入训练成本。
  • 微调时不要一开始就全量训练,先尝试 LoRA 等参数高效微调方案。

调参方面,先固定噪声调度和网络结构,再单独调整学习率、批量大小和时间步。每改动一个变量,记录一组结果,避免多变量同时变动导致无法定位问题。

7.2 数据、评测与日志

数据质量直接决定生成质量。训练数据需要经过清洗、去重、版权审查。对于视频模型,还要额外关注帧率、时长分布和镜头切换频率。评测时建议同时使用定量指标(如 FID、CLIP Score)和人工主观评分,因为生成结果“是否好看”无法完全用数值衡量。

训练日志至少记录:损失、学习率、当前 epoch、GPU 利用率、显存峰值。分布式训练时要保存全局步数,方便中途恢复。

7.3 生产落地注意事项

  • 资源规划:扩散模型推理比传统模型重,提前估算并发和显存需求,必要时使用模型并行和批处理。
  • 安全合规:生成内容必须经过审核,避免生成虚假信息、侵权内容或不当内容。涉及真实人物肖像时需获得授权。
  • 版本可控:模型权重、采样器、提示词模板需要版本化管理,方便回滚和复现。
  • 成本控制:视频生成的成本是图像生成的数倍甚至数十倍,在生产环境中要考虑缓存高频生成结果,减少重复计算。

8. 下一步学什么

读到这里,你已经掌握了扩散模型的核心原理:加噪、去噪、噪声预测、条件控制,以及视频生成中的时空建模思路。下一步可以从三个方向深入:

  1. 动手跑一个开源图像生成项目:从 Stable Diffusion WebUI 或 ComfyUI 开始,亲手调提示词、切换采样器、对比 CFG Scale 差异,把本文讲到的参数在实际环境里体会一遍。
  2. 深入 LDM 结构:阅读 Stable Diffusion 的 UNet 和 VAE 代码,理解潜空间扩散、Cross-Attention 的具体实现。
  3. 尝试微调与训练:准备一个小型数据集,用 LoRA 或全量微调方式训练自己的图像风格模型,理解不同超参数对生成效果的影响。

扩散模型依然在快速演进。视频生成、多模态生成、实时生成是目前最活跃的方向,也意味着大量工程问题值得研究。对于初入 AI 生成领域的开发者来说,先把加噪-去噪这条主线吃透,再去看各种层出不穷的新架构,就不会被概念泡沫带偏。

如果这篇文章对你有帮助,可以收藏备用。下一篇“扩散模型(下)”,我们会继续拆解 Stable Diffusion 与视频生成工程落地的详细方案,欢迎保持关注,也可以把你在扩散模型实践中遇到的问题写在评论区一起讨论。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/7 10:18:24

SpringBoot开源进销存ERP系统部署、避坑与二次开发实战拆解

简介:星云ERP是基于SpringBoot框架打造的开源免费进销存管理系统,面向中小企业,致力于解决开店、管理及数据统计难题,实现业务线上化、透明化与简易化。系统包含基础信息、商品中心、采购、销售、零售、库存、盘点、结算等核心模块…

作者头像 李华
网站建设 2026/10/7 10:18:14

配电现场RAG知识库:本地部署的中文语义检索方案

简介:本资源是一个面向电力行业基层配电工作人员的RAG工程实践项目,聚焦于解决大模型在专业领域知识准确性不足的问题,提供文档解析、向量存储、混合检索与智能问答一体化解决方案,适用于计算机相关专业学生、教师及企业技术人员开…

作者头像 李华
网站建设 2026/10/7 10:17:46

无需正版的26.X原版生存服务器:CloudRain稳定运营之道

开头(≥200字,需自然融入核心关键词)玩我的世界,尤其是JAVA版原版生存,最大的痛点不是不会玩,而是找不到一个能长久待下去的服务器。我见过太多玩家在几个服务器之间反复横跳,有的开服两周就人间…

作者头像 李华
网站建设 2026/10/7 10:17:42

中国喀斯特岩溶空间分布SHP矢量数据集:GIS叠加分析与面积统计实战

简介:这份中国喀斯特岩溶空间分布矢量数据集面向GIS从业者、地质地理研究者及环境规划人员,用于获取全国岩溶地块的边界与岩性属性信息,支撑地貌分析、农业规划、水利工程与旅游开发等场景。资源包共8个文件,约1.2MB,以…

作者头像 李华
网站建设 2026/10/7 10:17:36

基于Springboot+Vue的大型商场应急预案管理系统毕业设计实战指南

简介:这份资源是面向计算机专业应届生的Java毕业设计完整项目包,主题为基于SpringBoot与Vue的大型商场应急预案管理系统,适合需要高分毕设、课程设计或期末作业参考的本科与专科学生。项目已通过导师指导与答辩评审,获得97分成绩&…

作者头像 李华
网站建设 2026/10/7 10:17:06

大华Java SDK开发指南:基于JNA调用C库实现视频取流与录像

简介:面向需要对接大华视频监控设备的Java工程师,这份大华Java SDK开发资料包以Windows环境下Winform界面开发为例,提供了一套适合二次开发的完整工程模板。包内共3663个文件,压缩后约17.12MB,主要由3548个class编译类…

作者头像 李华