
做三维内容这几年被问得最多的一类问题是一张图能不能直接给我转出十几个角度而且要能直接塞进引擎里转起来不穿帮。多视角合成这条线上画质早就不是瓶颈了真正卡住落地的是几何一致性——同一个马克杯正面数第二圈把手转到侧面就变成两个把手或者把手莫名其妙歪进杯壁里墙面明明平得像块钢板镜头偏转四十五度就开始起伏像被人拿锤子敲过。**几何潜在扩散GLD**这套思路就是冲这个毛病来的它不去像素层面硬拗每一帧而是在扩散模型的潜空间里维护一份可被反复查询、反复修正的几何表征让多个视角在去噪过程中共享同一份“空间记忆”。这篇东西写给谁看给已经跑通过基础图生图、想往三维生成迈一步的算法同学给在做资产生成流水线、被客户投诉“转起来会闪”的工程同学也给还在选技术路线的技术负责人。我会把设计取舍、关键模块、参数怎么算、坑在哪一次讲透。1. 多视角合成为什么总在几何上翻车先把病灶说清楚不然后面所有设计都会显得像玄学。多视角合成multi-view synthesis本质上是“条件生成 空间约束”的混合体而绝大多数失败案例都不是生成模型不够强是约束给的方式不对。1.1 视角失忆扩散模型并不知道自己刚才画了啥图像扩散模型的训练目标是逐帧的似然它对“第 3 个视角和第 7 个视角是否描述同一个物体”这件事天生没有义务。你在 UNet 里塞进一个相机位姿嵌入模型学到的只是“位姿向量 → 画面应该长什么样”的统计关联而不是“位姿向量 → 三维空间里哪些点被看到”的几何推理。于是就有两个典型症状。第一个是跨视角漂移单帧看都挺像连成序列播放物体的边缘像果冻一样轻微抖动纹理块在相邻帧之间来回跳半像素到两像素。第二个是局部结构重解释某个凹槽在第 1 帧是凹陷到第 5 帧模型觉得凹陷不好画干脆重画成凸起反正单帧的扩散损失也不惩罚它。我做过一个很朴素的对照实验同样的参考图、同样的位姿序列只把跨视角信息从“共享注意力”换成“完全独立采样”LPIPS 从 0.19 掉到 0.27 左右但人眼主观上觉得“独立采样那一版更糊、更不真实”而共享注意力那一版虽然单帧更锐播放起来抖得让人头晕。这个现象说明单帧指标和序列指标是背离的你拿 FID 去挑模型很可能挑出一个抖得最厉害的那个。1.2 几何一致性的三条硬指标别只看 PSNR我在项目里评估几何一致性一般固定看三样东西缺一不可。这三样也可以直接拿去当验收标准甲方问“你这算不算一致”你拿数据说话。指标怎么算合格线参考说明重投影深度误差用估计深度把视角 A 的像素投到视角 B比对 B 的深度RMSE 0.03归一化尺度最直接但对深度质量敏感跨视角光度一致性相邻视角重叠区做 warp 后的 RGB 差值重叠区平均差 8/255便宜、快适合 CI 里跑序列闪烁率相邻帧同一语义区域的高频能量变化相对基线下降 40% 以上主观感受最贴近第一项是根第二项是表第三项是用户实际看到的东西。很多团队只跑第一项结果发现数字很漂亮产品经理拿着手机一转就说“还是在抖”原因是深度图的低频误差很小、高频噪声很大RMSE 这种 L2 指标对椒盐噪声不敏感但人眼对闪烁极其敏感。提示验收几何一致性时务必把序列渲染成 mp4 逐帧看而不是只看抽帧的对比图。我吃过这个亏抽帧图非常完美播放起来像水面波纹。还有一个容易被忽略的点位姿质量本身就是几何一致性的下限。如果你的相机位姿来自单目位姿估计误差在两三度以上那么任何跨视角约束都会把错误信息互相污染越约束越糊。这一点在后面第 4 章讲数据准备时还会再提一次因为它是很多“训不动”问题的真凶。2. GLD 的整体设计把几何先验挪进潜空间先说结论性的判断在像素空间做几何约束代价高、噪声大、梯度还脏在潜空间做代价低一个数量级而且能复用预训练扩散模型的先验。GLD 的核心主张就是后者。2.1 为什么不在像素空间硬约束最直觉的做法是每个视角生成 RGB然后拿多视角立体MVS或者可微渲染重建一遍用重建误差回传梯度。这条路在学术上叫“渲染式自监督”能work但工程上很难受。原因有三。第一显存换不来。512×512 的 RGB 图一张就是 78 万像素四视角就是 300 多万个位置每一步去噪都要做一次可微光栅化反向传播还要存中间结果。我粗略算过在 24GB 卡上batch size 只能压到 1 到 2训练周期直接翻三倍。第二梯度噪声大。MVS 重建在无纹理区域、遮挡边界、反光面上会给出完全错误的对应这些错误通过渲染误差回传等于给模型灌噪声。你调小权重约束就形同虚设调大权重画面就出现奇怪的拉丝。第三和扩散的时间步语义冲突。扩散早期高噪声图像几乎是纯噪这时候做 MVS 重建纯属浪费算力后期低噪声才该上几何约束。像素空间方案很难在时间轴上优雅地开关而潜空间方案天然可以按时间步加权。注意这不是说像素级约束没用。正确的用法是把它当“微调期的精修手段”而不是“训练全程的主损失”。我在最后一轮 5k step 会加一点渲染损失其作用主要是收边缘而不是塑形。2.2 三路输入如何汇入同一个去噪网络GLD 的输入我一般组织成三路参考视角的 RGB 潜变量、几何潜变量、相机条件。三者在通道维拼接之后送进 UNet而不是各自单独过一遍编码器再相加——拼接更省事也避免了多分支对齐的问题。第一路RGB 潜变量。参考图经过 VAE 编码512×512 输入、8 倍下采样得到 64×64×4 的 latent。注意这里用的是参考视角不是目标视角目标视角的 latent 在训练时是加噪的真值推理时是纯噪声。第二路几何潜变量。这是 GLD 真正的主角。它可以是三平面triplane特征、可以是稀疏体素、也可以只是参考视角的深度图加表面法向。我实测下来三平面 深度图双路性价比最高三平面负责承载“我大致知道这个物体是什么形状”的粗粒度记忆深度图负责提供逐像素的精确锚点。三平面分辨率用 32×32三张平面各 32 通道总共 3×32×32×32 ≈ 9.8 万个浮点数存成 fp16 不到 200KB几乎不占显存。第三路相机条件。目标视角的相机参数包括内参焦距、主点和外参旋转、平移。这里有个小细节值得展开位姿的编码方式对结果影响很大我下面 3.1 节单独讲。三路拼完之后通道数是 4 3三平面压缩后 深度 1 相机嵌入若干具体数值取决于你的实现。拼接位置我建议放在 UNet 的第一个卷积之后而不是直接作为输入层因为输入层卷积核感受野太小几何信息还没扩散开就被 RGB 淹没了。2.3 训练目标怎么拆三份损失各管一段GLD 的训练损失我拆成三块权重分别是 1.0、0.3、0.1起步值后面会讲怎么调。扩散主损失负责画面质量就是标准的噪声预测 MSE或者 v-prediction 的 MSE。这块不要动动了就是和预训练权重打架。几何一致性损失负责跨视角约束作用在预测的深度图或者三平面重建出的点图上。具体做法是把视角 A 预测的深度投到视角 B和 B 的深度做一致性检验只对置信度高的像素算损失置信度用深度梯度、边缘距离来筛。跨视角匹配损失负责纹理层面的对齐作用在 UNet 中间层的特征图上让不同视角在重叠区域的注意力图尽量相似。这一项我一开始觉得是玄学后来做消融发现它确实有用——去掉之后闪烁率指标会回退大约 25%但对 PSNR 几乎没有影响属于典型的“指标看不见、眼睛看得见”的损失。权重不是固定的。我的做法是按扩散时间步 t 做调度t 大噪声重时几何损失权重压到接近 0t 小接近清晰图时拉到满值。理由很朴素高噪声阶段模型预测的深度本身就是噪声拿噪声去约束噪声没有意义。3. 关键模块的工程实现细节这一章是我个人觉得最值钱的部分因为大部分论文里一笔带过的东西实际落地时能耗掉你两周。3.1 相机嵌入别再用裸的 4×4 矩阵了直接拿 4×4 外参矩阵展平成 16 维送进 MLP是最常见也最糟糕的做法。问题在于这个表示对旋转的连续性很差绕 Y 轴转 180 度和转 181 度在矩阵空间里距离很远模型学起来很吃力。我推荐两种替代方案都实测更稳。第一种是 Plücker 射线表示对每个像素生成一条射线的方向和矩方向和矩各 3 维一共 6 维然后按 latent 分辨率下采样拼接到特征图通道上。这种表示的好处是“每个像素都知道自己对应空间里哪条射线”和卷积的局部性天然契合而且对旋转连续。第二种是位姿的球面插值编码把旋转拆成四元数平移做归一化然后各自过正弦位置编码。这种做法实现简单适合显存紧张、不想给每个像素都算射线的场景。编码方式维度开销旋转连续性实现复杂度我的推荐场景裸 4×4 矩阵16差低不建议Plücker 射线6×H×W好中高分辨率、多视角四元数正弦编码约 64好低显存紧张、快速验证还有一个坑内参必须归一化。不同数据集的焦距像素值差好几倍模型会把焦距当成一个强条件去拟合导致换数据集就崩。我的做法是统一把焦距除以图像短边主点归一化到 [-1,1]这样跨数据集迁移时几乎不用改代码。3.2 几何潜变量怎么构造才不会一开始就崩几何潜变量的初始化方式直接决定了训练前 2k step 是稳步下降还是原地爆炸。我踩过的坑是一开始直接把三平面随机初始化然后让模型从零学结果前 5k step 模型根本没学会“三平面代表形状”它干脆把三平面当成噪声通道忽略掉了损失曲线看着在降实际几何损失一直不动。后来改了策略分两步走。第一步用参考视角的深度和法向做监督预训练让三平面先学会重建出大致形状这一步只需要几千个样本收敛很快因为没有扩散过程参与。第二步再把三平面冻结或者以低学习率接入扩散训练。提示如果你手上没有深度真值用现成的单目深度估计模型生成伪标签也能跑但要记得做尺度对齐中位数对齐或者最小二乘对齐否则尺度漂移会把三平面带歪。三平面本身的采样方式也有讲究。标准做法是在三个正交平面上做双线性采样后求和但我建议加一个可学习的平面权重初始化成 1/3 均匀。原因是在实际物体上三个平面的贡献并不均等——扁平的物体比如书本在某个平面上信息量极低均等加权等于引入噪声。3.3 跨视角注意力放在哪一层是一道算术题跨视角信息怎么交互最直接的是把所有视角的 token 拼起来做全局注意力。但这是显存杀手必须算清楚账。以 64×64 的 latent 为例每个视角 4096 个 token4 个视角就是 16384 个 token。自注意力的矩阵大小是 16384² ≈ 2.68 亿个元素fp16 下单个注意力矩阵就是 0.5GB多头 8 头的话 4GB再乘上层数和反向传播的中间存储24GB 卡直接爆。所以我的做法是只在下采样最狠的几层做跨视角注意力。在 UNet 的 8×8 latent 分辨率层每个视角只有 64 个 token四视角 256 个 token注意力矩阵才 6.5 万几乎免费。在 16×16 层做每视角 256 个 token四视角 1024矩阵 100 万也就 2MB 量级完全可以接受。交互层分辨率单视角 token四视角 token注意力矩阵元素建议8×8642566.5 万必做16×162561024105 万建议做32×32102440961677 万视显存而定64×644096163842.68 亿不要做这套“低分辨率全局交互 高分辨率局部卷积”的组合本质上是拿 UNet 自己的层级结构当多尺度方案用不需要额外设计。我在 8×8 和 16×16 两层都加了跨视角注意力显存只涨了不到 1.5GB闪烁率指标降了约 35%。3.4 采样阶段的引导权重别照抄文生图那套推理阶段几何引导的强度和分类器无关引导CFG之间会打架。CFG 的 scale 调到 7 以上画面会变得锐利但过饱和几何上表现为深度图出现不该有的尖峰几何引导权重一高画面又会变糊、纹理变成塑料感。我实际调下来比较稳的区间是CFG scale 3.0 到 4.5几何引导权重从 0.5 线性升到 1.0注意是随去噪步数递增不是固定值。为什么递增因为早期步数决定的是整体构图这时候强几何引导会把模型锁死在一个粗糙形状上后面再也改不回来后期步数负责细节几何引导越强越能把边缘钉住。注意如果你用的是 DDIM 这类确定性采样器几何引导的梯度可以直接加在预测噪声上用 Euler 之类的求解器要注意步长缩放否则后期会过冲表现为边缘出现一圈黑边。4. 从零跑通一套 GLD 流水线原理讲完进实操。这一章我按真实项目顺序来数据、训练、推理、验收每步给参数和计算过程。4.1 数据与位姿这一步偷懒后面全是坑数据准备我只认三条硬规矩。第一全部去畸变。鱼眼或者广角相机不做去畸变内参就不是一个针孔模型能描述的你在模型里学到的“射线”全是弯的。去畸变之后再重算内参这一步很多人省了结果是边缘视角的几何误差是中心的两三倍。第二位姿对齐到统一坐标系。具体做法是把所有相机的平移取均值作为原点把点云的主方向对齐到坐标轴整体缩放到单位球内。归一化的意义在于让模型见到的平移数值始终在 [-1,1] 附近避免不同场景尺度差异把位置编码搞乱。第三位姿精度自检。我的门槛是在验证集上用估计位姿做三角化重投影误差的中位数要低于 1.5 像素。超过这个数先去优化位姿别急着训模型。曾经有一次我图省事拿了一组误差 3 像素左右的位姿直接开训损失曲线一路平稳生成的模型转 30 度就开始重影查了三天才定位到位姿。数据量的经验值单物体类别2 万到 5 万个“参考图 4 到 8 个目标视角”的样本组合够训一个可用模型。样本不是越多越好视角分布的覆盖度更重要——我宁愿要 1 万组覆盖上半球均匀分布的也不要 5 万组全挤在正面 ±30 度。4.2 训练配置与显存预算算清楚再开跑先给一套我实际用过的配置A100 40GB 单卡能跑24GB 卡需要开梯度检查点加 batch 减半。项目取值说明基础模型SD 类 latent diffusionUNet 约 8.6 亿参数直接用预训练权重微调方式LoRA rank 64 几何分支全参几何分支是新加的必须全参分辨率512×512latent 64×64VAE 8 倍下采样batch size每卡 2梯度累积 4等效 batch 8视角数41 参考 3 目标视角数增加线性涨显存学习率主干 1e-5几何分支 1e-4差一个量级训练步数3 万到 5 万超过 5 万开始过拟合参考视角显存怎么估我一般按这个框架算模型权重 fp16 约 1.7GBLoRA 加几何分支约 0.5GB优化器状态AdamW 对可训练参数存 fp32 一阶二阶动量约是可训练参数量的 8 倍字节数如果全参是 8.6 亿那就是 6.9GB用 LoRA 只训 5% 的话就降到 0.35GB 左右。剩下的大头是激活值512 分辨率、batch 2、四视角的情况下不开梯度检查点大概 14GB 到 18GB开了能压到 6GB 上下代价是训练速度慢 30% 左右。我个人的建议是先用小分辨率 256 跑通全流程确认损失能降、几何指标能改善再上 512。256 分辨率下显存占用只有 512 的四分之一左右迭代一圈只要几小时试错成本低太多。训练中的监控指标除了总损失一定要单独打三条曲线扩散损失、深度重投影误差、跨视角光度一致性。三条曲线的形状能告诉你很多事。比如扩散损失降但几何指标不降说明几何分支没学到东西多半是三平面初始化或者学习率的问题几何指标先降后升多半是过拟合了参考视角模型开始“背”训练集的形状。4.3 推理流水线与验收姿势推理阶段我固定成四步编码参考图 → 构建几何潜变量 → 逐视角条件去噪 → 后处理对齐。第一步编码参考图VAE 编码后记得乘 0.18215 这个缩放系数沿用预训练模型的约定忘了这一步画面会灰得像蒙了层雾。第二步构建几何潜变量把参考图送进几何分支得到三平面和深度图深度图做一次中值滤波去掉飞点。这一步大概占单次推理时间的 8%。第三步逐视角去噪这是大头。4 个视角、30 步采样、CFG 加几何引导在 A100 上大概 9 到 12 秒。这里有一个可以省时间的技巧多个视角并行去噪共享同一份几何潜变量而不是串行地一个一个生成。串行的好处是后一个视角可以参考前一个的结果但会累积误差并行更快且一致性由几何潜变量统一保证。我两种都试过并行方案的闪烁率指标反而更好因为不存在“前面的错被后面继承”的问题。第四步后处理主要是把生成的视角做一次全局的颜色一致性校正避免不同视角之间的亮度跳变。做法很简单取所有视角重叠区域的均值做一次仿射变换对齐到参考视角。验收的时候我建议按这个顺序看先看单帧画质有没有结构崩坏再看两两相邻视角的重叠区有没有错位最后整段播放有没有闪烁。前两项用静态图就能判断第三项必须播视频而且要在大屏上看手机小屏会把闪烁糊掉。4.4 消融怎么做才说明问题而不是凑数消融实验最容易犯的错是只消一个模块的“有无”结论是“有用”。这种结论没有信息量。我一般做三组消融。第一组几何潜变量的表达形式三平面 vs 纯深度图 vs 三平面深度。这组能说明“粗粒度形状记忆”和“精确定位”是不是互补的。我实测的结果是纯深度图的单帧质量最好但视角跨度超过 60 度就开始崩纯三平面跨度能力好但边界模糊两者结合在跨度和锐度上都接近最优。第二组跨视角注意力的位置只放 8×8、只放 16×16、两层都放。这组能说明尺度选择的影响。结论是两层都放最稳只放 8×8 在细节处仍有轻微错位。第三组几何损失的时间调度全程恒定权重 vs 随时间步递增。这组最能说明“为什么要在潜空间做”因为恒定权重那一组的训练极不稳定前 3k step 经常出现损失尖峰。提示消融实验务必固定随机种子和评估集并且每个配置至少跑两次。扩散训练本身的方差就不小我见过同一配置两次跑的闪烁率差 8%单次结果直接下结论容易翻车。5. 常见问题与排查实录这一章全是踩过的坑按症状来查最快。5.1 转起来会闪、边缘果冻状抖动这是最高频的问题我统计过八成的原因集中在三处。原因一跨视角注意力的 mask 没做对。当两个视角完全没有重叠时强制做注意力对齐等于让模型凭空捏造对应关系。我的做法是用相机夹角和视锥重叠率算一个软 mask重叠率低于 15% 的视角对直接置零中间区域用余弦衰减。原因二几何潜变量在去噪过程中被反复更新但没有阻尼。有些实现会在每个去噪步都用当前预测的深度去刷新几何潜变量这会导致潜变量抖得比画面还厉害。正确做法是只在固定的几个时间步更新比如 t 在 800 到 600、400 到 200 这两段各更新一次并且用指数滑动平均平滑。原因三VAE 解码器本身的高频不稳定。这一点很容易被忽略。同一个 latent 附近做微小扰动解码出来的高频纹理可能变化很大。缓解办法是在解码前对 latent 做轻微的低通或者干脆在损失里加一项 latent 的平滑正则。5.2 几何分支训着训着就“躺平”表现是几何损失一开始降降到某个值之后完全不动同时扩散损失继续正常下降画面看起来还行但换个视角就露馅。根因通常是梯度断流。检查三件事几何潜变量进 UNet 的那条路径上有没有.detach()很多人为了省显存顺手加的三平面的学习率是不是被主干的低学习率带偏了几何损失前面那个置信度 mask 是不是筛得太狠导致有效像素不到 5%。我遇到过一次特别隐蔽的置信度筛选用的是深度梯度阈值但深度图归一化之后数值范围变了阈值还是老的值结果 95% 的像素被筛掉几何损失等于没算。后来我把阈值改成用分位数自适应这个问题就再没出现过。5.3 损失震荡、偶发尖峰扩散训练本身有噪声轻微震荡正常。但如果出现周期性尖峰或者尖峰之后损失回不到原来的水平就要查了。第一查学习率 warmup。几何分支是全参训练学习率 1e-4如果不做 warmup 直接上前几百步很容易把三平面带崩。第二查数据里的异常样本。我遇到过一批样本的位姿是镜像的左右手坐标系搞反单看图像完全正常但几何约束的方向全是反的损失会周期性爆一次。第三查混合精度下的数值溢出。几何分支里的归一化和反归一化操作在 fp16 下容易出 inf建议这几处强制 fp32。5.4 问题速查表症状最可能原因快速验证处理方式相邻视角边缘重影位姿误差偏大三角化重投影误差重估位姿或降低跨视角注意力权重转 60 度以上结构崩坏几何潜变量容量不足加大三平面分辨率看是否缓解升到 48×48 或加一路点图特征画面发灰发白VAE 缩放系数漏乘打印 latent 均值方差补上 0.18215 缩放训练早期损失尖峰缺 warmup看前 500 步曲线加 500 步线性 warmup深度图有椒盐噪点单目深度伪标签质量问题可视化深度图中值滤波加边缘引导平滑推理速度慢视角串行生成计时各阶段改并行去噪共享几何潜变量6. 这套东西适合用在哪、哪里别硬上技术选型最怕的是拿着锤子看什么都像钉子。GLD 有它明确的舒适区也有明显不划算的地方。6.1 舒适区物体级、中小视角跨度、需要批量产出我判断一个需求适不适合用 GLD看三个特征。物体级、背景简单或者需要抠掉背景。单物体、白底或者纯色背景是 GLD 最舒服的场景因为几何潜变量只需要承载一个紧凑的形状容量够用。一旦场景变成整间屋子三平面的分辨率就得往上翻好几倍显存和训练成本都会失控。视角跨度在 120 度以内。超过这个范围参考视角看不到的部分全靠模型“脑补”几何潜变量也只能给出一个模糊的先验一致性会明显下降。如果你的需求是 360 度环绕老老实实走重建路线或者用多张参考图。需要批量、快速、低成本的素材产出。相比走“重建 渲染”的路线GLD 不需要每个资产都做一遍优化前向一次几十秒就能出一组视角适合电商图、游戏里的小道具、AR 展示这类量大但精度要求中等的场景。6.2 什么时候别用它高精度和可编辑是硬伤如果你的下游需要精确的几何尺寸比如工业件展示、需要测量GLD 给不了。它的几何潜变量是一个隐式表征重建出来的网格精度有限而且尺度是靠归一化猜的不是真实尺度。如果需要可编辑改颜色、换材质、拆件GLD 也不合适。它生成的是图像序列不是带语义分层的资产。真要编辑还是得回到显式表示那条路上去。还有一类情况要想清楚你的评估标准是什么。如果甲方只看单帧截图那用更简单的方案就够了上 GLD 属于杀鸡用牛刀还多了训练成本。只有当他们真的会“转起来看”几何一致性的投入才划得来。6.3 一个务实的组合方案最后说说我目前觉得最划算的工程组合用 GLD 做快速预览和视角扩增用重建方案做最终资产。具体流程是这样先用 GLD 在几秒内生成 8 到 12 个视角的图作为重建的输入相当于用生成模型帮你把稀疏视角补密。这一步做完重建的成功率和质量都会明显提升因为输入视角的覆盖度上去了。然后再走一遍精细重建得到最终资产。这个组合的好处是把两者的短板互补了GLD 缺精度但它擅长补视角重建缺输入但它擅长出精度。我在几个小道具类项目上这么干过整体耗时比纯重建方案缩短了差不多一半因为省掉了反复补拍、反复调位姿的时间。至于训练这边我个人最实在的一条经验是别一上来就追求端到端。先把几何分支单独训好、验证它能重建出靠谱的形状再把它接进扩散训练能省掉大量“到底是哪个模块坏了”的排查时间。我最早那版是端到端一把梭损失曲线看着挺美实际生成的模型转 40 度就开始长第二个把手回头拆模块单独验证才发现几何分支其实一直没学到东西全程靠 RGB 先验在硬撑。