AI/ML 详解:元学习与小样本

Day 39 · 2026-06-25 · 难度 ★★★☆☆
面向:有编程经验的非 AI 方向工程师
工程对应 → super-individual D1: Prompt Engineering(few-shot 示例怎么挑、怎么排)
今日主线

小样本」是一个问题:只给几个例子,怎么学会一个新任务?今天的四个概念是四种逐级递进的答案——从「复用旧权重」(迁移学习),到「学一个好的起点」(MAML),到「干脆不更新权重、用距离查表」(度量学习),最后到 LLM 最神奇的「连前向传播都不出、在 prompt 里就学会了」(In-context Learning)。核心张力始终是一句话:数据少到不够梯度下降时,「学习」该发生在哪一层?

迁移学习Transfer Learning

基础范式特征复用
一句话类比

迁移学习就是不从零写服务,而是 fork 一个跑顺了的基础镜像(base image),只改最上面那层业务逻辑。预训练模型 = 已经预热好连接池、装好通用依赖的母镜像;你的小数据集 = 那点业务定制。底层的通用能力(识别边缘、理解语法)早就有了,你只补「最后一公里」。

它解决什么问题 + 工作机制

痛点:从零训一个深度网络要海量标注数据 + 巨量算力。但很多任务的底层特征是共享的——识别猫和识别狗都要先会识别边缘、纹理、形状。重新学一遍这些是浪费。

机制:拿一个在大数据集上预训练好的网络,冻结(freeze)前面大部分层(它们已经学会通用特征),只重新训练最后一两层来适配你的新任务。神经网络天然分层:浅层学通用低级特征(边缘、词法),深层学任务相关的高级特征。所以「底层冻结、顶层微调」既省数据又省算力。这是后面三个概念的共同地基——没有好的预训练表示,小样本学习根本无从谈起。

代码示例
import torch, torch.nn as nn
from torchvision import models

# 1) 载入在 ImageNet 上预训练好的 ResNet(母镜像)
net = models.resnet50(weights="IMAGENET1K_V2")

# 2) 冻结所有层——通用特征不再更新
for p in net.parameters():
    p.requires_grad = False

# 3) 把最后的分类头换成你的任务(比如 5 类)——只有这层会训练
net.fc = nn.Linear(net.fc.in_features, 5)

# 4) 优化器只收集 requires_grad=True 的参数(即新分类头)
opt = torch.optim.Adam(
    (p for p in net.parameters() if p.requires_grad), lr=1e-3)
# → 几百张图就能训出一个像样的分类器,而非几百万张
常见误区 + 实践场景
误区:「冻结越多越好、永远只训最后一层」。错。当你的新任务和预训练数据差异很大时(医学影像 vs 自然照片),深层的高级特征也不再适用,这时该「解冻更多层 + 用更小学习率」做全网微调。数据极少→只训顶层;数据中等且域接近→解冻几层;数据较多且域差异大→全网微调。
📌 超级个体场景:你想做一个「自动给个人项目截图分类」的小工具,手头只有 200 张标注图。别从零训——拿预训练 ViT/ResNet 冻结、只训分类头,一个下午就能上线。迁移学习是「小数据也能玩深度学习」的入场券。
Takeaway + 思考题
💡 迁移学习的本质不是「学得更快」,而是「把昂贵的通用表示当成公共基础设施复用」——和你复用开源库、复用 base image 是同一种工程智慧。
🤔 如果浅层特征是「通用」的,为什么不同模态(图像 vs 文本)的预训练模型几乎无法互相迁移?通用到什么粒度才是真通用?

元学习 / MAMLMeta-Learning / MAML

学会学习双层优化2017
一句话类比

普通训练是「为某个具体任务找最优解」;MAML 是「找一个最好的『起点』,让它对任意新任务只需几步就能适应」。类比:你不是为每个新项目手搭环境,而是精心配一个黄金母镜像(golden base image)——任何新项目从它 clone 后,改三五行配置就能跑。MAML 优化的不是终点,是起点。

它解决什么问题 + 工作机制

痛点:迁移学习复用的是「特征」,但新任务还是要训。能不能让模型学会「如何快速学新任务」本身?这就是元学习(meta-learning,「学会学习」)。MAML(Model-Agnostic Meta-Learning,Finn et al. 2017)给了一个优雅答案。

机制是双层优化(bi-level optimization),两个嵌套的循环:

  • 内循环(inner loop):拿当前初始参数 θ,对某个任务用它的几个样本做 1~几步梯度下降,得到任务专属参数 θ'。这模拟「快速适应」。
  • 外循环(outer loop / meta-update):用 θ' 在该任务新样本上的表现,反过来更新原始 θ。注意——更新的是起点 θ,不是 θ'

用一行直觉化的公式说清外循环更新(每个符号都解释):

θ ← θ − β ∇θ Σ任务 i Li( θ − α ∇θ Li(θ) )

内层括号 θ − α∇Li(θ) 就是「在任务 i 上走一步」得到的 θ'(α 是内循环学习率);外层对这个适应后的损失再求一次梯度,去更新起点 θ(β 是外循环学习率)。关键反直觉点:这里出现了「梯度的梯度」——你在对「一步梯度下降之后会有多好」求导。MAML 不是在找「现在好」的参数,而是在找「一推就到位」的参数。

MAML 双层结构(meta vs inner)
起点 θ──内循环 α 几步──▶θ'₁ (任务1)
└─θ'₂ (任务2)θ'ₙ

外循环 β:用各 θ' 的「适应后表现」回头修正 θ → 让 θ 成为更好的起点
代码示例
# MAML 一步外循环的骨架(伪 PyTorch,省去数据加载)
def maml_step(theta, tasks, alpha=0.01, beta=0.001):
    meta_loss = 0
    for task in tasks:
        sup, qry = task.support(), task.query()   # 支持集/查询集
        # 内循环:在 support 上走一步,得到适应后的 θ'
        loss = forward_loss(theta, sup)
        grad = torch.autograd.grad(loss, theta, create_graph=True)
        theta_prime = [w - alpha*g for w, g in zip(theta, grad)]
        # 用 θ' 在 query 上的损失累加到 meta_loss(注意是 query!)
        meta_loss += forward_loss(theta_prime, qry)
    # 外循环:对起点 θ 求二阶梯度并更新
    meta_grad = torch.autograd.grad(meta_loss, theta)
    return [w - beta*g for w, g in zip(theta, meta_grad)]
# create_graph=True 让我们能对「一步梯度后的损失」再求导(梯度的梯度)
常见误区 + 实践场景
误区:「MAML 和迁移学习一样,都是给个好初始化」。表面像,本质不同。迁移学习的初始化是预训练任务的副产品(碰巧通用);MAML 的初始化是显式地为『快速适应』优化出来的——它在训练时就模拟了「来个新任务、走几步」的全过程。代价:二阶梯度计算和显存开销大,所以实践中常用一阶近似(FOMAML / Reptile)。
📌 跨学科思考场景:MAML 的「优化起点而非终点」是一个可迁移的元认知模型。你培养孩子、或自己学新领域时,与其灌满某个具体技能(终点),不如打磨「快速进入任意新领域的元能力」(起点)——好的提问方式、类比迁移习惯。这正是「超级个体」的底层算法。
Takeaway + 思考题
💡 MAML 把「学习」抬高了一个抽象层:普通训练优化参数,MAML 优化「学习参数的过程」。这种「对过程求导」的思路,是 2017 年后小样本研究的分水岭。
🤔 如果「学会学习」可以再往上叠一层(「学会『学会学习』」),它会收敛到什么?还是会无限递归?

度量式小样本 / 原型网络Metric-based / Prototypical Networks

无梯度适应嵌入 + 距离
一句话类比

前两个概念都还在「训练/更新权重」。原型网络换了思路:新任务来了根本不训,把每个类算成一个『质心向量』存起来,新样本来了算它离哪个质心最近——这就是答案。本质就是你熟悉的向量检索 + 最近邻(KNN),只不过嵌入空间是学出来的。「分类」退化成了「查表」。

它解决什么问题 + 工作机制

痛点:MAML 每个新任务还要跑内循环梯度下降,在线推理时不够轻。能不能让「适应新类」完全不涉及梯度?原型网络(Prototypical Networks,Snell et al. 2017)的答案:把分类变成几何问题。

机制(这是 N-way K-shot 的标准设定——N 个新类、每类 K 个样本):

  • 用一个学好的编码器 f 把每个样本映射成向量;
  • 每个类的 K 个支持样本向量取平均 = 该类的「原型」ck(质心);
  • 新样本 x 来了,算它的向量 f(x) 到各原型的距离,最近的原型就是预测类别

用 softmax 把距离变成概率(每个符号都解释):

p(y=k | x) = softmax( −d( f(x), ck ) )

d 是距离(通常欧氏距离),距离越近 → −d 越大 → 概率越高。整个「适应」过程就是「算几个平均向量」——零次梯度更新。模型真正学的是那个编码器 f:让同类样本在嵌入空间里抱团、异类拉开。一旦空间学好,分类新类就只是查询最近质心。这和 RAG 里「查最相关文档」是同一套向量几何。

代码示例
import torch, torch.nn.functional as F

# support: [N, K, D] 已编码向量;query: [Q, D]
def proto_classify(support, query):
    # 1) 每个类的原型 = K 个支持向量的均值 → [N, D]
    prototypes = support.mean(dim=1)
    # 2) 每个 query 到每个原型的欧氏距离 → [Q, N]
    dist = torch.cdist(query, prototypes)
    # 3) 负距离过 softmax = 类别概率(越近概率越高)
    return F.softmax(-dist, dim=1)

# 推理时:来一个全新的 5-way 任务,直接算原型即可分类
# 不需要任何反向传播——"适应"就是几次 mean()
probs = proto_classify(support_emb, query_emb)
pred = probs.argmax(dim=1)
常见误区 + 实践场景
误区:「原型网络这么简单,肯定不如 MAML」。恰恰相反——在很多 few-shot 基准上,简单的度量法持平甚至超过复杂的 MAML,且推理快得多、没有二阶梯度的麻烦。教训:小样本场景里,一个好的嵌入空间 + 简单几何,往往打败花哨的优化技巧。简单的归纳偏置在数据稀缺时反而是优势。
📌 个人项目场景:做「人脸/声纹/商品识别」这类类别会不断新增的系统,别用固定分类头(每加一类要重训)。用度量式:编码器固定,新类只需存一个原型向量。这正是现代人脸识别、向量库语义检索的工作方式——「注册即可用」,不重训
Takeaway + 思考题
💡 度量式小样本把「学习」从「调权重」彻底搬到了「设计一个好的表示空间」——之后所有新任务都用同一把几何尺子去量。这是「表示 > 模型」哲学的极致体现。
🤔 如果一个类的 K 个样本本身很分散(高方差),「取平均当原型」就会失真。你会怎么改进——加权?多原型?还是这暴露了「类」这个概念本身的局限?

上下文学习机制In-context Learning (ICL)

无权重更新前向传播内学习LLM 涌现
一句话类比

前三个概念好歹都「算了点东西」(训权重、求原型)。ICL 最神奇:你在 prompt 里塞几个示例,模型权重一个字节都不变,它就「学会」了新任务。类比:数据库的 prepared statement——同一个引擎不重新编译,根据你传入的几个参数即时生成一个执行计划。「学习」发生在一次前向传播内部,推理结束即蒸发。

它解决什么问题 + 工作机制

现象:GPT-3(Brown et al. 2020,「Language Models are Few-Shot Learners」)发现一件怪事——不微调、只在 prompt 里给几个「输入→输出」示例,大模型就能做新任务。这就是 in-context learning(上下文学习),是 prompt engineering 中 few-shot 的底层原理。但「为什么不更新权重也能学」一直是谜,目前有两条主流解释:

  • 隐式贝叶斯推断(Xie et al. 2021):预训练让模型见过海量「有共同潜在主题的连贯文本」。给几个示例时,模型其实在推断这些示例共享的「潜在任务概念」,然后按那个概念续写。示例不是在「教」,而是在「定位」你想要哪个已学会的能力。
  • 隐式梯度下降(von Oswald et al. 2023):在简化的线性 attention 设定下,可以证明 Transformer 处理示例的前向计算,等价于对一个内部小模型做梯度下降。换句话说,attention 层在前向传播里「偷偷」实现了一个学习器——这把 ICL 和 MAML 在数学上联系了起来。

一个反直觉的实证(Min et al. 2022):把 few-shot 示例的标签随机打乱、故意标错,性能几乎不掉。说明示例的核心作用不是提供「正确答案」,而是提供任务的「格式、标签空间、输入分布」——即帮模型「定位」该激活哪种能力,呼应了贝叶斯解释。

四范式:「学习」发生在哪一层?
范式更新权重?「适应」发生在
迁移学习是(顶层)微调阶段
MAML是(内循环几步)显式梯度下降
原型网络算几个均值向量
ICL否(永不变)一次前向传播内
代码示例
from anthropic import Anthropic
client = Anthropic()  # 读 ANTHROPIC_API_KEY 环境变量

# few-shot ICL:在 prompt 里给 3 个示例,权重完全不动
shots = (
    "评论: 物流太慢了 → 负面\n"
    "评论: 质量超出预期 → 正面\n"
    "评论: 包装一般般 → 中性\n")
resp = client.messages.create(
    model="claude-opus-4-8", max_tokens=16,
    messages=[{"role": "user",
        "content": shots + "评论: 客服回复很耐心 → "}])
print(resp.content[0].text)  # → 正面
# 模型从 3 个示例里"读懂"了任务格式与标签空间,
# 无需任何训练就完成分类——这就是 in-context learning
常见误区 + 实践场景
误区:「ICL 是模型在 prompt 里真的『学到了新知识』」。要小心——示例主要在「定位任务、规范格式」,而非灌输新事实。模型答不出的知识,给几个示例也变不出来(那是 RAG/微调的活)。ICL 擅长的是「把已有能力切换到你要的模式」:风格、格式、分类边界。
📌 决策辅助场景:你想让 AI 按你的固定框架分析问题(比如「先列假设→再找反例→最后给置信度」)。与其每次长篇描述要求,不如给 1~2 个完整范例,模型立刻 in-context 对齐你的思维格式。这比写一大段指令更稳——示范胜过说明。
Takeaway + 思考题
💡 ICL 是小样本学习的「终极形态」:学习从「训练阶段」彻底移进了「推理的那一次前向传播」,零权重更新、即用即弃。从迁移学习到 ICL,「学习」一路向运行时(runtime)迁移——这条线索本身就是过去十年 ML 的缩影。
🤔 既然示例标签错了也不太影响,那 few-shot「学习」到底有几分是「学」,几分是「检索 + 定位」?
工程对应 → super-individual D1: Prompt Engineering(few-shot 示例怎么挑、怎么排序、几个最优)

深入资源Further Reading

深入思考Deep Questions

1. 把今天四个概念排成一条线(迁移学习 → MAML → 原型网络 → ICL),「学习」这件事在沿线发生了什么迁移?
一条清晰的「学习向运行时迁移」主线。迁移学习仍在训练阶段学,只是复用了别人的底座。MAML 抬高一层,训练阶段学「如何快速学」,但适应新任务仍要跑几步真梯度。原型网络的适应阶段不再有梯度,退化成「算几个均值 + 比距离」。ICL 连算原型都省了,适应完全发生在一次前向传播内,权重恒定不变。所以这条线是「把适应成本从训练时一路推到推理时」:越往后边际成本越低,代价是越来越依赖一个强大的预训练底座。这也解释了 LLM 时代为何 ICL 成主角——底座够强,运行时适应几乎免费。BigCat 的分布式直觉:像「把计算从批处理推向实时流」,延迟换灵活,前提是基础设施够厚。
2. MAML 的「梯度的梯度」到底在优化什么?为什么说它和普通预训练「碰巧给个好初始化」有本质区别?
普通预训练优化「在预训练任务上表现好」,它给的初始化恰好对下游也不错,是个副产品——没人保证它易于适应。MAML 的二阶梯度直接优化「走一步梯度后会有多好」:内层 θ−α∇L 模拟适应一步,外层对适应后的损失再求导。几何上它在找一个「对所有任务都近、且梯度方向友好」的中心点。本质区别:迁移学习找「一个好位置」,MAML 找「一个好、且周围地形利于快速下降的位置」——后者把「未来的优化过程」纳入了当前目标。代价是二阶导很贵,故有 FOMAML/Reptile 一阶近似;它们丢掉二阶项却往往依然好用,提示 MAML 的多数收益可能来自「找到任务中心」而非二阶修正。
3. 「示例标签打乱也不太掉点」(Min et al. 2022)——这对「in-context learning 是不是真『学习』」意味着什么?
它逼我们重新定义「学习」。若把学习理解为「从示例的输入-标签对应中提取规律」,那 ICL 在分类任务上很大程度不是这种学习——打乱标签破坏了对应关系,性能却几乎不变。Min et al. 认为示例真正传递的是标签空间、输入分布、序列格式,以及「这是个分类任务」本身——即「唤起/定位」模型已习得的能力,而非现场教新映射,呼应 Xie 的贝叶斯解释。但有边界:这主要基于分类/多选;对需真正从示例归纳新映射的任务(如学没见过的合成函数),von Oswald 的「隐式梯度下降」更贴切。所以答案是「看任务」——ICL 是「检索定位」与「隐式优化」之间的连续谱,而非非黑即白。
4. 原型网络说「学好嵌入空间比设计复杂模型更重要」——这个「表示优先」哲学还在哪些地方反复出现?
这是现代 ML 的一条暗线。(a) RAG / 语义检索:质量几乎全取决于 embedding 空间,检索算法只是工程细节——与原型网络「编码器决定一切」同构。(b) 对比学习:SimCLR、CLIP 就是「不训分类器,只训一个让同类抱团、异类拉开的表示」,下游线性探针甚至零样本就能解——原型网络思想的大规模版。(c) 词向量线性结构(Day 30):king−man+woman≈queen,意义被编码进几何。共同信念:瓶颈是「如何表示世界」,而非「如何在表示上决策」——表示对了,决策往往退化成简单几何。BigCat 的可迁移启发:与其堆复杂业务逻辑,不如先投资「把数据嵌入好空间」,很多下游问题自动变简单——和数据库「schema 设计对了,查询自然好写」是同一种智慧。
5. 既然「学习」可以一路推到运行时(ICL),那「训练」和「推理」的边界还清晰吗?这对未来 AI 系统设计意味着什么?
边界正系统性模糊。传统里训练(改权重、慢、离线)与推理(用权重、快、在线)泾渭分明,但 ICL 把「适应新任务」搬进推理;o1/推理模型让模型在推理时「花更多算力思考」(test-time compute);带 memory 的 Agent 让经验跨会话累积,像慢速在线学习。未来更像一个连续谱:权重(最慢最持久)→ 长期 memory → context/prompt → 单次前向的隐式计算(最快即蒸发)。设计意涵:(1) 稳定通用能力固化进权重,多变个性化留给 context——是 Day 8 context engineering「数据生命周期分层」放大到「学习生命周期」。(2) 会 in-context 适应的模型「会什么」取决于你喂什么,静态 benchmark 失真。(3) 对超级个体最现实:协作质量越来越不取决于「模型训得多好」(改不了),而取决于「你运行时给它什么 context」(你可控)——主动权交回用户手里。