一文看懂 CLIP 文本编码器:如何把文字变成能和图像比大小的向量
【免费下载链接】CLIPCLIP (Contrastive Language-Image Pretraining), Predict the most relevant text snippet given an image项目地址: https://gitcode.com/GitHub_Trending/cl/CLIP
不用手写一条标注数据,CLIP 文本编码器就能把一句英文描述变成定长向量,让你直接拿它和图像向量比相似度——这正是跨模态检索的底层能力。
它到底解决了什么问题
图片天生是像素矩阵,文字天生是字符序列,两者没法直接相减、更没法比"像不像"。CLIP 文本编码器的职责,就是把任意一段文字变成一个向量,使它能和图像编码器产出的向量住进同一套坐标系,从而可以用余弦相似度来衡量匹配程度。
🧭 可以把它想成一台"坐标转换器":给一张照片、一句话各分配一个地图坐标点,之后判断它们是否匹配,就变成量这两个点之间距离的小事。
这一节的价值一句话:文本编码器是"文字端"的坐标转换器,它决定了文字能否被放进和图像同等的空间里。
内部工作原理
下面按"数据进来 → 中间变换 → 最后输出"三个问题拆一遍,对应源码在 clip/clip.py 和 clip/model.py。
数据进来时变成了什么?
你传入"a photo of a cat",它先被拆成一串整数。拆分的依据是字节对编码(BPE, Byte Pair Encoding):常见子词整块保留,生僻词切成更小的片段,具体逻辑在 clip/simple_tokenizer.py。tokenize()再在序列头尾各塞一个特殊标记——<|startoftext|>(句首)和</s>(句尾,下文称 eot),最后填成一个固定 77 长度的整数张量,不够就用 0 补齐。到这里,文字已经变成"能喂给神经网络"的数字,但还只是孤立的编号。
中间经历了哪些变换?
拿到整数序列后,encode_text做三件事:
- 词嵌入:
nn.Embedding(vocab_size, transformer_width)把每个编号换成一个稠密向量(ViT-B 系列维度为 768)。 - 位置嵌入:
positional_embedding是可学习参数,按位置逐一加上,告诉模型"哪个词在第几个位置",因为嵌入本身不携带顺序信息。 - Transformer 编码:向量转成
LND布局后进入Transformer,由多层ResidualAttentionBlock堆叠,每层含多头自注意力 + 前馈网络 + 层归一化 + 残差连接。
其中最有讲究的是注意力掩码:build_attention_mask用-inf填充上三角,让每个词只能"看到"它自己和它前面的词。这是因果(causal)结构,保证第 n 个词在汇总信息时不会偷看后面的内容,编码出的向量自然带有"从左到右读完"的语义。
最后输出了什么?
Transformer 跑完得到[batch, 77, 768]的向量组。模型并不取第一个词,而是定位到 eot 位置——由于 eot 的编号是序列里最大的,text.argmax(dim=-1)恰好能把它找出来——取该位置的向量再乘投影矩阵,映射到与图像特征相同的 512 维空间。
# 取 eot 位置特征并投影到 512 维 x = x[torch.arange(x.shape[0]), text.argmax(dim=-1)] @ self.text_projection这一节的价值一句话:分词、嵌入+自注意力、eot 投影,三段变换把离散编号一路加工成可与图像对表的 512 维向量。
动手跑起来
最小可运行示例(需先pip install ftfy regex tqdm与 PyTorch):
import clip import torch model, _ = clip.load("ViT-B/32") # 加载模型(含文本编码器) texts = ["a photo of a cat", "a picture of a dog", "an image of a bird"] tokens = clip.tokenize(texts).to(model.device) # 分词成定长 77 的整数序列 with torch.no_grad(): feats = model.encode_text(tokens) # 文本编码器输出 print(feats.shape) # torch.Size([3, 512])输出torch.Size([3, 512]):3 个句子,每个变成一个 512 维向量。接着算句间相似度:
import torch.nn.functional as F sim = F.cosine_similarity(feats, feats.T, dim=-1) # 3x3 余弦相似度矩阵 print(sim)得到一个 3×3 矩阵,对角线恒为 1;语义接近的句子得分更高,比如 cat 与 dog 通常比 cat 与 bird 更接近。
这一节的价值一句话:两行调用就能拿到可直接比大小的文字向量,门槛低到适合当第一个实验。
模型规格对比与选型
不同规模模型的文本编码器参数如下(clip.load时按名称选取):
| 模型 | Transformer 层数 | 注意力头数 | 隐藏维度 |
|---|---|---|---|
| ViT-B/32 | 12 | 12 | 768 |
| ViT-B/16 | 12 | 12 | 768 |
| ViT-L/14 | 24 | 16 | 1024 |
注意 ViT-B/32 与 ViT-B/16 的文本编码器完全相同,差别只在图像端分辨率。🎯 新手建议从 ViT-B/32 起步:速度最快、显存占用最低,足够验证"文字→向量→比相似度"整条链路;确认流程跑通后,再按需升级到 ViT-L/14 换取更高精度。
这一节的价值一句话:先用最小的 B/32 把链路跑通,再谈精度升级,避免一上来就堆大模型。
写在最后
- 一条流水线:BPE 分词 → 嵌入+自注意力 → eot 投影,全程把文字加工成 512 维向量。
- 一个关键结构:因果注意力掩码让编码带有从左到右的阅读语义。
- 一次比大小:输出向量与图像向量做余弦相似度,即得到匹配得分。
典型场景一句话:以文搜图、零样本分类、跨模态检索都建立在这套"文字向量 ↔ 图像向量"之上。
延伸阅读:README.md 与官方教程 notebooks/Interacting_with_CLIP.ipynb。
【免费下载链接】CLIPCLIP (Contrastive Language-Image Pretraining), Predict the most relevant text snippet given an image项目地址: https://gitcode.com/GitHub_Trending/cl/CLIP
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考