🏠 总目录📚 本教程 08 · ControlNet 与风格 LoRA ← →
📑 本页目录(点开跳转)

08 · ControlNet 与风格 LoRA

⏱ 22 分钟 | ⭐ 提示词管「画什么」,这一章补上「画成什么形状」和「用什么风格画」


🎯 一句话

文字说得清「一只猫在雪地里」,说不清「猫站在画面左三分之一、头偏右、镜头俯视」。 ControlNet 补形状,风格 LoRA 补风格。⭐ 它们和提示词三者互不替代 —— 这是这一章最容易搞混的地方。


🖐️ 一、提示词到底控制不了什么

上一章把接口钉死了:去噪网络吃 (x_t, t, c)。提示词只是 c 的一种,所以「加控制」只有两条路:往 c 里塞更强的东西,或者改那个函数本身。下面两个主角各走一条。

你想控制的 文字够不够
画什么(一只猫、雪地、黄昏) ✅ 够,这正是文本编码器擅长的语义
画成什么形状(构图、姿势、线稿) ❌ 说不清 —— 每加一条空间约束,全部命中的概率就掉一截,你还无法验证它听了哪几条
用什么风格画(某种笔触、你的角色) ❌ 说了也没用 —— 不是描述得更细就行,是底座根本没见过它

🧬 二、ControlNet:复制一份主干,再用零卷积接回去

复制一份可训练的副本,用零初始化卷积接回冻结的主干🔒 冻结的原主干编码器瓶颈解码器🔥 可训练副本编码器(复制)条件图编码线稿 / 深度 / 姿态0零初始化卷积⭐ 第 0 步这条支路输出恒为 0 —— 加了它的模型和原模型逐位相同(实测差 0.0)但权重梯度是 2501.0 不是 0,所以它照样从第一步就开始学
看中间那个标着 **0** 的圆:训练开始时它让整条支路输出为零,⭐ 于是**加了 ControlNet 的模型和原模型逐位相同** —— 不破坏已训好的东西,却照样有梯度可学。
  1. 冻结原来的去噪主干(上一章那个 U-Net),一个权重都不动。
  2. 把它编码器那一半复制一份,这份可训练 —— 起点是会画画的权重,不是随机数。
  3. 条件图(Canny 边缘图 / 深度图 / 姿态骨架)经一个小编码器,加到副本输入上。
  4. 副本每一级的输出,各经一个零初始化的 1×1 卷积,加进冻结主干解码器同级。

第 4 步那个「零初始化」是整个设计的支点:

# 零初始化卷积:训练前输出恒为 0,梯度却不为 0 —— 所以它接得进去,也学得起来
import torch
import torch.nn as nn

torch.manual_seed(0)
frozen = torch.randn(1, 320, 8, 8)      # 冻结主干这一级的输出
branch = torch.randn(1, 320, 8, 8)      # 可训练副本这一级的输出
zc = nn.Conv2d(320, 320, 1)             # ⭐ ControlNet 接回主干用的 1×1 卷积
nn.init.zeros_(zc.weight); nn.init.zeros_(zc.bias)

out = frozen + zc(branch)               # ControlNet 就是这么接回去的
print("接回后的最大差", out.sub(frozen).abs().max().item())
out.sum().backward()
print("权重梯度范数  ", round(zc.weight.grad.norm().item(), 1))
print("默认初始化的话", round(nn.Conv2d(320, 320, 1)(branch).abs().max().item(), 3))
接回后的最大差 0.0
权重梯度范数   2501.0
默认初始化的话 2.217

0.0 说明第 0 步加了 ControlNet 的模型和原模型逐位相同;但梯度 2501 不是 0(里面带着副本这一级输出了什么),所以它从第一步就开始长。⚠️ 换成默认初始化,训练还没开始就往训好的模型里灌进 2.217 的随机改动。

⭐ 零初始化把「加一条新支路」从破坏性改动变成了从零长出来的增量。 这也是它只用几万张图就训得起来的原因 —— 不必重新学画画,只需学「怎么把条件图掺进去」。

💡 上一章 DiT 的 adaLN-Zero 门控也是零初始化,同一个想法。


🎨 三、风格 LoRA:和语言模型那个是同一个东西

不是「像」,是同一个低秩适配:底座 W 冻结,旁边挂一对窄矩阵,前向变成 W·x + B(A·x),中间那个窄维度叫 rank(记作 r)。⭐ B 零初始化,所以挂上那一刻 W + BA = W —— 和上一节的零卷积同一个动机。

拿交叉注意力里 768 → 320 那层算笔账:原层 768×320 = 245760 个参数,LoRA 只有 r×(768+320) = 1088r 个。

r 可训练参数 占原层
4 4352 1.77%
64 69632 28.33%

⚠️ 所以 r 不是越大越好:到 64 已经离全量微调不远,小数据下更容易把训练集背下来。常见取值就在 4~64,主要挂在交叉注意力的 Q/K/V 和输出投影上 —— 那正是文本条件落到图像特征的地方。

为什么风格只能走这条路:风格是分布层面的偏移(笔触走向、色调、留白),几个形容词定位不了,得拿 20~100 张风格一致的图去改权重。


⚖️ 四、三者的分工(这一章最该记住的一张表)

管什么 怎么进模型 代价
提示词 画什么 —— 内容、语义 文本编码器 → 条件 c 免费,改字就行
ControlNet 画成什么形状 —— 构图、姿势 一条并行支路,逐级加进主干 多跑一份编码器副本
风格 LoRA 用什么风格画 —— 笔触、角色 直接改主干若干层的权重 算力几乎不加,但要训

💸 五、代价

① ControlNet 要多跑一份主干。 副本是编码器那一半,推理时那部分跑两遍,参数和激活都多一份。⚠️ 更贵的是它和 CFG 相乘 —— CFG 本来就要跑两次去噪网络,加了 ControlNet 之后这两次都得带上副本。

② 多个 ControlNet 会打架。 条件互相矛盾时(线稿说手在这儿、深度图说手在那儿),出图就崩在那个位置。

③ 多个 LoRA 更麻烦:BA 直接加进同一个 W,⚠️ 它们没有任何机制知道对方存在,只能每个配一个系数靠试(diffusers 里就是 set_adapters([...], adapter_weights=[0.8, 0.6]) 那两个数)。风格 LoRA 和角色 LoRA 打架是最常见的一种。

④ 风格 LoRA 会越界。 训练集只有几十张时,它常连背景和构图一起学走,那就侵占了 ControlNet 的地盘。症状很好认:不管提示词怎么改,构图都像训练集那几张。解法是减 r、减步数,或让训练集构图更杂。


🔗 这一章连到哪里

去哪 为什么
大模型全景导论 主线 5 · 怎样把模型变成你的助手 ⭐ 同一个低秩适配:那页讲原权重 W、全量微调要学的 ΔW、以及用两个更窄的矩阵 BA 去近似它,还多讲一件本章没讲的 —— 什么时候根本不该微调
机器学习与深度学习基础 12 · CNN 处理图像 「零卷积」就是它「三个变体」那节的 1×1 卷积:不看空间、只在通道间做线性组合。⭐ 接回主干那个 +,也是它残差连接那节的同一个 +
AI基础设施 09 · 显存优化全家桶 训 ControlNet 多出来的副本让参数、梯度、优化器状态三块一起翻。那章第一节的判断很实用:把 batch 调到 1 还 OOM 吗 —— 还 OOM 是这三块的问题,不 OOM 才是激活的
大模型全景导论 10b · 图像生成 14 分钟的索引版,这两样在那里只占组件表一行。⭐ 而它的「📦 深挖的话要学什么」把 ControlNet 和风格 LoRA 训练标成 📕 整块要外找 —— 本章就是那一行

✅ 检查点

  1. 提示词说不清「形状」和说不清「风格」,失败方式有什么不同?
  2. ControlNet 冻结哪一份、训练哪一份?副本复制主干的哪一半,又加回哪一半?
  3. 零初始化的卷积第 0 步输出是多少?那它靠什么学起来?换成默认初始化会怎样?
  4. r=64 时 LoRA 的可训练参数占原层多少?为什么它不是越大越好?
  5. 为什么 ControlNet 的算力代价会和 CFG「相乘」?多个 LoRA 叠加时又要调什么、为什么?
👀 答案
  1. 形状是说不清(文字表达不了逐像素的空间约束);风格是说了也没用(底座根本没见过那个角色或笔触)。
  2. 原主干全部冻结,复制出来的编码器那一半可训练;副本每级输出经零卷积加进冻结主干的解码器同级。
  3. 恒为 0,所以模型和原模型逐位相同(0.0)。但权重梯度是 2501.0 不是 0,里面带着副本这一级的输出,所以它从第一步就开始长。默认初始化则在第 0 步就把主干改动 2.217,等于往训好的模型里灌噪声。
  4. 28.33%(r=4 只有 1.77%)。r 一大就接近全量微调,小数据下更容易背下训练集,常见 4~64。
  5. CFG 本身要跑两次去噪网络,加了 ControlNet 后这两次都得带上编码器副本,所以相乘不是相加。多个 LoRA 要调各自的权重系数(如 0.8 / 0.6),因为它们的 BA 直接加进同一个 W,没有任何机制知道对方存在。

🛑 可以停在这里

读到这里你已经能看懂一份出图工作流:哪部分是提示词、哪部分是 ControlNet 的条件图、挂了几个 LoRA、那几个 0.x 在调什么。⭐ 更重要的是出了问题知道该动哪一个。

什么时候回来:加了 LoRA 之后构图被锁死时回看第五节 ④;显存或耗时突然翻倍时回看第五节 ①。

⚡ 走神救援

先记住这几件事

下一节 👉 09-怎么评估.md

打卡记录保存在你的浏览器里,首页能看到总进度