
目录
摘要
学了新的忘了旧的,指的是持续预训练或领域微调之后,旧任务与通用能力大幅下降的现象。本文从现象证据讲到参数覆盖机理,再依次给出数据重放、EWC、LoRA、模型合并四类缓解工具。 遗忘的度量是旧任务性能下降幅度,学新与保旧构成一条双曲线,鱼与熊掌要靠显式付出才能兼得。 工程结论是领域适配优先 LoRA 加重放,不做全参微调,并保留通用回归测试集持续监控。
1. 遗忘是怎么发生的
灾难性遗忘(catastrophic forgetting)指模型在新任务或新语料上训练后,旧任务性能大幅下降的现象。这个词在 1989 年前后由连接主义研究者提出,比大模型早了三十多年。它不是大模型特有的 bug,而是梯度下降这种学习方式的固有属性。
先给一个可感的类比。一位全科医生去进修法律,三年只读法条,回来后看病水平明显退化。原因不是脑子坏了,而是这三年的练习里没有任何一道题需要用到医学知识。模型的处境完全一样:训练数据里没有旧知识,更新就只朝新知识的方向走。
#mermaid-svg-LZmTEXse4oQI2PK3{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-LZmTEXse4oQI2PK3 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-LZmTEXse4oQI2PK3 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-LZmTEXse4oQI2PK3 .error-icon{fill:#552222;}#mermaid-svg-LZmTEXse4oQI2PK3 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-LZmTEXse4oQI2PK3 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-LZmTEXse4oQI2PK3 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-LZmTEXse4oQI2PK3 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-LZmTEXse4oQI2PK3 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-LZmTEXse4oQI2PK3 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-LZmTEXse4oQI2PK3 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-LZmTEXse4oQI2PK3 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-LZmTEXse4oQI2PK3 .marker.cross{stroke:#333333;}#mermaid-svg-LZmTEXse4oQI2PK3 svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-LZmTEXse4oQI2PK3 p{margin:0;}#mermaid-svg-LZmTEXse4oQI2PK3 .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-LZmTEXse4oQI2PK3 .cluster-label text{fill:#333;}#mermaid-svg-LZmTEXse4oQI2PK3 .cluster-label span{color:#333;}#mermaid-svg-LZmTEXse4oQI2PK3 .cluster-label span p{background-color:transparent;}#mermaid-svg-LZmTEXse4oQI2PK3 .label text,#mermaid-svg-LZmTEXse4oQI2PK3 span{fill:#333;color:#333;}#mermaid-svg-LZmTEXse4oQI2PK3 .node rect,#mermaid-svg-LZmTEXse4oQI2PK3 .node circle,#mermaid-svg-LZmTEXse4oQI2PK3 .node ellipse,#mermaid-svg-LZmTEXse4oQI2PK3 .node polygon,#mermaid-svg-LZmTEXse4oQI2PK3 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-LZmTEXse4oQI2PK3 .rough-node .label text,#mermaid-svg-LZmTEXse4oQI2PK3 .node .label text,#mermaid-svg-LZmTEXse4oQI2PK3 .image-shape .label,#mermaid-svg-LZmTEXse4oQI2PK3 .icon-shape .label{text-anchor:middle;}#mermaid-svg-LZmTEXse4oQI2PK3 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-LZmTEXse4oQI2PK3 .rough-node .label,#mermaid-svg-LZmTEXse4oQI2PK3 .node .label,#mermaid-svg-LZmTEXse4oQI2PK3 .image-shape .label,#mermaid-svg-LZmTEXse4oQI2PK3 .icon-shape .label{text-align:center;}#mermaid-svg-LZmTEXse4oQI2PK3 .node.clickable{cursor:pointer;}#mermaid-svg-LZmTEXse4oQI2PK3 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-LZmTEXse4oQI2PK3 .arrowheadPath{fill:#333333;}#mermaid-svg-LZmTEXse4oQI2PK3 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-LZmTEXse4oQI2PK3 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-LZmTEXse4oQI2PK3 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-LZmTEXse4oQI2PK3 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-LZmTEXse4oQI2PK3 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-LZmTEXse4oQI2PK3 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-LZmTEXse4oQI2PK3 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-LZmTEXse4oQI2PK3 .cluster text{fill:#333;}#mermaid-svg-LZmTEXse4oQI2PK3 .cluster span{color:#333;}#mermaid-svg-LZmTEXse4oQI2PK3 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-LZmTEXse4oQI2PK3 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-LZmTEXse4oQI2PK3 rect.text{fill:none;stroke-width:0;}#mermaid-svg-LZmTEXse4oQI2PK3 .icon-shape,#mermaid-svg-LZmTEXse4oQI2PK3 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-LZmTEXse4oQI2PK3 .icon-shape p,#mermaid-svg-LZmTEXse4oQI2PK3 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-LZmTEXse4oQI2PK3 .icon-shape .label rect,#mermaid-svg-LZmTEXse4oQI2PK3 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-LZmTEXse4oQI2PK3 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-LZmTEXse4oQI2PK3 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-LZmTEXse4oQI2PK3 :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}#mermaid-svg-LZmTEXse4oQI2PK3 .default>*{fill:#faf9f5!important;stroke:#ffffff!important;color:#000000!important;stroke-width:0px!important;}#mermaid-svg-LZmTEXse4oQI2PK3 .default span{fill:#faf9f5!important;stroke:#ffffff!important;color:#000000!important;stroke-width:0px!important;}#mermaid-svg-LZmTEXse4oQI2PK3 .default tspan{fill:#000000!important;}
基座模型
通用能力达标
新领域语料继续训练
参数朝新领域最优解移动
领域基准上升
通用基准下降
灾难性遗忘
图 1-1 灾难性遗忘的因果链。同一次参数移动同时产生一升一降两个结果,上升与下降共享同一批梯度更新。
1.1 现象证据:通用基准掉分
持续预训练(CPT,continued pre-training)是在基座上继续用领域语料预训练。社区与论文反复报告同一现象:领域基准上升的同时,通用基准如 MMLU 掉分。掉分幅度没有统一数字,文献里常见从几个点到两位数点的区间,取决于语料规模、训练步数与配比。
方向上可以确定三件事。第一,领域语料越多、训练越深,通用能力越容易被侵蚀。第二,指令微调做过头同样会损基座能力,语言流畅度与推理稳定性一起退化。第三,侵蚀往往先出现在通用知识的边缘部分,比如冷门事实与多步推理,常用的格式化能力最后才退化。
| 全参 CPT,纯领域语料 | 明显上升 | 明显下降 | 无旧数据约束 |
| 全参 CPT,混通用语料 | 上升 | 基本持平 | 重放起作用 |
| LoRA 微调,冻结基座 | 上升 | 掉分很小 | 结构上隔离更新 |
| 指令微调过深 | 对话格式上升 | 基座能力受损 | 过拟合到对话模板 |
表 1-1 四种适配方式的方向性对比。具体数字随模型与数据浮动,表中给出的是文献与社区报告的普遍方向。
方向性表述的边界也要讲清楚。掉分不是线性的,前几百步可能几乎无感,超过某个训练量后加速下滑。这说明存在一个可用的适配区间,工程上的目标不是零遗忘,而是把遗忘压在自己可接受的阈值内。
还有一个判断技巧。适配后的模型如果只在通用基准上掉分,而领域基准也没涨,说明训练本身没生效,不是遗忘问题。真正的遗忘画像是一边明确上涨一边明确下滑,两条曲线同时移动。排查时先把这两条曲线画在一张图上,避免把训练失败误诊为遗忘。
观测样本也有讲究。通用基准要选与领域距离远的子集。比如做法律微调,就别拿法律相关的那部分 MMLU 题目当通用参照,那部分反而会上涨。选远域子集才能干净地测出通用能力的侵蚀幅度。
基准选择上还有一个实际问题。MMLU 这类静态基准本身有题库泄漏风险,领域语料若来自爬取网页,可能含基准题目。掉分读数要先用未泄漏的私有题集复核,再下结论。泄漏方向是虚高,复核方向是找真实值,两者结合才可信。
时间维度也别忽略。同一基座在不同月份复测,分数本身就有波动。把适配前的分数当唯一定基线,会把正常波动算成遗忘。更稳的做法是适配前连测两三次取均值,让基线自带置信区间。
评测口径还要固定解码参数。温度与采样种子不固定时,同一模型的复测分数本身就有波动,幅度可达一两个点,足以掩盖或放大真实的遗忘读数。适配前后两次评测必须用同一套解码配置,报告里也要注明。
再看一类特殊证据。有些团队报告适配后代码能力掉分,这看似与领域无关。原因在于代码与通用推理共享底层能力,领域语料挤掉的不只是事实,还有结构化表达。这说明通用基准要覆盖代码类,不能只考知识题。
把这些证据整理成一条经验规律。同样训练步数下,领域语料与原语料的分布距离越大,通用掉分越早越重。法条与网页距离远,掉分猛。客服对话与网页距离近,掉分缓。预估遗忘幅度时先估分布距离,比直接估训练量更准。
还有规模效应。小模型掉分往往比大模型更重,因为参数冗余少,共享冲突更尖锐。做迁移结论时别把小模型的掉分幅度直接外推到大模型,量级可能差不少。
1.2 一升一降:为什么必然同时出现
一升一降的根源在于参数是共享的。模型的每一层权重同时服务于通用能力与领域能力,不存在一块只属于法律、一块只属于医学的独立分区。新语料的梯度落在这些共享参数上,更新在优化领域损失的同时,不可避免地移动了通用能力的解。
#mermaid-svg-ffdlZZUWDYlPnCmk{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-ffdlZZUWDYlPnCmk .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-ffdlZZUWDYlPnCmk .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-ffdlZZUWDYlPnCmk .error-icon{fill:#552222;}#mermaid-svg-ffdlZZUWDYlPnCmk .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-ffdlZZUWDYlPnCmk .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-ffdlZZUWDYlPnCmk .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-ffdlZZUWDYlPnCmk .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-ffdlZZUWDYlPnCmk .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-ffdlZZUWDYlPnCmk .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-ffdlZZUWDYlPnCmk .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-ffdlZZUWDYlPnCmk .marker{fill:#333333;stroke:#333333;}#mermaid-svg-ffdlZZUWDYlPnCmk .marker.cross{stroke:#333333;}#mermaid-svg-ffdlZZUWDYlPnCmk svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-ffdlZZUWDYlPnCmk p{margin:0;}#mermaid-svg-ffdlZZUWDYlPnCmk .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-ffdlZZUWDYlPnCmk .cluster-label text{fill:#333;}#mermaid-svg-ffdlZZUWDYlPnCmk .cluster-label span{color:#333;}#mermaid-svg-ffdlZZUWDYlPnCmk .cluster-label span p{background-color:transparent;}#mermaid-svg-ffdlZZUWDYlPnCmk .label text,#mermaid-svg-ffdlZZUWDYlPnCmk span{fill:#333;color:#333;}#mermaid-svg-ffdlZZUWDYlPnCmk .node rect,#mermaid-svg-ffdlZZUWDYlPnCmk .node circle,#mermaid-svg-ffdlZZUWDYlPnCmk .node ellipse,#mermaid-svg-ffdlZZUWDYlPnCmk .node polygon,#mermaid-svg-ffdlZZUWDYlPnCmk .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-ffdlZZUWDYlPnCmk .rough-node .label text,#mermaid-svg-ffdlZZUWDYlPnCmk .node .label text,#mermaid-svg-ffdlZZUWDYlPnCmk .image-shape .label,#mermaid-svg-ffdlZZUWDYlPnCmk .icon-shape .label{text-anchor:middle;}#mermaid-svg-ffdlZZUWDYlPnCmk .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-ffdlZZUWDYlPnCmk .rough-node .label,#mermaid-svg-ffdlZZUWDYlPnCmk .node .label,#mermaid-svg-ffdlZZUWDYlPnCmk .image-shape .label,#mermaid-svg-ffdlZZUWDYlPnCmk .icon-shape .label{text-align:center;}#mermaid-svg-ffdlZZUWDYlPnCmk .node.clickable{cursor:pointer;}#mermaid-svg-ffdlZZUWDYlPnCmk .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-ffdlZZUWDYlPnCmk .arrowheadPath{fill:#333333;}#mermaid-svg-ffdlZZUWDYlPnCmk .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-ffdlZZUWDYlPnCmk .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-ffdlZZUWDYlPnCmk .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ffdlZZUWDYlPnCmk .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-ffdlZZUWDYlPnCmk .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ffdlZZUWDYlPnCmk .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-ffdlZZUWDYlPnCmk .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-ffdlZZUWDYlPnCmk .cluster text{fill:#333;}#mermaid-svg-ffdlZZUWDYlPnCmk .cluster span{color:#333;}#mermaid-svg-ffdlZZUWDYlPnCmk div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-ffdlZZUWDYlPnCmk .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-ffdlZZUWDYlPnCmk rect.text{fill:none;stroke-width:0;}#mermaid-svg-ffdlZZUWDYlPnCmk .icon-shape,#mermaid-svg-ffdlZZUWDYlPnCmk .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ffdlZZUWDYlPnCmk .icon-shape p,#mermaid-svg-ffdlZZUWDYlPnCmk .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-ffdlZZUWDYlPnCmk .icon-shape .label rect,#mermaid-svg-ffdlZZUWDYlPnCmk .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ffdlZZUWDYlPnCmk .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-ffdlZZUWDYlPnCmk .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-ffdlZZUWDYlPnCmk :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}#mermaid-svg-ffdlZZUWDYlPnCmk .default>*{fill:#faf9f5!important;stroke:#ffffff!important;color:#000000!important;stroke-width:0px!important;}#mermaid-svg-ffdlZZUWDYlPnCmk .default span{fill:#faf9f5!important;stroke:#ffffff!important;color:#000000!important;stroke-width:0px!important;}#mermaid-svg-ffdlZZUWDYlPnCmk .default tspan{fill:#000000!important;}
共享参数池
通用能力的解
领域A的解
领域B的解
新语料梯度
领域B解被强化
通用解被挤出
图 1-2 共享参数池的挤出效应。梯度只能作用于唯一的一份参数,强化一处必然挤压他处。
用一份玩具实验把这条曲线跑出来。两个线性任务先后训练,观察任务 A 的性能在训练任务 B 时如何崩塌。
# 来源:自实现 / forgetting_demo.py
import numpy as np
def make_task(dim=40, seed=0):
# 每个任务一组线性权重,代表一种知识
rng = np.random.default_rng(seed)
w = rng.normal(size=dim)
X = rng.normal(size=(200, dim))
y = X @ w
return w, X, y
def sgd_train(w, X, y, steps=300, lr=0.05):
# 极简梯度下降,模拟顺序训练
for _ in range(steps):
grad = 2 * X.T @ (X @ w – y) / len(X)
w = w – lr * grad
return w
def score(w, w_true, X):
# 用预测误差的倒数衡量保留度,越大越好
err = np.mean((X @ w – X @ w_true) ** 2)
return 1.0 / (1.0 + err)
w_a, X_a, y_a = make_task(seed=1)
w_b, X_b, y_b = make_task(seed=2)
w = np.zeros(40)
w = sgd_train(w, X_a, y_a) # 阶段一:只学任务A
s_a_before = score(w, w_a, X_a)
w = sgd_train(w, X_b, y_b) # 阶段二:只学任务B
s_a_after = score(w, w_a, X_a)
s_b = score(w, w_b, X_b)
print(f"阶段一后 任务A分数 {s_a_before:.3f}")
print(f"阶段二后 任务A分数 {s_a_after:.3f}") # 典型输出接近 0.00x
print(f"阶段二后 任务B分数 {s_b:.3f}")
典型输出是任务 A 分数从 0.9 以上掉到 0.01 量级,任务 B 接近满分。这段代码证明两件事:顺序训练不需要任何错误操作,遗忘自然发生;遗忘幅度不是小幅退化,而是接近清零的崩塌。
1.3 知识型微调的具体损失
对知识型微调而言,被侵蚀的不只是某个旧基准分数。具体有三层损失。第一层是通用知识,模型对领域外事实的召回变差,常见表现是冷门知识开始编造。第二层是推理能力,多步推理链更容易断,这一点本系列第 7 篇讨论过。第三层是指令遵循,输出格式不稳定,长指令的中段要求被忽略。
第三层最容易被误判。团队看到领域问答分数上涨,就认为微调成功。但格式漂移与指令遗漏要到上线后才暴露,因为领域评测集通常不考察这两项。这也是后文强调回归监控的原因:评测集必须覆盖被训练目标之外的维度。
| 通用知识 | 领域外事实开始编造 | 上线后随机出现 |
| 多步推理 | 推理链中段断裂 | 复杂任务返工 |
| 指令遵循 | 长指令中段要求被忽略 | 上线后格式投诉 |
| 输出稳定性 | 同题多次答案不一致 | 抽检时发现 |
表 1-2 知识型微调的四类隐性损失。后两类在领域评测集上不可见,是误判的主要来源。
三层损失的出现顺序也有规律。格式能力最先退化,因为它依赖的是输出分布的精细校准。推理其次,它需要多条知识同时可用。通用知识最后退化,因为高频事实在领域语料里往往仍有间接出现。据此可以设计分阶段监控,早期盯格式,后期盯推理。
还有一个反直觉现象值得一提。领域微调后,模型对领域内问题的自信度上升,但对领域外问题的自信度没有同步下降。于是出现"答错但很自信"的输出,比单纯不知道更危险。这属于校准受损,回归集里应加入置信度抽查。
把这些损失落到验收清单上。领域评测集之外,至少加四组题:远域事实问答、多步推理、长指令遵循、同题多次采样一致性。每组几十题,适配前后各跑一次。这份清单的成本远低于上线返工,也是第 8 章监控体系的最小可用版本。
顺带说一句术语命名。领域微调后通用能力下降,常被团队口头称为"过拟合",但严格说过拟合指训练集上好测试集上差。这里的现象是能力此消彼长,更接近持续学习里的后向干扰。名称混用会让排查方向跑偏。
损失之间还有传染性。推理能力下降会连带知识答题变差,因为很多知识题实际需要一到两步推理才能落到答案上。表现为知识题掉分,根因却在推理。排查时要分维度看,也要看维度间是否共因,否则补错方向。
给一个自查问句清单。适配后的模型,远域事实还能答对吗,两步推理还能走通吗,长指令中段要求还记得吗,同题三次答案一致吗。四个问题各答一次,就能在十分钟内判断有没有明显遗忘,成本远低于完整回归。
损失的严重度还与训练阶段有关。预训练阶段的继续训练伤知识底座,指令微调阶段的过深训练伤行为校准。两者叠加时最危险,知识底座与行为层同时松动。分阶段适配并在阶段间插入回归,能把损失定位到具体阶段。
给个量级感受。轻度领域适配常见掉一两个点,重度适配可到五个点以上。超过十个点通常意味着训练配置有实质问题,比如学习率过高或语料过窄,这时先修配置再谈缓解。
2. 机理:新解覆盖旧解
机理层面,遗忘是参数空间的覆盖问题。旧任务在参数空间里有一个解,新任务有另一个解。顺序训练时,参数先停在旧解附近,再被拉到新解。旧解丢失,不是因为被删除,而是因为参数离开了那个位置。
2.1 SGD 没有旧约束
随机梯度下降(SGD)的更新规则只由当前 batch 的梯度决定。如果当前 batch 全来自新领域,那么这一步更新里没有任何一项阻止参数偏离旧任务的解。换句话说,旧任务的性能不在损失函数里,优化器自然不会为它负责。
#mermaid-svg-Frj2aGBq2SzhUiDs{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-Frj2aGBq2SzhUiDs .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Frj2aGBq2SzhUiDs .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Frj2aGBq2SzhUiDs .error-icon{fill:#552222;}#mermaid-svg-Frj2aGBq2SzhUiDs .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Frj2aGBq2SzhUiDs .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Frj2aGBq2SzhUiDs .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Frj2aGBq2SzhUiDs .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Frj2aGBq2SzhUiDs .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Frj2aGBq2SzhUiDs .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Frj2aGBq2SzhUiDs .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Frj2aGBq2SzhUiDs .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Frj2aGBq2SzhUiDs .marker.cross{stroke:#333333;}#mermaid-svg-Frj2aGBq2SzhUiDs svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Frj2aGBq2SzhUiDs p{margin:0;}#mermaid-svg-Frj2aGBq2SzhUiDs .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-Frj2aGBq2SzhUiDs .cluster-label text{fill:#333;}#mermaid-svg-Frj2aGBq2SzhUiDs .cluster-label span{color:#333;}#mermaid-svg-Frj2aGBq2SzhUiDs .cluster-label span p{background-color:transparent;}#mermaid-svg-Frj2aGBq2SzhUiDs .label text,#mermaid-svg-Frj2aGBq2SzhUiDs span{fill:#333;color:#333;}#mermaid-svg-Frj2aGBq2SzhUiDs .node rect,#mermaid-svg-Frj2aGBq2SzhUiDs .node circle,#mermaid-svg-Frj2aGBq2SzhUiDs .node ellipse,#mermaid-svg-Frj2aGBq2SzhUiDs .node polygon,#mermaid-svg-Frj2aGBq2SzhUiDs .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Frj2aGBq2SzhUiDs .rough-node .label text,#mermaid-svg-Frj2aGBq2SzhUiDs .node .label text,#mermaid-svg-Frj2aGBq2SzhUiDs .image-shape .label,#mermaid-svg-Frj2aGBq2SzhUiDs .icon-shape .label{text-anchor:middle;}#mermaid-svg-Frj2aGBq2SzhUiDs .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-Frj2aGBq2SzhUiDs .rough-node .label,#mermaid-svg-Frj2aGBq2SzhUiDs .node .label,#mermaid-svg-Frj2aGBq2SzhUiDs .image-shape .label,#mermaid-svg-Frj2aGBq2SzhUiDs .icon-shape .label{text-align:center;}#mermaid-svg-Frj2aGBq2SzhUiDs .node.clickable{cursor:pointer;}#mermaid-svg-Frj2aGBq2SzhUiDs .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-Frj2aGBq2SzhUiDs .arrowheadPath{fill:#333333;}#mermaid-svg-Frj2aGBq2SzhUiDs .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-Frj2aGBq2SzhUiDs .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-Frj2aGBq2SzhUiDs .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Frj2aGBq2SzhUiDs .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-Frj2aGBq2SzhUiDs .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Frj2aGBq2SzhUiDs .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-Frj2aGBq2SzhUiDs .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-Frj2aGBq2SzhUiDs .cluster text{fill:#333;}#mermaid-svg-Frj2aGBq2SzhUiDs .cluster span{color:#333;}#mermaid-svg-Frj2aGBq2SzhUiDs div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-Frj2aGBq2SzhUiDs .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-Frj2aGBq2SzhUiDs rect.text{fill:none;stroke-width:0;}#mermaid-svg-Frj2aGBq2SzhUiDs .icon-shape,#mermaid-svg-Frj2aGBq2SzhUiDs .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Frj2aGBq2SzhUiDs .icon-shape p,#mermaid-svg-Frj2aGBq2SzhUiDs .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-Frj2aGBq2SzhUiDs .icon-shape .label rect,#mermaid-svg-Frj2aGBq2SzhUiDs .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Frj2aGBq2SzhUiDs .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-Frj2aGBq2SzhUiDs .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-Frj2aGBq2SzhUiDs :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}#mermaid-svg-Frj2aGBq2SzhUiDs .default>*{fill:#faf9f5!important;stroke:#ffffff!important;color:#000000!important;stroke-width:0px!important;}#mermaid-svg-Frj2aGBq2SzhUiDs .default span{fill:#faf9f5!important;stroke:#ffffff!important;color:#000000!important;stroke-width:0px!important;}#mermaid-svg-Frj2aGBq2SzhUiDs .default tspan{fill:#000000!important;}
当前batch只有新数据
损失只含新任务项
梯度只朝新最优解方向
旧任务项不在损失里
无任何力拉住参数
旧解被覆盖
图 2-1 SGD 缺少旧约束的链条。遗忘不需要额外机制,只需要旧任务缺席损失函数。
这条机理直接给出缓解方向。既然问题是旧任务缺席,补法就有三类。把旧数据放回来,即数据重放。给重要参数加惩罚,即正则化。干脆不动原参数,即低秩适配。后文的四个工具全部落在这三类里。
| 数据侧 | 损失函数 | 重放 replay | 需要留旧数据,占用训练预算 |
| 正则侧 | 损失函数加惩罚项 | EWC | 需算 Fisher,超参敏感 |
| 结构侧 | 参数更新路径 | LoRA、适配器 | 容量受限,深度适配不足 |
| 合并侧 | 训练后处理 | 任务向量加减 | 任务间可能互相干扰 |
表 2-1 四类缓解方法的作用位置与代价。没有免费午餐,每一类都在别处付费。
这条机理还能推出一个容易被忽略的结论。旧任务缺席不仅指数据缺席,也指评测缺席。很多团队在适配时完全没有旧任务的评测集,于是遗忘在训练过程中不可见,直到上线才被发现。约束缺失与观测缺失是同一个问题的两面。
另一个推论关于优化器。Adam 这类自适应优化器会为每个参数维护动量与二阶矩,切换到新领域数据后,这些状态量的惯性会加速参数偏离旧解。所以长任务切换数据分布时,重置优化器状态有时能减缓遗忘,代价是学习曲线短暂变陡。
还能解释为什么早停有效。遗忘随训练步数加深而加重,因为参数离旧解越来越远。在领域基准刚收敛时就停,位移量小,旧能力损失也小。工程上可以把领域分数的收敛点当停训候选点,再用回归分数确认是否可接受。
2.2 参数重叠度决定遗忘幅度
遗忘幅度不是随机的,它取决于两个任务的解在参数空间里的距离。如果新旧任务相似,解本来就接近,遗忘就轻。如果两个任务方向相反,参数被迫大位移,遗忘就重。
# 来源:自实现 / overlap_effect.py
import numpy as np
def run_pair(angle_deg, dim=8, steps=400, lr=0.08):
# 构造两个任务真值,夹角控制任务相似度
w1 = np.zeros(dim); w1[0] = 1.0
rad = np.deg2rad(angle_deg)
w2 = np.zeros(dim); w2[0] = np.cos(rad); w2[1] = np.sin(rad)
rng = np.random.default_rng(0)
X = rng.normal(size=(120, dim))
w = np.zeros(dim)
for _ in range(steps): # 先学任务1
w = w – lr * 2 * X.T @ (X @ w – X @ w1) / len(X)
s1 = 1.0 / (1.0 + np.mean((X @ w – X @ w1) ** 2))
for _ in range(steps): # 再学任务2
w = w – lr * 2 * X.T @ (X @ w – X @ w2) / len(X)
s1_after = 1.0 / (1.0 + np.mean((X @ w – X @ w1) ** 2))
return s1, s1_after
for ang in (0, 15, 45, 90, 180):
before, after = run_pair(ang)
print(f"夹角{ang:3d}度 保旧前{before:.3f} 保旧后{after:.3f}")
典型结果是:夹角 0 度时几乎没有遗忘,15 度轻微,45 度明显,90 度与 180 度接近崩塌。这段代码把"任务相似度决定遗忘幅度"量化出来,也解释了为什么领域语料与原语料分布差异越大,通用能力掉得越狠。
2.3 覆盖不是删除
有一个常见误解需要澄清。遗忘不等于知识被删除。实验上,用少量旧数据重放几个 epoch,旧任务性能常能部分恢复。这说明旧解的"痕迹"还在,只是参数离它远了,一个小的回拉力就能部分找回。
这也解释了为什么重放有效率高的一面。恢复旧能力不需要重放全部旧数据,少量样本足以提供方向信号。但恢复不等于完全复原,尤其对推理这类脆弱能力,重放后仍可能留缺口。
#mermaid-svg-GCr77neAk4B7NNVI{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-GCr77neAk4B7NNVI .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-GCr77neAk4B7NNVI .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-GCr77neAk4B7NNVI .error-icon{fill:#552222;}#mermaid-svg-GCr77neAk4B7NNVI .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-GCr77neAk4B7NNVI .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-GCr77neAk4B7NNVI .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-GCr77neAk4B7NNVI .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-GCr77neAk4B7NNVI .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-GCr77neAk4B7NNVI .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-GCr77neAk4B7NNVI .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-GCr77neAk4B7NNVI .marker{fill:#333333;stroke:#333333;}#mermaid-svg-GCr77neAk4B7NNVI .marker.cross{stroke:#333333;}#mermaid-svg-GCr77neAk4B7NNVI svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-GCr77neAk4B7NNVI p{margin:0;}#mermaid-svg-GCr77neAk4B7NNVI .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-GCr77neAk4B7NNVI .cluster-label text{fill:#333;}#mermaid-svg-GCr77neAk4B7NNVI .cluster-label span{color:#333;}#mermaid-svg-GCr77neAk4B7NNVI .cluster-label span p{background-color:transparent;}#mermaid-svg-GCr77neAk4B7NNVI .label text,#mermaid-svg-GCr77neAk4B7NNVI span{fill:#333;color:#333;}#mermaid-svg-GCr77neAk4B7NNVI .node rect,#mermaid-svg-GCr77neAk4B7NNVI .node circle,#mermaid-svg-GCr77neAk4B7NNVI .node ellipse,#mermaid-svg-GCr77neAk4B7NNVI .node polygon,#mermaid-svg-GCr77neAk4B7NNVI .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-GCr77neAk4B7NNVI .rough-node .label text,#mermaid-svg-GCr77neAk4B7NNVI .node .label text,#mermaid-svg-GCr77neAk4B7NNVI .image-shape .label,#mermaid-svg-GCr77neAk4B7NNVI .icon-shape .label{text-anchor:middle;}#mermaid-svg-GCr77neAk4B7NNVI .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-GCr77neAk4B7NNVI .rough-node .label,#mermaid-svg-GCr77neAk4B7NNVI .node .label,#mermaid-svg-GCr77neAk4B7NNVI .image-shape .label,#mermaid-svg-GCr77neAk4B7NNVI .icon-shape .label{text-align:center;}#mermaid-svg-GCr77neAk4B7NNVI .node.clickable{cursor:pointer;}#mermaid-svg-GCr77neAk4B7NNVI .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-GCr77neAk4B7NNVI .arrowheadPath{fill:#333333;}#mermaid-svg-GCr77neAk4B7NNVI .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-GCr77neAk4B7NNVI .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-GCr77neAk4B7NNVI .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-GCr77neAk4B7NNVI .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-GCr77neAk4B7NNVI .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-GCr77neAk4B7NNVI .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-GCr77neAk4B7NNVI .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-GCr77neAk4B7NNVI .cluster text{fill:#333;}#mermaid-svg-GCr77neAk4B7NNVI .cluster span{color:#333;}#mermaid-svg-GCr77neAk4B7NNVI div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-GCr77neAk4B7NNVI .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-GCr77neAk4B7NNVI rect.text{fill:none;stroke-width:0;}#mermaid-svg-GCr77neAk4B7NNVI .icon-shape,#mermaid-svg-GCr77neAk4B7NNVI .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-GCr77neAk4B7NNVI .icon-shape p,#mermaid-svg-GCr77neAk4B7NNVI .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-GCr77neAk4B7NNVI .icon-shape .label rect,#mermaid-svg-GCr77neAk4B7NNVI .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-GCr77neAk4B7NNVI .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-GCr77neAk4B7NNVI .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-GCr77neAk4B7NNVI :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}#mermaid-svg-GCr77neAk4B7NNVI .default>*{fill:#faf9f5!important;stroke:#ffffff!important;color:#000000!important;stroke-width:0px!important;}#mermaid-svg-GCr77neAk4B7NNVI .default span{fill:#faf9f5!important;stroke:#ffffff!important;color:#000000!important;stroke-width:0px!important;}#mermaid-svg-GCr77neAk4B7NNVI .default tspan{fill:#000000!important;}
有效
推得太远
旧解S1
训练新数据后到S2
少量旧数据重放
部分回到S1附近
回拉力不足
旧性能部分恢复
残留不可逆缺口
图 2-2 覆盖与恢复的不对称。参数离旧解的距离决定少量重放是否够用,距离过远时恢复不完整。
| 轻微偏离 | 基本恢复 | 高 |
| 中等偏离 | 部分恢复 | 中 |
| 推到远处 | 恢复有限 | 低 |
表 2-2 位移程度与可恢复性。位移越远,重放救回的比例越低,这是重放要持续混入的依据。
边界提示:如果训练步数极大、学习率较高,参数可能被推到离旧解非常远的区域,此时少量重放也救不回来。所以重放应当在新训练过程中持续混入,而不是等崩了再抢救。
还有一点工程含义。既然旧解的痕迹仍在,那么适配早期发现回归掉分时,立即停训并回滚到上一个 checkpoint,代价远小于继续训练后再补救。所以 checkpoint 间隔不宜拉得太长,常见做法是按训练步数固定间隔保存,并保留至少三份历史版本。
3. 遗忘的代价实测口径
度量是工程的前提。遗忘度量的标准定义是旧任务性能下降幅度:遗忘量等于旧任务初始性能减去新训练后的性能。下降越多,遗忘越重。
3.1 双曲线:学新与保旧的取舍
把新任务性能当横轴、旧任务性能当纵轴,扫一遍训练强度或重放比例,得到一条双曲线。曲线上的点不能同时到达右上角,学新与保旧此消彼长。缓解方法的作用是把整条曲线往右上方推,但推不穿取舍本身。
#mermaid-svg-az4A5K5VZEF7Y1Xn{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-az4A5K5VZEF7Y1Xn .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-az4A5K5VZEF7Y1Xn .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-az4A5K5VZEF7Y1Xn .error-icon{fill:#552222;}#mermaid-svg-az4A5K5VZEF7Y1Xn .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-az4A5K5VZEF7Y1Xn .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-az4A5K5VZEF7Y1Xn .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-az4A5K5VZEF7Y1Xn .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-az4A5K5VZEF7Y1Xn .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-az4A5K5VZEF7Y1Xn .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-az4A5K5VZEF7Y1Xn .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-az4A5K5VZEF7Y1Xn .marker{fill:#333333;stroke:#333333;}#mermaid-svg-az4A5K5VZEF7Y1Xn .marker.cross{stroke:#333333;}#mermaid-svg-az4A5K5VZEF7Y1Xn svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-az4A5K5VZEF7Y1Xn p{margin:0;}#mermaid-svg-az4A5K5VZEF7Y1Xn .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-az4A5K5VZEF7Y1Xn .cluster-label text{fill:#333;}#mermaid-svg-az4A5K5VZEF7Y1Xn .cluster-label span{color:#333;}#mermaid-svg-az4A5K5VZEF7Y1Xn .cluster-label span p{background-color:transparent;}#mermaid-svg-az4A5K5VZEF7Y1Xn .label text,#mermaid-svg-az4A5K5VZEF7Y1Xn span{fill:#333;color:#333;}#mermaid-svg-az4A5K5VZEF7Y1Xn .node rect,#mermaid-svg-az4A5K5VZEF7Y1Xn .node circle,#mermaid-svg-az4A5K5VZEF7Y1Xn .node ellipse,#mermaid-svg-az4A5K5VZEF7Y1Xn .node polygon,#mermaid-svg-az4A5K5VZEF7Y1Xn .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-az4A5K5VZEF7Y1Xn .rough-node .label text,#mermaid-svg-az4A5K5VZEF7Y1Xn .node .label text,#mermaid-svg-az4A5K5VZEF7Y1Xn .image-shape .label,#mermaid-svg-az4A5K5VZEF7Y1Xn .icon-shape .label{text-anchor:middle;}#mermaid-svg-az4A5K5VZEF7Y1Xn .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-az4A5K5VZEF7Y1Xn .rough-node .label,#mermaid-svg-az4A5K5VZEF7Y1Xn .node .label,#mermaid-svg-az4A5K5VZEF7Y1Xn .image-shape .label,#mermaid-svg-az4A5K5VZEF7Y1Xn .icon-shape .label{text-align:center;}#mermaid-svg-az4A5K5VZEF7Y1Xn .node.clickable{cursor:pointer;}#mermaid-svg-az4A5K5VZEF7Y1Xn .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-az4A5K5VZEF7Y1Xn .arrowheadPath{fill:#333333;}#mermaid-svg-az4A5K5VZEF7Y1Xn .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-az4A5K5VZEF7Y1Xn .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-az4A5K5VZEF7Y1Xn .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-az4A5K5VZEF7Y1Xn .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-az4A5K5VZEF7Y1Xn .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-az4A5K5VZEF7Y1Xn .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-az4A5K5VZEF7Y1Xn .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-az4A5K5VZEF7Y1Xn .cluster text{fill:#333;}#mermaid-svg-az4A5K5VZEF7Y1Xn .cluster span{color:#333;}#mermaid-svg-az4A5K5VZEF7Y1Xn div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-az4A5K5VZEF7Y1Xn .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-az4A5K5VZEF7Y1Xn rect.text{fill:none;stroke-width:0;}#mermaid-svg-az4A5K5VZEF7Y1Xn .icon-shape,#mermaid-svg-az4A5K5VZEF7Y1Xn .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-az4A5K5VZEF7Y1Xn .icon-shape p,#mermaid-svg-az4A5K5VZEF7Y1Xn .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-az4A5K5VZEF7Y1Xn .icon-shape .label rect,#mermaid-svg-az4A5K5VZEF7Y1Xn .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-az4A5K5VZEF7Y1Xn .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-az4A5K5VZEF7Y1Xn .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-az4A5K5VZEF7Y1Xn :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}#mermaid-svg-az4A5K5VZEF7Y1Xn .default>*{fill:#faf9f5!important;stroke:#ffffff!important;color:#000000!important;stroke-width:0px!important;}#mermaid-svg-az4A5K5VZEF7Y1Xn .default span{fill:#faf9f5!important;stroke:#ffffff!important;color:#000000!important;stroke-width:0px!important;}#mermaid-svg-az4A5K5VZEF7Y1Xn .default tspan{fill:#000000!important;}
训练强度或配比扫描
每个点测两个分数
新任务性能为横轴
旧任务性能为纵轴
连成学新保旧双曲线
曲线右上移即缓解生效
图 3-1 双曲线的生成方式。缓解方法的评价标准不是单点分数,而是整条曲线是否外移。
| 前向迁移 | 新任务初始性能 | 学新是否容易 |
| 后向遗忘 | 旧任务性能下降幅度 | 本文核心口径 |
| 平均性能 | 新旧任务均值 | 粗略综合指标 |
| 面积指标 | 双曲线下面积 | 比较方法整体水平 |
表 3-1 持续学习常用四种度量。后向遗忘是最直接的口径,面积指标适合跨方法比较。
双曲线还有一层含义。曲线上的每个点对应一种配置,选择哪一点是业务决策而不是技术决策。客服场景可能宁可少学一点领域也要守住指令遵循,研发助手场景可能反过来。把曲线画出来交给业务方选点,比单点调参更有效率。
画曲线的成本要控制。全量扫一遍配比代价高,常见做法是三点起步:低配比、中配比、高配比各跑一次,先确定曲线的大致走向,再在拐点附近加密采样。这样通常五到七个点就能定位到业务可接受的区间。
还要注意曲线会随数据变化。领域语料更新一批后,原来的最优点可能偏移。所以双曲线不是一次性产物,应随语料版本重跑关键点,把配比当持续维护的超参而不是定死的常数。
3.2 回归监控的代码骨架
遗忘度量落到工程上就是回归监控。做法是固定一套通用基准,每次适配后必跑,与基线分数对比,超阈值就报警。
# 来源:自实现 / forgetting_monitor.py
import numpy as np
def evaluate(w, suite):
# suite 是基准字典,值为真值方向
out = {}
for name, w_true in suite.items():
err = np.mean((w – w_true) ** 2)
out[name] = 1.0 / (1.0 + err)
return out
def forgetting_report(baseline, current, threshold=0.10):
# 遗忘量等于基线减当前,正值即退化
rows = []
for name in baseline:
drop = baseline[name] – current[name]
flag = "报警" if drop > threshold else "正常"
rows.append((name, baseline[name], current[name], drop, flag))
return rows
if __name__ == "__main__":
rng = np.random.default_rng(3)
suite = {"通用知识": rng.normal(size=16),
"通用推理": rng.normal(size=16),
"指令遵循": rng.normal(size=16)}
baseline = evaluate(np.zeros(16), suite) # 假装是适配前
w_after = rng.normal(size=16) * 0.6 # 假装是适配后
current = evaluate(w_after, suite)
for name, b, c, d, f in forgetting_report(baseline, current):
print(f"{name} 基线{b:.2f} 当前{c:.2f} 遗忘{d:+.2f} {f}")
这段代码的核心是 forgetting_report 函数:遗忘量按维度分别计算并各自设阈值,而不是看总分。总分会被领域分数的上涨掩盖,分维度才暴露指令遵循这类隐性退化。
3.3 常见误测与陷阱
第一类误测是只跑领域基准。领域分数上涨与通用退化同时发生,只看前者会得出微调成功的错误结论。第二类是基准泄漏,通用回归集里混入了与领域语料同源的样本,分数虚高。第三类是提示词漂移,适配后模型对旧提示词的敏感度变化,测的不是知识而是格式。
| 只跑领域基准 | 领域分涨通用分跌 | 误判微调成功 |
| 基准泄漏 | 回归集混入同源样本 | 遗忘被低估 |
| 提示词漂移 | 分数变化来自格式 | 测错对象 |
| 单次采样 | 未控制解码随机性 | 波动当趋势 |
表 3-2 四类常见误测。第三类最隐蔽,因为分数确实变了,只是变的原因不是知识。
对策是三件事。回归集与领域语料严格隔离来源。回归集固定提示词模板,版本化管理。每次跑回归同时记录分布,做横向对比而不只做纵向对比。
解码参数也要固定。温度设为零或固定值,采样种子固定,否则同一次评测的波动可能达到一两个点,把真实退化淹没在噪声里。对于开放式生成题,建议用固定参考答案加关键词命中判定,避免人工评分的主观漂移。
最后一类坑是样本量不足。回归集每个维度只有十来道题时,单题对错就能造成 5 个点以上的波动。经验做法是每个维度至少几十道题,覆盖不同难度与不同问法,让单题影响压到 2 个点以内。
还有一类陷阱与题目难度分布有关。回归集如果偏简单,适配后分数几乎不动,会得出零遗忘的假象。原因是大模型对简单题的冗余度高,参数位移不大时答案不变。回归集要保留一定比例的中高难度题,才对参数变化敏感。
监控频率也要匹配训练节奏。只在训练结束后跑一次回归,无法区分是哪个阶段开始退化。建议在训练中按 checkpoint 间隔抽样跑轻量版回归,定位到退化开始的位置,再决定回滚还是调参。
陷阱清单之外,还要防一种统计错误。只看单次差值就下结论,没有置信区间。回归集每维几十题时,两三个百分点的差异可能在噪声范围内。简单做法是同题集跑两次取均值,或把差异与历史波动幅度对比,超出波动才算真信号。
最后是流程陷阱。回归集只在与领域团队无关的人手里时才可信。如果评测由微调执行者自己跑自己判,主观上倾向放行。把回归评测独立成角色或用脚本全自动判分,能消掉这层偏差。
再列一个流程性陷阱。回归集建好后没有基线数据,第一次跑就是适配后的分数,无从对比。基线必须在适配前建立并归档,含分数、解码配置与题集版本。没有基线的回归等于没有刻度的尺子。
陷阱的最后一项是过度依赖单一基准。任何一个基准都只覆盖能力的一角。两三个互补基准交叉验证,比一个基准反复跑更能反映真实遗忘。常见组合是一个知识型基准加一个推理型基准加一组指令题。
4. 数据重放:旧数据当锚
数据重放(replay)是最直接的补法:旧数据不放走,按比例混进新训练里。旧样本出现在 batch 中,损失函数就重新含旧任务项,梯度里就有了回拉力。
4.1 重放比例与保留曲线
重放比例是关键超参。比例太低锚不住,比例太高学不动新领域。经验区间通常在 5% 到 30% 之间起步,再按回归分数微调。
#mermaid-svg-A1YS9uC3W5ddkoOr{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-A1YS9uC3W5ddkoOr .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-A1YS9uC3W5ddkoOr .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-A1YS9uC3W5ddkoOr .error-icon{fill:#552222;}#mermaid-svg-A1YS9uC3W5ddkoOr .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-A1YS9uC3W5ddkoOr .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-A1YS9uC3W5ddkoOr .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-A1YS9uC3W5ddkoOr .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-A1YS9uC3W5ddkoOr .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-A1YS9uC3W5ddkoOr .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-A1YS9uC3W5ddkoOr .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-A1YS9uC3W5ddkoOr .marker{fill:#333333;stroke:#333333;}#mermaid-svg-A1YS9uC3W5ddkoOr .marker.cross{stroke:#333333;}#mermaid-svg-A1YS9uC3W5ddkoOr svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-A1YS9uC3W5ddkoOr p{margin:0;}#mermaid-svg-A1YS9uC3W5ddkoOr .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-A1YS9uC3W5ddkoOr .cluster-label text{fill:#333;}#mermaid-svg-A1YS9uC3W5ddkoOr .cluster-label span{color:#333;}#mermaid-svg-A1YS9uC3W5ddkoOr .cluster-label span p{background-color:transparent;}#mermaid-svg-A1YS9uC3W5ddkoOr .label text,#mermaid-svg-A1YS9uC3W5ddkoOr span{fill:#333;color:#333;}#mermaid-svg-A1YS9uC3W5ddkoOr .node rect,#mermaid-svg-A1YS9uC3W5ddkoOr .node circle,#mermaid-svg-A1YS9uC3W5ddkoOr .node ellipse,#mermaid-svg-A1YS9uC3W5ddkoOr .node polygon,#mermaid-svg-A1YS9uC3W5ddkoOr .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-A1YS9uC3W5ddkoOr .rough-node .label text,#mermaid-svg-A1YS9uC3W5ddkoOr .node .label text,#mermaid-svg-A1YS9uC3W5ddkoOr .image-shape .label,#mermaid-svg-A1YS9uC3W5ddkoOr .icon-shape .label{text-anchor:middle;}#mermaid-svg-A1YS9uC3W5ddkoOr .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-A1YS9uC3W5ddkoOr .rough-node .label,#mermaid-svg-A1YS9uC3W5ddkoOr .node .label,#mermaid-svg-A1YS9uC3W5ddkoOr .image-shape .label,#mermaid-svg-A1YS9uC3W5ddkoOr .icon-shape .label{text-align:center;}#mermaid-svg-A1YS9uC3W5ddkoOr .node.clickable{cursor:pointer;}#mermaid-svg-A1YS9uC3W5ddkoOr .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-A1YS9uC3W5ddkoOr .arrowheadPath{fill:#333333;}#mermaid-svg-A1YS9uC3W5ddkoOr .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-A1YS9uC3W5ddkoOr .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-A1YS9uC3W5ddkoOr .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-A1YS9uC3W5ddkoOr .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-A1YS9uC3W5ddkoOr .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-A1YS9uC3W5ddkoOr .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-A1YS9uC3W5ddkoOr .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-A1YS9uC3W5ddkoOr .cluster text{fill:#333;}#mermaid-svg-A1YS9uC3W5ddkoOr .cluster span{color:#333;}#mermaid-svg-A1YS9uC3W5ddkoOr div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-A1YS9uC3W5ddkoOr .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-A1YS9uC3W5ddkoOr rect.text{fill:none;stroke-width:0;}#mermaid-svg-A1YS9uC3W5ddkoOr .icon-shape,#mermaid-svg-A1YS9uC3W5ddkoOr .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-A1YS9uC3W5ddkoOr .icon-shape p,#mermaid-svg-A1YS9uC3W5ddkoOr .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-A1YS9uC3W5ddkoOr .icon-shape .label rect,#mermaid-svg-A1YS9uC3W5ddkoOr .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-A1YS9uC3W5ddkoOr .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-A1YS9uC3W5ddkoOr .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-A1YS9uC3W5ddkoOr :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}#mermaid-svg-A1YS9uC3W5ddkoOr .default>*{fill:#faf9f5!important;stroke:#ffffff!important;color:#000000!important;stroke-width:0px!important;}#mermaid-svg-A1YS9uC3W5ddkoOr .default span{fill:#faf9f5!important;stroke:#ffffff!important;color:#000000!important;stroke-width:0px!important;}#mermaid-svg-A1YS9uC3W5ddkoOr .default tspan{fill:#000000!important;}
领域新语料
按比例混合
通用重放语料
一个batch内新旧共存
梯度含两项
新能力上升
旧能力被锚住
图 4-1 重放的混合训练流程。旧样本进入 batch 是全部机制所在,简单但有效。
# 来源:自实现 / replay_curve.py
import numpy as np
def make_task(dim=30, seed=0, n=150):
# 旧任务为基准方向,新任务在其上加扰动,模拟领域与通用语料高度重叠
rng = np.random.default_rng(seed)
w = rng.normal(size=dim)
X = rng.normal(size=(n, dim))
return w, X, X @ w
def train_mixed(w, Xa, ya, Xb, yb, ratio, steps=600, lr=0.03):
# ratio 是旧任务项在总损失里的权重,模拟重放数据占比
for _ in range(steps):
ga = 2 * Xa.T @ (Xa @ w – ya) / len(Xa) # 旧任务全批梯度
if len(Xb): # 空集时新任务项记零
gb = 2 * Xb.T @ (Xb @ w – yb) / len(Xb)
else:
gb = 0.0
w = w – lr * (ratio * ga + (1 – ratio) * gb)
return w
def score(w, wt, X):
return 1.0 / (1.0 + np.mean((X @ w – X @ wt) ** 2))
wa, Xa, ya = make_task(seed=10)
wb, Xb, yb = make_task(seed=11)
# 新领域目标与通用目标重叠约七成,贴近真实领域适配场景
wb = 0.7 * wa + 0.3 * wb / np.linalg.norm(wb) * np.linalg.norm(wa)
yb = Xb @ wb
w0 = train_mixed(np.zeros(30), Xa, ya, Xb[:0], yb[:0], 1.0) # 先只学旧任务
print("重放比例 保旧分数 学新分数")
for r in (0.0, 0.05, 0.1, 0.2, 0.5):
w = train_mixed(w0.copy(), Xa, ya, Xb, yb, r)
print(f"{r:8.2f} {score(w, wa, Xa):7.3f} {score(w, wb, Xb):7.3f}")
实测输出呈双曲线形态:重放 0 时保旧只有 0.21,学新满分。重放升到 0.2 时保旧回到 0.32,学新降到 0.85。重放 0.5 时保旧 0.56,学新 0.53,两边接近持平。这份表就是第 3 章双曲线的实测来源,也验证了任务重叠度决定可用区间。
4.2 重放数据从哪来
工程上有三个来源。第一是保留原预训练语料的抽样,成本最低但要拿到授权与存储。第二是合成回放,用基座模型自己生成通用样本,不依赖原始语料。第三是通用指令数据集的公开子集,用于对齐阶段的回锚。
| 原语料抽样 | 存储与授权 | 最好 | 版权与合规 |
| 自生成回放 | 推理算力 | 中等 | 自我强化偏差 |
| 公开通用子集 | 低 | 中等 | 分布覆盖不全 |
表 4-1 三类重放来源对比。实际项目常组合使用,原语料加公开子集是常见搭配。
| 自研基座团队 | 原语料抽样 | 加公开子集补推理 |
| 开源基座二次开发 | 公开通用子集 | 自生成回放补充 |
| 无法存原始数据 | 自生成回放 | EWC 顶替数据侧 |
表 4-2 三种团队形态的重放来源选择。数据可得性决定起点,效果再靠配比调优。
三类来源各有适配场景。原语料抽样适合自研基座的团队,数据在自己手里。自生成回放适合拿不到原语料的场景,比如基于开源基座做二次开发,代价是要控制生成多样性,否则重放的是模型的偏差。公开通用子集最省事,但覆盖面有限,推理类题目占比往往不足。
配比之外还要管采样策略。均匀抽样会让高频样本反复出现,低频但关键的能力被稀释。改进做法是按能力维度分层抽样,比如通用知识、推理、指令各占固定份额,确保每一维都有足够回拉力。
还有一个实用细节:重放样本要打乱后与新数据混合,不能先训一批旧的再训一批新的。分批顺序训练等于制造第二次顺序遗忘,混合均匀才能让两项约束在每个 batch 里同时生效。
数量级给个参考。重放集不需要与原预训练语料同量级,通常领域语料的 10% 到 30% 规模即可,关键是覆盖维度而不是样本总量。一个只有几千条但覆盖四类能力的重放集,往往好过几万条同类样本的堆量。
维护上要版本化。重放集本身会随业务演进,比如指令遵循的典型形态变化。每次更新重放集都重跑一次基线,否则新旧两版的分数不可比,趋势判断会失真。
自生成回放有个升级做法。不只生成通用问答,还生成针对回归集四维能力的定向样本。先用基座生成,再人工抽检质量,按维度归档。这样重放集与监控维度一一对应,哪个维度掉分就知道补哪个池子,闭环更清晰。
混合来源时要防一个坑。公开子集与自生成样本的语言风格不同,模型可能学到风格差异而不是能力。解决办法是两类来源各占一定份额并打乱混排,避免模型把来源当特征。
4.3 边界与失败模式
重放的失败模式有三类。第一类是分布不匹配,重放样本太窄,锚住了表层格式却没锚住推理。第二类是预算挤占,重放占 30% 训练量,等价于新领域少训三成,学习速度被迫放慢。第三类是配比失效,随着训练推进,最优重放比例会变化,固定比例后期可能不足。
#mermaid-svg-SqRLPYApFaD7DN4J{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-SqRLPYApFaD7DN4J .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-SqRLPYApFaD7DN4J .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-SqRLPYApFaD7DN4J .error-icon{fill:#552222;}#mermaid-svg-SqRLPYApFaD7DN4J .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-SqRLPYApFaD7DN4J .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-SqRLPYApFaD7DN4J .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-SqRLPYApFaD7DN4J .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-SqRLPYApFaD7DN4J .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-SqRLPYApFaD7DN4J .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-SqRLPYApFaD7DN4J .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-SqRLPYApFaD7DN4J .marker{fill:#333333;stroke:#333333;}#mermaid-svg-SqRLPYApFaD7DN4J .marker.cross{stroke:#333333;}#mermaid-svg-SqRLPYApFaD7DN4J svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-SqRLPYApFaD7DN4J p{margin:0;}#mermaid-svg-SqRLPYApFaD7DN4J .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-SqRLPYApFaD7DN4J .cluster-label text{fill:#333;}#mermaid-svg-SqRLPYApFaD7DN4J .cluster-label span{color:#333;}#mermaid-svg-SqRLPYApFaD7DN4J .cluster-label span p{background-color:transparent;}#mermaid-svg-SqRLPYApFaD7DN4J .label text,#mermaid-svg-SqRLPYApFaD7DN4J span{fill:#333;color:#333;}#mermaid-svg-SqRLPYApFaD7DN4J .node rect,#mermaid-svg-SqRLPYApFaD7DN4J .node circle,#mermaid-svg-SqRLPYApFaD7DN4J .node ellipse,#mermaid-svg-SqRLPYApFaD7DN4J .node polygon,#mermaid-svg-SqRLPYApFaD7DN4J .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-SqRLPYApFaD7DN4J .rough-node .label text,#mermaid-svg-SqRLPYApFaD7DN4J .node .label text,#mermaid-svg-SqRLPYApFaD7DN4J .image-shape .label,#mermaid-svg-SqRLPYApFaD7DN4J .icon-shape .label{text-anchor:middle;}#mermaid-svg-SqRLPYApFaD7DN4J .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-SqRLPYApFaD7DN4J .rough-node .label,#mermaid-svg-SqRLPYApFaD7DN4J .node .label,#mermaid-svg-SqRLPYApFaD7DN4J .image-shape .label,#mermaid-svg-SqRLPYApFaD7DN4J .icon-shape .label{text-align:center;}#mermaid-svg-SqRLPYApFaD7DN4J .node.clickable{cursor:pointer;}#mermaid-svg-SqRLPYApFaD7DN4J .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-SqRLPYApFaD7DN4J .arrowheadPath{fill:#333333;}#mermaid-svg-SqRLPYApFaD7DN4J .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-SqRLPYApFaD7DN4J .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-SqRLPYApFaD7DN4J .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-SqRLPYApFaD7DN4J .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-SqRLPYApFaD7DN4J .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-SqRLPYApFaD7DN4J .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-SqRLPYApFaD7DN4J .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-SqRLPYApFaD7DN4J .cluster text{fill:#333;}#mermaid-svg-SqRLPYApFaD7DN4J .cluster span{color:#333;}#mermaid-svg-SqRLPYApFaD7DN4J div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-SqRLPYApFaD7DN4J .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-SqRLPYApFaD7DN4J rect.text{fill:none;stroke-width:0;}#mermaid-svg-SqRLPYApFaD7DN4J .icon-shape,#mermaid-svg-SqRLPYApFaD7DN4J .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-SqRLPYApFaD7DN4J .icon-shape p,#mermaid-svg-SqRLPYApFaD7DN4J .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-SqRLPYApFaD7DN4J .icon-shape .label rect,#mermaid-svg-SqRLPYApFaD7DN4J .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-SqRLPYApFaD7DN4J .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-SqRLPYApFaD7DN4J .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-SqRLPYApFaD7DN4J :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}#mermaid-svg-SqRLPYApFaD7DN4J .default>*{fill:#faf9f5!important;stroke:#ffffff!important;color:#000000!important;stroke-width:0px!important;}#mermaid-svg-SqRLPYApFaD7DN4J .default span{fill:#faf9f5!important;stroke:#ffffff!important;color:#000000!important;stroke-width:0px!important;}#mermaid-svg-SqRLPYApFaD7DN4J .default tspan{fill:#000000!important;}
是
否
固定重放比例
训练推进后回归掉分
比例已不足
维持比例继续
上调重放比例
重跑回归验证
图 4-2 重放比例的动态调节回路。比例不是一次定死的超参,而是随回归信号迭代的控制量。
| 分布不匹配 | 推理维度掉分最重 | 扩充重放集覆盖 |
| 预算挤占 | 领域分数上不去 | 延长训练或降重放 |
| 配比失效 | 后期回归再掉分 | 动态上调比例 |
表 4-3 重放的三类失败与修正。信号都来自回归监控,这也是回归集必须先建的原因。
对应做法:重放集要覆盖通用、推理、指令三类;把重放预算计入总预算再做排期;关键节点重跑回归并动态调比例。重放不解决全部问题,但它应当是所有方案的默认底座。
最后一个常被忽略的边界:重放只能守住重放集覆盖到的分布。模型基线能力是个很宽的分布,重放集只是抽样。抽样外的能力仍可能退化,只是测不到。所以重放加回归监控必须成对出现,重放提供约束,监控提供暴露。
两者配合的闭环是:监控发现某维度掉分,检查重放集是否覆盖该维度,不覆盖则补样本,覆盖则上调该维度份额。这个闭环让重放从静态配比变成可维护的资产。
5. EWC:重要参数上锁
弹性权重巩固(EWC,elastic weight consolidation)是正则化路线的代表。论文编号是 arXiv 1612.00796。它不留旧数据,改为对旧任务重要的参数加惩罚。本节先讲重要性怎么估计,再看惩罚怎么写进损失。
5.1 Fisher 信息近似重要性
EWC 用 Fisher 信息矩阵的对角线近似来度量参数对旧任务的重要性。直觉是:某参数轻微扰动会让旧任务损失大幅上升,它就是重要参数,应当锁住。损失函数加一项二次惩罚,权重就是 Fisher 值。
#mermaid-svg-QU4k0xe9DOy8kYJA{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-QU4k0xe9DOy8kYJA .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-QU4k0xe9DOy8kYJA .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-QU4k0xe9DOy8kYJA .error-icon{fill:#552222;}#mermaid-svg-QU4k0xe9DOy8kYJA .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-QU4k0xe9DOy8kYJA .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-QU4k0xe9DOy8kYJA .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-QU4k0xe9DOy8kYJA .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-QU4k0xe9DOy8kYJA .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-QU4k0xe9DOy8kYJA .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-QU4k0xe9DOy8kYJA .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-QU4k0xe9DOy8kYJA .marker{fill:#333333;stroke:#333333;}#mermaid-svg-QU4k0xe9DOy8kYJA .marker.cross{stroke:#333333;}#mermaid-svg-QU4k0xe9DOy8kYJA svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-QU4k0xe9DOy8kYJA p{margin:0;}#mermaid-svg-QU4k0xe9DOy8kYJA .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-QU4k0xe9DOy8kYJA .cluster-label text{fill:#333;}#mermaid-svg-QU4k0xe9DOy8kYJA .cluster-label span{color:#333;}#mermaid-svg-QU4k0xe9DOy8kYJA .cluster-label span p{background-color:transparent;}#mermaid-svg-QU4k0xe9DOy8kYJA .label text,#mermaid-svg-QU4k0xe9DOy8kYJA span{fill:#333;color:#333;}#mermaid-svg-QU4k0xe9DOy8kYJA .node rect,#mermaid-svg-QU4k0xe9DOy8kYJA .node circle,#mermaid-svg-QU4k0xe9DOy8kYJA .node ellipse,#mermaid-svg-QU4k0xe9DOy8kYJA .node polygon,#mermaid-svg-QU4k0xe9DOy8kYJA .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-QU4k0xe9DOy8kYJA .rough-node .label text,#mermaid-svg-QU4k0xe9DOy8kYJA .node .label text,#mermaid-svg-QU4k0xe9DOy8kYJA .image-shape .label,#mermaid-svg-QU4k0xe9DOy8kYJA .icon-shape .label{text-anchor:middle;}#mermaid-svg-QU4k0xe9DOy8kYJA .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-QU4k0xe9DOy8kYJA .rough-node .label,#mermaid-svg-QU4k0xe9DOy8kYJA .node .label,#mermaid-svg-QU4k0xe9DOy8kYJA .image-shape .label,#mermaid-svg-QU4k0xe9DOy8kYJA .icon-shape .label{text-align:center;}#mermaid-svg-QU4k0xe9DOy8kYJA .node.clickable{cursor:pointer;}#mermaid-svg-QU4k0xe9DOy8kYJA .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-QU4k0xe9DOy8kYJA .arrowheadPath{fill:#333333;}#mermaid-svg-QU4k0xe9DOy8kYJA .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-QU4k0xe9DOy8kYJA .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-QU4k0xe9DOy8kYJA .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-QU4k0xe9DOy8kYJA .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-QU4k0xe9DOy8kYJA .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-QU4k0xe9DOy8kYJA .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-QU4k0xe9DOy8kYJA .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-QU4k0xe9DOy8kYJA .cluster text{fill:#333;}#mermaid-svg-QU4k0xe9DOy8kYJA .cluster span{color:#333;}#mermaid-svg-QU4k0xe9DOy8kYJA div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-QU4k0xe9DOy8kYJA .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-QU4k0xe9DOy8kYJA rect.text{fill:none;stroke-width:0;}#mermaid-svg-QU4k0xe9DOy8kYJA .icon-shape,#mermaid-svg-QU4k0xe9DOy8kYJA .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-QU4k0xe9DOy8kYJA .icon-shape p,#mermaid-svg-QU4k0xe9DOy8kYJA .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-QU4k0xe9DOy8kYJA .icon-shape .label rect,#mermaid-svg-QU4k0xe9DOy8kYJA .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-QU4k0xe9DOy8kYJA .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-QU4k0xe9DOy8kYJA .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-QU4k0xe9DOy8kYJA :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}#mermaid-svg-QU4k0xe9DOy8kYJA .default>*{fill:#faf9f5!important;stroke:#ffffff!important;color:#000000!important;stroke-width:0px!important;}#mermaid-svg-QU4k0xe9DOy8kYJA .default span{fill:#faf9f5!important;stroke:#ffffff!important;color:#000000!important;stroke-width:0px!important;}#mermaid-svg-QU4k0xe9DOy8kYJA .default tspan{fill:#000000!important;}
旧任务训练完成
采样估计Fisher对角阵
Fisher大的参数标记为重要
新任务训练
损失加二次惩罚项
重要参数移动被抑制
旧解基本保住
图 5-1 EWC 的两阶段流程。重要性估计在前,惩罚约束在后,全程不使用旧数据本身。
# 来源:自实现 / ewc_demo.py,简化实现
import numpy as np
def fisher_diag(w_star, X, y, steps=200):
# 经验Fisher:用随机标签重采样估计参数敏感度
rng = np.random.default_rng(11)
acc = np.zeros_like(w_star)
for _ in range(steps):
idx = np.random.randint(0, len(X), 32)
y_p = y[idx] + rng.normal(scale=0.1, size=len(idx)) # 标签扰动
g = 2 * X[idx].T @ (X[idx] @ w_star – y_p) / 32
acc += g ** 2 # 平方累积近似重要性
F = acc / steps
return F / (F.max() + 1e-12) # 归一到0到1,惩罚系数才可比
def train_ewc(w, X_new, y_new, fisher, w_star, lam, steps=400, lr=0.06, clip=1.0):
for _ in range(steps):
g = 2 * X_new.T @ (X_new @ w – y_new) / len(X_new)
g += lam * fisher * (w – w_star) # 关键行:重要参数加惩罚
n = np.linalg.norm(g)
if n > clip: # 梯度裁剪,大lam下防发散
g = g * clip / n
w = w – lr * g
return w
def score(w, wt, X):
return 1.0 / (1.0 + np.mean((X @ w – X @ wt) ** 2))
if __name__ == "__main__":
rng = np.random.default_rng(7)
dim, n = 24, 120
w_a = rng.normal(size=dim); X_a = rng.normal(size=(n, dim)); y_a = X_a @ w_a
w_b = rng.normal(size=dim); X_b = rng.normal(size=(n, dim)); y_b = X_b @ w_b
w = np.zeros(dim)
for _ in range(300): # 先学任务A到收敛
w = w – 0.06 * 2 * X_a.T @ (X_a @ w – y_a) / n
w_star = w.copy()
F = fisher_diag(w_star, X_a, y_a)
print("惩罚系数 保旧分数 学新分数")
for lam in (0.0, 1.0, 10.0, 100.0):
w2 = train_ewc(w_star.copy(), X_b, y_b, F, w_star, lam)
print(f"{lam:8.1f} {score(w2, w_a, X_a):7.3f} {score(w2, w_b, X_b):7.3f}")
惩罚系数那一列是核心。lam 为 0 退化为纯顺序训练,保旧崩到 0.02。lam 升到 10 时保旧回到 0.34,学新降到 0.04。lam 到 100 时保旧 0.97,学新被压到 0.02。这段代码直接复现 EWC 论文的核心取舍:锁得越紧,新知识越难进去。
5.2 与重放的互补关系
EWC 与重放不是二选一。重放提供数据侧的回拉力,EWC 提供参数侧的锁定力。当旧数据拿不到或存储受限时,EWC 是唯一选项。当旧数据充足时,重放通常更稳,因为约束直接来自真实分布而不是对角 Fisher 的近似。
| 依赖旧数据 | 是 | 否 |
| 额外计算 | 训练量增加 | Fisher 估计一次 |
| 超参敏感度 | 重放比例 | 惩罚系数 |
| 对角近似误差 | 无此问题 | 高维下有偏差 |
| 大模型可用性 | 高 | 受规模限制 |
表 5-1 重放与 EWC 的多维对比。实际大模型项目里重放更常用,EWC 思想常以软形式融入。
一个具体差异在于可解释性。重放出问题时,可以回溯到重放集的构成,缺哪类样本补哪类,归因路径清晰。EWC 出问题时,只能看到惩罚系数这一个旋钮,Fisher 值本身不直观,排查往往退化为重新扫参。这也是工程上重放更受欢迎的原因之一。
两者也可以叠加。重放管数据分布,EWC 管参数位移,叠加时惩罚系数要下调,否则双重约束会把可动空间压得太小,新领域学不进去。叠加的价值在重放拿不全旧分布时,用参数锁补上没覆盖到的部分。
边界提示:对角 Fisher 在大模型上只是粗近似,参数间的相关性被忽略。惩罚过强会导致新领域学不进去,形成另一种失败:模型看似没遗忘,其实是拒绝学新。上表"大模型可用性"一行说的就是这个,Fisher 估计本身也要在全量数据上前向若干遍,规模一大成本就不低。
从 toy 实验还能读出一条规律。惩罚系数每升一个量级,保旧分数大幅上升而学新分数几乎贴地。这说明 EWC 的可用窗口偏窄,调参要细扫而不是粗扫。真实项目里建议按对数间隔扫惩罚系数,每档都记录双曲线点位。
一个判断标准帮你在两者间选边。如果能拿到旧数据,优先重放,因为约束直接来自真实分布。如果拿不到,先用 LoRA 从结构上隔离,EWC 作为补充。直接对大模型算 Fisher 的场景相对少,多数团队在数据侧解决。
EWC 思想还有个轻量变体:不显式算 Fisher,只对参数加权重衰减式的位移惩罚,权重对所有参数一致。这损失了重要性区分,但实现成本接近零,常作为默认配置先挂上,效果不够再升级到真 EWC。
如果一定要在大模型上用 EWC 思想,实操上是简化版。只在适配相关的层上估计 Fisher,其余层直接冻结或低学习率。这样 Fisher 计算量大幅下降,效果损失有限。全模型 Fisher 估计在工程上很少真的做,成本与收益不匹配。
从双曲线视角比较两者,重放的曲线通常整体更靠右上,因为约束来自真实分布。EWC 曲线更靠内,但对角近似让它在小任务上表现尚可。选型时如果两条曲线都能画出来,直接比面积指标即可。
从实现难度看,重放只改数据管道,训练代码不动。EWC 要改损失函数并新增 Fisher 估计流程。工程改造成本上重放明显更低,这也是它成为默认选择的原因。先低成本方案跑通,再按需升级。
还有一个组合细节。如果同时用重放与 EWC,Fisher 应基于重放后的旧任务分布估计,而不是原始分布。否则锁住的是旧分布的参数位置,与重放的数据约束可能打架,调参空间变得更复杂。
6. LoRA:结构上防遗忘
LoRA(low-rank adaptation)从结构上解决问题。做法是冻结基座全部参数,只在旁边挂低秩矩阵 B 与 A,前向变成冻结 W 加 B 乘 A 的增量。基座的旧解从结构上不可能被覆盖。
6.1 参数量与效果对照
LoRA 的数学形式是输出等于冻结 W 乘输入加 B 乘 A 乘输入,其中 B 与 A 是两个小矩阵。可训练参数量从全部参数降到两个小矩阵,通常只有原模型的一小部分,量级在百分之一以下。
#mermaid-svg-yliCtMNlgwRT1C5e{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-yliCtMNlgwRT1C5e .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-yliCtMNlgwRT1C5e .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-yliCtMNlgwRT1C5e .error-icon{fill:#552222;}#mermaid-svg-yliCtMNlgwRT1C5e .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-yliCtMNlgwRT1C5e .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-yliCtMNlgwRT1C5e .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-yliCtMNlgwRT1C5e .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-yliCtMNlgwRT1C5e .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-yliCtMNlgwRT1C5e .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-yliCtMNlgwRT1C5e .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-yliCtMNlgwRT1C5e .marker{fill:#333333;stroke:#333333;}#mermaid-svg-yliCtMNlgwRT1C5e .marker.cross{stroke:#333333;}#mermaid-svg-yliCtMNlgwRT1C5e svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-yliCtMNlgwRT1C5e p{margin:0;}#mermaid-svg-yliCtMNlgwRT1C5e .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-yliCtMNlgwRT1C5e .cluster-label text{fill:#333;}#mermaid-svg-yliCtMNlgwRT1C5e .cluster-label span{color:#333;}#mermaid-svg-yliCtMNlgwRT1C5e .cluster-label span p{background-color:transparent;}#mermaid-svg-yliCtMNlgwRT1C5e .label text,#mermaid-svg-yliCtMNlgwRT1C5e span{fill:#333;color:#333;}#mermaid-svg-yliCtMNlgwRT1C5e .node rect,#mermaid-svg-yliCtMNlgwRT1C5e .node circle,#mermaid-svg-yliCtMNlgwRT1C5e .node ellipse,#mermaid-svg-yliCtMNlgwRT1C5e .node polygon,#mermaid-svg-yliCtMNlgwRT1C5e .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-yliCtMNlgwRT1C5e .rough-node .label text,#mermaid-svg-yliCtMNlgwRT1C5e .node .label text,#mermaid-svg-yliCtMNlgwRT1C5e .image-shape .label,#mermaid-svg-yliCtMNlgwRT1C5e .icon-shape .label{text-anchor:middle;}#mermaid-svg-yliCtMNlgwRT1C5e .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-yliCtMNlgwRT1C5e .rough-node .label,#mermaid-svg-yliCtMNlgwRT1C5e .node .label,#mermaid-svg-yliCtMNlgwRT1C5e .image-shape .label,#mermaid-svg-yliCtMNlgwRT1C5e .icon-shape .label{text-align:center;}#mermaid-svg-yliCtMNlgwRT1C5e .node.clickable{cursor:pointer;}#mermaid-svg-yliCtMNlgwRT1C5e .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-yliCtMNlgwRT1C5e .arrowheadPath{fill:#333333;}#mermaid-svg-yliCtMNlgwRT1C5e .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-yliCtMNlgwRT1C5e .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-yliCtMNlgwRT1C5e .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-yliCtMNlgwRT1C5e .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-yliCtMNlgwRT1C5e .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-yliCtMNlgwRT1C5e .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-yliCtMNlgwRT1C5e .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-yliCtMNlgwRT1C5e .cluster text{fill:#333;}#mermaid-svg-yliCtMNlgwRT1C5e .cluster span{color:#333;}#mermaid-svg-yliCtMNlgwRT1C5e div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-yliCtMNlgwRT1C5e .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-yliCtMNlgwRT1C5e rect.text{fill:none;stroke-width:0;}#mermaid-svg-yliCtMNlgwRT1C5e .icon-shape,#mermaid-svg-yliCtMNlgwRT1C5e .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-yliCtMNlgwRT1C5e .icon-shape p,#mermaid-svg-yliCtMNlgwRT1C5e .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-yliCtMNlgwRT1C5e .icon-shape .label rect,#mermaid-svg-yliCtMNlgwRT1C5e .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-yliCtMNlgwRT1C5e .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-yliCtMNlgwRT1C5e .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-yliCtMNlgwRT1C5e :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}#mermaid-svg-yliCtMNlgwRT1C5e .default>*{fill:#faf9f5!important;stroke:#ffffff!important;color:#000000!important;stroke-width:0px!important;}#mermaid-svg-yliCtMNlgwRT1C5e .default span{fill:#faf9f5!important;stroke:#ffffff!important;color:#000000!important;stroke-width:0px!important;}#mermaid-svg-yliCtMNlgwRT1C5e .default tspan{fill:#000000!important;}
输入x
冻结的基座W
可训练低秩B乘A
两路相加
输出y
旧解原封不动
图 6-1 LoRA 的双路结构。旁路增量与冻结主干并行,这是它防遗忘的全部秘密。
# 来源:自实现 / lora_demo.py,mock 版本
import numpy as np
class LinearLoRA:
def __init__(self, d_in, d_out, rank=4, seed=0):
rng = np.random.default_rng(seed)
self.W = rng.normal(scale=0.05, size=(d_in, d_out)) # 冻结基座
self.B = np.zeros((rank, d_out)) # 初始为零保证起点一致
self.A = rng.normal(scale=0.01, size=(d_in, rank))
self.W_frozen = self.W.copy() # 备份旧解
self.trainable = [self.A, self.B]
def forward(self, x):
return x @ self.W + x @ self.A @ self.B
def param_count(self):
full = self.W.size
lora = self.A.size + self.B.size
return full, lora, lora / full
if __name__ == "__main__":
layer = LinearLoRA(512, 512, rank=8)
full, lora, ratio = layer.param_count()
print(f"全参微调参数量 {full}")
print(f"LoRA可训练参数量 {lora}")
print(f"占比 {ratio:.4f}")
print(f"基座是否原封未动 {np.array_equal(layer.W, layer.W_frozen)}")
这段代码展示两件事。512 乘 512 的层全参要 26 万参数,秩 8 的 LoRA 只要约 8 千,占比约百分之三。训练结束后基座矩阵与备份逐元素相等,遗忘在结构层面被排除。
6.2 为什么结构隔离仍有代价
结构隔离不等于零代价。第一,容量上限变低,秩 8 到 32 的旁路难以承载大量新知识,深度领域适配可能欠拟合。第二,干扰转移,旁路与主干相加,旁路学到的偏置仍会在领域外样本上生效,表现为通用任务上轻微掉分。第三,多个任务的 LoRA 不能同时挂载推理,切换有工程成本。
| 全参微调 | 全部 | 无 | 最大 | 最高 |
| LoRA 秩 8 | 约 0.1 到 1 个百分点 | 强 | 小 | 低 |
| LoRA 秩 32 | 约 1 到 5 个百分点 | 中 | 中 | 低 |
| 重放加全参 | 全部 | 中 | 大 | 最高 |
表 6-1 各方案的多维权衡。表中比例为常见区间,随模型规模与目标模块配置浮动。
旁路挂载位置也影响防遗忘效果。只挂在注意力层的投影矩阵上,通用能力保护得好但知识容量小。同时挂到 FFN 层,容量上来,干扰风险也随之上升。本系列第 2 篇讲过 FFN 承担事实存储,动它就是动知识本体,所以要更谨慎。
容量问题值得展开。LoRA 的旁路矩阵秩为 r 时,能表达的方向数上限就是 r。领域知识如果需要多个独立方向才能分开,秩低于这个数就学不进去。判断方法很直接:领域基准收敛但明显低于全参微调的参考分数,大概率是秩不够,先升秩再怀疑数据。
干扰转移的量级通常不大,但方向值得知道。旁路对领域外样本输出一个固定偏置,等价于给所有输出加了一个领域先验。重放通用样本就是在教旁路"领域外时把增量压回零",这也是 6.3 组合拳的原理。
挂载与切换的工程成本也要算。多任务各自一套 LoRA 权重,推理时按请求切换,需要网关层支持热加载与显存预算管理。任务数超过个位数时,合并或路由方案往往比多套旁路更省。
与全参微调的对比要给个量化感受。同量级领域语料下,全参微调的领域分数通常高于 LoRA,差距随任务难度拉大。防遗忘的代价就是这份学习上限,选型时先确认业务能接受多大的领域分数让步,再决定是否上全参。
还有推理侧的差异。挂载 LoRA 后每次前向多两次小矩阵乘法,延迟增加通常在小比例区间,但高并发场景要计入成本。多套旁路并存时显存也要预算,每套旁路虽小,数量多了不可忽略。
还要区分两种掉分来源。基座没动,掉分只能来自旁路,这叫旁路偏置。基座动了,掉分来自主干,这才叫经典遗忘。LoRA 把第二种归零,第一种仍在。排查时先冻结旁路复测,能立刻分辨掉分来自哪一层。
这个区分也指导修复。旁路偏置靠重放通用样本压回去,主干遗忘靠回滚或重放。修错层等于白费功夫,所以诊断这一步不能省。冻结旁路是一次推理实验,成本极低。
旁路的初始化也影响防遗忘表现。标准做法是 B 初始化为零、A 随机小值,保证训练起点等于基座行为。如果两个矩阵都随机初始化,训练一开始就引入扰动,等于自带一层初始噪声,回归起点就不干净。
另一个细节是学习率。旁路参数量小,常用学习率比全参微调高一个量级。但学习率过高时旁路快速偏移,领域外偏置随之放大。调参时旁路学习率与重放比例要一起看,两者共同决定旁路的行为边界。
6.3 组合拳:LoRA 加重放
LoRA 防住主干被覆盖,但旁路仍可能在通用分布上产生偏置。组合拳是在 LoRA 训练数据里同时混入通用重放样本,让旁路学到"领域内偏、领域外零"的行为。这是工程上最常见的稳定配置,也是本文选型建议的默认起点。
#mermaid-svg-ri4Sy5TUMGc9k08b{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-ri4Sy5TUMGc9k08b .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-ri4Sy5TUMGc9k08b .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-ri4Sy5TUMGc9k08b .error-icon{fill:#552222;}#mermaid-svg-ri4Sy5TUMGc9k08b .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-ri4Sy5TUMGc9k08b .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-ri4Sy5TUMGc9k08b .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-ri4Sy5TUMGc9k08b .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-ri4Sy5TUMGc9k08b .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-ri4Sy5TUMGc9k08b .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-ri4Sy5TUMGc9k08b .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-ri4Sy5TUMGc9k08b .marker{fill:#333333;stroke:#333333;}#mermaid-svg-ri4Sy5TUMGc9k08b .marker.cross{stroke:#333333;}#mermaid-svg-ri4Sy5TUMGc9k08b svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-ri4Sy5TUMGc9k08b p{margin:0;}#mermaid-svg-ri4Sy5TUMGc9k08b .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-ri4Sy5TUMGc9k08b .cluster-label text{fill:#333;}#mermaid-svg-ri4Sy5TUMGc9k08b .cluster-label span{color:#333;}#mermaid-svg-ri4Sy5TUMGc9k08b .cluster-label span p{background-color:transparent;}#mermaid-svg-ri4Sy5TUMGc9k08b .label text,#mermaid-svg-ri4Sy5TUMGc9k08b span{fill:#333;color:#333;}#mermaid-svg-ri4Sy5TUMGc9k08b .node rect,#mermaid-svg-ri4Sy5TUMGc9k08b .node circle,#mermaid-svg-ri4Sy5TUMGc9k08b .node ellipse,#mermaid-svg-ri4Sy5TUMGc9k08b .node polygon,#mermaid-svg-ri4Sy5TUMGc9k08b .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-ri4Sy5TUMGc9k08b .rough-node .label text,#mermaid-svg-ri4Sy5TUMGc9k08b .node .label text,#mermaid-svg-ri4Sy5TUMGc9k08b .image-shape .label,#mermaid-svg-ri4Sy5TUMGc9k08b .icon-shape .label{text-anchor:middle;}#mermaid-svg-ri4Sy5TUMGc9k08b .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-ri4Sy5TUMGc9k08b .rough-node .label,#mermaid-svg-ri4Sy5TUMGc9k08b .node .label,#mermaid-svg-ri4Sy5TUMGc9k08b .image-shape .label,#mermaid-svg-ri4Sy5TUMGc9k08b .icon-shape .label{text-align:center;}#mermaid-svg-ri4Sy5TUMGc9k08b .node.clickable{cursor:pointer;}#mermaid-svg-ri4Sy5TUMGc9k08b .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-ri4Sy5TUMGc9k08b .arrowheadPath{fill:#333333;}#mermaid-svg-ri4Sy5TUMGc9k08b .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-ri4Sy5TUMGc9k08b .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-ri4Sy5TUMGc9k08b .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ri4Sy5TUMGc9k08b .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-ri4Sy5TUMGc9k08b .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ri4Sy5TUMGc9k08b .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-ri4Sy5TUMGc9k08b .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-ri4Sy5TUMGc9k08b .cluster text{fill:#333;}#mermaid-svg-ri4Sy5TUMGc9k08b .cluster span{color:#333;}#mermaid-svg-ri4Sy5TUMGc9k08b div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-ri4Sy5TUMGc9k08b .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-ri4Sy5TUMGc9k08b rect.text{fill:none;stroke-width:0;}#mermaid-svg-ri4Sy5TUMGc9k08b .icon-shape,#mermaid-svg-ri4Sy5TUMGc9k08b .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ri4Sy5TUMGc9k08b .icon-shape p,#mermaid-svg-ri4Sy5TUMGc9k08b .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-ri4Sy5TUMGc9k08b .icon-shape .label rect,#mermaid-svg-ri4Sy5TUMGc9k08b .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ri4Sy5TUMGc9k08b .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-ri4Sy5TUMGc9k08b .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-ri4Sy5TUMGc9k08b :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}#mermaid-svg-ri4Sy5TUMGc9k08b .default>*{fill:#faf9f5!important;stroke:#ffffff!important;color:#000000!important;stroke-width:0px!important;}#mermaid-svg-ri4Sy5TUMGc9k08b .default span{fill:#faf9f5!important;stroke:#ffffff!important;color:#000000!important;stroke-width:0px!important;}#mermaid-svg-ri4Sy5TUMGc9k08b .default tspan{fill:#000000!important;}
领域语料
混合训练
通用重放样本
只更新旁路BA
领域样本产生偏置
通用样本压回零
领域内生效领域外归零
图 6-2 LoRA 加重放的行为塑造。旁路学到的是条件化增量,而不是无条件偏置。
| 纯 LoRA | 结构保证 | 无 | 低 |
| 纯重放加全参 | 数据约束 | 不适用 | 高 |
| LoRA 加重放 | 结构保证 | 数据约束 | 中 |
表 6-2 三种配置的防护层次。组合拳是唯一同时覆盖两层遗忘路径的配置。
需要注意秩的选择。秩过小新领域学不进去,过大接近全参的干扰风险。常见做法是从秩 8 或 16 起步,看领域基准是否收敛,再决定是否上调。回归分数与领域分数要同时看,单看任何一边都会误判。
组合拳的调参顺序有讲究。先定秩再看配比,因为秩决定容量上限,配比不足可以用更多训练步数补,容量不足则补不动。常见路径是秩 16 起步,领域分数到平台期后判断是否升秩,重放比例始终跟随回归分数调整。
一个实用验收标准:领域基准达到目标,同时四个回归维度降幅都在阈值内。两条同时满足才放行。只满足第一条的组合拳配置不成立,说明重放比例或旁路秩需要再调。
7. 模型合并:任务向量加减
模型合并(model merging)是训练后处理路线。做法是先算任务向量,等于微调后权重减去基座权重,再在向量层面做加减与组合,不触碰原始训练数据。相关方向的系统讨论见 arXiv 2212.04089,此处按方向性表述处理。
7.1 任务向量的加减法
任务向量提供了一个直观视角:微调学到的东西可以表示为基座上的一个位移。两个任务的向量相加得到一个同时具备两种能力的模型,两个向量相减可以移除某种能力。这种线性视角在多数场景是近似成立,不是精确成立。
#mermaid-svg-eri8CfJoh99FztE7{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-eri8CfJoh99FztE7 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-eri8CfJoh99FztE7 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-eri8CfJoh99FztE7 .error-icon{fill:#552222;}#mermaid-svg-eri8CfJoh99FztE7 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-eri8CfJoh99FztE7 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-eri8CfJoh99FztE7 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-eri8CfJoh99FztE7 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-eri8CfJoh99FztE7 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-eri8CfJoh99FztE7 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-eri8CfJoh99FztE7 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-eri8CfJoh99FztE7 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-eri8CfJoh99FztE7 .marker.cross{stroke:#333333;}#mermaid-svg-eri8CfJoh99FztE7 svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-eri8CfJoh99FztE7 p{margin:0;}#mermaid-svg-eri8CfJoh99FztE7 .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-eri8CfJoh99FztE7 .cluster-label text{fill:#333;}#mermaid-svg-eri8CfJoh99FztE7 .cluster-label span{color:#333;}#mermaid-svg-eri8CfJoh99FztE7 .cluster-label span p{background-color:transparent;}#mermaid-svg-eri8CfJoh99FztE7 .label text,#mermaid-svg-eri8CfJoh99FztE7 span{fill:#333;color:#333;}#mermaid-svg-eri8CfJoh99FztE7 .node rect,#mermaid-svg-eri8CfJoh99FztE7 .node circle,#mermaid-svg-eri8CfJoh99FztE7 .node ellipse,#mermaid-svg-eri8CfJoh99FztE7 .node polygon,#mermaid-svg-eri8CfJoh99FztE7 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-eri8CfJoh99FztE7 .rough-node .label text,#mermaid-svg-eri8CfJoh99FztE7 .node .label text,#mermaid-svg-eri8CfJoh99FztE7 .image-shape .label,#mermaid-svg-eri8CfJoh99FztE7 .icon-shape .label{text-anchor:middle;}#mermaid-svg-eri8CfJoh99FztE7 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-eri8CfJoh99FztE7 .rough-node .label,#mermaid-svg-eri8CfJoh99FztE7 .node .label,#mermaid-svg-eri8CfJoh99FztE7 .image-shape .label,#mermaid-svg-eri8CfJoh99FztE7 .icon-shape .label{text-align:center;}#mermaid-svg-eri8CfJoh99FztE7 .node.clickable{cursor:pointer;}#mermaid-svg-eri8CfJoh99FztE7 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-eri8CfJoh99FztE7 .arrowheadPath{fill:#333333;}#mermaid-svg-eri8CfJoh99FztE7 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-eri8CfJoh99FztE7 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-eri8CfJoh99FztE7 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-eri8CfJoh99FztE7 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-eri8CfJoh99FztE7 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-eri8CfJoh99FztE7 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-eri8CfJoh99FztE7 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-eri8CfJoh99FztE7 .cluster text{fill:#333;}#mermaid-svg-eri8CfJoh99FztE7 .cluster span{color:#333;}#mermaid-svg-eri8CfJoh99FztE7 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-eri8CfJoh99FztE7 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-eri8CfJoh99FztE7 rect.text{fill:none;stroke-width:0;}#mermaid-svg-eri8CfJoh99FztE7 .icon-shape,#mermaid-svg-eri8CfJoh99FztE7 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-eri8CfJoh99FztE7 .icon-shape p,#mermaid-svg-eri8CfJoh99FztE7 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-eri8CfJoh99FztE7 .icon-shape .label rect,#mermaid-svg-eri8CfJoh99FztE7 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-eri8CfJoh99FztE7 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-eri8CfJoh99FztE7 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-eri8CfJoh99FztE7 :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}#mermaid-svg-eri8CfJoh99FztE7 .default>*{fill:#faf9f5!important;stroke:#ffffff!important;color:#000000!important;stroke-width:0px!important;}#mermaid-svg-eri8CfJoh99FztE7 .default span{fill:#faf9f5!important;stroke:#ffffff!important;color:#000000!important;stroke-width:0px!important;}#mermaid-svg-eri8CfJoh99FztE7 .default tspan{fill:#000000!important;}
基座权重T0
领域微调后T1
任务向量等于T1减T0
向量按系数相加
得到合并后权重
单模型多能力
向量相减则移除能力
图 7-1 任务向量的构造与合并。关键洞察是微调增量可以脱离原数据被独立操作。
| 向量相加 | 两个位移叠加 | 合并多个领域能力 |
| 向量相减 | 去掉某位移 | 移除不良行为 |
| 系数缩放 | 位移乘小于1的系数 | 降低干扰 |
| 逐层加权 | 不同层不同系数 | 精细合并 |
表 7-1 任务向量的四种操作。方向性结论来自模型合并方向的公开研究,具体效果随模型浮动。
这套操作的工程价值在于解耦。传统做法是一份权重上迭代,每加一个能力都要重跑全部回归。任务向量方式下,每个能力独立训练独立验证,组合时只验证组合点,验证工作量从随能力数线性增长降到只与组合数相关。
还有一个被低估的用途是退化修复。某次微调引入了不良行为,比如过度拒答,可以用该次微调的任务向量按小于 1 的系数减回去,比重新训练便宜得多。前提是保留了基座权重与微调后权重,否则算不出向量。
实现层面这套操作的门槛很低。只需要保存基座权重与每次微调后的权重,相减得到向量,合并就是基座加各向量按系数求和。不涉及训练,只需要权重算术与一次验证评测,几小时内可以试完多种组合。
系数选择上有个经验方向。直接用系数 1 相加常会过冲,表现为主干能力下降。用 0.5 到 0.8 的系数往往更稳,牺牲一点领域能力换主干的稳定。多任务时各系数可以不同,重要任务给高系数。
7.2 合并的边界与失败模式
合并不是万能药。第一类失败是任务间干扰,两个向量在同一参数上方向相反,相加后互相抵消,两边都掉分。第二类是能力不对齐,合并后的模型在两个任务的混合指令上表现不稳。第三类是符号性局限,权重空间的线性叠加不等于能力的线性叠加,深层网络存在大量非线性行为。
#mermaid-svg-H0qLPkxg8DDfpK9o{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-H0qLPkxg8DDfpK9o .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-H0qLPkxg8DDfpK9o .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-H0qLPkxg8DDfpK9o .error-icon{fill:#552222;}#mermaid-svg-H0qLPkxg8DDfpK9o .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-H0qLPkxg8DDfpK9o .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-H0qLPkxg8DDfpK9o .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-H0qLPkxg8DDfpK9o .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-H0qLPkxg8DDfpK9o .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-H0qLPkxg8DDfpK9o .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-H0qLPkxg8DDfpK9o .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-H0qLPkxg8DDfpK9o .marker{fill:#333333;stroke:#333333;}#mermaid-svg-H0qLPkxg8DDfpK9o .marker.cross{stroke:#333333;}#mermaid-svg-H0qLPkxg8DDfpK9o svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-H0qLPkxg8DDfpK9o p{margin:0;}#mermaid-svg-H0qLPkxg8DDfpK9o .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-H0qLPkxg8DDfpK9o .cluster-label text{fill:#333;}#mermaid-svg-H0qLPkxg8DDfpK9o .cluster-label span{color:#333;}#mermaid-svg-H0qLPkxg8DDfpK9o .cluster-label span p{background-color:transparent;}#mermaid-svg-H0qLPkxg8DDfpK9o .label text,#mermaid-svg-H0qLPkxg8DDfpK9o span{fill:#333;color:#333;}#mermaid-svg-H0qLPkxg8DDfpK9o .node rect,#mermaid-svg-H0qLPkxg8DDfpK9o .node circle,#mermaid-svg-H0qLPkxg8DDfpK9o .node ellipse,#mermaid-svg-H0qLPkxg8DDfpK9o .node polygon,#mermaid-svg-H0qLPkxg8DDfpK9o .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-H0qLPkxg8DDfpK9o .rough-node .label text,#mermaid-svg-H0qLPkxg8DDfpK9o .node .label text,#mermaid-svg-H0qLPkxg8DDfpK9o .image-shape .label,#mermaid-svg-H0qLPkxg8DDfpK9o .icon-shape .label{text-anchor:middle;}#mermaid-svg-H0qLPkxg8DDfpK9o .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-H0qLPkxg8DDfpK9o .rough-node .label,#mermaid-svg-H0qLPkxg8DDfpK9o .node .label,#mermaid-svg-H0qLPkxg8DDfpK9o .image-shape .label,#mermaid-svg-H0qLPkxg8DDfpK9o .icon-shape .label{text-align:center;}#mermaid-svg-H0qLPkxg8DDfpK9o .node.clickable{cursor:pointer;}#mermaid-svg-H0qLPkxg8DDfpK9o .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-H0qLPkxg8DDfpK9o .arrowheadPath{fill:#333333;}#mermaid-svg-H0qLPkxg8DDfpK9o .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-H0qLPkxg8DDfpK9o .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-H0qLPkxg8DDfpK9o .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-H0qLPkxg8DDfpK9o .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-H0qLPkxg8DDfpK9o .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-H0qLPkxg8DDfpK9o .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-H0qLPkxg8DDfpK9o .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-H0qLPkxg8DDfpK9o .cluster text{fill:#333;}#mermaid-svg-H0qLPkxg8DDfpK9o .cluster span{color:#333;}#mermaid-svg-H0qLPkxg8DDfpK9o div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-H0qLPkxg8DDfpK9o .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-H0qLPkxg8DDfpK9o rect.text{fill:none;stroke-width:0;}#mermaid-svg-H0qLPkxg8DDfpK9o .icon-shape,#mermaid-svg-H0qLPkxg8DDfpK9o .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-H0qLPkxg8DDfpK9o .icon-shape p,#mermaid-svg-H0qLPkxg8DDfpK9o .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-H0qLPkxg8DDfpK9o .icon-shape .label rect,#mermaid-svg-H0qLPkxg8DDfpK9o .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-H0qLPkxg8DDfpK9o .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-H0qLPkxg8DDfpK9o .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-H0qLPkxg8DDfpK9o :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}#mermaid-svg-H0qLPkxg8DDfpK9o .default>*{fill:#faf9f5!important;stroke:#ffffff!important;color:#000000!important;stroke-width:0px!important;}#mermaid-svg-H0qLPkxg8DDfpK9o .default span{fill:#faf9f5!important;stroke:#ffffff!important;color:#000000!important;stroke-width:0px!important;}#mermaid-svg-H0qLPkxg8DDfpK9o .default tspan{fill:#000000!important;}
同向或正交
同参数上反向
向量A与向量B
方向关系
相加基本有效
互相抵消两边掉分
合并收益高
改用逐层加权或路由
图 7-2 任务向量方向的两种结局。合并前先看两个向量的余弦相似度,能预判干扰风险。
| 任务间干扰 | 合并后两边都掉 | 降系数或逐层加权 |
| 能力不对齐 | 混合指令不稳 | 任务路由代替合并 |
| 线性假设失效 | 系数怎么调都不行 | 回到分别部署 |
表 7-2 合并的三类失败与处置。合并省显存的收益要用双回归验证来换。
工程上要做的验证很朴素:合并后必须重跑两个领域各自的回归集,确认两边都没有退化。不能假设向量相加等于能力相加,这个假设在很多任务对上不成立。
判断两个任务向量是否冲突,有个便宜的预检方法。算两个向量的整体余弦相似度,接近零或为正,合并风险低。明显为负说明大方向相反,先做逐层检查或直接放弃合并。这个预检只需要权重算术,成本可忽略。
失败的兜底方案也要提前想好。合并不成就退回分别部署加路由,用网关按请求类型分发到不同实例。代价是显存与运维翻倍,但能力保全。合并是优化项,不是必选项。
逐层加权是常用的补救手段。不同层对任务的贡献不同,浅层偏通用特征,深层偏任务特征。给深层向量高系数、浅层低系数,常能在保留主干能力的同时拿到大部分领域能力。代价是要逐层扫系数,验证次数上升。
还有正则化思路的合并,比如在合并时对结果做插值约束,限制合并后权重离基座的距离。这相当于把 EWC 的思想搬到合并环节,实现简单,对小规模合并足够用。
7.3 与遗忘问题的关系
合并对遗忘问题的价值是提供了一条不改主干的扩展路径。与其在一份权重上反复继续训练,不如为每个领域维护独立任务向量,按需组合。这样旧能力的主干始终不动,新领域以旁挂形式加入。
#mermaid-svg-gEGnqs5ZssHKIbjj{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-gEGnqs5ZssHKIbjj .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-gEGnqs5ZssHKIbjj .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-gEGnqs5ZssHKIbjj .error-icon{fill:#552222;}#mermaid-svg-gEGnqs5ZssHKIbjj .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-gEGnqs5ZssHKIbjj .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-gEGnqs5ZssHKIbjj .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-gEGnqs5ZssHKIbjj .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-gEGnqs5ZssHKIbjj .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-gEGnqs5ZssHKIbjj .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-gEGnqs5ZssHKIbjj .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-gEGnqs5ZssHKIbjj .marker{fill:#333333;stroke:#333333;}#mermaid-svg-gEGnqs5ZssHKIbjj .marker.cross{stroke:#333333;}#mermaid-svg-gEGnqs5ZssHKIbjj svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-gEGnqs5ZssHKIbjj p{margin:0;}#mermaid-svg-gEGnqs5ZssHKIbjj .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-gEGnqs5ZssHKIbjj .cluster-label text{fill:#333;}#mermaid-svg-gEGnqs5ZssHKIbjj .cluster-label span{color:#333;}#mermaid-svg-gEGnqs5ZssHKIbjj .cluster-label span p{background-color:transparent;}#mermaid-svg-gEGnqs5ZssHKIbjj .label text,#mermaid-svg-gEGnqs5ZssHKIbjj span{fill:#333;color:#333;}#mermaid-svg-gEGnqs5ZssHKIbjj .node rect,#mermaid-svg-gEGnqs5ZssHKIbjj .node circle,#mermaid-svg-gEGnqs5ZssHKIbjj .node ellipse,#mermaid-svg-gEGnqs5ZssHKIbjj .node polygon,#mermaid-svg-gEGnqs5ZssHKIbjj .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-gEGnqs5ZssHKIbjj .rough-node .label text,#mermaid-svg-gEGnqs5ZssHKIbjj .node .label text,#mermaid-svg-gEGnqs5ZssHKIbjj .image-shape .label,#mermaid-svg-gEGnqs5ZssHKIbjj .icon-shape .label{text-anchor:middle;}#mermaid-svg-gEGnqs5ZssHKIbjj .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-gEGnqs5ZssHKIbjj .rough-node .label,#mermaid-svg-gEGnqs5ZssHKIbjj .node .label,#mermaid-svg-gEGnqs5ZssHKIbjj .image-shape .label,#mermaid-svg-gEGnqs5ZssHKIbjj .icon-shape .label{text-align:center;}#mermaid-svg-gEGnqs5ZssHKIbjj .node.clickable{cursor:pointer;}#mermaid-svg-gEGnqs5ZssHKIbjj .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-gEGnqs5ZssHKIbjj .arrowheadPath{fill:#333333;}#mermaid-svg-gEGnqs5ZssHKIbjj .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-gEGnqs5ZssHKIbjj .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-gEGnqs5ZssHKIbjj .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-gEGnqs5ZssHKIbjj .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-gEGnqs5ZssHKIbjj .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-gEGnqs5ZssHKIbjj .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-gEGnqs5ZssHKIbjj .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-gEGnqs5ZssHKIbjj .cluster text{fill:#333;}#mermaid-svg-gEGnqs5ZssHKIbjj .cluster span{color:#333;}#mermaid-svg-gEGnqs5ZssHKIbjj div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-gEGnqs5ZssHKIbjj .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-gEGnqs5ZssHKIbjj rect.text{fill:none;stroke-width:0;}#mermaid-svg-gEGnqs5ZssHKIbjj .icon-shape,#mermaid-svg-gEGnqs5ZssHKIbjj .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-gEGnqs5ZssHKIbjj .icon-shape p,#mermaid-svg-gEGnqs5ZssHKIbjj .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-gEGnqs5ZssHKIbjj .icon-shape .label rect,#mermaid-svg-gEGnqs5ZssHKIbjj .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-gEGnqs5ZssHKIbjj .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-gEGnqs5ZssHKIbjj .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-gEGnqs5ZssHKIbjj :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}#mermaid-svg-gEGnqs5ZssHKIbjj .default>*{fill:#faf9f5!important;stroke:#ffffff!important;color:#000000!important;stroke-width:0px!important;}#mermaid-svg-gEGnqs5ZssHKIbjj .default span{fill:#faf9f5!important;stroke:#ffffff!important;color:#000000!important;stroke-width:0px!important;}#mermaid-svg-gEGnqs5ZssHKIbjj .default tspan{fill:#000000!important;}
基座权重
领域A向量
领域B向量
领域C向量
按需组合
单模型多能力
主干永不重训
图 7-3 向量库式的扩展方式。主干冻结,新能力以增量形式入库,这是持续学习的一种落地形态。
这与 RAG 的分工值得点一句。合并解决"能力内化进参数",RAG 解决"知识外挂可更新"。领域术语与推理模式适合内化,高频变动的事实适合外挂,两者不冲突。
这条路径也有代价。向量数量增长后,组合空间爆炸,哪些向量能安全共存要靠实验验证。工程上先限制同时合并的任务数在两到三个,超出就用路由分发到不同实例,把组合验证的成本控制在可接受范围。
对持续学习而言,这条路把问题从"如何不遗忘"改写为"如何管理增量库"。增量可以随时增删,主干不动,遗忘风险被限制在合并环节。管理成本从训练时转移到组合验证时,对小团队反而更可控。
前提条件要满足:基座权重必须长期保留且不变。如果基座本身定期更新,所有任务向量都要基于新基座重算,等于重训。所以走这条路要先冻结基座版本策略,再做领域扩展。
从成本视角看这条路的开销构成。训练侧每个领域一次微调,与迭代式相同。存储侧多份向量,每份比完整权重小一个量级。推理侧一份合并权重或多实例路由。总体上把重训成本换成了存储加验证成本,规模大了更划算。
风险集中在基座版本管理上。基座升级后旧向量全部失效,要么重算要么放弃。所以走这条路前要评估基座的更新频率,更新频繁的团队用这条路会反复付费,不如老老实实做重放式持续训练。
8. 回归监控与选型建议
最后一章收束到工程落地。原则一句话:领域适配优先 LoRA 加重放,不做全参微调,并保留通用回归测试集持续监控。
8.1 选型决策路径
#mermaid-svg-pV3wLhGa8pYM88HV{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-pV3wLhGa8pYM88HV .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-pV3wLhGa8pYM88HV .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-pV3wLhGa8pYM88HV .error-icon{fill:#552222;}#mermaid-svg-pV3wLhGa8pYM88HV .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-pV3wLhGa8pYM88HV .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-pV3wLhGa8pYM88HV .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-pV3wLhGa8pYM88HV .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-pV3wLhGa8pYM88HV .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-pV3wLhGa8pYM88HV .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-pV3wLhGa8pYM88HV .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-pV3wLhGa8pYM88HV .marker{fill:#333333;stroke:#333333;}#mermaid-svg-pV3wLhGa8pYM88HV .marker.cross{stroke:#333333;}#mermaid-svg-pV3wLhGa8pYM88HV svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-pV3wLhGa8pYM88HV p{margin:0;}#mermaid-svg-pV3wLhGa8pYM88HV .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-pV3wLhGa8pYM88HV .cluster-label text{fill:#333;}#mermaid-svg-pV3wLhGa8pYM88HV .cluster-label span{color:#333;}#mermaid-svg-pV3wLhGa8pYM88HV .cluster-label span p{background-color:transparent;}#mermaid-svg-pV3wLhGa8pYM88HV .label text,#mermaid-svg-pV3wLhGa8pYM88HV span{fill:#333;color:#333;}#mermaid-svg-pV3wLhGa8pYM88HV .node rect,#mermaid-svg-pV3wLhGa8pYM88HV .node circle,#mermaid-svg-pV3wLhGa8pYM88HV .node ellipse,#mermaid-svg-pV3wLhGa8pYM88HV .node polygon,#mermaid-svg-pV3wLhGa8pYM88HV .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-pV3wLhGa8pYM88HV .rough-node .label text,#mermaid-svg-pV3wLhGa8pYM88HV .node .label text,#mermaid-svg-pV3wLhGa8pYM88HV .image-shape .label,#mermaid-svg-pV3wLhGa8pYM88HV .icon-shape .label{text-anchor:middle;}#mermaid-svg-pV3wLhGa8pYM88HV .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-pV3wLhGa8pYM88HV .rough-node .label,#mermaid-svg-pV3wLhGa8pYM88HV .node .label,#mermaid-svg-pV3wLhGa8pYM88HV .image-shape .label,#mermaid-svg-pV3wLhGa8pYM88HV .icon-shape .label{text-align:center;}#mermaid-svg-pV3wLhGa8pYM88HV .node.clickable{cursor:pointer;}#mermaid-svg-pV3wLhGa8pYM88HV .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-pV3wLhGa8pYM88HV .arrowheadPath{fill:#333333;}#mermaid-svg-pV3wLhGa8pYM88HV .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-pV3wLhGa8pYM88HV .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-pV3wLhGa8pYM88HV .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-pV3wLhGa8pYM88HV .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-pV3wLhGa8pYM88HV .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-pV3wLhGa8pYM88HV .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-pV3wLhGa8pYM88HV .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-pV3wLhGa8pYM88HV .cluster text{fill:#333;}#mermaid-svg-pV3wLhGa8pYM88HV .cluster span{color:#333;}#mermaid-svg-pV3wLhGa8pYM88HV div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-pV3wLhGa8pYM88HV .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-pV3wLhGa8pYM88HV rect.text{fill:none;stroke-width:0;}#mermaid-svg-pV3wLhGa8pYM88HV .icon-shape,#mermaid-svg-pV3wLhGa8pYM88HV .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-pV3wLhGa8pYM88HV .icon-shape p,#mermaid-svg-pV3wLhGa8pYM88HV .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-pV3wLhGa8pYM88HV .icon-shape .label rect,#mermaid-svg-pV3wLhGa8pYM88HV .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-pV3wLhGa8pYM88HV .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-pV3wLhGa8pYM88HV .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-pV3wLhGa8pYM88HV :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}#mermaid-svg-pV3wLhGa8pYM88HV .default>*{fill:#faf9f5!important;stroke:#ffffff!important;color:#000000!important;stroke-width:0px!important;}#mermaid-svg-pV3wLhGa8pYM88HV .default span{fill:#faf9f5!important;stroke:#ffffff!important;color:#000000!important;stroke-width:0px!important;}#mermaid-svg-pV3wLhGa8pYM88HV .default tspan{fill:#000000!important;}
是
否
是
否
领域适配需求
需要内化大量新知识吗
LoRA较高秩加重放
LoRA低秩或仅提示工程
回归分数掉超过阈值吗
提高重放比例或降秩
定版并冻结回归基线
重跑回归直到通过
图 8-1 领域适配选型决策路径。回归分数是唯一的放行闸门,领域分数只用于确认学习是否发生。
| 少量领域术语 | LoRA 低秩,不重放 | 干扰面小 |
| 大量领域知识 | LoRA 中秩加重放 10 到 20 个百分点 | 防旁路偏置 |
| 必须全参 | 重放至少 20 到 30 个百分点加早停 | 唯一防线是数据侧 |
| 多领域并存 | 各自 LoRA 或任务向量合并 | 主干不动 |
表 8-1 四类场景的默认配置。重放比例为常见起点区间,需按回归分数调整。
决策路径里有三个容易走岔的口子。第一个是把"需要内化大量新知识"误判为必须全参。实际上秩 32 到 64 的 LoRA 加足够领域语料,多数领域能压到可接受差距,先试便宜的。第二个是把回归阈值设得过松,导致拦截形同虚设。第三个是阈值一刀切,指令遵循这类用户直接感知的维度应设更紧的阈值。
阈值设定可以分级。核心维度如指令遵循设在 2 到 3 个百分点,一般维度如通用知识设在 5 个百分点,冷门维度可以放宽到 8 个百分点。分级后既有拦截力又不至于频繁误报,团队才愿意持续执行。
8.2 监控清单
落地要一份可执行的清单。回归集构成:通用知识、通用推理、指令遵循、格式稳定四类,各固定题量,与领域语料严格隔离来源。执行节奏:适配中每若干 checkpoint 跑一次,定版前必跑,上线后随版本跑。判定标准:任一维度下降超过预设阈值即阻断发布,阈值常设在 2 到 5 个百分点区间,按业务容忍度定。
# 来源:自实现 / regression_gate.py
import numpy as np
def gate(domain_score, regression_scores, thresholds):
# 双闸门:领域要涨,回归每个维度都要守住
reasons = []
if domain_score["after"] <= domain_score["before"]:
reasons.append("领域分数未提升")
for name, s in regression_scores.items():
drop = s["before"] – s["after"]
if drop > thresholds.get(name, 0.05):
reasons.append(f"{name}遗忘{drop:.2f}超阈值")
return ("通过" if not reasons else "阻断", reasons)
if __name__ == "__main__":
domain = {"before": 0.52, "after": 0.71}
reg = {"通用知识": {"before": 0.80, "after": 0.78},
"通用推理": {"before": 0.66, "after": 0.58},
"指令遵循": {"before": 0.74, "after": 0.73}}
th = {"通用知识": 0.05, "通用推理": 0.05, "指令遵循": 0.05}
verdict, reasons = gate(domain, reg, th)
print(f"发布判定 {verdict}")
for r in reasons:
print(f"原因 {r}")
这段代码的闸门逻辑是双条件:领域分数必须上升,同时回归每个维度下降都不得超阈值。例子中通用推理掉 0.08 超过 0.05,因此被阻断,说明分维度判定确实能拦住总分掩盖的退化。
8.3 反模式清单
三个常见反模式要点名。第一,全参微调加纯领域语料,这是遗忘最重的组合,除非重放配足,否则不要选。第二,只看领域基准就定版,通用与指令维度的退化会在上线后暴露,返工成本远高于多跑一次回归。第三,拿领域评测题当重放数据,这既是泄漏也是自欺,回归分数会虚高。
| 全参加纯领域语料 | 遗忘最重 | 加重放或改 LoRA |
| 只看领域基准定版 | 上线后返工 | 双基准放行 |
| 领域题当重放数据 | 回归虚高 | 数据源隔离 |
| 一次微调塞多领域 | 互相干扰 | 分领域迭代 |
表 8-2 四类反模式与修正。第三行的欺骗性最强,因为它让监控本身失效。
还有一个隐蔽的坑:连续多轮适配的累积遗忘。每轮掉 3 个点看似可接受,三轮累积近 10 个点就不可接受。对策是每轮适配后更新冻结基线,并把累积降幅纳入发布评审。
多领域同时要加的情况也要留意。一次微调塞进多个领域,领域间会互相竞争参数,结果常是每个领域都只学到一半。更稳的路径是分领域迭代,每轮只针对一个领域,其余领域靠重放守住,代价是训练轮数增加。
最后一句话收束工程原则:先建回归集,再谈微调。监控先行意味着每次尝试都有否决依据,顺序反过来则等于闭眼开车,出了问题无从归因。
最后补一个组织层面的反模式。没有明确的责任人时,回归监控会逐渐流于形式,跑过了但没人看结果,阻断规则形同虚设。对策是把回归结果写进发布流程,发布单必须附回归报告,责任人签字后才允许上线。
另一个组织坑是阈值争论无限拖延。业务方希望松,技术方希望紧,僵持下先按默认阈值执行,事后用数据回顾调整。有阈值且被执行,好过完美阈值永远在讨论中。
清单之外还有一个静默失败。回归集长期不更新,题目被领域语料间接覆盖后逐渐失敏,分数常年稳定,实际防护力在下降。对策是定期抽查回归集题目与近期语料的相似度,过高的换掉,保持题集的独立性。
最后是度量本身的反模式。用单一综合分替代分维度分,等于把四个独立信号压成一个,任何一个维度的退化都可能被其他维度的上涨抵消。分维度报告是最低成本的防自欺手段,发布单上四个分数分开列。
工具层面的反模式也提一句。用自动评测工具时不锁定模型版本与提示词模板,工具升级后评分逻辑变化,历史分数不可比。工具链本身要版本化,升级工具后重跑一次全量基线,重建可比性。
最后是知识管理的反模式。回归集、重放集、领域评测集混在同一目录,边界靠人记。时间一长必然串数据。三套数据分库存储加命名规范,是最便宜的隔离手段,也是防泄漏的第一道墙。
9. 总结
学了新的忘了旧的,根源是参数共享加 SGD 缺少旧约束。新语料的最优解覆盖旧任务的解,通用知识、推理与指令遵循一起被侵蚀。度量口径是旧任务性能下降幅度,学新与保旧构成双曲线,任何方法只能外移曲线,不能取消取舍。
工具箱按作用位置分四类。数据重放把旧数据放回损失函数,是最稳的底座。EWC 用 Fisher 近似给重要参数上锁,适合拿不到旧数据的场景。LoRA 冻结基座只动小矩阵,从结构上排除覆盖,配重放是默认选型。模型合并用任务向量加减扩展能力,不动主干。工程上的落点是一句话:优先 LoRA 加重放,保留通用回归测试集,分维度设阈值阻断发布。
外部引用
- EWC 原始论文 Overcoming catastrophic forgetting in neural networks:https://arxiv.org/abs/1612.00796
- 任务向量论文 Editing Models with Task Arithmetic:https://arxiv.org/abs/2212.04089
- LoRA 原始论文 LoRA: Low-Rank Adaptation of Large Language Models:https://arxiv.org/abs/2106.09685
- 持续学习三种场景与度量 Three scenarios for continual learning:https://arxiv.org/abs/1904.07734
- 梯度情景记忆方法 Gradient Episodic Memory for Continual Learning:https://arxiv.org/abs/1706.08840
- Wikipedia 条目 Catastrophic forgetting:https://en.wikipedia.org/wiki/Catastrophic_interference
- 模型合并方法综述 Model Merging in LLMs, MLLMs and Beyond:https://arxiv.org/abs/2408.07666




