论文精读 · 第 1 篇 · 2026-08
单图反射分离:一个扩散模型,同时生成透射层与反射层
这一页写给刚从 LLM 世界回来的你:先用你熟悉的语言把扩散模型补齐,再把这篇论文的四个组件一个一个拆开——每一步都有公式、有原文插图,还有两个可以动手拖的小实验。
§1问题:一张图,拆成两层
隔着玻璃拍照,传感器收到的是两个场景的叠加:玻璃后面你想拍的东西,叫透射层 \(\mathcal T\)(transmission);玻璃反射出来的东西,叫反射层 \(\mathcal R\)(reflection)。反射分离要做的,就是从一张混合图 \(\mathcal I\) 出发,把 \(\mathcal T\) 和 \(\mathcal R\) 都还原出来。
难点在于:这是一个严重病态(ill-posed)的问题。一张图要拆成两张图,未知数是观测量的两倍,解本质上不唯一——同一张混合图,可以有无数种「两层怎么分」的方案。要选出合理的那一种,只能靠先验:你得知道自然图像长什么样、反射通常长什么样。
这就像给你一段两个人同时说话被混在一起的转写文本,让你还原出各自说了什么——单看混合结果信息不够,必须依赖「人说话的先验」。在 LLM 世界里,先验来自预训练语言模型;在这里,先验来自预训练扩散模型。整篇论文的主张一句话就能说完:把 Stable Diffusion 的生成先验,微调来做反射分离。
为什么以前的方法不够用?看两个极端:
强反射/眩光——透射层的内容被反射整个盖掉,被盖住的信息根本不在输入里。判别式网络(DSRNet、DSIT 这类直接回归输出的模型)只能给出模糊或带伪影的结果,因为它们没有「脑补」的能力。
弱反射/低光——反射信号太微弱,大多数方法干脆输出一张几乎全黑的反射层,把有意义的反射内容全丢掉。
生成式先验恰好补上这两个短板:强反射时,模型可以像文生图那样幻构出被盖住的细节;弱反射时,它知道「反射层应该长什么样」,能把微弱的信号捞出来。这篇论文是第一个专门为反射分离微调的扩散模型,而且两层一起出。此前最接近的 L-DiffER 只输出干净透射层,还要依赖对每张图的文字描述;这篇只用两个固定 prompt——"Transmission" 和 "Reflection"——就把两层全都要了。
§2补课:从 LLM 到扩散模型
你熟 transformer、熟后训练,但扩散这套可能生疏了。好消息是:两边的骨架惊人地对称,补的其实只有「生成范式」这一层。先上对照表:
| 概念 | LLM 世界 | 扩散世界(本文用的 LDM) |
|---|---|---|
| 生成方式 | 自回归,一次一个 token | 迭代去噪,一次「干净一点」 |
| 模型学什么 | 预测下一个 token 的分布 | 预测当前图里掺了什么噪声 \(\varepsilon\) |
| 压缩表示 | tokenizer:文本 → token 序列 | VAE:图像 → latent(下采样 8×) |
| 主干网络 | Transformer | U-Net(里面同样塞满 attention) |
| 条件注入 | prompt 拼进上下文 | 文本经 cross-attention 进 U-Net |
| 「引导采样」 | 对比解码 / logit 处理 | Classifier-Free Guidance(§6 要用) |
| 推理时补算力 | test-time compute、self-consistency | 测试时 latent 优化(§7 要用) |
2.1 前向:把图一步步埋进噪声里
取一张干净图的 latent \(z_0\),扩散的前向过程按预定的噪声表 \(\{\beta_t\}\) 一步步加高斯噪声。妙处是任意时刻 \(t\) 都有闭式解,一步就能从 \(z_0\) 跳到 \(z_t\):
\(t\) 越大,\(\bar\alpha_t\) 越小:信号系数 \(\sqrt{\bar\alpha_t}\) 缩水,噪声系数 \(\sqrt{1-\bar\alpha_t}\) 长大,直到 \(z_T\) 几乎是纯噪声。拖一拖下面的滑块,亲手感受一下:
2.2 反向:训练一个「猜噪声」的网络
生成的任务是从纯噪声一步步走回干净图。为此训练一个网络 \(\varepsilon_\theta\),输入带噪 latent \(z_t\)、时间步 \(t\)、文本条件 \(c\),让它猜出「刚才掺进去的噪声是什么」:
把它当作扩散世界的 next-token prediction:一个简单得不像话的自监督目标,规模上去之后,模型被迫学会了「自然图像是什么样」的全部知识。你做 SFT 时复用的是语言先验;这篇论文微调时复用的,就是这个噪声预测网络里压着的图像先验。
推理时从 \(z_T\sim\mathcal N(0,\mathbf I)\) 出发,反复「预测噪声 → 去掉一点 → 得到 \(z_{t-1}\)」,走 50 步(本文的设置)就得到干净的 \(z_0\)。
2.3 Tweedie 公式:随时偷看「当前的答案」
还有一个后面反复要用的工具。在任意中间时刻 \(t\),不必走完全程,用当前的噪声预测就能一步估出干净 latent:
这个式子从哪来?(30 秒推导)
把前向闭式解 \(z_t=\sqrt{\bar\alpha_t}\,z_0+\sqrt{1-\bar\alpha_t}\,\varepsilon\) 当作方程,把 \(z_0\) 解出来:\(z_0=(z_t-\sqrt{1-\bar\alpha_t}\,\varepsilon)/\sqrt{\bar\alpha_t}\)。真噪声 \(\varepsilon\) 不知道,但网络的预测 \(\varepsilon_\theta\) 就是它的最优估计,代入即得。这是 Tweedie 公式在扩散里的形式——「当前图减掉预测噪声,再把幅度缩放回去」。§7 的 latent 优化全靠它把中间状态变成可以打分的「预览图」。
2.4 Latent Diffusion:在 VAE 的隐空间里做这一切
Stable Diffusion 的「L」指 latent:先用一个冻结的 VAE 编码器 \(\mathcal E\) 把 \(H\times W\times 3\) 的图压成 \(\tfrac H8\times\tfrac W8\times 4\) 的 latent,扩散全程在这个小空间里做,最后用解码器 \(\mathcal D\) 还原回像素。本文推理分辨率 960×960,对应 latent 只有 120×120——这就是为什么后面的「latent 空间优化」能比像素空间快一个数量级。
U-Net 内部有两种 attention,和你熟悉的公式一模一样(\(H=\operatorname{softmax}(QK^{\top}/\sqrt d)\,V\)):self-attention 里 \(Q,K,V\) 都来自空间特征(把图的每个位置当 token);cross-attention 里 \(K,V\) 来自文本编码。§5 的改动,动的就是 self-attention。
§3方法鸟瞰:一个 U-Net,两条轨迹
整体设计先看一眼,再逐个拆。输入图 \(\mathcal I\) 编码成 \(z^{\mathcal I}\);两条扩散轨迹 \(z_t^{\mathcal T}\) 和 \(z_t^{\mathcal R}\) 从各自的纯噪声出发,共享同一个微调过的 U-Net,分别被 "Transmission" / "Reflection" 两个固定 prompt 引导,同步去噪 \(T\) 步,最后解码出两层图像。
- 条件微调(§4)
把输入图的 latent 拼进 U-Net 输入,全量微调,一个模型靠 prompt 区分两层。这是地基。
- 跨层自注意力 CLSA(§5)
让两条轨迹在 U-Net 内部互相「看见」对方,各自认领自己的内容,减少互相污染。
- 互斥采样 Disjoint Sampling(§6)
采样时把对方层的预测噪声当负向引导,每一步都把两条轨迹往两边推;带出的色偏由 FGFM 修正。
- 测试时 latent 优化(§7)
用一个学出来的「组合函数」检验两层能否拼回原图,不满足就对 latent 做梯度修正。
§4组件一:条件微调——扩散模型的「SFT」
怎么让文生图模型「看着一张图」工作?做法直白:把输入图的 VAE 编码 \(z^{\mathcal I}\) 和带噪 latent \(z_t\) 沿通道维拼接成 \([z_t;\,z^{\mathcal I}]\) 喂给 U-Net。唯一的结构改动是 U-Net 第一层卷积的输入通道翻倍(4→8),新增通道零初始化。这是 Marigold 一路「扩散模型做感知任务」的标准做法。
一个模型要管两层,靠 prompt 区分:训练时两层各算一个噪声预测损失,加在一起:
其中 \(c^{\mathcal T}\)="Transmission",\(c^{\mathcal R}\)="Reflection",两层的噪声 \(\varepsilon^{\mathcal T},\varepsilon^{\mathcal R}\) 独立采样。真实数据往往没有反射层的真值(想想怎么采集:透射层可以撤掉玻璃再拍一张,反射层很难单独拍),那就只算透射那一项。
这一步在气质上就是 SFT:拿一个强预训练基座,换上任务格式(条件拼接 + 两个固定 prompt),小学习率全量微调。连「预训练权重有多重要」的消融都和 LLM 世界一致——§8 会看到,从头训 PSNR 掉 3.4 dB,反射层掉得更惨,因为反射信号弱、真实数据又没监督,全靠生成先验撑着。
只做到这一步,效果已经「还行」(§9 消融表的第一行),但难例里两层会互相拖泥带水:透射层里残留反射影子,反射层里带进透射内容。下面三个组件就是冲着这个来的。
§5组件二:跨层自注意力——让两层互相看见
标准做法里,两条轨迹各自过 U-Net,谁也不知道对方在生成什么。CLSA(Cross-Layer Self-Attention)把每个 self-attention 块改成联合处理两层:每层的 query 去 attend 两层拼起来的 key/value:
\([\,\cdot\,;\cdot\,]\) 是沿空间(token)维拼接;\(Q^i,K^i,V^i\) 由对应 prompt 激活的那条支路产生。
公式完全是你熟悉的味道:相当于把「另一层的特征」拼进了上下文窗口。直觉像两个 agent 各写一份摘要,但共享一块草稿区——透射支路能看到反射支路正在认领哪些内容,于是「这块你要了,我就不要了」,在真值监督下形成显式分工。
消融很能说明问题:CLSA 对反射层帮助最大(SIR² 上反射层 DISTS 从 0.382 → 0.284)。反射层质量上去之后,反过来又给透射层提供了更准的「减数」,透射也跟着变干净:
§6组件三:互斥采样——把对方当负向引导
6.1 先补一块地基:Classifier-Free Guidance
文生图的标准操作 CFG:同一个模型算两次噪声预测——一次带条件 \(\varepsilon_{\text{cond}}\),一次无条件 \(\varepsilon_{\text{uncond}}\)——然后沿「有条件相对无条件的方向」外推:
效果是采样更「听 prompt 的话」。原理:噪声预测正比于分数函数(score,对数概率的梯度),这样组合等价于在采样 \(p(z\mid c)\bigl[p(z\mid c)/p(z)\bigr]^{k}\)——把条件与无条件的概率比抬了 \(k\) 次方。
这就是扩散版的 contrastive decoding:拿「想要的分布」减去「不想要的分布」,放大差异方向。LLM 里是 logits 相减,这里是预测噪声相减——同一个念头,不同的空间。
6.2 Disjoint Sampling:负向引导换成「对方那层」
微调加 CLSA 之后仍有残留重叠。作者的招数:透射轨迹想最大化的不是 \(p(z_t\mid\mathcal T)\),而是概率比 \(p(z_t\mid\mathcal T)/p(z_t\mid\mathcal R)\)——既要像透射,又要不像反射。由于微调后 \(\varepsilon^{\mathcal T},\varepsilon^{\mathcal R}\) 分别对应 \(\nabla\log p(z_t\mid\mathcal T)\) 和 \(\nabla\log p(z_t\mid\mathcal R)\),照 CFG 的葫芦画瓢:
再用修改后的 \(\hat\varepsilon\) 走标准 DDPM 一步:\(z_{t-1}^{\mathcal T}=\tfrac{1}{\sqrt{1-\beta_t}}\big(z_t^{\mathcal T}-\tfrac{\beta_t}{\sqrt{1-\bar\alpha_t}}\hat\varepsilon^{\mathcal T}\big)\)。每一步都推一把,整条轨迹被持续拉开。拖下面的 \(k\) 看看向量怎么动:
6.3 副作用与解药:FGFM
直接改噪声预测会带来色偏(color drift)——毕竟你在偏离模型认为「最可能」的方向。解药是 FGFM(Fidelity-Guided Feature Modulation,保真引导的特征调制):解码时,把原始混合图的编码特征「抄」回来调制解码特征:
\(f\) 是几层卷积,\(y_{\mathrm{enc}}\) 是原图特征,\(w\) 是保真度旋钮。训练用 L2 + LPIPS(\(\beta_1{=}1,\beta_2{=}0.1\)):\(\;\mathcal L=\beta_1\lVert\hat{\mathcal T}-\mathcal T\rVert_2^2+\beta_2\sum_i w_i\lVert\phi_i(\hat{\mathcal T})-\phi_i(\mathcal T)\rVert_2^2\)。FGFM 只用在透射层——反射层本来就没多少高频内容可抄。
§7组件四:测试时 latent 优化——用「能拼回原图」自检
一次前向分离不保证满足组合约束:两层拼回去应该还原输入。传统做法假设像素空间线性叠加 \(\mathcal I=\mathcal T+\mathcal R\),但真实成像(玻璃吸收、二次反射、色移)并不严格满足。这篇有两个聪明点:
7.1 组合函数是「学」出来的,而且在 latent 空间
训一个小卷积网络 \(\mathcal C\),吃两层的 latent,吐出混合图的 latent。在有真值三元组的合成数据上,用组合损失训练:
比手写 \(\mathcal I=\mathcal T+\mathcal R\) 更贴真实成像;而且工作在 120×120 的 latent 上,梯度不需要穿过 VAE 解码器和大特征图。
7.2 推理时用它迭代修 latent
每 5 个扩散步做一轮、每轮 4 次:先用 Tweedie 公式(§2.3)从当前 \(z_t\) 一步估出两层的「预览」\(\hat z_0^{\mathcal T},\hat z_0^{\mathcal R}\),拼成伪混合图和真的 \(z^{\mathcal I}\) 比,把误差梯度回传到两层 latent 上:
(反射层同理;梯度按 latent 范数归一化,步长稳定。)关键在于:这一轮里 \(\varepsilon\) 是固定的——每个 \(t\) 只跑一次 U-Net,Tweedie 映射是线性的,所以梯度只流过小小的 \(\mathcal C\),完全不反传 U-Net 和解码器。代价便宜得惊人:512² 下每次更新 0.15 秒;像素空间优化要 1.53 秒还更费显存,指标反而更差:
| 优化空间 | PSNR ↑ | SSIM ↑ | LPIPS ↓ | DISTS ↓ | 每次更新耗时 |
|---|---|---|---|---|---|
| 像素空间(\(\mathcal I=\mathcal T+\mathcal R\)) | 21.53 | 0.735 | 0.168 | 0.127 | 1.53 s |
| latent 空间(本文) | 25.54 | 0.808 | 0.164 | 0.116 | 0.15 s |
这就是图像版的 test-time compute:推理时多花一点算力,用一个可验证的信号(组合一致性,类似 verifier)来修正生成。补充材料里还有个很妙的实验:拿一个完全没微调过的文生图模型、空 prompt,光靠这个组合引导也能做出像样的两层分离——「约束本身就是很强的监督」。
7.3 完整推理流程
把 §4–§7 串起来,就是补充材料的 Algorithm 1。先看原文,再看小c给你标注的伪代码:
z_T^T, z_T^R ~ N(0, I); z_I = Encoder(I) # 两条轨迹从纯噪声出发
for t = 50 … 1:
ε_T = ε_θ([z_t^T ; z_I], t, "Transmission") ┐ 同一个 U-Net
ε_R = ε_θ([z_t^R ; z_I], t, "Reflection") ┘ CLSA 让两支互通
if t % 5 == 0: # —— latent 优化,每 5 步一轮
for j = 1 … 4:
ẑ0_T, ẑ0_R = Tweedie(z_t^T, ε_T), Tweedie(z_t^R, ε_R)
L = ‖ z_I − C(ẑ0_T, ẑ0_R) ‖² # 拼回去像不像原图?
z_t^T −= γ·‖z_t^T‖·∇L; z_t^R −= γ·‖z_t^R‖·∇L
ε̂_T = ε_T + k·(ε_T − ε_R) # —— 互斥采样,k = 0.2
ε̂_R = ε_R + k·(ε_R − ε_T)
z_{t−1}^T, z_{t−1}^R = DDPM_step(ε̂_T), DDPM_step(ε̂_R)
T = Decoder(z_0^T) with FGFM(w=0.8) # 透射层解码时抄回原图特征
R = Decoder(z_0^R)§8训练配方
训练分两阶段,和「先预训练、再对齐」的直觉一致:阶段一从 Stable Diffusion 2.1 初始化,按 §4 的联合损失全量微调 U-Net;阶段二冻住 U-Net,单独训 FGFM(只训 10 个扩散步、只作用于透射层)。组合网络 \(\mathcal C\) 只用合成数据单独训。
| 基座模型 | Stable Diffusion 2.1(冻结 VAE,全量微调 U-Net) |
| 优化器 / 学习率 | Adam · 3×10⁻⁵ |
| 等效 batch size | 32 |
| 训练硬件 | 单张 NVIDIA A6000(48 GB) |
| 数据 | 与 DSRNet 相同(Setting 2 w/ Nature,合成 + 真实;真实数据只有透射真值) |
| 推理设置 | 50 步 DDPM · 960×960 · k=0.2 · w=0.8 · latent 优化每 5 步 × 4 次 |
补充材料里最值得记住的一张小表:预训练权重有多重要(SIR²,不带优化与互斥采样):
| 设置 | PSNR ↑ | SSIM ↑ | LPIPS ↓ | DISTS ↓ |
|---|---|---|---|---|
| 透射 · 从头训 | 21.31 | 0.763 | 0.191 | 0.171 |
| 透射 · 用 SD 预训练权重 | 24.67 | 0.858 | 0.120 | 0.094 |
| 反射 · 从头训 | 19.34 | 0.595 | 0.543 | 0.365 |
| 反射 · 用 SD 预训练权重 | 20.87 | 0.659 | 0.381 | 0.285 |
反射层的感知指标差距(LPIPS 0.543 → 0.381)比透射还大:反射信号弱、真实数据没监督,重建质量几乎全押在生成先验上。这验证了整篇论文的立论。
§9实验结果怎么读
三个真实数据集:Real20(20 张)、Nature(20 张)、SIR²(454 张);四个指标:PSNR/SSIM(逐像素保真)、LPIPS/DISTS(感知质量)。作者把七个对比方法在同一份数据上重训了做公平对比(重训版普遍还比官方权重更强),官方权重的对照表在补充材料里,结论一致。
9.1 透射层
| 数据集 | 指标 | YTMT | RobustSIRR | DSRNet | RRW | DSIT | RDNet | ControlNet | Ours |
|---|---|---|---|---|---|---|---|---|---|
| Real20 | PSNR ↑ | 23.01 | 22.91 | 23.75 | 20.66 | 24.04 | 24.89 | 18.68 | 25.32 |
| SSIM ↑ | 0.791 | 0.796 | 0.809 | 0.737 | 0.796 | 0.826 | 0.645 | 0.850 | |
| LPIPS ↓ | 0.181 | 0.206 | 0.157 | 0.269 | 0.173 | 0.145 | 0.312 | 0.107 | |
| DISTS ↓ | 0.123 | 0.137 | 0.110 | 0.165 | 0.118 | 0.103 | 0.216 | 0.089 | |
| Nature | PSNR ↑ | 24.70 | 25.43 | 26.11 | 25.83 | 25.90 | 26.44 | 19.92 | 26.71 |
| SSIM ↑ | 0.822 | 0.826 | 0.835 | 0.828 | 0.825 | 0.836 | 0.721 | 0.837 | |
| LPIPS ↓ | 0.127 | 0.168 | 0.140 | 0.174 | 0.167 | 0.114 | 0.242 | 0.080 | |
| DISTS ↓ | 0.082 | 0.104 | 0.090 | 0.110 | 0.100 | 0.078 | 0.168 | 0.064 | |
| SIR² | PSNR ↑ | 23.94 | 23.64 | 23.95 | 23.05 | 25.03 | 25.62 | 20.65 | 25.35 |
| SSIM ↑ | 0.887 | 0.875 | 0.901 | 0.862 | 0.911 | 0.909 | 0.812 | 0.911 | |
| LPIPS ↓ | 0.129 | 0.178 | 0.113 | 0.171 | 0.108 | 0.109 | 0.174 | 0.075 | |
| DISTS ↓ | 0.088 | 0.108 | 0.078 | 0.108 | 0.077 | 0.074 | 0.138 | 0.065 |
读法:感知指标(LPIPS/DISTS)全面第一且优势大;PSNR/SSIM 大都第一,SIR² 的 PSNR 略输 RDNet。作者的辩护有道理——分离问题的解本身逐像素不唯一(能量在两层间怎么分不唯一),PSNR 会惩罚「合理但不同」的解,感知指标更能反映分离质量。你实测时也建议以视觉效果和 LPIPS/DISTS 为主。
9.2 反射层——这篇的杀手锏
| 指标 | YTMT | DSRNet | DSIT | RDNet | Ours |
|---|---|---|---|---|---|
| PSNR ↑ | 16.64 | 20.59 | 18.51 | 18.00 | 21.14 |
| SSIM ↑ | 0.252 | 0.671 | 0.462 | 0.362 | 0.681 |
| LPIPS ↓ | 0.646 | 0.533 | 0.520 | 0.526 | 0.373 |
| DISTS ↓ | 0.576 | 0.380 | 0.402 | 0.340 | 0.275 |
别的方法反射层经常输出一片黑;这篇能把反射内容真的画出来。对我们的课题来说,这一点比透射层的分数更重要——3DGS 那边要的就是「有内容的反射层」。
9.3 消融:三个组件各自值多少
| 配置 | PSNR ↑ | SSIM ↑ | LPIPS ↓ | DISTS ↓ |
|---|---|---|---|---|
| 基线(仅条件微调) | 24.66 | 0.843 | 0.133 | 0.107 |
| + C | 24.67 | 0.858 | 0.120 | 0.094 |
| + C + O | 25.03 | 0.866 | 0.115 | 0.091 |
| + C + O + D(完整) | 25.35 | 0.911 | 0.075 | 0.065 |
三个组件都有贡献,互斥采样带来最后一大跳(LPIPS 0.115 → 0.075)。官方代码里三个组件都有开关,正好可以逐个复现这张表——这是你上手实验的最佳起点。
还有一个对课题很有意义的结果:分离后的透射层拿去做目标检测、深度估计,下游任务直接受益:
§10局限,以及对我们 3DGS 课题的意义
作者自己承认的局限:优化阶段的参数(\(\gamma_i\)、\(k\)、\(w\))需要仔细调;FGFM 偶尔压不干净反射,透射层会残留少量伪影。
站在课题的角度,小c补三条更要紧的:
① 它给的是逐视角的 2D 分离先验。每张训练视图都能拆出「有内容的」\(\mathcal T/\mathcal R\) 两层,可以当 3DGS 重建的伪真值或正则来用——这正是把它选作课题第一步的理由。
② 但要小心多视角一致性。它是生成式的:强反射区域靠幻构补内容,不同视角、甚至不同随机种子下补出的内容可能不一致。实测时建议专门拿同一场景的相邻几帧跑,看两层输出的跨视角稳定性——这直接决定它能不能直接喂给 3DGS,还是需要在重建端做一致性约束。
③ 预处理成本要心里有数。50 步扩散 × 双分支,一张图几十秒量级;一个场景几百张训练视图,预处理是小时级的。
§11术语表
- VAE(变分自编码器)
- SD 里负责「图像 ↔ latent」的压缩器,8× 下采样、4 通道;本文全程冻结。类比 tokenizer。
- latent / 隐空间
- VAE 压缩后的表示空间。960×960 的图对应 120×120×4 的 latent,扩散和 §7 的优化都在这里做。
- DDPM 采样
- 逐步去噪的标准采样器,每步用预测噪声算出上一时刻的均值。本文推理用 50 步。
- Tweedie 公式
- \(z_{0|t}=(z_t-\sqrt{1-\bar\alpha_t}\,\varepsilon_\theta)/\sqrt{\bar\alpha_t}\):任意中间步一步估出干净 latent,「偷看当前答案」。
- CFG(Classifier-Free Guidance)
- 用「条件 − 无条件」的噪声差做外推,放大对条件的服从。本文互斥采样是它的变体:负向端换成对方层。
- score / 分数函数
- \(\nabla_z\log p(z)\),对数概率的梯度。噪声预测与它成正比,这是 CFG 一族方法的理论根基。
- PSNR / SSIM
- 逐像素/局部结构的保真指标,对「合理但不同」的生成解偏严苛。
- LPIPS / DISTS
- 用深度特征算的感知相似度,更接近人眼判断;本文主张以这两个为准。
- ill-posed(病态问题)
- 解不唯一或不稳定的反问题。一图拆两层未知数翻倍,必须靠先验收窄解空间。
- U-Net
- 编码-解码带跳连的卷积主干,SD 2.1 的噪声预测网络(≈0.87B 参数),内部混有 self-/cross-attention。
§12上手:在 3080 Ti 上跑起来
官方仓库只提供推理(没有训练脚本),结构基于 Marigold 的 pipeline 改造。在实验室那台 Windows 3080 Ti(12 GB)上,推理大概率能直接跑:SD 2.1 U-Net 的 fp16 权重约 1.7 GB,latent 优化又特意设计成不反传 U-Net——显存大头只是 960² 下的注意力和 VAE 解码。万一 OOM,把分辨率降到 768 或 640,先看效果完全够用。
conda create -n diffrefsep python=3.10 -y
conda activate diffrefsep
pip install torch==2.5.1 torchvision==0.20.1 --index-url https://download.pytorch.org/whl/cu121
git clone https://github.com/Brian90709/diff-reflection-separation-code
cd diff-reflection-separation-code
pip install -r requirements.txt权重从 Hugging Face 的 Brian9999/diff-reflection-separation 下载到 ./checkpoints;SD 2.1 基座首次运行自动下载。国内网络先设镜像:
# PowerShell 里:$env:HF_ENDPOINT = "https://hf-mirror.com"
set HF_ENDPOINT=https://hf-mirror.com
hf download Brian9999/diff-reflection-separation --local-dir ./checkpoints
python infer_layersep.py --input_dir ./samples --save_to_dir ./outputs每张输入会输出透射层、反射层和一个中间结果。命令行开关正好对应论文三个组件(关 latent 优化、调 refinement 强度、关互斥采样)——照着 §9.3 的消融表逐个开关跑一遍,是理解这篇论文最快的动手路径。
如果 Windows 上有包装不动(个别编译依赖偶尔闹脾气),WSL2 + Ubuntu 是最稳的兜底。需要微调或复现训练时再考虑租卡:作者用单张 A6000(48 GB)、等效 batch 32 做全量微调,12 GB 不够;按小时租 A100 40G/80G 或 A6000/L40S 最省心。