ControlNet 的原理是什么?为什么用零卷积?
简化版
ControlNet 让 Stable Diffusion 能被空间结构条件(边缘图、深度图、人体姿态、涂鸦等)精确控制。做法是:冻结原始 SD 的 U-Net,复制它编码器部分做成一个可训练副本接收控制图,再用**零卷积(zero convolution,权重初始化为 0 的 1×1 卷积)**把副本的输出接回原网络。零卷积保证训练刚开始时控制分支输出为 0、完全不干扰原模型,从「原模型的完好状态」平滑地开始学习,因此训练稳定、不破坏 SD 已有能力,小数据也能训好。
详细版
要解决的问题
文本能控制「画什么」,但控制不了「精确的空间布局」——你没法用简要说让人物摆出某个确切姿势、让建筑贴合某张线稿。ControlNet 引入逐像素的空间条件来补上这一块。
结构设计
- 锁定原网络:SD 的 U-Net 参数全部冻结,保留其强大的生成先验。
- 可训练副本:把 U-Net 编码器(下采样部分)+ 中间块复制一份,参数可训练,输入端接收控制图(如 Canny 边缘)。
- 零卷积连接:可训练副本每个尺度的输出,经过一个零初始化的 1×1 卷积,加回到原 U-Net 解码器对应的跳连特征上。
零卷积的作用
- 权重初始化为 0 → 训练第一步,控制分支贡献恰好为 0 → 整个网络等价于原始 SD,输出不变。
- 于是训练从「一个已经很好的模型」出发,控制信号的影响从 0 逐渐长出来,不会一上来就破坏预训练权重,也避免了随机初始化带来的噪声干扰。
能控制什么
Canny/HED 边缘、深度图、法线图、人体姿态(OpenPose)、语义分割图、涂鸦、直线(M-LSD)等——每种条件训一个 ControlNet,即插即用。
完整版教学
一、为什么文本 + CFG 还不够
文生图 + CFG 解决的是「语义服从度」,但它对几何/空间结构是弱控制的:
- 你想让生成的人物摆出手臂上举的确切姿势,靠堆文字几乎做不到;
- 你有一张建筑线稿,想让模型严格贴着线稿上色出图;
- 你想保持某张图的深度层次/构图,只换风格。
这些都需要逐像素对齐的空间条件。ControlNet 就是给 SD 装上这类「结构遥控器」的通用框架。
二、核心难题:如何加条件又不毁掉预训练模型
一个自然的想法是「把控制图和噪声图拼起来,微调整个 SD」。但这有两个大问题:
- SD 是在海量数据上训出来的,直接微调容易灾难性遗忘,破坏原有的生成质量;
- 控制类数据集通常小得多(几万到几十万对),在小数据上全量微调大模型很容易过拟合、崩坏。
ControlNet 的解法是**「锁死原模型 + 旁挂可训练副本 + 零卷积渐入」**,在几乎不动原模型的前提下,安全地注入新控制能力。
三、为什么复制”编码器”而不是从零搭一个分支
ControlNet 复制的是 SD U-Net 的编码器(下采样)+ 中间块,而不是随机初始化一个新网络。原因很关键:
- 复制过来的副本继承了 SD 编码器强大的特征提取能力(它本来就会「理解图像结构」),只需在此基础上学会「如何把控制图对齐进去」,比从零学高效得多、稳得多。
- 副本处理「控制图 + 当前噪声潜图」,抽取多尺度结构特征,再注回原解码器。
解码器则复用原网络的、不复制——因为最终的「画质与细节」还是靠原 SD 的解码能力,我们只想影响它「往哪画」,不想替换它「怎么画」。
四、把零卷积讲透
零卷积是 ControlNet 的灵魂,理解它才算真懂。
它是什么:一个 1×1 卷积,权重和偏置都初始化为 0。控制分支的输出在接回主干前,先过这么一层。
它解决什么:
- 训练起点安全:第一步 forward 时,零卷积输出恒为 0,控制分支对主干「零贡献」,网络输出 = 原始 SD 输出。相当于「先保证不搞坏」,再慢慢学。
- 梯度不为 0,能学起来:有人担心「权重是 0,梯度是不是也是 0,永远学不动?」——不会。对 1×1 卷积
y = W·x + b,即使 W=0,损失对 W 的梯度∂L/∂W = (∂L/∂y)·xᵀ只要输入 x 和上游梯度非 0 就非 0,所以 W 会从 0 开始被更新、逐渐长大。这是零卷积能「既安全又可训」的数学原因。
记忆点:零卷积 = 「开局零影响,梯度不为零」——从原模型的完好状态平滑接管控制信号,这就是 ControlNet 训练稳定、小数据可用的关键。
五、训练与推理
- 训练:准备成对数据(控制图 ↔ 目标图),冻结 SD,只训 ControlNet 副本和零卷积。损失仍是扩散的噪声预测 MSE,只是网络多了控制输入。文本提示可同时保留。
- 推理:给一张控制图 + 文本提示,SD 在「文本 + 空间结构」双重条件下去噪。可调控制强度(control weight)平衡「贴合控制」与「自由发挥」。
- 可组合:多个 ControlNet 能叠加(如同时用姿态 + 深度),多条件协同控制。
六、验证零卷积是否真的“零影响”
设控制分支某位置输出特征为 h=[2,-1],零卷积初始权重矩阵和偏置全为 0,则注入主干的残差严格为 [0,0],首个前向与原模型一致。若上游梯度为 [0.3,-0.2],权重梯度包含外积 g·hᵀ,并不为零,所以优化器第一步后控制通路就能开始生长。
y = W h + b, W=0, b=0 => y=[0,0]
dL/dW = (dL/dy) h^T => [[0.6,-0.3],[-0.4,0.2]]
| 检查点 | 预期 |
|---|---|
| control weight=0 | 接近原始基座输出 |
| 权重逐步增大 | 结构遵循增强 |
| 多 ControlNet | 冲突条件仍可控 |
测试 ControlNet 不能只看最终图片“像不像”。还应在 control weight=0 时验证输出与基座近似一致,再逐步增大权重,观察边缘/姿态遵循率、文本一致性和画质是否形成合理权衡;多个控制器叠加时还要检查条件冲突。
七、常见误区与追问
- 误区:ControlNet 微调了整个 SD。 不是,SD 主干冻结,只训练旁挂的副本 + 零卷积。
- 误区:零卷积权重为 0 就学不动。 输入非 0 时梯度非 0,权重会从 0 长出来。
- 追问:为什么复制编码器而非随机初始化? 继承 SD 的结构理解能力,训练更快更稳。
- 追问:ControlNet 和 LoRA 有什么区别? LoRA 是往权重里加低秩增量、常用于改风格/主体;ControlNet 是旁挂结构分支、专注空间结构控制。两者可叠加使用。
- 追问:和 T2I-Adapter 区别? T2I-Adapter 是更轻量的适配器(小网络注入条件),成本更低但控制精度和通用性通常不如 ControlNet;二者思路相近,都是「冻结主干 + 旁挂条件模块」。
八、加强记忆
ControlNet 记「锁主干、挂副本、零卷积渐入」:冻结 SD 的 U-Net,复制它的编码器做可训练副本来吃控制图(边缘/深度/姿态…),再用零初始化的 1×1 卷积把副本接回主干——开局零影响不破坏原模型,梯度非零又能慢慢学出控制能力。 简要说抓本质:文本管”画什么”,ControlNet 管”照着这个结构画”。 零卷积「开局零、梯度非零」的巧思,是它能在小数据上稳训不崩的根本。