文字生成3D这个方向真正出圈,靠的是Google Research在2022年发布的DreamFusion。它的核心贡献不是训练了一个多大的3D生成模型,而是提出了Score Distillation Sampling(SDS)这个巧妙的优化技巧:不需要任何3D数据集,只用一个冻结参数的2D文生图扩散模型,就能驱动一个可优化的3D表示(比如NeRF)收敛到符合文本描述的几何与外观。这篇文章我们从扩散模型的训练目标开始,把SDS的推导链条完整走一遍,看看这个梯度到底是怎么来的。

一、前置知识:扩散模型的score到底在学什么
要理解SDS,先要回到扩散模型本身。DDPM的前向过程定义了一个加噪序列:给定干净图像 x,在时间步 t 加入高斯噪声得到 x_t = α_t x + σ_t ε,其中 ε ~ N(0, I),α_t 和 σ_t 是随时间调度的系数,满足 α_t² + σ_t² ≈ 1(方差保持假设)。当 t 足够大时,x_t 近似退化为纯噪声。
训练时,模型 ε_φ(x_t, t) 的目标是预测加入的噪声,损失函数就是简单的MSE:
loss = torch.mean((eps_phi(x_t, t) - eps) ** 2)
这个看似简单的目标背后藏着深刻的等价关系。根据Tweedie公式,对于高斯分布 N(x_t; α_t x, σ_t² I),后验均值满足 E[x | x_t] = (x_t + σ_t² ∇ log p(x_t)) / α_t。也就是说,预测噪声 ε_φ 实际上等价于学习了被污染图像的score函数 ∇_{x_t} log p(x_t),两者满足 ε_φ(x_t, t) ≈ -σ_t ∇_{x_t} log p(x_t)。这一点是理解SDS的关键:扩散模型内部储存的是一个对数似然的梯度场,它能告诉你往哪个方向修改当前图像,可以让它变得更像真实数据分布。SDS要做的,就是把这个梯度场借给3D表示用。
二、DreamFusion的整体框架:通过可微渲染连接2D与3D
DreamFusion的优化对象是一个NeRF(论文中用的是LightNeRF,做了内存优化)。流程大致是:随机采样一个相机姿态,用体渲染得到一张图像 x = g(θ),其中 θ 是NeRF的参数;然后随机采样时间步 t 和噪声 ε,构造加噪图像 x_t;再把 x_t 和 t、文本条件一起喂给冻结的扩散模型,计算一个关于 x_t 的梯度;最后通过 x = g(θ) 的雅可比矩阵把这个梯度回传到 θ 上。
这里有一个直接想到的做法:能不能直接用扩散模型的去噪MSE损失 ||ε_φ(x_t, t, y) - ε||² 作为损失函数,对 θ 求梯度?DreamFusion论文里确实尝试了,但效果很差,主要原因是渲染图 x 本身就在扩散模型的伪似然高原上——它不是真数据,MSE损失对它的梯度方向混乱且微弱,优化难以收敛。所以需要从概率的角度重新构造目标。
三、SDS的核心推导:从变分下界到Mean Score
正确的做法是最大化渲染图在扩散模型隐含的似然分布下的概率密度。由于扩散模型的似然本身难以显式计算,我们用扩散前向过程来构造一个变分下界。定义目标函数:
# 伪代码示意:L(θ) 是关于渲染图 x = g(θ) 的期望对数似然下界
# L(θ) = E_{t, ε} [ w(t) / (2 σ_t²) * || x - E[ x | x_t ; φ ] ||² ] + const把 x = g(θ) 代入并对 θ 求梯度。推导的关键一步是:高斯分布的对数似然梯度可以写成均值差的形式,再利用Tweedie公式把 E[x | x_t] 替换成噪声预测,最终得到一个干净的表达式:
∇_θ L_SDS(φ, x) = E_{t, ε} [ w(t) (∂x/∂θ) (ε_φ(x_t; y, t) - ε) ]注意这个形式和直接用MSE损失的区别:MSE损失对 θ 求导时会带上U-Net参数 φ 的二阶导项 ∂²ε_φ/∂x²,这一项计算代价巨大且数值不稳定。SDS推导中最漂亮的近似就是把这一项丢掉——论文在附录里专门讨论了这个近似,后来的工作(比如SDS的变体理论分析)也证明丢掉二阶项之后的梯度方向依然是有效的下降方向。最终梯度里只剩下 (∂x/∂θ) 这个体渲染的雅可比,正是可微渲染能提供的部分。
进一步利用score等价关系 ε_φ - ε ≈ -σ_t ∇ log p(x_t),可以把SDS梯度理解成对 g(θ) 在所有噪声水平上加权平均后的mean score。换句话说,扩散模型在每一个时间尺度上都对渲染图给出一个改进方向,SDS把它们加权混合后推动3D表示更新。这也是“蒸馏”这个名字的来源:学生(NeRF)不直接从数据学习,而是模仿老师(扩散模型)在中间带噪状态下的判断。
四、工程细节与guidance的作用
实际实现中还有几个不可忽略的细节。第一个是classifier-free guidance。SDS直接用无条件模型的效果很差,因为无条件score缺乏文本的指向性。DreamFusion采用CFG的方式计算梯度,把条件噪声预测与无条件噪声预测的差放大后再叠加:
eps_hat = eps_uncond + guidance_scale * (eps_cond - eps_uncond) grad = w(t) * (eps_hat - eps) # SDS 梯度主体 target = (x_t - sigma_t * eps_hat) / alpha_t # 等价写法:把 grad 直接作为重建损失的反传梯度,省去手动链式求导 loss = 0.5 * F.mse_loss(x_t, target.detach(), reduction="sum") / sigma_t**2 loss.backward() # 注意 x_t 中只有 x = g(θ) 参与梯度
论文中guidance scale取100,远高于文生图采样时常用的7.5。这个偏大的取值加剧了过饱和问题,也就是生成的3D资产颜色过饱和、对比度异常,后续研究指出这是因为大guidance下条件分布的均值估计有偏,可以配合噪声偏置(noise offset)等手段缓解。
第二个细节是时间步采样与权重 w(t)。DreamFusion故意用了一个非标准的加权函数,取 w(t) = 1,这在理论上对应的是一个扭曲的加权分布,实践上反而更稳定。此外时间步 t 通常只在某个区间内均匀采样,避免过小或过大的 t 造成梯度信噪比过低。NeRF本身也做了简化,比如用球谐系数阶数降低、参数量缩减,都是为了在单卡上跑通整套优化流程。
五、SDS的缺陷与后续改进方向
SDS开创了这个领域,但缺陷也很明确。一是梯度方差大,因为每次只采样一个视角、一个时间步、一个噪声实例,梯度噪声非常重,需要靠学习率调度和EMA等手段平滑。二是过饱和与过平滑问题,表现为生成结果缺少高频细节、颜色失真。三是多面性问题:扩散模型对不同视角的评分是独立的,容易导致生成的3D资产出现Janus问题,也就是一张脸上出现两只正脸这种几何不一致。
后续工作沿着几条线改进。ProlificDreamer提出的VSD(Variational Score Distillation)指出SDS本质上是把渲染图当作单个样本来匹配,而正确的做法应该对渲染分布做变分推断,用一个LoRA微调的粒子来估计view-dependent的score,显著改善了细节和Janus问题。另一条线是改进score的参数化,比如基于v-prediction的蒸馏(NoisESD等工作)发现CFG导致的均值偏移可以用v空间的预测自然抵消。还有的工作直接绕开蒸馏,用扩散模型采样出的多视角图像做监督。这些方法各有取舍,但它们的共同源头都可以追溯到SDS这个最初的推导框架。
回头看,SDS的思想本质上是把预训练生成模型当作一个可微的、通用性的先验:任何能把参数映射为图像的可微表示,都可以挂在这个先验上被优化。这个范式后来被推广到文本到3D、图像到3D、甚至文本驱动的网格纹理生成等任务上,理解了SDS的推导,也就理解了这一大类方法的公共骨架。
DreamFusionScore Distillation Sampling文生3D修改时间:2026-09-06 20:00:51