共计 2402 个字符,预计需要花费 7 分钟才能阅读完成。
背景与痛点
多模态学习旨在让机器理解不同模态数据(如图像、文本)之间的关联。传统方法面临以下核心挑战:

- 特征空间不对齐 :独立训练的视觉和文本模型难以建立跨模态语义关联
- 模态鸿沟 :手工设计的融合策略(如早期 / 晚期融合)难以捕捉复杂交互
- 数据效率低下 :需要大量标注数据学习模态间对应关系
CLIP 通过对比学习实现端到端的跨模态对齐,其核心创新在于:
– 使用 Transformer 统一处理不同模态
– 采用图像 - 文本对作为自然监督信号
– 构建对称的双流编码架构
技术选型对比
文本模态:Transformer
- 输入处理 :
- Byte Pair Encoding (BPE) 分词
- 位置编码采用可学习参数
-
最大序列长度限制为 77
-
架构特点 :
- 12 层标准 Transformer
- 512 隐藏维度
- 8 头注意力机制
视觉模态:Vision Transformer (ViT)
- 图像分块处理 :
- 输入图像划分为 16×16 的 patch
- 线性投影得到 patch embedding
-
添加可学习的位置编码
-
与 NLP Transformer 差异 :
- 无 decoder 部分
- 分类头替换为特征投影层
- 归一化层使用 LayerNorm
核心实现
双流架构设计
- 对称编码器结构 :
- 图像编码器:ViT-B/32
- 文本编码器:12 层 Transformer
-
共享投影维度(512 维)
-
特征归一化 :
- L2 归一化后计算相似度
- 温度系数可学习参数
跨模态注意力机制
关键实现步骤:
- 计算图像特征 I 和文本特征 T 的相似度矩阵:
logits_per_image = (I @ T.t()) * torch.exp(t) - 双向对比损失:
- 图像到文本分类:softmax(logits_per_image)
- 文本到图像分类:softmax(logits_per_text)
对比损失函数
对称交叉熵损失实现:
def contrastive_loss(logits_per_image, logits_per_text):
labels = torch.arange(len(logits_per_image))
loss_i = F.cross_entropy(logits_per_image, labels)
loss_t = F.cross_entropy(logits_per_text, labels)
return (loss_i + loss_t) / 2
代码示例:ViT 图像编码器
import torch
import torch.nn as nn
class PatchEmbedding(nn.Module):
"""将图像分割为 patch 并嵌入"""
def __init__(self, img_size=224, patch_size=16, in_chans=3, embed_dim=768):
super().__init__()
self.proj = nn.Conv2d(in_chans, embed_dim,
kernel_size=patch_size,
stride=patch_size)
def forward(self, x):
# x: [B, C, H, W]
x = self.proj(x) # [B, E, H/P, W/P]
x = x.flatten(2).transpose(1, 2) # [B, N, E]
return x
class ViTEncoder(nn.Module):
"""CLIP 使用的 ViT 实现"""
def __init__(self, num_layers=12, embed_dim=768):
super().__init__()
self.cls_token = nn.Parameter(torch.zeros(1, 1, embed_dim))
self.pos_embed = nn.Parameter(torch.zeros(1, 50, embed_dim)) # 可学习位置编码
# Transformer 层
self.layers = nn.ModuleList([
nn.TransformerEncoderLayer(
d_model=embed_dim,
nhead=8,
dim_feedforward=3072,
activation="gelu"
) for _ in range(num_layers)
])
def forward(self, x):
# 添加 [CLS] token
cls_tokens = self.cls_token.expand(x.shape[0], -1, -1)
x = torch.cat((cls_tokens, x), dim=1)
# 添加位置编码
x += self.pos_embed[:, :x.size(1)]
# 通过 Transformer 层
for layer in self.layers:
x = layer(x)
# 返回 [CLS] token 作为图像特征
return x[:, 0]
性能考量
计算效率优化
- 混合精度训练 :
- FP16 计算加速
-
动态 loss scaling
-
梯度检查点 :
- 在 Transformer 层激活检查点
-
以时间换显存
-
数据加载优化 :
- 预取线程设置
- 分布式 sampler
模型规模权衡
| 模型变体 | 参数量 | 图像分辨率 | 推荐场景 |
|---|---|---|---|
| ViT-B/32 | 86M | 224×224 | 快速实验 |
| ViT-B/16 | 150M | 224×224 | 平衡场景 |
| ViT-L/14 | 428M | 336×336 | 高精度需求 |
避坑指南
数据预处理
- 图像增强 :
- RandomResizedCrop (scale=(0.9, 1.0))
-
禁用颜色扰动(保持语义不变)
-
文本处理 :
- 统一转为小写
- 最大长度截断
- 特殊 token 处理
超参数调优
关键参数建议值:
- 初始学习率:5e-4(余弦衰减)
- 批量大小:至少 1024(对比学习需要)
- 温度系数 τ:初始 0.07(可学习)
- warmup 步数:10000
总结与展望
多模态模型的发展方向:
- 更高效的架构 :
- 参数共享机制改进
-
稀疏注意力应用
-
自监督创新 :
- 跨模态 masked modeling
-
动态对比学习
-
应用挑战 :
- 长尾分布处理
- 细粒度语义对齐
开放性问题:
– 如何设计更适合视频 - 文本的多模态架构?
– 小样本场景下如何提升跨模态泛化能力?
– 动态温度系数是否能改善难样本学习?
正文完
发表至: 未分类
近一天内
