深夜的厨房,一位老食客端来一道从未见过的菜,只说了句“帮我尝尝这是哪个菜系的”。大厨拿起筷子蘸了一点汤汁,在舌尖上转了一圈:“咸鲜回甘,有豆瓣酱的醇厚,还带一丝花椒的麻——川菜,改良过的。”他没有系统的菜谱,甚至没听过这道菜名,但凭十几年的味觉记忆,只尝一口,就完成了别人需要完整菜谱才能完成的判断。 这就是少样本(Few-shot)文本分类的日常。传统机器学习像一位“按菜谱做菜”的新手——看得越多做得越好,数据量少了就无从下手;而 Few-shot 学习像经验老到的大厨——每个类别哪怕只见到几个样例,也能快速提炼出“风味特征”,把新到的文本稳稳归入正确的类别。研究者们走出了两条路:一条是“自建味觉坐标”的原型网络,将每个类别的少量样本浓缩成一个“招牌风味点”;另一条是“请见多识广的老饕出山”的大语言模型,靠提示模板和几个上下文示例,甚至零例子也能直接判断。本文就用“大厨尝菜”这根线头,把 Few-shot 文本分类的来龙去脉一针一线地拆给你看。
掌握 Few-shot 文本分类,意味着你能够在标注资源稀缺的真实业务中快速上线分类服务,这是 NLP 工程师面试与架构评审中体现“工程判断力”的高价值考点。
目录
可视化演示
展示系统处理流水线、实时性能指标曲线及多方案对比分析,包含数据流转、吞吐延迟监控与方案评估。
本节配有交互动效(进入视口后自动加载,约 3KB)。
系统可视化 处理流程:输入→处理→模型→输出 性能监控:实时指标 P=L×T
少样本学习:大厨的“尝一口”本领
大厨为什么敢只尝一口就下判断?因为他把几十年的做菜经验浓缩成了“味觉直觉”。他不需要把整道菜吃完,更不需要翻看厚厚一本菜谱——只需观察汤汁颜色、闻香气、尝咸淡,就能锁定菜系。少样本文本分类要的正是这种本事:每个类别只给你几个标注样本,模型就要学会把新文本正确归档。
传统监督分类像“按菜谱照做”,动辄需要成千上万个标注样本才敢开火。而 Few-shot 学习设定了一种更苛刻的考验:假设有 N 个类别,每个类别只给 K 个标注样本,这被称为 N-way K-shot 问题。这里的“支撑集”就是大厨面前那几口能尝的菜,而“查询集”是后续源源不断端上来的新菜。训练阶段模型可能在其他任务上学过“如何尝菜”,但面对这些新类别时,只能用 K 个样本快速适应。
这个设定可以用数学语言精确描述。支撑集就是所有可用标注样本的集合:
大厨的“尝一口”看似轻松,背后是长期练就的味觉迁移能力。同样,Few-shot 学习真正的难点不在“记住这几道菜”,而在于把在别处学到的“通用味道辨别能力”迁移到眼前的 N 个新类别上——这正是它与普通监督学习的本质分水岭。
- 类别数 N(N-way)N 表示本次任务一共有几种可能的类别,相当于桌上摆了 N 种待辨别的菜系。
- 每类样本数 K(K-shot)K 表示每个类别只给出几条标注文本,相当于每个菜系只允许你尝 K 道菜。
- 支撑集合并所有类别的样本合在一起构成支撑集,是模型在本次任务中唯一能看到的标注数据。
特征空间:调料构成的味觉坐标
大厨尝菜时,脑子里并不是记菜名,而是记“味道坐标”:这口汤汁偏咸还是偏甜?酸度几分?辣度几分?花椒的麻和辣椒的辣各占多少?当所有味道维度摆在眼前,每道菜就成了这个“味觉坐标系”里的一个点。文本分类也要做类似的事:把文字变成向量,让语义相近的句子在空间里靠在一起。
负责把文本变成向量的部分叫嵌入函数,通常用 f(x) 表示。它可以是 BERT 这类预训练编码器,也可以是大语言模型的内部表示。经过编码后,“AI 芯片发布”和“科技公司推出处理器”这两个句子会在向量空间中距离很近,而“国足今晚出战”则落在很远的位置。这样一来,分类问题就被转化成了“找最近的邻居”问题,也就是所谓的度量学习——学习一个好的距离度量,让同类近、异类远。
衡量两个向量亲近程度最常用的工具是余弦相似度,它关注方向的契合而非长度的差异:
对于大厨来说,一套好的“味觉坐标”能让他对任何菜系都快速定位;对于模型来说,一个高质量的特征空间决定了 Few-shot 分类的上限。如果嵌入空间本来就“类间分离、类内紧凑”,那么即使每类只有一两个样本,分类也能稳如老狗。
- 向量点积将两个嵌入向量逐维度相乘再求和,衡量它们在每个维度上是否“同向共振”。
- 模长归一化分别除以两个向量的长度,消除文本长短带来的数值差异。
- 夹角余弦结果落在 [-1, 1] 区间,越接近 1 代表方向越一致,语义越相近。
原型网络:把一群菜汇成招牌风味
大厨面对一种新菜系时,不会把尝过的几道菜分别记在脑子里,而是会总结出一个“招牌风味”:川菜就是麻辣鲜香,粤菜就是清鲜本味。这个招牌风味不是一个具体的菜,而是对多道菜的抽象概括。原型网络(Prototypical Networks)干的就是这件事:把某个类别的 K 个样本向量做平均,得到该类别的“原型”。
具体流程分三步。第一步,用嵌入函数 f 把支撑集中的每条文本变成向量。第二步,对每个类别 k,把属于它的 K 个向量求平均,得到类原型 c_k——相当于“这道菜系的风味均值”。第三步,把待分类的查询文本也变成向量,然后计算它到每个类原型的欧氏距离,距离最近的那个类就是预测结果。整个过程不需要梯度更新,只需一次前向计算,快如闪电。
类原型的计算公式非常简洁:
得到原型后,预测就变成了“比对招牌风味”:
大厨总结出“招牌风味”后,新菜一上桌,他只需拿它和脑中的几个风味模板逐一比对,就能脱口而出答案。原型网络正是用这种“求平均—比距离”的朴素哲学,在 K 很小(甚至 K=1)时依然能给出可用的分类结果,是少样本文本分类最经典的基线方法之一。
- 查询编码待分类文本同样经嵌入函数变成向量。
- 距离计算计算查询向量与每个类原型的欧氏距离平方。
- 取最小值选择距离最小的类别索引作为预测标签。
大语言模型:见多识广的老饕出山
自家大厨再厉害,也有拿不准的新品类。这时候,不妨请一位“吃遍天下”的老饕来把关。大语言模型(LLM)就是这样一位老饕——它在互联网级别的文本上预训练过,见过无数种“菜系风格”和“品评标准”。你甚至不需要给它正式的标注数据,只要把任务写进一句话提示里,它就能给出判断;或者随手给它两三个例子,它就能举一反三。
这种能力的学名叫提示学习(Prompt Learning)。零样本分类是指提示中不包含任何当前任务的标注示例,直接让模型输出标签,例如“将以下新闻分类为科技、体育或财经:……”。上下文学习(In-Context Learning) 则是在提示中拼接 K 个“输入→标签”示例,再接上待分类文本,让模型“照猫画虎”地输出答案。整个过程模型参数完全不动,纯粹靠“读题”完成新任务。
用概率的语言刻画这个过程:模型在给定提示模板和示例的条件下,对每个候选标签词打分,取分数最高的那个作为答案:
老饕的厉害之处在于,他不需要“重新学做菜”——几十年的阅历本身就是知识。大语言模型也是同理:海量预训练已经让它掌握了丰富的语言与知识关联,少样本分类不再是“从零学习”,而是“唤醒已有知识”。这解释了为什么它能在标注数据几乎为零时依然表现出色,成为当前 Few-shot 文本分类最热门的技术路线。
- 模板拼接把 K 个示例和待分类文本按固定模板拼成一个文本序列。
- 候选标签打分模型对每个候选标签词输出一个条件概率。
- 取概率最大者从所有候选标签中选择概率最高的作为预测结果。
工程设计:后厨怎么选人用人
知道了两种主流做法,后厨到底该请老饕坐镇,还是让自家大厨多练几手?这取决于预算、时效和业务场景。工程设计的第一步是选路线:如果数据合规要求严、推理成本敏感、类别是垂直领域专属,那么“小模型编码器 + 原型网络”更稳妥——训练快、可私有化部署、行为可解释;如果类别五花八门、响应速度要求高、且有稳定的 LLM API 可用,那么“提示学习”几乎是零成本启动的最佳选择。
第二步是定评估指标。少样本场景不能只看单次准确率,因为随机抽到的 K 个样本不同,结果波动很大。常用的做法是跑多个随机 episode(每次重新抽样支撑集和查询集),取平均准确率。对于类别不平衡的业务,还要关注宏平均 F1。准确率的定义是:
第三步是设计迭代流程:先用几十条样本快速验证哪条路线效果好,再逐步扩充支撑集、调优提示模板或微调编码器。大厨开新店不会一上来就准备满汉全席,而是先试菜、定菜单、再标准化。工程上最忌讳的是一步到位——少样本任务的性能天花板往往不在模型,而在“样本选得是否代表类别”和“评估是否足够稳定”。
- 指示函数当预测与真实标签相等时记 1,否则记 0。
- 求和计数遍历测试集所有样本,统计预测正确的个数。
- 取平均除以测试集总数,得到 0 到 1 之间的准确率。
挑战与展望:也有失手的时候
再厉害的大厨也有翻车的瞬间。客人说“来点辣的”,他端出重麻重辣的川菜,结果客人想要的是湖南的香辣——几个样本很难覆盖一个类别的全部变化。这就是少样本学习最大的心魔:样本偏差。如果 K 个“科技新闻”恰好都是手机发布会,模型就会把“科技”理解成“手机相关”,遇到“AI 芯片”的新文本就判错。
原型网络对这种偏差尤其敏感,因为类原型是 K 个样本的均值,一个离群样本就能把原型拉偏。从统计角度看,原型估计的方差与 K 成反比:
除了样本偏差,提示学习还有自己的“娇气”:模板敏感。提示词换个措辞、示例换个顺序,准确率可能相差好几个百分点。更进一步的跨域泛化难题是,在一个领域(如新闻)上学到的原型度量空间,迁移到另一个领域(如医疗)时可能水土不服。未来的方向包括元学习、数据增强、检索增强等,这些探索本质上都指向同一个目标——让大厨在只尝一口的情况下,依然能凭最少的线索,做出最稳的判断。
- 真实中心假设每个类别存在一个理想的中心向量,是无数样本的平均。
- 估计偏差用 K 个样本估计出的原型与真实中心之间的平方距离就是误差。
- 方差反比误差随 K 增大按 1/K 的速度缩小,说明“多看几道菜”确实能稳住风味判断。
AI 应用场景
电商新品评论快速打标
阶段:数据标注与冷启动
解决的问题:电商平台上新类目(如“折叠屏支架”)上线时,历史标注数据几乎为零,传统分类模型无法启动训练,而人工标注数千条评论耗时又费钱。
具体案例:运营团队用大语言模型的提示学习,在提示中给出 3 条正例和 2 条反例(“质量很好,安装方便”→好评;“用两天就断了”→差评),对首批 500 条新品类评论进行零训练分类。模型在 10 分钟内完成打标,人工抽检准确率约 92%,随后将高置信预测结果加入支撑集,用小模型+原型网络建立可自部署的轻量分类服务。
金融新事件类型冷启动分类
阶段:小样本类别建模
解决的问题:金融风控中每季度都会出现新兴的违规事件类型(如“虚拟货币洗钱”“人工智能伪造证件”),起初只有零星几个真实案例,传统监督学习无法用几个样本训练出一个可靠的检测器。
具体案例:风控团队从人工审核记录中挑出每个新事件类型 K=3 个典型样本,用预训练编码器提取嵌入,构建原型网络。当新案件进入时,先计算它与所有已知类型原型的距离,距离均超过阈值则进入人工审核,否则直接归类。该系统将新类型案件的初筛准确率从 40% 提升到 85%,且模型上线仅需一条 SQL 级别的批处理脚本。
Python 演示
import numpy as np def build_embeddings(n_classes=6, n_per_class=50, dim=16, seed=42): rng = np.random.default_rng(seed) centers = rng.normal(size=(n_classes, dim)) embs, labels = [], [] for c in range(n_classes): for _ in range(n_per_class): embs.append(centers[c] + rng.normal(scale=0.5, size=dim)) labels.append(c) return np.array(embs), np.array(labels) def get_prototypes(support_x, support_y, n_classes): protos = [] for c in range(n_classes): mask = support_y == c protos.append(support_x[mask].mean(axis=0)) return np.array(protos) def few_shot_accuracy(emb, label, n_classes, k_shot=3, n_episodes=200, seed=1): rng = np.random.default_rng(seed) accs = [] for _ in range(n_episodes): support_idx = [] for c in range(n_classes): support_idx.append(rng.choice(np.where(label == c)[0], k_shot, replace=False)) support_idx = np.concatenate(support_idx) query_mask = np.ones(len(emb), dtype=bool) query_mask[support_idx] = False protos = get_prototypes(emb[support_idx], label[support_idx], n_classes) dist = np.linalg.norm(emb[query_mask][:, None, :] - protos[None, :, :], axis=2) pred = dist.argmin(axis=1) accs.append((pred == label[query_mask]).mean()) return np.mean(accs) if __name__ == "__main__": emb, label = build_embeddings() for k in [1, 3, 5]: acc = few_shot_accuracy(emb, label, n_classes=6, k_shot=k) print(f"K-shot={k}: 平均准确率={acc:.2%}")
embs.append(centers[c] + rng.normal(scale=0.5, size=dim))在真实类别中心附近生成带噪声的文本嵌入向量。np.where(label == c)[0]找到第 c 类所有样本的下标,等价于“把同一菜系的菜挑出来”。rng.choice(..., k_shot, replace=False)每类随机抽取 K 个样本作为支撑集,其余作为查询集。support_x[mask].mean(axis=0)对同类样本向量求平均,得到该类别的类原型。np.linalg.norm(..., axis=2)计算每个查询向量到所有类原型的欧氏距离矩阵。dist.argmin(axis=1)对每个查询样本取距离最近的类原型下标,完成最近邻匹配。
常见误区
误区既然数据少,那就把这几条数据反复喂给模型,多训练几个 epoch,让模型把样本背下来。
正解少样本学习的核心是“用少量样本学会可泛化的类别边界”,而不是“记住这几个样本”。原型网络通过求均值提炼共性,大模型通过触发已有知识完成分类,两者都强调泛化能力。如果只是反复训练,模型会过拟合到那 K 条样本上,换一条新文本立刻露馅,相当于大厨只记住了那几道菜的味道,却总结不出菜系规律。
为何常见:“数据不够,训练来凑”是传统深度学习的直觉惯性,容易忽略 Few-shot 问题本身的设定就是“只想给你看几眼”。
误区上下文示例是很厉害,那我放 20 个示例进去,分类肯定比 3 个示例更准。
正解示例并非多多益善。超出模型上下文窗口会导致截断,重复或矛盾的示例会引入噪声,示例的顺序也会显著影响效果。实践中存在一个“最佳示例数”,通常 4~8 个即可,超过后性能可能不升反降,就像给老饕连上十道菜他也会味觉疲劳。
为何常见:日常经验中“例题越多学得越好”的认知迁移到了提示学习上,忽略了 LLM 推理时的上下文容量和注意力稀释。
误区原型网络对每个样本算距离再取最近,和 K 近邻分类一模一样。
正解KNN 是拿查询样本与每一个历史样本逐一比较,本质上是“记菜名”;原型网络先把同类样本融合成一个原型点,再用查询向量与原型比较,本质上是“总结菜系”。融合步骤让原型对个别离群样本更鲁棒,且在推理时只需比较 N 个原型而非 N×K 个样本,速度更快。两者在 K=1 时恰好相等,但原型网络在 K>1 时引入了“类内信息聚合”这一关键差异。
为何常见:两者的预测公式都是“距离最近”,初学者容易只看表象而忽略“原型是学出来的类代表”这一核心。
误区既然叫 zero-shot,那模型对这些标签概念应该一无所知,纯粹靠推理猜出来。
正解“零样本”指的是推理时不给当前任务的标注示例,但大语言模型在海量预训练语料中已经见过无数带标签的文本。它知道“科技”通常与芯片、互联网相关,“财经”与股票、基金相关。零样本分类本质上是“唤醒已有知识并执行指令”,而不是“凭空推理”。如果标签是非常罕见的专有名词,零样本性能就会明显下降。
为何常见:“zero“这个词太有迷惑性,让人望文生义,忽略了 LLM 预训练阶段已经”偷看”过大量监督信号。
面试题
Q1. Few-shot 文本分类中"K-shot"的 K 指什么?
- A.每个类别的标注样本数← 正确答案
- B.模型训练的总轮数
- C.输入文本的最大长度
- D.支撑集的样本总数
答案:A。K-shot 指每个类别提供 K 个标注样本,是“每道菜系只给你尝 K 道菜”的意思。支撑集总样本数应为 N×K,训练轮数和文本长度都与 K 无关。
Q2. 原型网络中“类原型”通常如何得到?
- A.该类样本向量的均值← 正确答案
- B.距离中心最近的样本
- C.随机选中的一个样本
- D.类别标签的独热编码
答案:A。类原型是对同类 K 个样本的嵌入向量求平均,相当于大厨总结出的“招牌风味”。随机选一个样本无法代表整个类别,独热编码只是标签表示而非文本特征。
Q3. 原型网络对查询文本进行分类的依据是?
- A.与各类原型的欧氏距离← 正确答案
- B.与所有样本的平均编辑距离
- C.与训练集样本的 Jaccard 相似度
- D.词频统计的卡方检验值
答案:A。原型网络将查询向量与每个类原型计算欧氏距离,取最近者作为预测类别。编辑距离是字符层面的相似度,Jaccard 与卡方检验都不是该网络的匹配机制。
Q4. 大语言模型的“上下文学习”指的是?
- A.通过提示中的示例完成新任务← 正确答案
- B.用梯度下降更新模型参数
- C.对上下文窗口做数据增强
- D.在隐层中存储知识图谱
答案:A。上下文学习是把若干输入-标签示例拼进提示文本,模型不改参数直接推理,像老饕听你举两个例子就能举一反三。它不涉及梯度更新和参数修改。
Q5. 提示学习中“标签词”的选择为什么重要?
- A.它决定了候选标签的概率空间← 正确答案
- B.它直接改变支撑集的类别数
- C.它会修改嵌入向量的维度
- D.它决定训练集的数据量大小
答案:A。模型在标签词上输出概率分布,选择“科技/体育/财经”还是"Tech/Sports/Finance",会改变概率空间和最终预测。它不影响支撑集、向量维度或训练数据量。
Q6. 与传统监督分类相比,Few-shot 分类的核心目标是?
- A.用极少标注样本快速适应新类别← 正确答案
- B.在超大样本上提升极限精度
- C.完全抛弃监督信号做无监督聚类
- D.用模型压缩减小存储体积
答案:A。Few-shot 的核心约束是每类仅几个标注样本,目标是快速适应新类别。它并不排斥少量监督信号,也不是为了压缩模型或追求超大样本精度。
Q7. 少样本评估中"episode"指的是什么?
- A.一次随机采样支撑集和查询集的评估回合← 正确答案
- B.一轮完整的梯度下降迭代
- C.一次数据增强的预处理流程
- D.一个完整的模型训练周期
答案:A。少样本评估通常随机采样多个划分(支撑集+查询集),每个划分称为一个 episode,最后取平均指标以消除抽样波动。它不等同于训练轮次或预处理流程。
Q8. 以下哪些属于 Few-shot 文本分类的可行技术路线?
- A.原型网络上做最近邻匹配← 正确答案
- B.构造提示模板引导大模型← 正确答案
- C.在训练集上随机打乱标签
- D.用元学习训练“会学习”的初始化← 正确答案
答案:ABD。原型网络、提示学习、元学习都是少样本分类的主流路线。随机打乱标签会破坏监督信号,不可能学到有效分类器。
Q9. 原型网络在 K=1 时最容易出现的风险是?
- A.单个样本将类原型带偏← 正确答案
- B.模型彻底欠拟合训练数据
- C.嵌入向量维度直接爆炸
- D.反向传播梯度消失导致崩溃
答案:A。K=1 时类原型就是那一个样本本身,它若是离群点,整个类别的代表点就偏离真实中心,这正是方差公式中 K 很小时的隐患。它不涉及欠拟合、维度或梯度问题,因为原型网络在推理时甚至不依赖梯度。
Q10. 缓解少样本文本分类中样本偏差的常见思路包括?
- A.在相似任务上先做元学习← 正确答案
- B.利用大模型的外部知识补充← 正确答案
- C.盲目增加每类的单词数量
- D.用数据增强扩充支撑集← 正确答案
答案:ABD。元学习提供更好的初始化,大模型提供外部知识,数据增强扩充样本多样性,三者都能对冲样本偏差。增加单条文本的单词数不改变类别覆盖面,无法解决“样本代表性不足”问题。