CLIP 详解:Stable Diffusion 文本理解的核心机制

·17 分钟阅读·3342·

什么是 CLIP?

在 Stable Diffusion 的整体体系中,图像的生成由 U-Net 完成,图像的潜空间映射与还原交由 VAE 负责。然而,这一流程能否按照用户的提示词准确执行,取决于另一个关键组件——CLIP(Contrastive Language-Image Pre-training,对比语言-图像预训练)。如果说 VAE 是负责把“数据”变成“图片”的图像翻译官,那么 CLIP 就是负责听懂你说话的语言翻译官,它的职能是理解文本输入,并将语言转化为模型能够处理的语义向量,使得绘图引擎能执行与文本一致的视觉生成。

CLIP 在 Stable Diffusion 中的角色

Stable Diffusion 的生成过程本质上依赖条件扩散,而条件信号便由 CLIP 提供。文本提示词经过 CLIP 的处理后,被映射为固定维度的特征向量,并在 U-Net 的交叉注意力模块中作为控制条件。因此,CLIP 的语言理解能力直接影响生成图像的语义精确性、细节表现与风格倾向。

CLIP 的任务可以概括为两点:

  • 将自然语言转化为语义向量
  • 向 U-Net 提供语义引导,使图像朝指定方向生成

可以将其视作整个系统的“语言翻译器”,负责把用户的文本提示词转化为可操作的视觉语义信号,告诉 AI "你想要什么样的图片"。

graph LR
    %% 定义样式类
    classDef input fill:#ff9f43,stroke:#333,stroke-width:2px,color:#fff,rx:5,ry:5;
    classDef process fill:#54a0ff,stroke:#333,stroke-width:2px,color:#fff,rx:5,ry:5;
    classDef data fill:#5f27cd,stroke:#333,stroke-width:2px,color:#fff,stroke-dasharray: 5 5;
    classDef output fill:#1dd1a1,stroke:#333,stroke-width:2px,color:#fff,rx:5,ry:5;

    %% 节点定义与连接
    A([文本提示词<br/>'a beautiful cat']):::input
    --> B[CLIP Text Encoder<br/>文本编码器]:::process
    --> C[文本特征向量<br/>77, 768/]:::data
    --> D[UNet<br/>噪声预测]:::process
    --> E([引导图像生成]):::output

    %% 可以在这里添加额外的关联,例如噪声输入
    %% Noise[(随机噪声)]:::data -.-> D

CLIP 的工作原理

CLIP 的双塔架构

CLIP 通过对比学习训练而成,由文本编码器与图像编码器组成。训练阶段,模型接收大规模图文对,并学习让匹配样本的特征向量接近,不匹配样本的特征向量远离。 由此,CLIP 建立了稳定的跨模态语义空间。

在 Stable Diffusion 中,实际使用的是 CLIP 的文本编码器部分(图像编码器的核心价值在于预训练阶段 —— 通过 4 亿图文对的对比学习,为文本编码器提供 “语义锚点”,即文本向量的空间分布需与图像向量对齐,这是 CLIP 实现跨模态理解的基础。此外,图像编码器在图像检索、零样本分类等场景中也有重要应用,例如提取图像特征后与文本特征比对,可实现 “按文本搜图”)。

graph TB
    A[训练数据:<br/>4亿图文对] --> B[Text Encoder<br/>文本编码器]
    A --> C[Image Encoder<br/>图像编码器]

    B --> D[文本特征空间]
    C --> E[图像特征空间]

    D --> F[对齐学习<br/>Contrastive Learning]
    E --> F

    F --> G[理解文本和图像的关系]

    style A fill:#e1f5ff
    style D fill:#ff6b6b
    style E fill:#4ecdc4
    style G fill:#f7b731

训练时,设置一个任务:给定一张图片和一段文字,判断它们是否匹配

正样本中给出匹配的图文对:一只橙色的猫(图片),"an orange cat"(文字),给出结论:特征向量接近

负样本给出不匹配的图文对:一只橙色的猫(图片),"a blue car"(文字),给出结论:特征向量远离

通过大量的训练,CLIP 能够理解文字含义、理解图像内容,并关联文字和图像,通过语义相似性来判断它们是否匹配。

文本编码过程

文本编码过程是 CLIP 模型将输入的文本转换为语义向量的过程。它包括以下几个步骤:

  • 分词 (Tokenization)
  • 词嵌入 (Token Embedding)
  • 位置编码 (Positional Embedding)
  • Transformer 编码
graph LR
    %% 样式
    classDef orange fill:#f0932b,stroke:#333,color:#fff,rx:5;
    classDef blue fill:#22a6b3,stroke:#333,color:#fff,rx:5;
    classDef purple fill:#be2edd,stroke:#333,color:#fff,rx:5;
    classDef dark fill:#130f40,stroke:#fff,color:#fff,rx:5;

    %% 流程
    In(Input</br>'a beautiful sunset'):::orange --> P1
    
    subgraph Preprocess [预处理阶段]
        direction TB
        P1[分词</br>Tokenize]:::blue --> P2[IDs: 49406, 320, ...]:::blue
    end

    Preprocess --> Emb
    
    subgraph Emb [向量化阶段]
        direction TB
        E1[词嵌入</br>Token Embedding]:::purple 
        E2[位置编码</br>Positional Embedding]:::purple
        E1 & E2 -.-> Sum((+))
    end
    
    Sum --> T[Transformer<br/>Encoder]:::dark
    T --> Out(Feature Vector<br/>77x768):::dark

    %% 连接线
    linkStyle default stroke:#333,stroke-width:2px,curvetype:basis;

分词 (Tokenization)

用户输入的文本会被拆解成最多 77 个 token,长度超限将被截断,不足部分以占位符填充(<pad>),首尾添加特殊token。由于 CLIP 按 token 而非单词处理,所以长词可能被拆分。

一个 Token 通常是一个完整的短单词: "cat", "dog", "red",也可能是一个长单词的一部分: "beautiful" 可能是 2个token,也有可能是一个标点符号: ",", "."。

提示词: "a beautiful girl with long hair, wearing white dress, in garden, natural lighting, masterpiece, best quality, highly detailed" 约 25-30 个token,若超过 77 token,末尾的 “best quality, highly detailed” 可能被截断,导致生成图像细节不足。建议优先保留核心描述(主体、场景、风格),次要修饰词用逗号分隔,避免长句拆分关键 token,减少 AI 理解偏差。

graph TB
    %% --- 样式 ---
    classDef raw fill:#fab1a0,stroke:#e17055,color:#2d3436,stroke-width:2px;
    classDef engine fill:#74b9ff,stroke:#0984e3,color:#fff,rx:10;
    classDef array fill:#dfe6e9,stroke:#636e72,color:#2d3436,rx:5;
    
    %% --- 流程 ---
    Input[fa:fa-keyboard 输入文本<br/>'a beautiful sunset over the ocean']:::raw
    
    Input ==> Process{CLIP<br/>Tokenizer}:::engine
    
    Process ==> Output
    
    subgraph Output [Token Sequence Output]
        direction TB
        L1["[0] < start >"]:::array
        L2["[1] a"]:::array
        L3["[2] beautiful"]:::array
        L4["[3] sunset ... ocean"]:::array
        L5["[7] < end >"]:::array
        L6["[8-76] < pad > ..."]:::array
        
        style Output fill:#fff,stroke:#333,stroke-dasharray: 5 5
    end

所以在 Stable Diffusion 中文本提示词的长度通常要限制在 77 个 token 以内,越精简越好,因为超出的部分会被截断,导致一些想要的图片效果无法实现。

词嵌入 (Token Embedding)

每个 token 会映射为一个固定维度的向量(例如 768 维),语义相近的词向量在空间中距离较近,如'beautiful' 和 'pretty' 距离近,'ugly' 和 'pretty' 距离远。

graph LR
    %% --- 样式定义 ---
    classDef token fill:#ff9f43,stroke:#333,stroke-width:2px,color:#fff,rx:5;
    classDef vector fill:#5f27cd,stroke:#333,stroke-width:2px,color:#fff,rx:0,font-family:'Courier New';
    classDef arrow stroke:#b2bec3,stroke-width:2px;

    %% --- 映射关系 ---
    T1(Token: 'a'):::token --> V1["[ 0.23, -0.45, 0.67, ... , 0.12 ]<br/><i style='font-size:12px'>Shape: (1, 768)</i>"]:::vector
    
    T2(Token: 'beautiful'):::token --> V2["[ 0.56, 0.34, -0.23, ... , 0.89 ]<br/><i style='font-size:12px'>Shape: (1, 768)</i>"]:::vector
    
    T3(Token: 'sunset'):::token --> V3["[ -0.12, 0.78, 0.45, ... , -0.34 ]<br/><i style='font-size:12px'>Shape: (1, 768)</i>"]:::vector

    %% --- 布局调整 ---
    linkStyle default stroke:#a29bfe,stroke-width:2px;

位置编码 (Position Embedding)

Transformer 虽然能处理 token 序列,但结构本身对“顺序”毫无概念,位置编码的作用是保留语序,将顺序信息显式注入模型,使模型能够理解句法结构。

为什么需要位置编码? 因为相同的 token 在不同位置的含义不同,如'cat' 在 'cat chasing mouse' 中是主体, 'mouse chasing cat' 中的主体却是 mouse。

在实际模型中,位置编码主要有两类:绝对位置编码(Absolute Position Embedding)和 相对位置编码(Relative Position Embedding)。

绝对位置编码是 CLIP、BERT、ViT 等模型普遍采用的方式,也是 Stable Diffusion 文本编码器使用的方式。其原理非常直接,就是为每个 token 分配一个固定的位置索引,然后将位置索引映射为一个向量,与 token embedding相加,得到最终的位置编码向量。

形式如下:

Embedding(token_i) + Position(i)

其中 Position(i) 与 token 本身无关,只与位置编号相关。

绝对位置编码的特点是简单易实现,模型训练时学习一个固定位置表,例如长度 77,每个位置对应一个固定的向量。绝对位置编码适合固定序列长度的任务,但是不能自然推广到比训练更长的序列,如 CLIP 的 77 token 限制,输入固定为 77 个 token,对应 77 个位置向量,如果超过 77 token 会被截断,因为模型没有更多的位置编码。

相对位置编码主要用于最新模型,如 Transformer-XL、T5、DeBERTa、部分扩散模型的 cross-attention等,这些模型不关心“绝对位置”,而关心“当前位置与另一个位置之间的相对关系”。例如,在一个句子中,“beautiful” 与 “girl” 的距离比与 “sky” 的距离更重要。

相对位置编码提供了相邻性、依赖距离和方向性(前后),可以让模型更自然。

相比绝对位置编码,相对位置编码的优势在于:

  1. 模型可以自然推广到更长的序列,而不需要额外的位置编码。
  2. 模型可以更有效地捕捉长距离依赖,因为它考虑了当前 token 与其他 token 之间的相对位置。
  3. 模型可以更好地处理变长序列,因为它不依赖于固定的位置编码长度。

但 CLIP 并未使用这一机制,因为其设计目标是稳定文本编码,而非长序列理解。

Transformer Encoder(编码器)

在 Stable Diffusion 中,CLIP 文本编码器正是由多层 Transformer Encoder 堆叠而成。

对于 CLIP 而言,Transformer Encoder 的任务可以概括为理解 token 之间的上下文关系、建模长距离依赖(long-range dependency)、从词级、短语级逐步提取语义特征和为每个 token 输出更高层的语义表示。简言之,Transformer 让 CLIP 不仅”识字”,还能“读懂语义”。比如,"apple" 在 "eat an apple" 中是水果,而在 "Apple Inc" 中是公司;"the girl who wore red dress"中"girl" 与 "wore" 之间的关系是“主体-动作”,而 "wore" 与 "red dress" 之间的关系是“动作-对象”。

Transformer Encoder 由多个重复的结构块(Block)组成,每个 Block 包含两大模块:

  1. 多头自注意力机制(Multi-Head Self-Attention)
  2. 前馈神经网络(Feed-Forward Network, FFN)

每个模块都带有:

  • 残差连接(Residual Connection)
  • LayerNorm(层归一化)

整体结构如下:

Input Layer (Token + Position Embedding)
    ↓
12 × Transformer Block
    • Multi-Head Self-Attention (12 heads)
    • Feed-Forward Network
    • Layer Normalization
    • Residual Connections
    ↓
Output Layer

但是 Transformer 并不是一层就读懂所有语义,而是逐层抽象。CLIP 文本编码器通常为 12 层 Transformer Block。

1–3 层是词汇层:解析词义,建立基本依赖关系,识别简单修饰结构

4–6 层是短语层:形成更复杂的短语结构,识别语法关系(主谓宾、定状补等)

7–9 层是句法层:建立长距离依赖,理解句子整体语义结构

10–12层是语义层:概念抽象,风格理解,表达高级语义(例如“忧郁的氛围”、“未来主义风格”)

在 Stable Diffusion 的 Web UI 中有个参数 CLIP Skip,参数值是 1 ~ 12,对应的就是 12 层 Transformer Block。它的作用是改变Transformer 的“语义抽象程度”,越靠后的层,语义越抽象。

Skip 1 (默认): 最精确的语义理解,可精准捕捉 “photorealistic, skin texture, 8k” 等细节描述,还原真实质感,适合写实风格

Skip 2: 宽松的语义约束,允许更夸张的发型、五官比例,符合动漫风格特性,常用于动漫模型

Skip 3+: 可能导致核心语义偏差,例如 “girl” 被误生成为 “boy”,或 “garden” 变成 “forest”,需避免使用

多层 Transformer 综合上下文与语义关联,最终生成形状为 [77, 768] 的语义向量矩阵。该矩阵将作为 U-Net 的生成条件,直接影响图像结构与内容。

多头注意力机制(Multi-Head Self-Attention)

在 Transformer 中有个很重要的概念,就是多头注意力机制,体现在每个 Transformer Block 中。

每个 Transformer Block 都包含多个头(head)的自注意力机制,每个头都独立计算注意力权重,然后将结果拼接起来。

这样做的好处是,每个头可以关注不同的位置和不同的特征,从而更好地捕捉到序列中的长距离依赖关系。

例如,在 CLIP 中,每个头都关注不同的位置,从而更好地理解句子中的语法关系。

%%{init: {'theme': 'base', 'themeVariables': {'fontSize': '12px'}}}%%
graph TB
    %% --- 节点定义 ---
    Input([输入: Token 序列<br/>Input Sequence])

    %% 定义子图:多头注意力层
    subgraph MultiHead [多头注意力层 / Multi-Head Attention Layer]
        direction LR
        H1[Head 1<br/>关注主语]
        H2[Head 2<br/>关注动词]
        H3[Head 3<br/>关注宾语]
        Hm[...]
        H12[Head 12<br/>关注修饰词]
    end

    Concat[拼接 & 线性变换<br/>Concat & Linear]
    Output([综合理解<br/>Contextual Representation])

    %% --- 连接关系 ---
    Input ==> H1 & H2 & H3 & Hm & H12
    
    H1 & H2 & H3 & Hm & H12 -.-> Concat
    
    Concat ==> Output

    %% --- 样式定义 ---
    classDef io fill:#37474f,stroke:#263238,stroke-width:2px,color:#fff,font-size:12px
    classDef head fill:#e1f5fe,stroke:#039be5,stroke-width:2px,color:#01579b,font-size:12px
    classDef process fill:#fff3e0,stroke:#ff9800,stroke-width:2px,color:#e65100,font-size:12px
    classDef cluster fill:#f5f5f5,stroke:#bdbdbd,stroke-width:1px,color:#616161,font-size:12px

    %% 应用样式
    class Input,Output io
    class H1,H2,H3,Hm,H12 head
    class Concat process
    class MultiHead cluster

在处理 "The girl wearing red dress is smiling" 语句时,

Head 1 关注: "girl" ← → "wearing" 理解主语和动作的关系

Head 2 关注: "wearing" ← → "dress" 理解动作和对象

Head 3 关注: "red" ← → "dress" 理解修饰关系

Head 4 关注: "girl" ← → "smiling" 理解主语和状态

综合结果: 完整理解句子的语义结构,生成准确的特征表示

相关推荐

Stable Diffusion 的版本演进

深入解析 Stable Diffusion 的版本演进,了解各个版本的特性和差异。

·14 分钟·
#Stable Diffusion#AI绘画

Stable Diffusion 采样器

深入解析 Stable Diffusion 中各类采样器的工作原理、特点和适用场景,帮助你选择最合适的采样器

·19 分钟·
#Stable Diffusion#采样器

Stable Diffusion 模型下载指南

详细介绍 Stable Diffusion 模型的下载渠道、文件格式说明以及安装方法

·19 分钟·
#Stable Diffusion#Checkpoint