作为AI技术专家兼学习规划博主,我经常收到开发者的提问:
“南木,想做图像生成,该选GAN还是VAE?”
“Diffusion Model为什么能生成比GAN更细腻的图?”
“Stable Diffusion的文本引导是怎么实现的?能不能自己跑通代码?”

生成式AI(AIGC)的核心魅力,在于让机器从“识别数据”走向“创造数据”——从早期VAE生成模糊的低分辨率图像,到GAN实现高保真人脸生成,再到Diffusion Model掀起文本生成图像(Text-to-Image)的浪潮,生成式模型的每一次迭代,都在突破“机器创意”的边界。

这篇文章会以“技术演进+原理拆解+实战落地”为脉络,系统讲解三大主流生成式模型(VAE、GAN、Diffusion Model):从核心思想、数学原理,到优缺点对比,最后聚焦工业级应用——用PyTorch+Diffusers库实现Stable Diffusion的文本生成图像、图像优化、模型微调。全程贯穿“公式推导+代码注释+结果分析”,既适合初学者入门,也能为开发者提供实战参考。

同时需要学习规划、就业指导、技术答疑和系统课程学习的同学 欢迎扫码交流
在这里插入图片描述

一、生成式模型的核心目标:从“概率分布”到“创意生成”

在拆解具体模型前,我们先明确一个核心问题:生成式模型到底在做什么?

简单来说,生成式模型的目标是“学习真实数据的概率分布,然后从该分布中采样,生成新的、与真实数据相似的样本”。比如:

  • 图像生成:学习“真实猫图片”的分布,生成新的、不存在但逼真的猫图片;
  • 文本生成:学习“人类语言”的分布,生成通顺、有逻辑的句子;
  • 多模态生成:学习“文本-图像”的联合分布,根据文本描述(如“一只坐在月球上的兔子”)生成对应图像。

传统判别式模型(如CNN分类器、Transformer文本分类)只关注“判断样本属于哪个类别”,而生成式模型需要“还原数据的全貌”——这也是生成式模型更复杂、但应用场景更广阔的原因。

接下来,我们按“技术演进顺序”,逐个拆解VAE、GAN、Diffusion Model这三大里程碑式的生成模型。

二、生成式模型的“先行者”:VAE(变分自编码器)

VAE(Variational Autoencoder,变分自编码器)是2013年由Kingma和Welling提出的生成模型,核心思想是“通过自编码器结构,结合变分推断,学习数据的潜在概率分布”。它是第一个能稳定生成多样化样本的模型,为后续生成式模型奠定了基础。

2.1 VAE的核心思想:“概率化”的自编码器

传统自编码器(Autoencoder)由“编码器(Encoder)”和“解码器(Decoder)”组成:

  • 编码器:将高维输入(如28×28的MNIST图像)压缩为低维 latent 向量(如10维);
  • 解码器:将 latent 向量解压,还原为与输入维度一致的输出;
  • 训练目标:最小化“输入与输出的重构误差”(如MSE)。

但传统自编码器有个致命缺陷:latent 空间不连续,无法用于生成新样本——比如随机采样一个 latent 向量,解码器可能生成无意义的图像。

VAE的改进在于:将 latent 向量的生成“概率化”——不再让编码器输出确定的 latent 向量,而是输出 latent 向量的“均值(μ)”和“方差(σ²)”,然后从该正态分布中随机采样得到 latent 向量。这样一来,latent 空间是连续的,任意采样的 latent 向量都能生成有意义的样本。

2.2 VAE的结构与数学原理:3步理解生成过程

VAE的生成过程可分为“编码-采样-解码”三步,配合“重构损失+KL散度损失”训练,确保生成样本既逼真又多样。

步骤1:编码(Encoder):输出 latent 分布的参数

编码器接收输入样本 ( x )(如图像),通过神经网络(如CNN)输出两个向量:

  • 均值向量 ( \mu(x) ):维度为 ( d_{\text{latent}} )(如10);
  • 对数方差向量 ( \log\sigma^2(x) )(用对数避免方差为负)。

公式表示:
μ,log⁡σ2=Encoder(x) \mu, \log\sigma^2 = \text{Encoder}(x) μ,logσ2=Encoder(x)

步骤2:采样(Reparameterization Trick):从 latent 分布中采样

为了让 latent 向量的采样过程可微分(便于反向传播),VAE引入“重参数化技巧”:
先从标准正态分布 ( \mathcal{N}(0,1) ) 中采样一个噪声向量 ( \epsilon ),再通过以下公式得到 latent 向量 ( z ):
z=μ+σ⋅ϵ z = \mu + \sigma \cdot \epsilon z=μ+σϵ
其中 ( \sigma = \exp(\log\sigma^2 / 2) )(将对数方差转为方差,再开方得到标准差)。

为什么需要重参数化?
如果直接采样 ( z \sim \mathcal{N}(\mu, \sigma^2) ),采样过程是随机的,梯度无法从 ( z ) 回传至编码器参数;而重参数化后,随机性转移到 ( \epsilon )(与模型参数无关),梯度可通过 ( \mu ) 和 ( \sigma ) 回传。

步骤3:解码(Decoder):从 latent 向量生成样本

解码器接收采样得到的 latent 向量 ( z ),通过神经网络(如反卷积CNN)生成与输入 ( x ) 维度一致的输出 ( \hat{x} )(生成样本)。

公式表示:
x^=Decoder(z) \hat{x} = \text{Decoder}(z) x^=Decoder(z)

步骤4:VAE的损失函数:重构误差+KL散度

VAE的训练目标是“让生成样本 ( \hat{x} ) 既像真实样本(重构误差小),又让 latent 分布接近标准正态分布(KL散度小)”,损失函数为两者之和:
LVAE=Lrecon+β⋅LKL \mathcal{L}_{\text{VAE}} = \mathcal{L}_{\text{recon}} + \beta \cdot \mathcal{L}_{\text{KL}} LVAE=Lrecon+βLKL

  1. 重构误差(( \mathcal{L}_{\text{recon}} )):衡量生成样本与真实样本的差异,根据样本类型选择损失函数:

    • 图像(连续值,如MNIST灰度图):用均方误差(MSE):
      Lrecon=1N∑i=1N∥xi−x^i∥2 \mathcal{L}_{\text{recon}} = \frac{1}{N} \sum_{i=1}^N \| x_i - \hat{x}_i \|^2 Lrecon=N1i=1Nxix^i2
    • 图像(离散值,如RGB图):用交叉熵损失(CE):
      Lrecon=−∑i=1Nxilog⁡x^i \mathcal{L}_{\text{recon}} = -\sum_{i=1}^N x_i \log\hat{x}_i Lrecon=i=1Nxilogx^i
  2. KL散度(( \mathcal{L}_{\text{KL}} )):衡量 latent 分布 ( \mathcal{N}(\mu, \sigma^2) ) 与标准正态分布 ( \mathcal{N}(0,1) ) 的差异,强制 latent 空间连续、可采样。
    数学上可推导出闭式解(无需数值积分):
    LKL=12∑i=1dlatent(μi2+σi2−log⁡σi2−1) \mathcal{L}_{\text{KL}} = \frac{1}{2} \sum_{i=1}^{d_{\text{latent}}} \left( \mu_i^2 + \sigma_i^2 - \log\sigma_i^2 - 1 \right) LKL=21i=1dlatent(μi2+σi2logσi21)

  3. 超参数 ( \beta ):平衡重构误差和KL散度,( \beta ) 越大,latent 分布越接近标准正态分布(多样性强,但重构质量可能下降);( \beta ) 越小,重构质量越高(但多样性可能不足)。

2.3 VAE的优缺点与适用场景

优势 劣势
1. latent 空间连续可解释:任意采样 latent 向量都能生成有意义的样本,支持插值生成(如“猫→狗”的渐变图);
2. 训练稳定:无对抗过程,只需最小化损失函数,不易出现模式崩溃;
3. 概率生成:天然支持不确定性建模(如生成多个版本的同一输入)。
1. 生成质量低:受限于重构误差,生成图像通常模糊(如MNIST清晰,但高分辨率图像模糊);
2. latent 空间利用率低:部分 latent 维度对生成结果影响小,存在冗余;
3. 缺乏细节控制:无法精准控制生成样本的局部细节(如“让猫的眼睛变成蓝色”)。

适用场景:低计算成本的生成任务(如低分辨率图像生成、数据增广、异常检测),或需要 latent 空间插值的场景(如风格迁移的中间过渡效果)。

三、生成式模型的“革命者”:GAN(生成对抗网络)

GAN(Generative Adversarial Network,生成对抗网络)是2014年由Goodfellow提出的生成模型,核心思想是“通过生成器与判别器的零和博弈,迫使生成器学习真实数据的分布”。GAN彻底改变了生成式模型的范式,首次实现了高保真图像生成,成为AIGC早期的核心技术。

3.1 GAN的核心思想:“造假者与鉴宝师”的博弈

GAN的结构像一场“对抗游戏”,包含两个核心角色:

  • 生成器(Generator,G):“造假者”,输入随机噪声 ( z )(如100维),通过神经网络(如反卷积CNN)生成假样本 ( G(z) )(如64×64的人脸图像);
  • 判别器(Discriminator,D):“鉴宝师”,输入样本(真实样本 ( x ) 或假样本 ( G(z) )),通过神经网络(如CNN)输出“样本为真实数据的概率” ( D(x) )(范围0~1)。

训练目标:

  • 判别器 ( D ):尽量区分真实样本和假样本,即 ( D(x) \to 1 )(真实样本判为真),( D(G(z)) \to 0 )(假样本判为假);
  • 生成器 ( G ):尽量欺骗判别器,让判别器无法区分假样本和真实样本,即 ( D(G(z)) \to 1 )(假样本判为真)。

这场博弈的最终平衡点是:生成器生成的假样本与真实样本无法区分(( D(G(z)) = 0.5 )),判别器无法提升性能——此时生成器已完全学习到真实数据的分布。

3.2 GAN的数学原理: minimax 博弈与损失函数

GAN的训练过程是“极小极大(minimax)优化问题”,目标函数如下:
min⁡Gmax⁡DL(D,G)=Ex∼pdata(x)[log⁡D(x)]+Ez∼pz(z)[log⁡(1−D(G(z)))] \min_G \max_D \mathcal{L}(D, G) = \mathbb{E}_{x \sim p_{\text{data}}(x)} \left[ \log D(x) \right] + \mathbb{E}_{z \sim p_z(z)} \left[ \log (1 - D(G(z))) \right] GminDmaxL(D,G)=Expdata(x)[logD(x)]+Ezpz(z)[log(1D(G(z)))]

  • ( p_{\text{data}}(x) ):真实数据的分布;
  • ( p_z(z) ):随机噪声的分布(通常为标准正态分布或均匀分布);
  • ( \mathbb{E} ):期望操作。
1. 判别器的损失(最大化 ( \mathcal{L}(D, G) ))

判别器的目标是“正确区分真实样本和假样本”,损失可拆分为两部分:

  • 真实样本损失:( \log D(x) )——希望 ( D(x) ) 越大,该项越大;
  • 假样本损失:( \log (1 - D(G(z))) )——希望 ( D(G(z)) ) 越小,该项越大。

实际训练中,常用“二元交叉熵(BCE)”损失实现,公式如下:
LD=−1N[∑x∈真实样本log⁡D(x)+∑z∈噪声log⁡(1−D(G(z)))] \mathcal{L}_D = -\frac{1}{N} \left[ \sum_{x \in \text{真实样本}} \log D(x) + \sum_{z \in \text{噪声}} \log (1 - D(G(z))) \right] LD=N1[x真实样本logD(x)+z噪声log(1D(G(z)))]

2. 生成器的损失(最小化 ( \mathcal{L}(D, G) ))

生成器的目标是“欺骗判别器”,损失为假样本损失的相反数(因为生成器希望 ( \log (1 - D(G(z))) ) 越小越好):
LG=−1N∑z∈噪声log⁡D(G(z)) \mathcal{L}_G = -\frac{1}{N} \sum_{z \in \text{噪声}} \log D(G(z)) LG=N1z噪声logD(G(z))

为什么不用原目标中的 ( \log (1 - D(G(z))) )?
训练初期,生成器生成的假样本质量差,( D(G(z)) \approx 0 ),此时 ( \log (1 - D(G(z))) \approx 0 ),梯度接近0,生成器难以更新(“梯度消失”问题)。改用 ( -\log D(G(z)) ) 后,当 ( D(G(z)) \approx 0 ) 时,损失很大,梯度充足,生成器能快速学习。

3.3 GAN的改进:从原始GAN到WGAN-GP

原始GAN存在两大致命问题,限制了其工业应用:

  1. 训练不稳定:生成器和判别器的能力难以平衡,常出现一方“碾压”另一方的情况(如判别器过强,生成器梯度消失;生成器过强,判别器无法区分);
  2. 模式崩溃(Mode Collapse):生成器只生成少数几种“高逼真度”样本,缺乏多样性(如生成人脸时,所有脸都是同一种发型、肤色)。

为解决这些问题,研究者提出了多种改进方案,其中WGAN-GP(Wasserstein GAN with Gradient Penalty) 是最经典、应用最广的改进版本。

WGAN-GP的核心改进:
  1. 用Wasserstein距离替代JS散度
    原始GAN用JS散度衡量“真实分布与生成分布的差异”,但JS散度在分布不重叠时为常数,导致梯度消失;Wasserstein距离(Earth-Mover距离)能更平滑地衡量分布差异,即使分布不重叠,也能提供稳定梯度。

  2. 引入梯度惩罚(Gradient Penalty)
    强制判别器的梯度范数不超过1(满足Lipschitz连续条件),避免判别器过强,同时防止模式崩溃。梯度惩罚项加入判别器损失后,公式如下:
    LDWGAN-GP=LD+λ⋅Ex^∼px^[(∥∇x^D(x^)∥2−1)2] \mathcal{L}_{D_{\text{WGAN-GP}}} = \mathcal{L}_D + \lambda \cdot \mathbb{E}_{\hat{x} \sim p_{\hat{x}}} \left[ \left( \|\nabla_{\hat{x}} D(\hat{x})\|_2 - 1 \right)^2 \right] LDWGAN-GP=LD+λEx^px^[(x^D(x^)21)2]
    其中 ( \hat{x} ) 是“真实样本与假样本之间的插值样本”,( \lambda ) 是惩罚系数(通常取10)。

3.4 GAN的优缺点与适用场景

优势 劣势
1. 生成质量高:能生成高分辨率、细节丰富的样本(如1024×1024的人脸、风景图);
2. 生成速度快:直接从噪声生成样本,无需逐步去噪(比Diffusion Model快1~2个数量级);
3. 可控性强:通过条件GAN(如cGAN)可精准控制生成样本的属性(如“生成男性、黑发、微笑的人脸”)。
1. 训练不稳定:需精细调整超参数(如学习率、批次大小),否则易出现梯度消失或模式崩溃;
2. 缺乏概率解释:latent 空间不连续,无法量化生成样本的不确定性;
3. 多模态生成弱:难以处理文本-图像等多模态输入,文本引导能力远不如Diffusion Model。

适用场景:高保真单模态生成任务(如人脸生成、风格迁移、图像修复),或对生成速度有要求的场景(如实时图像生成)。

四、生成式模型的“当前王者”:Diffusion Model(扩散模型)

Diffusion Model(扩散模型)是2015年提出、2020年后爆发的生成模型,核心思想是“通过逐步向真实样本添加噪声,再学习逐步去除噪声的过程,实现样本生成”。它完美解决了VAE的模糊问题和GAN的训练不稳定问题,成为当前AIGC的主流技术(如Stable Diffusion、MidJourney、DALL-E 2均基于Diffusion Model)。

4.1 Diffusion Model的核心思想:“逐步加噪-逐步去噪”

Diffusion Model的灵感来自物理学中的“扩散过程”——比如墨滴在水中的扩散:墨滴(真实样本)会逐渐扩散到水中,最终变成均匀的噪声;反之,如果能逆转这个过程,均匀噪声也能逐步恢复为墨滴。

Diffusion Model将这个过程分为两个阶段:

  1. 前向扩散(Forward Diffusion):在T步内,逐步向真实样本 ( x_0 ) 添加高斯噪声,得到一系列噪声样本 ( x_1, x_2, …, x_T ),最终 ( x_T ) 接近纯高斯噪声;
  2. 反向扩散(Reverse Diffusion):训练一个“去噪模型(Denoiser)”,学习从噪声样本 ( x_t ) 恢复出前一步的样本 ( x_{t-1} ),最终从纯噪声 ( x_T ) 出发,经过T步去噪,生成真实样本 ( x_0 )。

4.2 Diffusion Model的数学原理:DDPM的基础框架

Diffusion Model的经典实现是DDPM(Denoising Diffusion Probabilistic Models,去噪扩散概率模型),我们以DDPM为例,拆解前向扩散和反向扩散的数学过程。

阶段1:前向扩散(Forward Process):可控的加噪

前向扩散是一个固定、无需训练的过程,每一步加噪都遵循高斯分布,且满足“马尔可夫性”(即 ( x_t ) 只依赖 ( x_{t-1} ))。

为了让加噪过程可控,DDPM定义了一个“噪声调度表”——一系列逐渐增大的噪声系数 ( \beta_1, \beta_2, …, \beta_T )(通常 ( \beta_1 \approx 10^{-4} ),( \beta_T \approx 0.02 )),并衍生出以下参数:

  • ( \alpha_t = 1 - \beta_t ):每一步的“保真性系数”(( \alpha_t ) 越小,加噪越强);
  • ( \bar{\alpha}t = \prod{i=1}^t \alpha_i ):前t步的累积保真性系数(( \bar{\alpha}_t ) 随t增大而减小,( \bar{\alpha}_T \approx 0 ))。

每一步加噪的公式为:
xt=αˉt⋅x0+1−αˉt⋅ϵ x_t = \sqrt{\bar{\alpha}_t} \cdot x_0 + \sqrt{1 - \bar{\alpha}_t} \cdot \epsilon xt=αˉt x0+1αˉt ϵ
其中 ( \epsilon \sim \mathcal{N}(0, I) ) 是高斯噪声。

关键特性:任意步骤t的样本 ( x_t ) 都可由原始样本 ( x_0 ) 直接生成(无需逐步加噪),这为反向扩散的训练提供了便利。

阶段2:反向扩散(Reverse Process):可学习的去噪

反向扩散是需要训练的过程,目标是学习从 ( x_t ) 恢复 ( x_{t-1} ) 的条件分布 ( p(x_{t-1} | x_t) )。DDPM假设该分布是高斯分布:
p(xt−1∣xt)=N(xt−1;μθ(xt,t),σt2I) p(x_{t-1} | x_t) = \mathcal{N}(x_{t-1}; \mu_\theta(x_t, t), \sigma_t^2 I) p(xt1xt)=N(xt1;μθ(xt,t),σt2I)
其中:

  • ( \mu_\theta(x_t, t) ):高斯分布的均值,由去噪模型 ( \theta ) 预测;
  • ( \sigma_t^2 ):高斯分布的方差,通常固定为 ( \beta_t ) 或由噪声调度表计算(无需训练)。
阶段3:去噪模型的训练:预测噪声而非直接生成

直接预测 ( x_{t-1} ) 难度较大,DDPM采用了更巧妙的策略:让去噪模型预测“前向扩散过程中添加的噪声 ( \epsilon )”——因为根据前向扩散公式,( x_0 ) 可由 ( x_t ) 和 ( \epsilon ) 推导得到:
x0=1αˉt(xt−1−αˉt⋅ϵ) x_0 = \frac{1}{\sqrt{\bar{\alpha}_t}} \left( x_t - \sqrt{1 - \bar{\alpha}_t} \cdot \epsilon \right) x0=αˉt 1(xt1αˉt ϵ)

训练目标是“最小化模型预测的噪声 ( \epsilon_\theta(x_t, t) ) 与真实噪声 ( \epsilon ) 的MSE损失”:
LDDPM=Ex0,ϵ,t[∥ϵ−ϵθ(xt,t)∥2] \mathcal{L}_{\text{DDPM}} = \mathbb{E}_{x_0, \epsilon, t} \left[ \| \epsilon - \epsilon_\theta(x_t, t) \|^2 \right] LDDPM=Ex0,ϵ,t[ϵϵθ(xt,t)2]

为什么预测噪声?

  • 噪声是加性的,预测难度低于直接预测样本;
  • 噪声与样本维度一致,损失计算简单(MSE即可);
  • 可通过噪声间接推导样本,保证生成过程的稳定性。

4.3 Stable Diffusion的创新:让Diffusion Model走向实用

DDPM虽然能生成高质量样本,但存在一个致命缺陷:计算成本极高——需要在高维像素空间(如512×512×3=786432维)进行T步(如1000步)扩散,普通GPU无法承受。

Stable Diffusion(2022年由Stability AI提出)通过两大创新,将Diffusion Model的计算成本降低了两个数量级,使其能在消费级GPU上运行:

创新1:Latent Diffusion( latent 空间扩散)

Stable Diffusion引入“自动编码器(VAE)”,将高维像素空间的扩散转移到低维 latent 空间:

  • 编码阶段:用VAE的编码器将512×512×3的图像压缩为64×64×4的 latent 向量(维度从786432降至16384,压缩率48倍);
  • 扩散阶段:在 latent 空间进行T步(如50步)扩散(加噪+去噪),计算成本大幅降低;
  • 解码阶段:用VAE的解码器将去噪后的 latent 向量解压为512×512×3的图像。
创新2:文本引导(Text Guidance):Cross-Attention机制

Stable Diffusion通过“文本编码器(如CLIP ViT-L/14)”和“Cross-Attention机制”,实现“文本描述控制图像生成”:

  1. 文本编码:用CLIP将文本描述(如“a photo of an astronaut riding a horse on mars”)编码为77维的文本嵌入向量(text embedding);
  2. Cross-Attention:在去噪模型(U-Net)中加入Cross-Attention层,让 latent 空间的去噪过程“关注文本嵌入中的关键信息”(如“astronaut”“horse”“mars”);
  3. 条件生成:通过“Classifier-Free Guidance(CFG)”超参数控制文本引导强度——CFG越大,生成图像与文本的匹配度越高(但可能损失多样性)。

4.4 Diffusion Model的优缺点与适用场景

优势 劣势
1. 生成质量极高:能生成超高清、细节丰富、语义一致的样本(如1024×1024的复杂场景图);
2. 多模态能力强:完美支持文本-图像、图像-图像等多模态生成,文本引导精度高;
3. 训练稳定:无对抗过程,只需最小化MSE损失,不易出现模式崩溃;
4. 可控性强:通过CFG、LoRA微调等技术,可精准控制生成样本的风格、细节。
1. 生成速度慢:需T步(如50100步)去噪,生成一张512×512图像需15秒(比GAN慢10~100倍);
2. 计算成本高:即使在 latent 空间,仍需较大显存(如生成1024×1024图像需8GB以上显存);
3. latent 空间不可解释:难以通过手动调整 latent 向量控制生成结果(需依赖文本或图像引导)。

适用场景:高保真多模态生成任务(如文本生成图像、图像超分、图像编辑、3D资产生成),或对生成质量有高要求的场景(如游戏美术、广告设计、影视特效)。

五、三大生成式模型对比:如何选择适合自己的模型?

为了帮助开发者快速选择模型,我们从“核心思想、生成质量、训练难度、计算成本”等6个关键维度,对VAE、GAN、Diffusion Model进行对比:

对比维度 VAE(变分自编码器) GAN(生成对抗网络) Diffusion Model(扩散模型)
核心思想 概率化自编码器,学习 latent 分布的参数 生成器与判别器的零和博弈 逐步加噪-逐步去噪,逆转扩散过程
生成质量 低(模糊,细节少) 高(高保真,细节丰富) 极高(超高清,语义一致)
样本多样性 高(latent 空间连续,支持插值) 中(易出现模式崩溃) 高(无模式崩溃,支持多模态)
训练难度 低(无对抗,损失稳定) 高(需平衡生成器与判别器,超参数敏感) 中(损失稳定,但需调噪声调度表)
计算成本 低(单前向传播,无多步过程) 中(对抗训练,单步生成) 高(多步去噪,需大显存)
适用场景 低分辨率生成、数据增广、异常检测 单模态高保真生成(人脸、风格迁移) 多模态高保真生成(文本→图像、图像编辑)
代表应用 MNIST生成、 latent 空间插值 StyleGAN(人脸生成)、Pix2Pix(图像翻译) Stable Diffusion(文本→图像)、MidJourney(创意生成)

选择建议

  1. 若需求是“快速生成低分辨率样本,或需要 latent 空间插值”→ 选VAE;
  2. 若需求是“单模态高保真生成,且对速度有要求”→ 选GAN(如WGAN-GP、StyleGAN);
  3. 若需求是“多模态生成(如文本→图像),或超高清样本生成”→ 选Diffusion Model(如Stable Diffusion)。

六、实战:用Stable Diffusion实现文本生成图像(附完整代码)

接下来,我们聚焦工业级实战——用Hugging Face的diffusers库,实现Stable Diffusion的三大核心功能:文本生成图像(txt2img)、图像生成图像(img2img)、LoRA微调(小数据集定制模型)。

6.1 环境准备

1. 硬件要求
  • 显存:至少4GB(生成512×512图像),推荐8GB以上(生成1024×1024图像);
  • GPU:支持CUDA的NVIDIA显卡(推荐RTX 3060及以上),AMD显卡需用ROCm(兼容性较差)。
2. 软件安装
# 安装PyTorch(支持CUDA 11.8,根据显卡型号调整)
pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118

# 安装Diffusers库(Hugging Face官方Stable Diffusion库)
pip install diffusers==0.24.0 transformers==4.35.2 accelerate==0.24.1

# 安装其他依赖(图像处理、模型下载)
pip install pillow matplotlib requests
3. 模型下载

Stable Diffusion的预训练模型需从Hugging Face Hub下载,推荐使用runwayml/stable-diffusion-v1-5(开源、稳定、效果好):

  • 无需手动下载,diffusers库会自动下载并缓存到本地(默认路径:~/.cache/huggingface/diffusers);
  • 若下载速度慢,可配置Hugging Face镜像(如export HF_ENDPOINT=https://hf-mirror.com)。

6.2 功能1:文本生成图像(txt2img)

文本生成图像是Stable Diffusion最核心的功能,输入文本描述(Prompt),输出对应图像。

完整代码
import torch
from diffusers import StableDiffusionPipeline
import matplotlib.pyplot as plt
from PIL import Image

# 1. 加载Stable Diffusion模型(指定GPU)
device = "cuda" if torch.cuda.is_available() else "cpu"
pipe = StableDiffusionPipeline.from_pretrained(
    "runwayml/stable-diffusion-v1-5",  # 预训练模型名称
    torch_dtype=torch.float16,         # 使用FP16精度,节省显存
    safety_checker=None                # 关闭安全检查(可选,避免过滤部分图像)
).to(device)

# 2. 配置生成参数
prompt = "A photo of a cute cat wearing a astronaut helmet, on the moon, stars in the sky, ultra-detailed, 8k resolution"  # 正向Prompt(要生成的内容)
negative_prompt = "blurry, low resolution, ugly, deformed, watermark, text"  # 反向Prompt(要避免的内容)
num_inference_steps = 50  # 去噪步数(越多越清晰,但越慢,推荐20~100)
guidance_scale = 7.5      # CFG Scale(文本引导强度,越大越贴合Prompt,推荐7~10)
height = 512              # 生成图像高度(推荐512/768/1024)
width = 512               # 生成图像宽度
num_images_per_prompt = 1 # 每次生成的图像数量

# 3. 生成图像
with torch.no_grad():  # 禁用梯度计算,节省显存
    images = pipe(
        prompt=prompt,
        negative_prompt=negative_prompt,
        num_inference_steps=num_inference_steps,
        guidance_scale=guidance_scale,
        height=height,
        width=width,
        num_images_per_prompt=num_images_per_prompt
    ).images

# 4. 保存并显示图像
save_path = "stable_diffusion_txt2img.png"
images[0].save(save_path)
print(f"图像已保存到:{save_path}")

# 显示图像
plt.figure(figsize=(8, 8))
plt.imshow(images[0])
plt.axis("off")
plt.title("Text-to-Image Result\nPrompt: " + prompt[:50] + "...")
plt.show()
关键参数说明
  • Prompt:文本描述需精准、详细,使用专业术语(如“ultra-detailed”“8k”“photorealistic”)提升生成质量;
  • negative_prompt:避免生成“模糊、低分辨率、畸形”等不良图像,是提升质量的关键;
  • num_inference_steps:50步足够生成清晰图像,超过100步后质量提升不明显,但时间翻倍;
  • guidance_scale:7.5是平衡点,小于5会偏离Prompt,大于10会导致图像失真。
生成结果示例

输入Prompt:“A photo of a cute cat wearing a astronaut helmet, on the moon, stars in the sky, ultra-detailed, 8k resolution”
生成结果:一只戴着宇航员头盔的可爱猫咪,站在月球表面,背景是星空,细节丰富,画质清晰。

6.3 功能2:图像生成图像(img2img)

图像生成图像(Image-to-Image)是在已有图像的基础上,根据文本Prompt调整风格或内容(如“将照片转为油画”“给猫咪添加围巾”)。

完整代码
import torch
from diffusers import StableDiffusionImg2ImgPipeline
import matplotlib.pyplot as plt
from PIL import Image

# 1. 加载输入图像(可替换为自己的图像路径)
init_image_path = "input_cat.jpg"  # 输入图像(如一张猫咪照片)
init_image = Image.open(init_image_path).convert("RGB")
init_image = init_image.resize((512, 512))  # 调整为512×512(与模型输入匹配)

# 2. 加载Stable Diffusion img2img模型
device = "cuda" if torch.cuda.is_available() else "cpu"
pipe = StableDiffusionImg2ImgPipeline.from_pretrained(
    "runwayml/stable-diffusion-v1-5",
    torch_dtype=torch.float16,
    safety_checker=None
).to(device)

# 3. 配置生成参数
prompt = "The cat in the image is wearing a red scarf, oil painting style, vibrant colors, ultra-detailed"  # 正向Prompt(在输入图像基础上添加围巾,转为油画风格)
negative_prompt = "blurry, low resolution, ugly, deformed, watermark"
num_inference_steps = 50
guidance_scale = 7.5
strength = 0.7  # 图像调整强度(0~1,越大越偏离原图,越小越接近原图,推荐0.5~0.8)

# 4. 生成图像
with torch.no_grad():
    images = pipe(
        prompt=prompt,
        negative_prompt=negative_prompt,
        image=init_image,
        num_inference_steps=num_inference_steps,
        guidance_scale=guidance_scale,
        strength=strength
    ).images

# 5. 保存并显示对比结果
save_path = "stable_diffusion_img2img.png"
images[0].save(save_path)
print(f"图像已保存到:{save_path}")

# 显示输入图像与生成图像对比
plt.figure(figsize=(12, 6))
# 输入图像
plt.subplot(1, 2, 1)
plt.imshow(init_image)
plt.axis("off")
plt.title("Input Image")
# 生成图像
plt.subplot(1, 2, 2)
plt.imshow(images[0])
plt.axis("off")
plt.title("Image-to-Image Result\nPrompt: " + prompt[:50] + "...")
plt.show()
关键参数说明
  • strength:控制“原图保留程度”,0.7表示“保留30%原图特征,70%按Prompt生成”;
  • init_image:输入图像需为RGB格式,分辨率建议与生成图像一致(如512×512),避免拉伸变形。
生成结果示例

输入图像:一张普通猫咪照片
生成结果:猫咪戴上了红色围巾,整体风格转为油画,色彩鲜艳,细节丰富,同时保留了猫咪的原始姿态。

6.4 功能3:LoRA微调(小数据集定制模型)

LoRA(Low-Rank Adaptation,低秩适配)是一种轻量级微调技术,只需少量数据(如10~100张图像),就能让Stable Diffusion生成特定风格或对象的图像(如“生成特定角色的动漫图”“生成特定画家的风格图”)。

1. 准备数据集
  • 数据集要求:10~100张同一风格/对象的图像(如10张“皮卡丘”动漫图),分辨率建议512×512;
  • 数据标注:每张图像需搭配Prompt(如“a photo of pikachu, anime style”),保存为CSV文件(格式:image_path,prompt)。

示例CSV文件(dataset.csv):

image_path,prompt
pikachu/1.jpg,a photo of pikachu, anime style, cute, yellow fur
pikachu/2.jpg,a photo of pikachu, anime style, standing, holding a ball
pikachu/3.jpg,a photo of pikachu, anime style, sitting, grass background
...
2. 完整微调代码
import torch
import csv
import os
from diffusers import StableDiffusionPipeline, LoRAConfig, get_scheduler
from diffusers.training_utils import EMAModel
from diffusers.optimization import get_scheduler
from torch.utils.data import Dataset, DataLoader
from PIL import Image
import torchvision.transforms as transforms

# 1. 定义数据集类
class LoRADataset(Dataset):
    def __init__(self, csv_path, image_dir, transform=None):
        self.data = []
        with open(csv_path, "r", encoding="utf-8") as f:
            reader = csv.DictReader(f)
            for row in reader:
                image_path = os.path.join(image_dir, row["image_path"])
                prompt = row["prompt"]
                self.data.append((image_path, prompt))
        self.transform = transform

    def __len__(self):
        return len(self.data)

    def __getitem__(self, idx):
        image_path, prompt = self.data[idx]
        image = Image.open(image_path).convert("RGB")
        if self.transform:
            image = self.transform(image)
        return {"image": image, "prompt": prompt}

# 2. 配置参数
csv_path = "dataset.csv"               # CSV文件路径
image_dir = "."                        # 图像文件夹路径
output_dir = "lora-pikachu"            # LoRA模型保存路径
batch_size = 2                         # 批次大小(根据显存调整,4GB显存用1~2)
num_train_epochs = 50                  # 训练轮数(10~50,数据少则多轮)
learning_rate = 1e-4                   # 学习率(推荐1e-4~1e-3)
lora_rank = 4                          # LoRA秩(越小参数越少,推荐4~8)
lora_alpha = 8                         # LoRA alpha(通常为rank的2倍)
image_size = 512                       # 图像尺寸

# 3. 数据预处理
transform = transforms.Compose([
    transforms.Resize((image_size, image_size)),
    transforms.ToTensor(),
    transforms.Normalize([0.5], [0.5])  # 归一化到[-1, 1](与模型输入匹配)
])
dataset = LoRADataset(csv_path, image_dir, transform)
dataloader = DataLoader(dataset, batch_size=batch_size, shuffle=True)

# 4. 加载基础模型与LoRA配置
device = "cuda" if torch.cuda.is_available() else "cpu"
# 加载Stable Diffusion基础模型
pipe = StableDiffusionPipeline.from_pretrained(
    "runwayml/stable-diffusion-v1-5",
    torch_dtype=torch.float16,
    safety_checker=None
).to(device)
# 配置LoRA(只微调U-Net的Cross-Attention层)
lora_config = LoRAConfig(
    r=lora_rank,
    lora_alpha=lora_alpha,
    target_modules=["to_q", "to_k", "to_v", "to_out.0"],  # 目标微调层
    lora_dropout=0.05,
    bias="none",
    task_type="TEXT_IMAGE_DIFFUSION"
)
# 为U-Net添加LoRA适配器
pipe.unet.add_adapter(lora_config)
# 冻结基础模型参数,只训练LoRA参数
for param in pipe.unet.parameters():
    param.requires_grad = False
for param in pipe.unet.lora_adapters.parameters():
    param.requires_grad = True

# 5. 配置优化器与学习率调度器
optimizer = torch.optim.AdamW(pipe.unet.lora_adapters.parameters(), lr=learning_rate)
lr_scheduler = get_scheduler(
    "cosine",
    optimizer=optimizer,
    num_warmup_steps=0,
    num_training_steps=len(dataloader) * num_train_epochs
)

# 6. 训练LoRA
pipe.unet.train()
for epoch in range(num_train_epochs):
    epoch_loss = 0.0
    for step, batch in enumerate(dataloader):
        # 准备数据
        images = batch["image"].to(device, dtype=torch.float16)
        prompts = batch["prompt"]
        # 编码文本
        text_inputs = pipe.tokenizer(
            prompts,
            padding="max_length",
            max_length=pipe.tokenizer.model_max_length,
            truncation=True,
            return_tensors="pt"
        ).to(device)
        # 生成随机噪声与时间步
        noise = torch.randn_like(images).to(device)
        timesteps = torch.randint(0, pipe.scheduler.num_train_timesteps, (images.shape[0],), device=device).long()
        # 前向扩散:生成带噪声的图像
        noisy_images = pipe.scheduler.add_noise(images, noise, timesteps)
        # 模型预测噪声
        model_output = pipe.unet(noisy_images, timesteps, text_inputs.input_ids).sample
        # 计算MSE损失(预测噪声与真实噪声的差异)
        loss = torch.nn.functional.mse_loss(model_output, noise)
        # 反向传播与参数更新
        loss.backward()
        optimizer.step()
        lr_scheduler.step()
        optimizer.zero_grad()
        # 累计损失
        epoch_loss += loss.item() * images.shape[0]
    
    # 打印每轮损失
    avg_loss = epoch_loss / len(dataset)
    print(f"Epoch {epoch+1}/{num_train_epochs} | Average Loss: {avg_loss:.4f}")

# 7. 保存LoRA模型
pipe.unet.save_attn_procs(output_dir)
print(f"LoRA模型已保存到:{output_dir}")

# 8. 加载LoRA模型进行生成测试
pipe = StableDiffusionPipeline.from_pretrained(
    "runwayml/stable-diffusion-v1-5",
    torch_dtype=torch.float16,
    safety_checker=None
).to(device)
# 加载LoRA模型
pipe.unet.load_attn_procs(output_dir)
# 生成测试图像
prompt = "a photo of pikachu, anime style, flying in the sky, clouds background, ultra-detailed"
negative_prompt = "blurry, low resolution, ugly, deformed"
with torch.no_grad():
    image = pipe(
        prompt=prompt,
        negative_prompt=negative_prompt,
        num_inference_steps=50,
        guidance_scale=7.5,
        height=512,
        width=512
    ).images[0]
# 保存测试图像
image.save("lora_test.png")
print("LoRA测试图像已保存到:lora_test.png")
plt.figure(figsize=(8, 8))
plt.imshow(image)
plt.axis("off")
plt.title("LoRA Fine-tuning Result\nPrompt: " + prompt[:50] + "...")
plt.show()
关键参数说明
  • lora_rank:LoRA的核心参数,秩越小,模型参数越少(如rank=4时,LoRA模型仅几十MB),微调速度越快;
  • num_train_epochs:小数据集(如10张图)需训练50轮以上,确保模型学习到目标风格/对象;
  • batch_size:根据显存调整,4GB显存用1,8GB显存用2~4,避免显存溢出。
微调结果示例

微调后,输入Prompt:“a photo of pikachu, anime style, flying in the sky, clouds background”
生成结果:符合训练数据风格的皮卡丘,在空中飞行,背景是云朵,与训练集中的皮卡丘风格高度一致。

七、南木的学习路径建议:从入门到精通生成式模型

生成式模型涉及概率统计、深度学习、优化理论等多个领域,初学者容易陷入“原理难懂、代码跑不通”的困境。结合我的经验,推荐一条“循序渐进”的学习路径:

阶段1:基础铺垫(2~3周)

  • 数学基础:复习概率统计(高斯分布、KL散度、期望)、线性代数(矩阵乘法、低秩分解)、微积分(梯度下降、链式法则)——无需深钻,能理解公式含义即可;
  • 工具基础:掌握PyTorch核心操作(张量、模型定义、反向传播)、图像处理(PIL、OpenCV)、数据加载(Dataset、DataLoader);
  • 前置知识:学习自编码器、CNN、Transformer的基础结构,理解“编码器-解码器”“注意力机制”的核心思想。

阶段2:核心原理(4~6周)

  • 第一步:入门VAE
    1. 实现简单VAE(如生成MNIST图像),理解“重参数化技巧”和“ELBO损失”;
    2. 可视化latent空间,观察插值生成效果,理解“概率生成”的意义;
  • 第二步:深入GAN
    1. 实现原始GAN(生成MNIST),观察训练不稳定问题;
    2. 实现WGAN-GP,对比原始GAN的改进效果,理解“Wasserstein距离”和“梯度惩罚”;
    3. 学习StyleGAN的“风格迁移”思想,尝试生成人脸图像;
  • 第三步:精通Diffusion Model
    1. 推导DDPM的前向/反向扩散公式,理解“噪声预测”的逻辑;
    2. 阅读Stable Diffusion论文,理解“latent diffusion”和“文本引导”的实现;
    3. diffusers库复现DDPM,对比与Stable Diffusion的差异。

阶段3:实战进阶(4~8周)

  • 基础实战
    1. 用Stable Diffusion实现txt2img、img2img、图像超分、图像修复;
    2. 学习Prompt工程,掌握“关键词组合”“权重调整”(如(astronaut:1.2))提升生成质量;
  • 进阶实战
    1. 实现LoRA微调,定制特定风格/对象的模型(如生成自己的漫画形象);
    2. 学习ControlNet,实现“姿态控制”“深度控制”(如用骨架图生成对应姿势的人物);
    3. 尝试多模态生成(如文本生成视频、文本生成3D模型),使用开源库(如Pika、DreamFusion);
  • 工程优化
    1. 学习模型量化(如FP16/FP8量化)、模型蒸馏,降低显存占用;
    2. 实现批量生成、异步生成,提升生成效率;
    3. 部署Stable Diffusion到Web端(如用Gradio、Streamlit搭建交互界面)。

阶段4:前沿扩展(长期)

  • 理论研究
    1. 阅读生成式模型的最新论文(如Google的Imagen、Meta的Make-A-Video),跟踪技术趋势;
    2. 研究生成式模型的评估指标(如FID、CLIP Score、Human Evaluation),理解“生成质量”的量化标准;
  • 跨领域应用
    1. 探索生成式模型在工业界的应用(如游戏美术、广告设计、影视特效、生物医药);
    2. 结合大语言模型(如GPT-4),实现“文本理解→精细Prompt生成→图像生成”的端到端流程;
  • 技术突破
    1. 研究生成速度优化(如Fast Diffusion、LCM),实现实时生成;
    2. 探索生成式模型的可控性(如编辑生成图像的局部内容),解决“生成结果不可控”的痛点。

生成式模型的发展,是AI从“感知”走向“创造”的关键一步——从VAE的“概率探索”,到GAN的“对抗创新”,再到Diffusion Model的“精细生成”,每一次技术迭代都在拓宽“机器创意”的边界。

当前,Diffusion Model凭借“高生成质量+强多模态能力”,成为AIGC的主流技术,但GAN在“单模态快速生成”场景仍有不可替代的优势,VAE则在“低计算成本”场景发挥作用。未来,生成式模型的发展方向将是“更高质量、更快速度、更强可控性、更多模态融合”——比如实时生成4K视频、精准控制3D模型生成、实现文本-图像-视频-3D的端到端生成。

对于开发者而言,学习生成式模型不仅是掌握一项技术,更是把握AIGC时代的核心竞争力。

如果在学习过程中遇到问题,欢迎在评论区留言,我会定期回复。觉得有用的话,记得点赞+收藏+关注,后续我会分享更多生成式模型的实战干货在这里插入图片描述

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐