构建文本嵌入模型
从 Sentence-BERT 到对比学习(SimCSE),再到 Matryoshka 嵌入和 MTEB 基准评估——系统讲解如何构建和优化高质量文本嵌入模型。
深入讲解为分类任务微调表示模型的完整流程:分类头设计、全量微调 vs LoRA 的选择、小样本场景下的 SetFit 方案,以及过拟合防范与模型评估。
前几层学的是低级特征(词法、语法),通用性强,通常冻结。后几层学的是高级语义特征,任务相关性强,需要微调。前馈层(FFN)存储的是知识记忆,注意力层存储的是关系模式。实践中的常见做法:数据少时只微调最后1-2层+分类头;数据中等时冻结前半微调后半;数据充足时全部微调。或者用LoRA,不必纠结冻哪层。
SetFit的核心思路:从少量标注样本中生成大量句子对。具体做法:将同类别的样本两两配对作为正例,不同类别的配对作为负例。假设每类8个样本、共三类,就能生成C(8,2)×3=84个正例对,加上负例对就有几百个训练样本。用这些句子对微调Sentence Transformer,再在微调后的嵌入上训练一个分类头。效果远超直接用冻结嵌入+分类器。
冻结模型的嵌入是通用的语义相似度,不一定能区分特定分类任务的类别。SetFit的对比学习微调会重新组织嵌入空间:1)让同类样本聚拢、不同类样本分开,形成更利于分类的嵌入布局;2)学到的是任务相关的距离度量,而不是通用语义相似度;3)减类内方差、增类间方差,让分类边界更清晰。这就是为什么SetFit在少样本下远超冻结嵌入+分类器。
1)混合语料——用领域数据和通用数据混合继续预训练,比例如 3:1;2)低学习率——用比预训练低得多的学习率,减少对原有参数的破坏;3)正则化——用EWC等方法约束重要参数的变化幅度;4)分阶段——先用少量领域数据预热,再逐渐增加比例。可以用通用基准测试监控通用能力是否退化。
(a)最简单——直接可用,但对领域术语理解不足,分词也不优。(b)最佳性价比——在(a)的基础上用医疗文本继续预训练,获得领域知识的同时保留通用语言能力,成本比(c)低得多,BioBERT就是这个思路。(c)理论上上限最高——但需要海量领域数据和计算资源,实际中很少有垂直领域能满足这个条件。大多数场景选(b)。
预训练时数据量巨大,梯度噎杂但整体方向正确,损失面相对平滑,对学习率不太敏感。微调时数据量小,损失面崎岖很多,学习率稍大就可能跳过好的极值点或振荡不收敛。而且预训练的参数已经在一个好的位置,太大的学习率会把它推离这个位置,破坏预训练学到的知识。实践中微调学习率通常是预训练的十分之一到百分之一。
常见做法:只用每个单词的第一个子词元的输出作为该单词的表征,用于分类。其他子词元的标签设为-100(PyTorch交叉熵损失的ignore_index),不参与损失计算。也有人用所有子词元的平均或最大池化作为单词表征,但第一个子词元策略最简单且效果很好,是Hugging Face官方推荐的做法。
用知识蒸馏+多任务学习。具体步骤:1)选一个小型encoder(如TinyBERT、64M参数);2)用领域数据继续预训练;3)设计多任务头——分类头、NER头、嵌入头共享同一个encoder;4)多任务联合训练,交替使用三个任务的数据;5)用大模型的特征做蒸馏目标,提升小模型效果;6)用ONNX、量化等优化部署到设备上。
1)扩充词汇表——加入中文字和常见词的token,减少中文被拆成过多子词元的问题,新加的嵌入用相似 token的均值初始化;2)用中英双语对照数据做对比学习,让中文和英文的相同语义在嵌入空间中对齐;3)用大量中文文本继续 MLM预训练,但混合英文数据防止英文能力退化;4)尽量保持低学习率,避免破坏英文嵌入空间。
评估指标:重点关注“严重不良反应”类别的召回率(不能漏检),同时看宏平均F1而不是准确率。处理不平衡:1)过采样少数类/欠采样多数类;2)用LLM生成合成数据增强少数类。损失函数:1)class_weight加权——给“严重”类更高的损失权重;2)用非对称损失,让“把严重分成轻微”的惩罚远大于反向错误;3)Focal Loss——自动让模型关注难分类的样本。
RELATED