共计 2592 个字符,预计需要花费 7 分钟才能阅读完成。
背景与痛点:少样本学习的现实挑战
少样本学习(Few-shot Learning)旨在通过极少量标注样本训练模型,这在医疗影像、工业质检等标注成本高的场景中尤为重要。但传统方法面临两大核心问题:

- 特征泛化能力弱 :当每类仅有 1 - 5 张样本时,CNN 等模型容易过拟合,无法捕捉判别性特征
- 域适应能力差 :预训练特征空间与目标任务差异较大时(如从自然图像迁移到医学图像),需要大量调整
技术选型:为什么选择 CLIP?
对比三种主流方案:
- 传统微调(Fine-tuning):需冻结部分层防止过拟合,但会损失模型容量
- 元学习(Meta-Learning):如 Prototypical Networks 需要设计复杂的 episode 训练机制
- CLIP+ 少样本学习 :
- 优势 1:零样本能力直接利用图文对齐的语义空间
- 优势 2:ViT backbone 对跨域数据更鲁棒
- 优势 3:无需复杂训练策略,简单线性分类器即可达到 SOTA
实验表明,在 5 -way 1-shot 设置下,CLIP 比 ProtoNet 精度高 12-15 个百分点。
核心实现:四步搞定 CLIP 少样本分类
1. 数据预处理
-
图像:保持 224×224 分辨率,使用 CLIP 预设的归一化参数
from torchvision.transforms import Compose, Resize, ToTensor, Normalize preprocess = Compose([Resize(224), ToTensor(), Normalize((0.48145466, 0.4578275, 0.40821073), (0.26862954, 0.26130258, 0.27577711)) ]) -
文本:将类别名称转化为自然语言描述(提升语义对齐)
如 ”cat” → “a photo of a cat”
2. 特征提取
冻结 CLIP 模型,并行提取图文特征:
import clip
model, _ = clip.load("ViT-B/32", device="cuda")
# 图像特征
image_features = model.encode_image(images)
# 文本特征
text_inputs = torch.cat([clip.tokenize(f"a photo of a {c}") for c in classes])
text_features = model.encode_text(text_inputs)
3. 分类器构建
利用余弦相似度实现非参数分类:
# 归一化特征
image_features /= image_features.norm(dim=-1, keepdim=True)
text_features /= text_features.norm(dim=-1, keepdim=True)
# 计算 logits
logits_per_image = image_features @ text_features.t()
4. 微调策略(可选)
当数据有一定规模时:
- 只微调最后的 Transformer 层
- 添加轻量适配层(Adapter)
- 使用 LoRA 进行低秩更新
完整代码示例
import torch
import clip
from sklearn.metrics import accuracy_score
# 初始化
device = "cuda" if torch.cuda.is_available() else "cpu"
model, preprocess = clip.load("ViT-B/32", device=device)
# 少样本数据准备 (5-way 1-shot)
support_images = [...] # 5 张支持集图像
support_labels = [...] # 对应类别索引
query_images = [...] # 待分类图像
# 特征提取
with torch.no_grad():
# 支持集特征(取均值)class_features = []
for cls_idx in range(5):
idxs = torch.where(support_labels == cls_idx)[0]
features = model.encode_image(torch.stack([preprocess(img) for img in support_images[idxs]]).to(device))
class_features.append(features.mean(dim=0))
# 查询集预测
query_features = model.encode_image(torch.stack([preprocess(img) for img in query_images]).to(device))
# 余弦相似度分类
query_features /= query_features.norm(dim=-1, keepdim=True)
class_features = torch.stack(class_features)
class_features /= class_features.norm(dim=-1, keepdim=True)
logits = query_features @ class_features.t()
preds = logits.argmax(dim=-1)
print(f"Accuracy: {accuracy_score(true_labels, preds.cpu()):.2f}")
性能对比
在 miniImageNet 5-way 分类上的实验结果:
| 方法 | 1-shot 精度 | 5-shot 精度 |
|---|---|---|
| Matching Networks | 43.56% | 55.31% |
| ProtoNet | 49.42% | 68.20% |
| CLIP (zero-shot) | 62.73% | – |
| CLIP+ 线性探针 | 76.18% | 82.44% |
避坑指南
- 类别名称工程 :
- 错误:直接使用 ”dog” 作为 prompt
-
正确:使用 ”a photo of a dog, animal” 等丰富描述
-
特征归一化 :
-
必须对特征进行 L2 归一化,否则相似度计算失效
-
少量样本时的稳定性 :
- 当支持集样本极少时,多次运行取平均可降低方差
延伸思考
未来可探索方向:
- 结合 Prompt Engineering 动态生成更好的类别描述
- 引入视觉提示学习(Visual Prompt Tuning)
- 扩展到跨模态 few-shot 任务(如文本→图像检索)
CLIP 为少样本学习提供了新的范式——通过大规模预训练建立的语义空间,即使只有几个样本也能实现可靠分类。这种『预训练 + 轻量适配』的思路,正成为解决数据稀缺问题的银弹。
正文完
发表至: 未分类
近三天内
