SPADE Generator:语义图像合成里,条件到底应该放在哪里?
SPADE Generator语义图像合成里条件到底应该放在哪里SPADE 这篇论文最值得看的地方不是 GauGAN 那个“画几笔变风景”的 demo而是它对 generator 条件注入方式的重新设计。语义图像合成的输入是一张 segmentation map。每个像素已经告诉模型这里是天空那里是道路旁边是树、车、人。照理说这比文本提示词明确得多。但早期方法还是经常生成“像照片但不听 mask”的结果局部纹理有了语义边界糊了整体风格对了物体位置不一定对。SPADE 的判断很朴素semantic map 不应该只在输入层出现一次。它应该参与 generator 的每个尺度而且最好直接调制 feature而不是被网络自己慢慢学着用。这篇文章就围绕这个问题展开SPADE generator 到底改了什么为什么简单 concat mask 不够以及这件事为什么后来在 ControlNet、layout-to-image diffusion 里又以另一种形式出现。先把任务说清楚SPADE 来自 CVPR 2019 Oral 论文Semantic Image Synthesis with Spatially-Adaptive Normalization作者是 Taesung Park、Ming-Yu Liu、Ting-Chun Wang、Jun-Yan Zhu。论文目标是 semantic image synthesis给定一张语义布局图生成一张真实图像并且图像内容要和布局对齐。这个任务和普通 image-to-image translation 有一点不同。pix2pix 那类方法通常把输入图当成条件图像经过 encoder-decoder 或 conditional GAN 生成输出。对边缘图、灰度图、低分辨率图来说这个思路很自然。但 segmentation map 比较特殊。它不是“待翻译的图像”而是一张密集控制信号。每个位置的类别都很重要。天空区域、建筑边缘、人和车的交界处都是生成器不能随便改的地方。pix2pixHD 这类方法把 semantic map 输入到网络开头然后希望后面的卷积和归一化层能保留这些信息。SPADE 认为这条路径太长了。条件在第一层进去经过多层下采样、卷积、normalization 之后信息会被稀释。论文真正改的就是这一点让 semantic map 不只作为输入而是作为每一层 normalization 的调制来源。普通 normalization 的问题先看普通 normalization。假设第iii层 feature map 是hih^ihibatch index 是nnnchannel 是ccc空间位置是(y,x)(y, x)(y,x)。BatchNorm / InstanceNorm 一类操作会先做标准化h^n,c,y,xihn,c,y,xi−μciσci \hat{h}^i_{n,c,y,x} \frac{h^i_{n,c,y,x} - \mu^i_c}{\sigma^i_c}h^n,c,y,xiσcihn,c,y,xi−μci然后再接一个 affine transformationγcih^n,c,y,xiβci \gamma^i_c \hat{h}^i_{n,c,y,x} \beta^i_cγcih^n,c,y,xiβci这里的问题在于γci\gamma^i_cγci和βci\beta^i_cβci是通道级参数。它们不关心(y,x)(y, x)(y,x)这个位置具体是天空还是道路。对分类模型来说这未必是坏事分类模型本来就希望对位置变化更鲁棒。但语义图像合成不一样。空间位置不是噪声而是条件本身。你不能让天空区域和道路区域共享同一套 affine 参数然后指望后面的卷积自己把语义边界补回来。这就是 SPADE 的出发点normalization 保留但 affine 参数不能再是全局通道参数。它应该来自 semantic map而且要随空间位置变化。SPADE layer 实际做了什么SPADE全称 Spatially-Adaptive Denormalization。名字有点绕其实就是“先 normalize再用 semantic map 生成的空间自适应γ\gammaγ和β\betaβ调回来”。SPADE 仍然先做 parameter-free normalizationh^n,c,y,xihn,c,y,xi−μciσci \hat{h}^i_{n,c,y,x} \frac{h^i_{n,c,y,x} - \mu^i_c}{\sigma^i_c}h^n,c,y,xiσcihn,c,y,xi−μci区别在后半步。它不再使用固定的γci\gamma^i_cγci和βci\beta^i_cβci而是从 segmentation mapmmm预测γc,y,xi(m),βc,y,xi(m) \gamma^i_{c,y,x}(m), \quad \beta^i_{c,y,x}(m)γc,y,xi(m),βc,y,xi(m)最终输出是SPADE(hi,m)n,c,y,xγc,y,xi(m)⋅h^n,c,y,xiβc,y,xi(m) \mathrm{SPADE}(h^i, m)_{n,c,y,x} \gamma^i_{c,y,x}(m) \cdot \hat{h}^i_{n,c,y,x} \beta^i_{c,y,x}(m)SPADE(hi,m)n,c,y,xγc,y,xi(m)⋅h^n,c,y,xiβc,y,xi(m)读公式时可以忽略一点符号细节抓住一件事就够了每个位置都有自己的缩放和平移参数而这些参数由 semantic map 决定。实现上SPADE 会把 semantic map resize 到当前 feature map 的分辨率再用几层卷积预测对应层的γ\gammaγ和β\betaβ。不同 ResNet block 的 feature 分辨率不同所以每个 block 看到的 semantic map 尺度也不同。这比 Conditional BatchNorm 更细。Conditional BatchNorm 通常根据类别标签生成一组 channel-wise 参数比如“这张图是狗”或“这张图是车”。SPADE 处理的是 dense condition这块是天空那块是树中间还有一条路。条件不是一个 label而是一整张空间图。generator 的变化从“编码语义图”到“持续调制特征”SPADE generator 更像一个 decoder。它从一个低分辨率 latent tensor 开始经过多层 SPADE ResNet block 和上采样逐步生成 RGB 图像。可以把流程想成这样semantic map m │ ├─ resize 到低分辨率 → 预测 block 1 的 gamma/beta ├─ resize 到中分辨率 → 预测 block 2 的 gamma/beta ├─ resize 到高分辨率 → 预测 block k 的 gamma/beta │ latent tensor → SPADE ResBlock → upsample → SPADE ResBlock → ... → image每个 SPADE ResBlock 内部大致是feature h → SPADE(h, mask) → activation → convolution → SPADE(h, mask) → activation → convolution → residual add这个结构和 pix2pixHD 的差异很关键。pix2pixHD 需要把 semantic map 编码到中间 feature再靠 decoder 解码回来。SPADE 不把所有语义信息压进一个 bottleneck而是在生成过程的每一层都重新问一次当前位置的语义是什么论文里有一个很有意思的 ablationgenerator 的初始输入用随机噪声或者用 downsampled segmentation map最后效果差不多。这个结果其实挺说明问题。它意味着 layout 信息主要不是从初始输入来的而是从 SPADE modulation 这条路径来的。也就是说SPADE generator 真正的条件入口分布在整个网络里。concat mask 为什么不等价一个自然反应是既然语义信息会丢那就在每一层把 segmentation map concat 到 feature map 上不就行了论文做了这个对照。结果不如 SPADE。原因不难理解。Concat 的意思是“这是当前 feature旁边放着 mask你自己学怎么用。”SPADE 的意思更直接“当前位置是天空所以这一层 feature 应该按天空区域的方式缩放和平移。”前者还是把条件当输入后者把条件变成了 feature distribution 的调制规则。在 dense generation 里这个差别很大。物体边界、类别区域、局部纹理都依赖空间位置。SPADE 把语义信号接到 normalization 后的 affine step 上路径短也更稳定。网络不需要在每层重新学习“如何从 concat 的 mask 里读条件”因为调制已经把条件作用到 feature 上了。论文表 3 的结果很能说明这个点。decoder w/ SPADE 在 COCO-Stuff 上达到 35.2 mIoUdecoder w/ Concat 是 31.9Cityscapes 上分别是 62.3 和 61.1。更重要的是pix2pixHD 加 SPADE 也比 pix2pixHD 加 concat 更好。这说明收益不只是来自某个 decoder 架构。SPADE 这个 layer 本身在起作用。和 AdaIN、FiLM、Conditional BatchNorm 的关系SPADE 可以放进 conditional normalization 这一类方法里理解。AdaIN 用 style code 调制 feature 的均值和方差常见于风格迁移。FiLM 用条件向量生成 feature-wise 的缩放和平移。Conditional BatchNorm 用类别条件生成 channel-wise affine 参数常见于类别条件生成。SPADE 的不同点是条件本身有空间结构调制也保留空间结构。方法条件输入调制粒度更适合的任务Conditional BatchNorm类别标签channel-wise类别条件生成AdaIN风格向量或风格图channel-wise风格迁移FiLM条件向量feature-wise多模态条件推理SPADEsemantic mapspatial channel语义图像合成所以 SPADE 不是简单地“又一个 normalization trick”。它把 conditional normalization 从类别条件推到像素级条件。对 semantic image synthesis 来说这一步正好卡在痛点上。多模态生成布局固定外观可变Segmentation map 只规定结构不规定所有视觉细节。同一张“天空 道路 建筑”的 mask可以生成白天、黄昏、阴天也可以生成不同材质和色调。SPADE 的做法是引入 VAE-style encoder。训练时encoder 从真实图像里提取 latent style codegenerator 用 semantic map 控制布局用 latent code 控制外观。推理时可以采样不同 latent code也可以用参考图像提取 style code。这样一来同一个 mask 可以生成多个版本但主要语义布局不变。这部分放到今天看并不陌生。扩散模型里的 ControlNet、T2I-Adapter、layout condition本质上也在分离两件事结构条件负责“东西在哪里”生成模型负责“东西长什么样”。SPADE 早期把这个思路用在 GAN generator 里而且做得很干净。论文结果Table 3 其实比 Table 1 更有意思Table 1 证明 SPADE 整体效果好。和 pix2pixHD 比SPADE 在 COCO-Stuff 上 mIoU 从 14.6 提到 35.2FID 从 111.5 降到 22.6在 ADE20K 上 mIoU 从 20.3 到 38.5FID 从 81.8 到 33.9Cityscapes 上 mIoU 从 58.3 到 62.3。这些数字当然重要但它们混合了很多因素架构、训练细节、loss、数据集差异。Table 3 更接近“SPADE layer 到底有没有用”这个问题。模型参数量COCO mIoUADE20K mIoUCityscapes mIoUdecoder w/ SPADE96M35.238.562.3compact decoder w/ SPADE61M35.238.062.5decoder w/ Concat79M31.933.661.1pix2pixHD w/ SPADE237M34.439.062.2pix2pixHD w/ Concat195M32.938.957.1pix2pixHD183M14.620.358.3这里最有意思的是 compact decoder w/ SPADE。它只有 61M 参数但 COCO 和 Cityscapes 上不输 96M 的版本也超过不少更大的 baseline。换句话说SPADE 不是靠单纯堆模型容量赢的。用户偏好测试也支持这个结论。论文用 AMT 做两两比较每个数据集随机生成 500 个问题每个问题 5 个 worker 作答并要求 worker 的 lifetime approval rate 大于 98%。和 pix2pixHD 相比用户在 COCO-Stuff 上 86.64% 的比较偏好 SPADEADE20K 上是 83.74%Cityscapes 上是 53.64%。Cityscapes 的提升没那么夸张也正常。街景布局相对规整pix2pixHD 已经能做得不错。COCO-Stuff 和 ADE20K 更复杂类别多、场景杂SPADE 这种逐位置调制的优势更容易显出来。复现时别低估旧代码成本官方仓库是NVlabs/SPADE。README 里写得很直接代码基于 PyTorch 1.0 和 Python 3还需要 Synchronized-BatchNorm-PyTorch。要复现论文结果官方提到需要一台 8 张 V100 的 NVIDIA DGX1。安装大致是gitclone https://github.com/NVlabs/SPADE.gitcdSPADE/ pipinstall-rrequirements.txtcdmodels/networks/gitclone https://github.com/vacancy/Synchronized-BatchNorm-PyTorchcp-rfSynchronized-BatchNorm-PyTorch/sync_batchnorm.cd../../生成预训练模型结果python test.py\--namecoco_pretrained\--dataset_modecoco\--dataroot/path/to/coco_stuffCPU 推理可以加--gpu_ids-1训练自定义数据集时官方给的入口是customdataset modepython train.py\--namemy_spade_experiment\--dataset_modecustom\--label_dir/path/to/labels\--image_dir/path/to/images\--label_nc20真正麻烦的地方通常不在命令而在数据。类别 id、ignore label、instance map、resize/crop 策略、mask 和 image 是否严格对齐都会影响结果。SPADE 对 layout 很敏感这是优点也是工程上的坑。还有一个现实问题这是一套 2019 年的 GAN 代码。今天直接跑可能会遇到 PyTorch、CUDA、SyncBatchNorm 依赖不兼容。NVIDIA README 也提到后续更高性能的重实现放在 Imaginaire 仓库里。只是想理解方法的话读原仓库足够真要复现建议优先看 Imaginaire 或社区里更新过的实现。SPADE 留下来的东西SPADE 的边界也很清楚。它不生成 layout不理解文本也不负责判断输入 mask 合不合理。如果 mask 本身荒谬模型大概率会认真地生成一个荒谬场景。它还依赖成对的 semantic map 和真实图像训练数据。GAN 训练成本不低复现也吃工程环境。放到今天它不是最方便的 layout-to-image 方案。但 SPADE 留下来的设计原则仍然很有用空间密集条件不要只塞在输入层。条件应该在多个尺度、多个位置持续影响生成过程。这也是为什么读 ControlNet、T2I-Adapter、segmentation-conditioned diffusion 的时候SPADE 仍然值得放在脑子里。生成主干从 GAN 换成 diffusion但问题没有变如何让模型既生成得真实又真的听条件。SPADE 的答案很干净把条件接到每层特征的调制上。参考资料Taesung Park, Ming-Yu Liu, Ting-Chun Wang, Jun-Yan Zhu,Semantic Image Synthesis with Spatially-Adaptive Normalization, CVPR 2019, retrieved 2026-06-29, https://openaccess.thecvf.com/content_CVPR_2019/html/Park_Semantic_Image_Synthesis_With_Spatially-Adaptive_Normalization_CVPR_2019_paper.htmlarXiv:1903.07291,Semantic Image Synthesis with Spatially-Adaptive Normalization, retrieved 2026-06-29, https://arxiv.org/abs/1903.07291NVIDIA SPADE Project Page, retrieved 2026-06-29, https://nvlabs.github.io/SPADE/NVlabs/SPADE GitHub Repository, retrieved 2026-06-29, https://github.com/NVlabs/SPADENVlabs/imaginaire GitHub Repository, retrieved 2026-06-29, https://github.com/NVlabs/imaginaire