如果模型在顺序学习新任务时只使用当前任务的数据,旧任务的识别能力往往会迅速退化。一个在MNIST上训练良好的分类器,继续学习FashionMNIST后,再回头测试MNIST,准确率可能出现明显下跌。这种现象被称为灾难性遗忘,是持续学习领域的核心障碍。重放缓冲区与正则化是当前应用最广泛的两类缓解手段。前者通过保存旧样本或生成伪样本,让模型在新任务训练时保持对旧数据的记忆;后者通过约束重要参数或蒸馏旧模型输出,降低新任务对旧知识的破坏。

要理解这两类方法为什么有效,需要先明确遗忘发生的机制。神经网络的参数是共享的,新任务的梯度更新不会考虑旧任务的损失,因此训练结束后,部分权重会移动到只适合新任务的位置,旧任务依赖的决策边界被覆盖。重放缓冲区相当于在新任务的优化过程中加入旧任务的经验,使梯度方向兼顾多个任务;正则化则相当于给参数更新增加阻力,让模型在可塑性受到限制的情况下找到新任务解。
一、灾难性遗忘的成因与参数重要度差异
灾难性遗忘并不是模型容量不足造成的。即使网络有足够参数同时表示多个任务,单纯按顺序训练仍会遗忘。原因在于损失函数只对当前任务数据求梯度,优化器没有机制保护已经学到的映射。共享特征提取层一旦被新任务更新,旧任务输入经过这些层后得到的特征表示会发生偏移,最后连分类头也无法恢复旧任务性能。
更关键的是,不同参数对旧任务的贡献并不相同。某些卷积核或注意力头可能承担了旧任务的核心特征提取,而另一些参数即使变化较大也不会影响旧任务。因此,如果能识别重要参数并限制其更新幅度,就有机会在不大幅牺牲新任务性能的前提下保留旧知识。EWC等正则化方法正是沿着这一思路设计。
稳定性与可塑性之间存在天然矛盾。过度限制参数会降低模型学习新任务的能力,完全放开又会导致遗忘。重放与正则化本质上都在寻找稳定性和可塑性之间的折中,只是控制手段不同:前者从数据侧注入旧任务信息,后者从优化侧施加约束。
二、重放缓冲区:从数据侧巩固旧任务
经验重放是最直观的解决方案。为每个旧任务保留少量样本,存入固定容量的缓冲区。在训练新任务时,每个批次不仅包含新数据,还从缓冲区随机采样一部分旧样本,共同计算损失。这样旧任务的梯度会持续参与参数更新,模型不会把全部权重都拉向新任务。
经验重放实现简单,对许多任务都有稳定效果。缓冲区大小是关键超参数,过小则旧任务代表性不足,过大则训练时间和存储成本上升。实际工程中通常采用固定容量队列,当缓冲区满时丢弃最早样本。下面是一个重放训练循环的简化实现:
# 经验重放训练循环
import random
import torch
replay_buffer = []
max_buffer_size = 2000
def store_sample(x, y):
replay_buffer.append((x.clone(), y.clone()))
if len(replay_buffer) > max_buffer_size:
replay_buffer.pop(0)
for x_new, y_new in new_task_loader:
batch_x = [x_new]
batch_y = [y_new]
if len(replay_buffer) > 0:
old_batch = random.sample(replay_buffer, min(len(replay_buffer), 32))
old_x = torch.stack([item[0] for item in old_batch])
old_y = torch.stack([item[1] for item in old_batch])
batch_x.append(old_x)
batch_y.append(old_y)
x = torch.cat(batch_x, dim=0)
y = torch.cat(batch_y, dim=0)
loss = criterion(model(x), y)
optimizer.zero_grad()
loss.backward()
optimizer.step()
for x_single, y_single in zip(x_new, y_new):
store_sample(x_single, y_single)
当旧任务样本不允许长期保存时,生成式重放可以提供替代方案。它训练一个生成模型,如变分自编码器或生成对抗网络,来学习旧任务的数据分布,之后在训练新任务时从生成模型中采样伪旧样本。生成式重放大幅降低存储需求,也避免直接存储原始数据带来的隐私风险。但生成模型本身会引入偏差,生成的样本质量会直接影响抗遗忘效果。
三、正则化方法:从优化侧限制遗忘
正则化方法不依赖旧数据,而是在损失函数中增加惩罚项,限制模型参数偏离旧任务解。EWC是其中的代表。它使用Fisher信息矩阵估计每个参数对旧任务的重要性,Fisher值越大,说明该参数对旧任务损失越敏感。训练新任务时,EWC在损失中加入二次惩罚:
def ewc_loss(model, fisher_dict, old_params, lambda_ewc):
reg = 0
for name, param in model.named_parameters():
if name in fisher_dict:
diff = param - old_params[name]
reg += (fisher_dict[name] * diff ** 2).sum()
return lambda_ewc * reg
total_loss = task_loss + ewc_loss(model, fisher_dict, old_params, lambda_ewc)
与EWC类似,突触智能SI通过参数沿训练轨迹的累积梯度变化来衡量重要度,内存感知突触MAS则依据输出对参数扰动的敏感度。它们都不需要旧任务数据,适合隐私敏感或旧数据不可长期保存的场景。但这类方法的估计精度依赖任务结束时的重要度快照,对于长序列任务,误差可能逐渐累积。
功能正则化采用另一条路线:保留旧模型副本,在新任务训练时用知识蒸馏让当前模型在旧任务数据上的输出尽量接近旧模型输出。LwF就是典型代表。它不需要原始旧数据,只要求能访问旧模型的输出分布。由于旧模型可能无法覆盖新类别,LwF通常在旧类别部分使用温度缩放后的软标签。功能正则化比权重正则化更贴近任务行为,但计算量略高,且同样存在偏差。
四、混合策略与工程落地建议
重放缓冲区与正则化并不互斥,实践中最稳健的方案往往同时使用两者。小型经验重放保存代表性旧样本,提供直接的数据监督;同时用EWC对重要参数施加额外约束,降低重放样本不足导致的权重漂移。这样做可以在存储预算有限的条件下获得比单一方法更好的抗遗忘效果。
超参数选择需要根据任务类型调整。如果任务之间相似度较高,重放缓冲区可以设置较小,正则化系数也可适当降低,因为共享特征可能有利于新任务。如果任务差异较大,则需要更大的缓冲区或更强的参数约束。经验回放还应注意类别不平衡问题,旧样本数量远少于新数据时,可以在损失函数中增加旧任务的权重,或按类别均衡采样。
落地时还要考虑训练效率。重放会增加每个批次的前向与反向计算量,生成式重放还需要额外训练生成模型。正则化方法通常只增加少量额外计算,但需要保存旧参数和重要度矩阵,参数量较大时会占用额外显存。建议先做小规模实验,比较仅重放、仅EWC和两者混合的旧任务保留率,再根据存储、隐私和推理延迟要求确定最终方案。