老师傅收了个新徒弟。别的学徒学一道菜,要照着菜谱反复练上几十遍;可这位徒弟有个特别的本事——师傅示范一道新菜,他只要看上一两遍,就能端出相似的味道。有人问他秘诀,他说:“当学徒这三年,我练得最多的不是某道菜,而是怎么学做菜:怎么判断火候、怎么搭配香料、怎么通过闻和尝认出食材的脾气。”小样本学习(Few-Shot Learning)要解决的,正是这个“只看一两遍就会”的问题。传统的 AI 模型就像笨学徒,识别一张猫图要喂它几千张猫图;小样本学习则希望模型像那位机灵的徒弟,每类新东西只给 1 到 5 个例子,就能举一反三。它靠的并不是魔法,而是一套完整的方法论:用大量的同类任务练出“学习如何学习”的能力(元学习),用“尝味道、比距离”的方式做分类(度量学习),用有限的食材变出更多花样(数据增强),再把多年练就的基本功搬到新灶台(迁移学习)。本文就带你走进这间“厨房”,看看小样本模型是如何炼成的。

岗位关联

数据标注不足是真实项目中最常见的“卡脖子”问题。掌握小样本学习,等于掌握了用极少量标注撬动模型效果的杠杆——这是算法工程师处理新业务冷启动、长尾识别、快速验证时不可或缺的核心技能。

目录
  1. 可视化演示
  2. 问题定义:摸清小样本任务的“考题”
  3. 元学习框架:学会“如何学习”
  4. 度量学习范式:用“味道距离”分类
  5. 数据增强策略:把有限的食材变出花样
  6. 迁移学习思路:把旧功夫搬到新灶台
  7. 模型选择与调优:哪把刀适合什么活
  8. AI 应用场景
  9. Python 演示
  10. 常见误区
  11. 面试题

可视化演示

本节配有交互动效(进入视口后自动加载,约 3KB)。

问题定义:摸清小样本任务的“考题”

老师傅收了个新徒弟,第一天没有急着教菜谱,而是出了一道考题:“今天三道新菜,每道我只示范一遍。明天你不仅要会做,还要把我随手做的一道菜认出来,说出它属于哪道。”徒弟捏了一把汗——这哪是考做菜,分明是考“看一遍就会”。小样本学习研究的,正是这道考题本身。

这道考题在 AI 里有标准叫法:N-way K-shot 分类。要识别 N 种新类别,每种类别只给 K 张带标注的样本。这些“示范样本”统称支持集(support set),需要模型判别的未知样本叫查询集(query set)。5-way 1-shot 就是 5 个类、每类 1 张图片。普通分类像把一道菜练一千遍再去考试,小样本则要求只看一眼就上场。

更关键的区别在训练方式。普通分类模型在一个大数据集上一次性学完所有类别,小样本模型则采用任务式采样(episodic training):每轮从任务分布中随机构造一个 N-way K-shot 小任务,用支持集做“临时学习”,用查询集算损失,然后不断换新任务。就像徒弟每天换新题考自己,模型被迫在“面对陌生类别”这件事上积累经验,而不是死记某个固定题库的答案。

把考题的规格拆开看,N 决定了难度面,K 决定了信息量。N 越大,新类越多越容易混;K 越小,每类能借用的示范越少。徒弟清楚地知道,这场考试的题眼不在于某道菜具体怎么做,而在于如何用最少的信息完成判断。定义清楚这个问题,后面所有方法才有了用武之地。

Dsupport={(xi,yi)}i=1N×K,Dquery={(xj,y~j)}j=1N×Q\displaystyle \mathcal{D}_{\text{support}} = \{(x_i, y_i)\}_{i=1}^{N \times K}, \quad \mathcal{D}_{\text{query}} = \{(x_j, \tilde{y}_j)\}_{j=1}^{N \times Q}
通俗说明:支持集是“师傅示范的少量样本”,查询集是“待考的新样本”。N 是类别数,K 是每类示范数,Q 是每类待判数。
  1. 支持集规模支持集由 N 个类别、每类 K 个样本组成,总样本数就是 N×K。这是模型唯一能“偷师”的信息来源。
    Dsupport={(xi,yi)}i=1N×K\mathcal{D}_{\text{support}} = \{(x_i, y_i)\}_{i=1}^{N \times K}
  2. 查询集规模查询集是每类 Q 个待判样本的总和,用于评估模型对陌生样本的判别能力,相当于“考官手中的评分表”。
    Dquery={(xj,y~j)}j=1N×Q\mathcal{D}_{\text{query}} = \{(x_j, \tilde{y}_j)\}_{j=1}^{N \times Q}
  3. way 的含义N 代表任务里的新类别数,5-way 等于考试出现 5 种新菜,N 越大类别间越容易混淆。
    N=∣{yi:(xi,yi)∈Dsupport}∣N = \left| \{ y_i : (x_i, y_i) \in \mathcal{D}_{\text{support}} \} \right|
  4. shot 的含义K 代表每类提供几个示范样本,1-shot 等于每道菜只示范一次;K 越大,模型可借鉴的信息越充分。
    K=∣{(xi,yi)∈Dsupport:yi=c}∣,∀cK = \left| \{(x_i, y_i) \in \mathcal{D}_{\text{support}} : y_i = c \} \right|, \quad \forall c

元学习框架:学会“如何学习”

一晃三年,徒弟出师了。其他学徒还在背菜谱,他却发现自己越学越快。原因很简单:每次学新菜,他都会下意识地总结“怎么判断火候、怎么搭香料、怎么用舌头分辨食材新旧”。老师傅看着他说:“你真正学会的不是做菜,是怎么学做菜。”元学习(Meta-Learning)就是这么一种“学习如何学习”的框架。

元学习不直接学“把这张图分成猫还是狗”,而是把大量结构相似的少样本任务当作训练数据。每个任务都有自己的支持集和查询集,类别可以完全不同,它们共同构成任务分布 $p(\mathcal{T})$。训练的终极目标,是得到一个“基础好、上手快”的初始模型——拿到任何新任务,只需在支持集上稍微学几下就能适应,就像徒弟无论转到哪个菜系都能快速上手。

最经典的实现是 MAML(模型无关的元学习)。它有两层循环:内循环先在某个任务的支持集上走几步梯度,得到一个临时适应后的参数;外循环再用这些任务查询集上的表现来更新初始参数。训练结束后,参数的初始位置被摆在了一个“处处都好微调”的地方——这是元学习最优雅之处。

MAML 练出来的模型就像那个总结出“切、炒、调味”通用心法的徒弟:不必提前知道明天是什么菜系,只要看师傅示范一次,他就能用最短时间调整到最佳状态。这种“基础好、上手快”的本质,正是小样本学习要提炼的核心能力。

min⁡θ∑Ti∼p(T)LTi(fθi′),θi′=θ−α∇θLTi(θ)\displaystyle \min_{\theta} \sum_{\mathcal{T}_i \sim p(\mathcal{T})} \mathcal{L}_{\mathcal{T}_i}\left( f_{\theta_i'} \right), \quad \theta_i' = \theta - \alpha \nabla_\theta \mathcal{L}_{\mathcal{T}_i}(\theta)
通俗说明:目标是找一个初始参数 θ,使得任何新任务只要在支持集上稍加学习(几步梯度),就能在查询集上有好表现。θ 是“天生的学习能力”,θ′ 是“看完示范后的临时状态”。
  1. 任务采样从任务分布中随机抽一个少样本任务,好比徒弟从题库里随机抽一道新菜品来练手。
    Ti∼p(T)\mathcal{T}_i \sim p(\mathcal{T})
  2. 内循环快学在任务 $\mathcal{T}_i$ 的支持集上用学习率 α 走几步梯度,得到临时适应参数 θ′,对应“看一遍示范后快速调整动作”。
    θi′=θ−α∇θLTi(θ)\theta_i' = \theta - \alpha \nabla_\theta \mathcal{L}_{\mathcal{T}_i}(\theta)
  3. 外循环评估用 θ′ 在查询集上算损失,对所有任务求和,检验“临时学习的效果”到底好不好。
    min⁡θ∑Ti∼p(T)LTi(fθi′)\min_{\theta} \sum_{\mathcal{T}_i \sim p(\mathcal{T})} \mathcal{L}_{\mathcal{T}_i}\left( f_{\theta_i'} \right)
  4. 元参数更新按这个目标反向更新初始参数 θ,让 θ 越来越“容易被人点拨”。
    θ←θ−β∇θ∑iLTi(θi′)\theta \leftarrow \theta - \beta \nabla_\theta \sum_i \mathcal{L}_{\mathcal{T}_i}(\theta_i')

度量学习范式:用“味道距离”分类

假设师傅端来四道新菜让徒弟归类:一道偏辣、一道偏甜、一道偏酸,第四道口味模糊。徒弟的策略很朴素——尝一口,感受它更像哪道已知的菜。味道离谁近,就归谁。度量学习(Metric Learning)正是这个思路:与其记住每个类别的全部细节,不如学会比较“谁跟谁像”。

度量学习的核心是一个特征提取器 $f_\phi$,它把原始图片映射到一个特征空间。训练时不断拉开不同类样本的距离、拉近同类样本的距离,让空间呈现“同类扎堆、异类分散”的结构。到了小样本测试时,模型不需要提前见过新类别很多次,只需把新样本的特征丢进这个空间,跟每类已有的代表样本比一比距离,选最近的即可。

围绕“怎么比距离”,衍生了几个经典家族:孪生网络(Siamese Network)成对训练,判断两张图是否同类;匹配网络(Matching Network)用注意力机制,让查询样本对所有支持样本加权投票;原型网络(Prototypical Network)最简洁——把每类支持样本的特征平均成一个原型,查询样本按到原型的欧氏距离分类。原型网络因为简单、稳定、几乎不用调参,成了小样本任务的默认基线。

度量学习的巧妙之处,在于把“认识一道新菜”化约为“记住一个平均味道”。徒弟不必背下每道菜的每一个摆盘细节,只要知道它在“味觉空间”里的坐标。哪怕一种新菜只尝过一口,他也敢在厨房里果断给出判断。

pc=1K∑(xi,yi)∈Dscfϕ(xi),pϕ(y=c∣x)=exp⁡ ⁣(−d(fϕ(x),pc))∑c′exp⁡ ⁣(−d(fϕ(x),pc′))\displaystyle \mathbf{p}_c = \frac{1}{K} \sum_{(x_i,y_i) \in \mathcal{D}_s^c} f_\phi(x_i), \qquad p_\phi(y=c \mid x) = \frac{\exp\!\left(-d\left(f_\phi(x), \mathbf{p}_c\right)\right)}{\sum_{c'} \exp\!\left(-d\left(f_\phi(x), \mathbf{p}_{c'}\right)\right)}
通俗说明:每道菜先浓缩出一个“平均味道”(原型),新菜拿来跟每个平均味道比距离,离谁近就归谁。
  1. 特征提取把原始图片通过神经网络变成特征向量,相当于把一道菜翻译成一段“味道描述符”。
    fϕ(x)∈Rdf_\phi(x) \in \mathbb{R}^d
  2. 类原型计算每类 K 个支持样本的特征求平均,得到该类在特征空间的“代表点”。
    pc=1K∑xi∈Dscfϕ(xi)\mathbf{p}_c = \frac{1}{K} \sum_{x_i \in \mathcal{D}_s^c} f_\phi(x_i)
  3. 距离转相似度负欧氏距离经过指数函数,距离越近得分越高,像“味道越接近,心里越有底”。
    exp⁡ ⁣(−d(fϕ(x),pc))\exp\!\left(-d\left(f_\phi(x), \mathbf{p}_c\right)\right)
  4. softmax 概率化对所有类归一化,输出属于每个类别的概率,总和为 1。
    pϕ(y=c∣x)=exp⁡(−dc)∑c′exp⁡(−dc′)p_\phi(y=c \mid x) = \frac{\exp(-d_c)}{\sum_{c'} \exp(-d_{c'})}

数据增强策略:把有限的食材变出花样

不过,徒弟碰上了新麻烦:师傅只给了每道菜一份食材,连练手都不够。老师傅点拨他:“食材是死的,做法是活的。换个摆盘、换个光线、换个切法,一道菜也能练出十遍的效果。”数据增强(Data Augmentation)就是这个思路——用有限样本变出更多“看起来不同、本质相同”的训练素材。

增强分几个层次。图像层面最直接:翻转、旋转、裁剪、调亮度色调,让模型对“不重要的变化”不再敏感。特征层面更聪明:在特征空间给支持样本加噪或插值,凭空造出“虚拟样本”。合成样本更进一步:用生成模型合成新图片,或把目标物体抠出来贴到不同背景上(copy-paste)。这些方法共同的目的,是帮模型抓住类别真正稳定的核心特征,而不是死记某个像素排布。

在小样本场景里,特征空间增强常常比像素级变换更划算。原因很直观:支持集只有三五张图,翻转裁剪的变化空间非常有限;而特征空间是高维连续的,两点之间可以无限插值。比如在原型网络里,把两个支持样本的特征按比例混合,生成一批“口味介于两者之间”的虚拟样本再参与原型计算,可以显著提升类原型的估计稳定性。

数据增强就像练菜时的“花式变换”:同样一锅红烧肉,今天换砂锅、明天换明火,徒弟才能分清哪些是这道菜的灵魂、哪些只是表象。当样本少得可怜时,这种“以变应变”的策略,把每一份食材的利用率都压榨到了极致。

z~=λfϕ(xi)+(1−λ)fϕ(xj),λ∼Beta(α,α),y~=λyi+(1−λ)yj\displaystyle \tilde{z} = \lambda f_\phi(x_i) + (1 - \lambda) f_\phi(x_j), \quad \lambda \sim \mathrm{Beta}(\alpha, \alpha), \quad \tilde{y} = \lambda y_i + (1 - \lambda) y_j
通俗说明:把两道菜的特征按比例调成一杯“混合味”,标签也跟着按比例混合,从而在特征空间制造出新的练习样本。
  1. 采样两样本从支持集中选两个样本,可以同类也可以异类,它们将作为“混合的原料”。
    (xi,yi),(xj,yj)(x_i, y_i), (x_j, y_j)
  2. 抽混合系数λ 从 Beta 分布采样,控制混合比例;α 越大,混合越倾向于均匀。
    λ∼Beta(α,α)\lambda \sim \mathrm{Beta}(\alpha, \alpha)
  3. 特征混合在特征空间而非像素空间做线性插值,产生一个“虚拟样本”。
    z~=λfϕ(xi)+(1−λ)fϕ(xj)\tilde{z} = \lambda f_\phi(x_i) + (1 - \lambda) f_\phi(x_j)
  4. 软标签新样本的标签是两个原标签的加权,模型据此学习模糊边界上的类别信息。
    y~=λyi+(1−λ)yj\tilde{y} = \lambda y_i + (1 - \lambda) y_j

迁移学习思路:把旧功夫搬到新灶台

徒弟在川菜馆学了三年,如今跳槽到一家湘菜馆。老板只给他看了五道新菜的图片,要求第二天就上岗。他却一点也不慌:刀工、火候、颠勺这些基本功,川湘相通;他要调整的只是调味方式。这就是迁移学习(Transfer Learning)的直觉——把旧场景练出的能力,搬到新场景上做小幅适配。

具体做法分三步:先用大量易得的数据(比如 ImageNet)预训练一个模型,得到预训练权重;预训练模型已经具备提取通用视觉特征(边缘、纹理、形状)的能力;到了小样本任务,保留这些能力,只做小幅微调(fine-tuning)——用很低的学习率在支持集上继续训练,或者干脆冻结前面的层,只更新最后几层。

围绕微调程度,工程上有两种常用姿势。一种是特征提取器模式:冻结预训练网络,把支持集和查询集都过一遍,拿到特征后直接做最近邻或原型分类,简单快速、几乎不过拟合。另一种是全量微调模式:所有层用 1e-4 以下的小学习率继续训练,适应目标域,但需要小心过拟合。实践中,“预训练 + 原型网络”的组合拳往往是小样本项目的第一个尝试方向。

从川菜到湘菜,迁移学习让小样本任务站在“巨人肩膀”上起步。它不是小样本学习的全部,却是几乎所有方案的“第一级台阶”——就像老师傅选徒弟时,总要先确认对方已经练过几年基本功。没有这个底子,再聪明的“看一遍就会”也无从谈起。

θ∗=arg⁡min⁡θ  Lnovel(Dsnovel;θpre+Δθ),s.t.  ∥Δθ∥≪∥θpre∥\displaystyle \theta^* = \arg\min_{\theta} \; \mathcal{L}_{\text{novel}}\left(\mathcal{D}_s^{\text{novel}}; \theta_{\text{pre}} + \Delta\theta\right), \quad \text{s.t.} \; \|\Delta\theta\| \ll \|\theta_{\text{pre}}\|
通俗说明:在已有知识的基础上做小幅度调整,而不是从零开始学。Δθ 很小,代表“微调”,保护预训练学到的通用能力不被破坏。
  1. 预训练起点θ_pre 是在大数据集上学到的通用能力,相当于徒弟多年练就的刀工和火候。
    θpre=arg⁡min⁡θLbase(θ)\theta_{\text{pre}} = \arg\min_{\theta} \mathcal{L}_{\text{base}}(\theta)
  2. 新任务损失只在新类的少量标注上计算损失,这是模型唯一能“尝到”的新菜味道。
    Lnovel(Dsnovel;θ)\mathcal{L}_{\text{novel}}\left(\mathcal{D}_s^{\text{novel}}; \theta\right)
  3. 小幅度更新约束Δθ 的规模远小于 θ_pre,防止大改旧知识和过拟合新类。
    ∥Δθ∥≪∥θpre∥\|\Delta\theta\| \ll \|\theta_{\text{pre}}\|
  4. 最终决策新旧知识叠加的结果,是一个“四两拨千斤”的微调参数。
    θ∗=θpre+Δθ\theta^* = \theta_{\text{pre}} + \Delta\theta

模型选择与调优:哪把刀适合什么活

徒弟终于出师,开了一家自己的小饭馆。客人点什么菜,他得决定用哪口锅、哪把刀:炒菜用铁锅,炖汤用砂锅,蒸鱼用大火,慢卤用小火。小样本学习也一样——现实中的数据千差万别,没有放之四海皆准的算法,关键是按场景选对方案。

几条实用的经验法则:如果基类数据丰富、且与目标域比较接近,“预训练 + 原型网络”是最稳妥的起点,简单高效;如果新任务和基类差异很大(域偏移严重),度量学习“长相相似就同类”的假设可能失效,此时元学习(如 MAML)更扛得住;如果每类样例稍多(K≥5),直接预训练加微调效果往往不输复杂的元学习算法;如果 K=1 且类别极多,数据增强和生成式方法更值得投入。

调参也有讲究。微调时学习率要小(1e-4 到 1e-5),否则几步就把预训练学到的特征“冲掉”了;距离度量上,欧氏距离在低维特征空间通常比余弦稳定;特征维度并非越高越好,小样本下过高的维度会放大方差。理解这些取舍,底层框架是经典的偏差-方差分解。

选对方案,小样本任务才能做得顺手。就像小饭馆的后厨,铁锅炒菜、砂锅炖汤、蒸屉配大火,各司其职才会忙而不乱。理解 N、K、数据分布与模型特性之间的关系,是算法工程师面对稀缺数据时最重要的一门“择刀”功夫。

泛化误差=偏差2+方差+噪声\displaystyle \text{泛化误差} = \text{偏差}^2 + \text{方差} + \text{噪声}
通俗说明:模型做错由三部分造成:想错了(偏差)、见得太少(方差)、数据本身有干扰(噪声)。小样本场景最头疼的是方差——样本太少,模型对训练集的细节过于敏感。
  1. 偏差模型容量不足、假设错误造成的系统性误差,相当于“刀法本身就不对”。
    偏差2=(E[f^]−f∗)2\text{偏差}^2 = \left(\mathbb{E}[\hat{f}] - f^*\right)^2
  2. 方差训练样本变动导致模型输出波动,相当于“同样的菜,换一批食客评价就忽高忽低”。
    方差=E[(f^−E[f^])2]\text{方差} = \mathbb{E}\left[(\hat{f} - \mathbb{E}[\hat{f}])^2\right]
  3. 噪声数据自身不可避免的干扰,即使完美模型也无法消除。
    噪声=E[(y−f∗(x))2]\text{噪声} = \mathbb{E}[(y - f^*(x))^2]
  4. 小样本对策用预训练、原型均值化、正则化等手段压低方差,从而降低整体泛化误差。
    方差↓  ⇒  泛化误差↓\text{方差} \downarrow \;\Rightarrow\; \text{泛化误差} \downarrow

AI 应用场景

医疗影像罕见病识别

阶段:模型训练与冷启动

解决的问题:罕见病的影像样本极度稀缺,专家标注成本高昂。传统监督学习需要数千张标注图才能稳定训练,小样本学习让“每类三五张图 + 大型医学影像预训练”快速搭建可用筛查模型,把模型上线周期从数月压缩到数周。

具体案例:某医疗 AI 公司为三甲医院开发眼底疾病筛查系统。团队先用 10 万张公开眼底图预训练特征提取器,再为 5 种罕见病变各收集 3-5 张专家精标图片作为支持集,用原型网络完成分类。新病变识别准确率达到约 85%,模型从立项到上线仅用两周,远超传统方案的速度。

新零售商品快速上新

阶段:数据准备与增量学习

解决的问题:快消品牌每周上新数十种商品,传统方案要为每个新品收集几百张多角度照片再训练识别器,人力成本高、上架慢。小样本学习让运营人员只需上传几张照片,就能让现有识别系统“认识”新品,实现边上新边学习。

具体案例:一家无人货柜公司的视觉识别系统原本只覆盖 200 种老商品。接入小样本模块后,运营为新品拍摄 5 张照片,系统在特征空间自动生成新类“原型”,次日即可上柜识别;新品识别准确率达 92%,覆盖品类从 200 个扩展到 2000 多个。

新用户声纹快速注册

阶段:特征提取与比对

解决的问题:声纹识别需要区分任意新说话人,传统方案要求每人录制几十句语音才能训练。小样本的思路是先用大规模语音预训练“说话人嵌入”模型,新用户只需说几句话即可完成注册,后续通过度量比对进行识别。

具体案例:某智能音箱厂商升级“家庭成员识别”功能:新成员只需对音箱说 3 句话(约 5 秒),系统提取嵌入向量存入声纹库;之后说话时与库内向量做距离比对,识别说话人是谁。实测 3 句注册将误识率降至 1% 以下,注册流程从 5 分钟缩短到 20 秒。

Python 演示

python81 行
"""Few-Shot Learning demos: Prototypical Network on synthetic data.先用基类训练特征提取器, 再在新类上做 N-way K-shot 分类.只依赖 numpy 和 torch, 可直接运行."""import numpy as npimport torchimport torch.nn as nn np.random.seed(42)torch.manual_seed(42)  def make_data(n_classes=20, n_per_class=60, dim=8):    centers = np.random.randn(n_classes, dim) * 2.0    xs = [centers[c] + np.random.randn(n_per_class, dim) * 0.6          for c in range(n_classes)]    ys = [np.full(n_per_class, c) for c in range(n_classes)]    return (np.concatenate(xs).astype("float32"),            np.concatenate(ys))  X, y = make_data()base_ids = set(range(15))            # 15 个基类, 样本充足novel_ids = list(range(15, 20))      # 5 个新类, 只用于小样本测试 # 1. 在基类上训练特征提取器 (迁移学习的一级台阶)embedder = nn.Sequential(    nn.Linear(8, 64), nn.ReLU(),    nn.Linear(64, 32),)head = nn.Linear(32, 15)opt = torch.optim.Adam(    list(embedder.parameters()) + list(head.parameters()), lr=1e-3)loss_fn = nn.CrossEntropyLoss() mask = np.array([v in base_ids for v in y])Xb = torch.tensor(X[mask])yb = torch.tensor(y[mask]).long() for epoch in range(300):    opt.zero_grad()    logits = head(embedder(Xb))    loss = loss_fn(logits, yb)    loss.backward()    opt.step()  # 2. 新类上的 N-way K-shot 评测: 支持集 -> 原型 -> 最近邻def few_shot_eval(n_way=5, k_shot=1, n_query=20, episodes=200):    embedder.eval()    accs = []    with torch.no_grad():        for _ in range(episodes):            chosen = np.random.choice(novel_ids, n_way, replace=False)            idx_per_cls = []            for c in chosen:                cand = np.where(y == c)[0]                idx_per_cls.append(                    np.random.choice(cand, k_shot + n_query, replace=False))            protos, que_x, que_y = [], [], []            for i, c in enumerate(chosen):                sup_idx = idx_per_cls[i][:k_shot]      # 支持集样本                que_idx = idx_per_cls[i][k_shot:]      # 查询集样本                z = embedder(torch.tensor(X[sup_idx]))                protos.append(z.mean(dim=0))           # 类原型 = 支持特征均值                que_x.append(embedder(torch.tensor(X[que_idx])))                que_y.append(torch.full((que_idx.shape[0],), i,                                        dtype=torch.long))            protos = torch.stack(protos)               # (n_way, d)            que_x = torch.cat(que_x)                   # (n_way*n_query, d)            que_y = torch.cat(que_y)            dists = torch.cdist(que_x, protos)         # 距离矩阵            preds = dists.argmin(dim=1)                # 取最近原型            accs.append((preds == que_y).float().mean().item())    return float(np.mean(accs))  for ks in [1, 3, 5, 10]:    acc = few_shot_eval(k_shot=ks)    print(f"{ks}-shot 平均准确率: {acc:.3f}")
目的:用合成数据演示小样本学习的完整流程——先在基类上训练特征提取器(迁移学习),再在新类上用支持集原型做最近邻分类(度量学习),输出不同 K-shot 下的准确率,直观验证“示范越多、准确率越高”。
  1. centers = np.random.randn(n_classes, dim) * 2.0生成每类的“风味中心”,让 20 个类在特征空间彼此分开,模拟真实类别差异
  2. mask = np.array([v in base_ids for v in y])筛选出基类样本,这些样本数量充足,用于训练特征提取器
  3. loss = loss_fn(head(embedder(Xb)), yb)在基类上做常规分类训练,让嵌入器学会“同类近、异类远”的特征结构
  4. protos.append(z.mean(dim=0))每类支持样本的特征求平均,得到该类“平均味道”的原型
  5. dists = torch.cdist(que_x, protos)计算所有查询样本到所有原型的欧氏距离矩阵
  6. preds = dists.argmin(dim=1)距离最近的原型对应的类别,就是预测结果
  7. for ks in [1, 3, 5, 10]:扫描不同 K 值,直观观察“示范越多,准确率越高”

常见误区

误区“新类只有 5 张图,那我把它翻转、裁剪、调色,变出 500 张,不就能训练一个普通的分类网络了吗?”

正解简单的复制粘贴并没有增加真实的类别信息,模型很容易过拟合到这些“假多样性”上。小样本学习的核心在于结构化特征空间(度量学习)和学会适应新任务(元学习),数据增强只是辅助手段。就像做菜的摆盘变换再多,也不会改变食材本身的稀缺性,真正解决问题的是让徒弟掌握“做菜的方法”。

为何常见:数据增强是深度学习里最简单直接的手段,人人都会用,容易产生“量变引起质变”的错觉;但少样本的瓶颈不是图像数量,而是类别本身的信息量。

误区“我直接加载一个 ImageNet 预训练模型,在新类上微调一下,这不就是小样本学习吗?”

正解预训练 + 微调属于迁移学习,只是小样本学习的基础设施之一。真正的小样本学习还包含任务式的训练方式(episodic training)、专门为快速适应设计的元学习目标、以及专门的度量结构。迁移学习解决“起点不差”,元学习和度量学习解决“几步到位”。

为何常见:很多工程里“预训练 + 微调”在少量数据上也能有不错表现,让人误以为这就是全部;但在真正的 1-shot / 5-shot 场景,两者差距会非常明显。

误区“few-shot 就是用小数据训练模型,那我的基类数据也不用很多吧?”

正解小样本指的是“目标新类的标注少”,而不是整个过程的数据少。几乎所有有效方法都依赖一个大规模基类数据集(或预训练模型)来学习通用特征。可以理解为:徒弟只看了新菜一次,但他在学徒期间练了几年的基本功。

为何常见:望文生义,把“目标域的样本少”误当成“整个训练过程中样本都少”。

误区“把图片提成特征,算一下余弦相似度,找最近的那个类,这就是度量学习了吧?”

正解余弦相似度只是距离度量的一种选择,度量学习的精髓在于“学”——通过训练让特征空间满足同类近、异类远的结构。距离函数本身也可以是学习出来的(如孪生网络的相似度子网络)。就像徒弟的“味觉”不是天生就准,而是多年训练出来的。

为何常见:原型网络和最近邻看起来都像是“比较相似度”,容易忽略特征提取器本身的训练对结果的决定性作用。

面试题

Q1. 在 5-way 1-shot 的小样本任务中,支持集一共有多少张带标注的图片?

单选题 · easy

  • A.5 张← 正确答案
  • B.1 张
  • C.25 张
  • D.10 张

答案:A。支持集总样本量 = N × K,N 是类别数,K 是每类样本数。5-way 1-shot 就是 5 个类别、每类 1 张,共 5 张。25 张对应 5-way 5-shot,10 张没有对应的 N/K 组合。类比考题:5 道菜各示范 1 次,示范总数当然是 5。

Q2. 关于支持集和查询集的描述,正确的是哪一项?

单选题 · easy

  • A.两者都用于训练模型参数
  • B.支持集提供少量示范样本← 正确答案
  • C.查询集标注比支持集更丰富
  • D.支持集只能有一个类别

答案:B。支持集提供每类少量带标注样本,是模型“偷师”的来源;查询集用于评估性能(在元学习中用于计算外循环损失)。A 错误,查询集主要用来评估而非训练;C 错误,两者标注形式相同;D 错误,支持集包含 N 个类别。如同考题中师傅示范的菜品集合与待考生做出的菜品集合,分工明确。

Q3. MAML 的内循环主要负责做什么?

单选题 · mid

  • A.在支持集上快速适应几步← 正确答案
  • B.在查询集上做数据增强
  • C.更新特征提取器的维度
  • D.采样更多的新任务进行训练

答案:A。MAML 内循环在某个任务的支持集上走几步梯度,得到临时适应参数 θ′,模拟“看示范后快速调整动作”;外循环才用查询集评估并更新初始参数。B、C 描述与内循环无关;D 属于任务采样环节。记住“内循环吃支持集,外循环评查询集”就不会错。

Q4. 原型网络中,类“原型”指的是什么?

单选题 · easy

  • A.支持样本的加权平均特征← 正确答案
  • B.支持样本的像素平均值
  • C.查询样本的特征向量
  • D.预训练模型的分类头权重

答案:A。原型网络把每类 K 个支持样本的特征求平均(或加权平均),得到该类的“原型”代表点。它生在特征空间而非像素空间,所以 B 错误;查询样本特征是待分类对象,C 错误;分类头权重是另一个概念,D 错误。原型就是“平均味道”。

Q5. 项目只有少量新类标注数据时,最值得优先试用的基线方法是?

单选题 · mid

  • A.直接使用随机森林分类器
  • B.原型网络加预训练特征← 正确答案
  • C.从头训练大型卷积网络
  • D.贝叶斯超参数搜索方案

答案:B。“预训练特征 + 原型网络”简单、稳定、几乎不用调参,是小样本项目公认的默认基线。A、C 在样本极少时容易严重过拟合;D 是调参手段而非分类方法。这就像新菜上桌时,先试最稳妥的铁锅快炒,而不是一上来就搞复杂分子料理。

Q6. 迁移学习中使用小学习率微调的主要目的是什么?

单选题 · mid

  • A.加速收敛并减少计算量
  • B.防止预训练特征被破坏← 正确答案
  • C.帮助自动选择更好的优化器
  • D.提高输入图像的分辨率大小

答案:B。预训练模型已经学到通用特征,用很小的学习率微调,是为了在新类上做“小幅适配”而不大幅改动旧知识,防止灾难性遗忘和过拟合。A 是附带好处并非本质;C、D 与微调学习率无关。

Q7. 特征空间插值(如 Mixup)与传统图像翻转裁剪的关键区别是什么?

单选题 · mid

  • A.它作用在抽象特征而非像素← 正确答案
  • B.它能显著减少模型参数量
  • C.它不需要任何标注信息
  • D.它只适用于小样本图像任务

答案:A。Mixup 在特征空间中做线性插值生成虚拟样本,而翻转裁剪直接操作原始像素,这是二者本质区别。B 错误,参数数量不变;C 错误,软标签仍依赖原标注;D 错误,Mixup 在普通监督学习中也常用。

Q8. 下列哪些属于小样本学习的核心范式?

多选题 · easy

  • A.基于元学习的范式← 正确答案
  • B.基于度量学习的范式← 正确答案
  • C.通用的随机梯度下降
  • D.基于数据增强的策略← 正确答案

答案:ABD。元学习、度量学习、数据增强是小样本学习的三大核心范式;随机梯度下降是任何深度学习通用的优化手段,不属于小样本特有的范式。就像“做饭的技术”和“烧火的方法”的区别——烧火人人都会,但小样本的功夫体现在怎么选料、调味和变换手法。

Q9. 关于元学习的训练过程,下列说法正确的有哪些?

多选题 · hard

  • A.每个训练任务都包含支持集和查询集← 正确答案
  • B.内循环动作发生在支持集之上← 正确答案
  • C.元学习训练不需要查询集
  • D.新类别必须出现在训练阶段

答案:AB。元学习的每个训练任务都由支持集 + 查询集构成,内循环在支持集上快速适应,查询集用于外循环的元学习信号,所以 A、B 正确,C 错误;小样本的泛化目标恰恰是处理好训练阶段未见过的新类别,因此 D 错误。

Q10. 关于 MAML 算法,下列说法错误的是哪些?

多选题 · extreme

  • A.外循环使用二阶梯度更新元参数
  • B.内循环的梯度是从零初始化的← 正确答案
  • C.内循环在查询集上做快速适配← 正确答案
  • D.FO-MAML 忽略部分高阶梯度

答案:BC。标准 MAML 外循环会透过内循环的梯度链计算二阶梯度(A 正确,代价较高);FO-MAML 忽略这些二阶项来加速(D 正确)。内循环不是从零初始化,而是从元参数 θ 出发计算梯度(B 错误);内循环在支持集上做快速适应,查询集只用于评估与外循环更新(C 错误)。题目问错误的是 B、C。