说实话我第一次看到这个标题的时候是带着一点怀疑点的。持续学习Continual Learning和灾难性遗忘Catastrophic Forgetting这摊子事我自己断断续续折腾了两三年试过重放、正则、蒸馏、参数隔离……哪一个不是又贵又复杂。结果你告诉我把 8 位量化拉进来让模型“笨”一点反而能把旧知识保住这不是反直觉这是想掀桌子。但把论文从头到尾读完又搭了个小实验验证了一部分结论之后我必须说这个思路确实有它成立的空间而且越品越有味道。今天我就从问题根源、方法设计、实验结果到复现注意事项把它掰开揉碎聊一遍也把我在验证过程中踩过的一些雷一并拿出来给想入坑的人做一个参考。1. 先把问题的根子挖出来持续学习为什么总被“灾难性遗忘”卡脖子1.1 从“学新忘旧”说起遗忘的数学直觉任何做过全参数微调的人应该都对这种感觉不陌生你让一个已经会识别猫的模型去学识别狗学完回头再测猫的准确率掉了。掉得还不少。这背后的数学直觉其实很朴素。我们训练一个模型本质上是在高维参数空间里找一个损失函数的低值区域。假设旧任务A的最优参数区域在参数空间里像一片盆地模型经过训练已经滚进了这个盆地。现在来新任务BB的损失函数在参数空间里有另一片盆地由于两个任务的输入分布、监督信号差异较大两片盆地的重叠部分往往非常有限。于是梯度下降的主导方向会把模型从A的盆地往B的盆地推。过程中经过的路径大概率会把A那片盆地的“关键地形”弄坏。所谓关键地形就是那些对A的损失影响非常大的参数组合。因为早期任务学到的东西通常在底层特征上有大量共享你要改它们就会影像到旧任务的高层特征于是灾难性遗忘就发生了。1.2 传统抗遗忘方案的代价为什么都那么重这么多年大家摸索出来的抗遗忘方案我按照流派大致整理了一下各有各的疼点流派代表性做法核心代价数据重放把旧任务样本缓存一部分和新任务混着训内存/存储开销大私域数据场景还得面对合规问题正则约束EWC、SI、LwF这类给重要参数戴“紧箍咒”需要额外记录重要度矩阵或生成蒸馏信号二次计算负担不轻参数隔离每个任务分一块子网络或者加Mask模型体积膨胀快对任务边界感知要求高动态扩展新任务来了就加分支、加专家推理路径变复杂训练完的部署维护也是麻烦这些方案没有一个错但它们普遍有一个共性需要你额外做很多设计要么存东西要么算重要性要么扩结构。它们本质上是“在训练流程之外加复杂的机制来对抗遗忘”所以重。这篇论文想做的事情恰恰相反。它没有往流程里加东西而是直接把模型权重的精度砍掉一截结果遗忘率反而下降了。这就有意思了。1.3 这篇论文想挑战的“知识免疫”命题论文全篇围绕着一条核心主线当模型参数被迫保持在一个“更粗糙”的表示形式上时是否会对后续任务的干扰产生一种天然的免疫能力这里用的不是那种“我往损失函数里加一项惩罚”的免疫而是“我改变参数空间的几何形状让干扰变得难以积累”。作者试图证明量化误差本身可以扮演隐式正则项的角色并且这种隐式正则的效果在很多场景下比显式加惩罚还稳。我第一次读到这里脑子里冒出的词是“钝感力”。一个人太敏感风吹草动都慌但如果你让他的神经反应阈值稍微提高一点那些无关紧要的小刺激就不会引发大的状态波动。量化干的事情就是把模型的“神经敏感度阈值”调高了。2. “少即是多”的思路从哪来量化本来是压缩工具怎么就成了抗遗忘神器2.1 量化到底做了什么从连续到离散量化本身是模型压缩里的老手艺。正常训练时权重是FP32也就是32位浮点连续取值极其细腻。8位量化简单说就是让权重只保留256个可能的取值之一如果是int8非对称可以是-128到127如果是有符号对称就是某个量化步长乘以整数索引。这个“从连续到离散”的转变丢掉的不只是精度还有一个非常关键的属性连续参数的微小扰动被抹平了。在FP32环境下一个参数的数值你可以微调到小数点后六位但int8情况下参数只能跳台阶想改一点点都做不到要么不动要么跨一个量化步长。在持续学习的语境下新任务带来的梯度信号里大量是“让参数稍微挪一点点”的微小干扰。这些干扰在FP32下会被老老实实地执行日积月累旧任务的决策边界就被一点点蚕食掉。但在int8下这些微小干扰可能落不到下一级台阶上直接就被舍入操作吞掉了相当于自动过滤掉了一大波有害更新。这个逻辑链非常漂亮。2.2 离散化为什么能“挡住”遗忘热力学与调音台两种类比我试着找了两个更生活化的类比帮我身边的朋友理解这件事。第一个类比是调音台旋钮。你把调音台上的一个高精度旋钮和一个人为做了卡扣的旋钮放在一起。高精度旋钮很流畅手一碰就会滑动一点音量的细微变化都能捕捉到。带卡扣的旋钮则不同你得花点力气越过一个阻力点它才会跳一格。持续学习时新任务就像不断有人在碰这个旋钮。少了卡扣每一次触碰都会细微地改变状态有了卡扣小扰动根本不足以让旋钮跳过卡扣只有真正靠谱的大动作才能改变最终位置。第二个类比可以参考晶体结构。多晶材料之所以比单晶材料在某些场景下更稳定是因为晶界的存在会阻碍位错运动让晶体更难发生塑性变形。量化后参数空间里的“离散台阶”就类似于晶界限制了参数被大范围推动的能力。当然类比只是为了辅助理解严谨机制还是要看实验。论文里做了一项很关键的梯度分析专门统计新任务训练前后旧任务关键权重的移动距离。结果显示8位模型参数的移动距离明显小于FP32模型说明梯度干扰确实被量化台阶“吸收”掉了。2.3 为什么偏偏是8位而不是4位、2位或者老老实实32位这个问题在论文里做了大量讨论我概括起来就是一句话8位处于“拦得住干扰又学得会新技能”的甜点区。如果位宽降得太低比如4位甚至2位模型的表达能力被砍得太狠参数可移动的空间太小新任务的信号本身也可能被量化噪声淹没。结果就是旧知识可能保住了但新任务学不会准确率双双崩盘。这属于抗遗忘抗成了“痴呆”。如果是32位模型表达能力完全OK但没有“卡扣”效果微小干扰全部会被执行遗忘照旧。8位不一样量化步长的颗粒度刚刚好小干扰被拦下真正有意义的大梯度信号仍然可以推动权重跨过台阶。而且从工程角度讲8位在现有AI芯片上往往有原生加速内存占用直接砍半属于“训练时没有额外重开销、推理时免费拿加速”的甜点位。这里还衍生出一个思考既然8位效果这么好是不是训练完部署时转8位就够了论文的观点是关键不在推理时是不是8位而在于整个训练更新过程都在8位参数空间里进行。因为只有在训练期间发生了“更新被量化台阶吸收”这个过程抗遗忘效果才会被刻进参数更新的历史里。你训练完再去量化那只是压缩表示并没有重塑优化路径抗遗忘增益自然出不来。2.4 与现有抗遗忘方法的本质区别隐式正则vs 显式约束我们来对比一个最流行的正则派代表EWC弹性权重巩固。EWC的思路是在损失函数上加一项惩罚限制那些对旧任务重要的参数不要大幅度更新。它需要计算Fisher信息矩阵而且超参惩罚强度λ调到多少是个玄学。量化方法的思路完全变了。它不告诉你“哪些参数重要”而是用离散台阶“惩罚一切微小更新”。EWC是显式、有方向性的约束量化是隐式、无差别的作用于所有参数。后者的好处是省心不用算重要度也几乎不需要新引入超参深度是用8位这件事本身就是那个超参。论文里也做了组合实验把量化与EWC叠在一起效果更好说明它的作用机理与现有方法是正交的。你可以在MML多任务学习或内存受限的持续学习场景里把它当成一个免费的“增强器”在有现有抗遗忘方案的基础上直接叠加它并不抢谁的饭碗更像是往轮子上涂了一层额外的稳定剂。3. 论文方法拆解量化到底怎么嵌进持续学习流程3.1 整体框架训练-量化-更新的三角关系复原一下论文的核心流程设计。假设我们有一个持续学习管线任务序列是Task 1 → Task 2 → Task 3 ... 每个任务到达时模型拿到的训练数据只属于这个新任务。在普通微调场景下流程是加载旧权重FP32 → 前向传播算损失 → 反向传播算梯度 → 更新权重。新任务数据一来梯度放行所有更新旧知识被冲散。在论文的方法里流程改成了加载旧权重 → 先量化fake quant后面细说 → 在量化后的权重表示上前向传播 → 反向传播时梯度经过量化器做近似直通 → 更新量化后的权重整数索引。这个流程里最核心的改动是模型的“工作状态”永远不是一个高精度的连续值而是一个离散的、被约束在8位阶梯上的权重。当你把整个更新过程都固定在离散参数空间里微小的梯度干扰自然无法改变整数索引于是旧任务的关键权重位置被“钉住”了。3.2 关键组件伪量化、直通估计器与量化范围实操层面你不可能真的在每一步都把权重复制一份低精度版本再来回转换常规做法是伪量化fake quantization。伪量化做的事情是前向传播时把高精度权重先量化再反量化即先映射到整数格点上再映射回浮点数。这样数值上你已经模拟了低精度效果但张量还是FP32容器在传。反向传播时因为量化器的导数几乎处处为0直接用链式法则会梯度消失所以要用直通估计器STE把量化器的梯度当成恒等映射让梯度顺利流过。这一段非常多新手会搞错我再强调一遍你为了做持续学习为了提升遗忘抗性不需要把模型真正导出成int8训练过程只要用伪量化让梯度能传同时让权重被“钉”在离散格点上就已经达到抗遗忘的目的了。量化范围也很有讲究。论文采取的是逐层per-tensor计算量化范围scale和zero_point并且每隔一定步数更新一次。更新的频率不能太高也不能太低太高的话量化格点自己也在漂移旧任务知识反而随着格点移动被破坏太低的话新任务的有效表达范围可能不足。经验做法是每个batch更新一次min/max统计量但训练若干步后再重新计算一次全局范围这里需要结合自己任务调。3.3 实验设计与评价指标准确率、遗忘率、后向迁移论文的标准实验配置我按常见的持续学习评估框架来讲。数据集方面采用了三个场景Split CIFAR-100100类分成10个任务、Split Tiny-ImageNet、以及跨域的5-Datasets类似CIFAR、SVHN、FashionMNIST这类跨域拼接的场景。三类场景分别测试了同域增量、细粒度增量、跨域增量下的适应性。评价指标这边用了三个指标计算方式含义ACC平均准确率所有任务学习完后对所有已学任务的平均测试准确率总体“学了多少”BWT后向迁移新任务训练前后旧任务准确率的平均变化负数越大遗忘越严重FGT遗忘度各任务学习到顶点时准确率与最终准确率之差的平均专门量化“忘掉多少”这些指标里最终看的是FGT和BWT因为它们才真正反映了抗遗忘性能。ACC反而是次要的因为一个完全不学新东西的模型可以保持上一个任务的ACC很高但后续任务学不会所以只看ACC会误导。3.4 核心结果几位量化带来的增益有多大先上结论论文报告在无重放no-replay设置下8位量化让遗忘度相对FP32模型平均下降了30%以上且平均准确率没有明显下降个别场景还反向提升了一点点。我当时看这些数字第一反应是会不会是量化让模型变笨笨到把旧任务过拟合的东西忘不掉新任务也没学好所以整体指标“看起来还行”仔细看实验细节发现不是这样。新任务的学习效果没有崩准确率与FP32基本持平同时旧任务保留度明显上升。这说明8位量化既没有阻碍新知识吸收又保住了旧知识。更刺激的是论文把8位量化与重放方法Experience Replay做了对比在只保留极小样本缓冲区的情况下量化方法的遗忘率居然低于重放基线。我知道这个结论争议会很大毕竟重放是工程上最有效的手段之一。论文自己也说了这不代表量化可以完全替代重放但在一些无法缓存样本的场景比如隐私敏感数据量化提供了一个零存储开销的替代方案。3.5 消融实验给我们的启示位宽背后的敏感性看一篇论文不能只看主结果消融实验才是理解作者思路的钥匙。他们的消融实验做了几个关键切片8位 vs 4位 vs 2位 vs FP32结果显示4位遗忘度更低但新任务的准确率明显掉2位直接学不动。8位是在“学习能力”和“遗忘抗性”之间平衡最好的点。量化范围更新频率范围更新太频繁抗遗忘效果反而下降适度更新频率效果最优。这说明量化格点的“静止”本身就是一种记忆锚点频繁变动等于刷新记忆。量化粒度per-channel量化比per-tensor效果更好因为每个通道有独立步长更贴合权重分布。虽然per-tensor实现简单但在持续学习场景里有一点精度损失。是否在训练时量化只做推理时量化抗遗忘效果消失训练时全程伪量化抗遗忘效果出现。这条前面说过是理解方法机制的关键。这些消融实验等于把机制掰开揉碎了给我们看量化抗遗忘的核心不在于最终权重必须存成低比特格式而在于训练过程中的参数空间离散化。4. 复现视角把论文思路落到自己项目里要注意的几件事4.1 伪量化在训练流程里的正确插法如果你像我一样想快速验证这篇论文的想法不用重头写量化器。在PyTorch里可以直接用torch.ao.quantization下面FakeQuantize或者直接手写一个简单的伪量化层原理并不复杂。伪代码思路大概是class FakeQuantize(torch.nn.Module): def __init__(self, bits8): super().__init__() self.quant_min -(2 ** (bits - 1)) self.quant_max 2 ** (bits - 1) - 1 def forward(self, x): scale x.abs().max() / self.quant_max x_q torch.clamp(torch.round(x / scale), self.quant_min, self.quant_max) x_dq x_q * scale return x_dq实际用的时候别抄这个极简版因为你还要处理zero_point非对称量化、梯度往返、截断处理等问题。我建议直接看PyTorch官方QAT文档里默认的FakeQuantize实现够用。嵌入位置也有讲究论文的做法是只对线性层和卷积层的权重做伪量化BatchNorm参数和偏置保持FP32。这很合理因为BatchNorm里的均值和方差是统计量不适合做离散化偏置的维度小量化颗粒粗反而会让输出飘移。4.2 评测协议别踩“任务标签泄露”的坑持续学习评测里最容易翻车的不是模型而是评测协议。很多人复现论文时“效果很好”但其实是任务标签泄露了。常见的泄露方式有三种你们自查一下评测时每个task的测试集分开测但模型知道当前任务是哪个网络结构里还带了task embedding。训练时虽然只给了新任务样本但样本顺序或数目被打上了旧任务的标签被模型当成辅助信息用。BatchNorm统计量直接跨任务更新把旧任务均值方差信息带到了新任务训练中。论文实验采取的协议是task-incremental的标准声明训练时知道任务边界测试时也提供任务ID但没有跨任务共享任何信息。复现时建议把协议写死并且每轮评测都跑全部旧任务不要只抽一个任务来测否则BWT算不出来。4.3 资源占用与工程化收益内存减半只是起步说点实际的好处。持续学习场景里模型规模一大了部署迭代也头疼。如果你使用8位量化训练模型权重占用的内存直接减半。对于要长期维护一个持续学习系统的团队来说这意味着一层额外的红利你为抗遗忘所做的改变顺便带来了推理速度和存储成本的优化。另外一点量化后的权重更接近部署环境。很多团队最终要把模型量化成int8部署到端侧过去是训练完FP32再离线量化现在如果你直接用8位训练把模型状态“驯化”好了离线量化时的精度损失会小很多。这个收益虽然是附带的但在生产环境里非常实际。5. 我踩过的坑与排查清单5.1 4位量化直接崩盘不是所有低比特都是朋友我最初做验证实验时顺手测了4位量化理由是“既然8位有效4位应该更有效吧”。结果毫不意外地崩了新任务准确率掉到接近随机旧任务保住了但没有任何实际意义。排查后发现问题出在表达空间太小。4位只有16个量化格点可供权重跳动这个步长太大模型在高维空间里根本找不到一个能同时拟合新旧任务的解。不过后来我把困惑跟一位做量化的朋友聊了一下他说4位实际上需要配合更复杂的量化范围学习或者混合精度分配才有救这已经完全超出论文的讨论范围了。论文之所以定在8位本质上是在“遗忘抗性”和“学习能力”之间找到了一个临界点。这是复现时最需要注意的心理陷阱你可能会觉得“少即是多”可以无限外推多降几位效果更好但8位这个甜点位不是随便选的它是实验推出来的。5.2 忘记处理量化范围更新的时机慢性遗忘的元凶另一个坑更隐蔽。我最初复现时每个batch都重新统计激活和权重的min/max并更新量化范围。结果抗遗忘效果很不稳定有些任务序列表现正常有些序列旧任务掉点特别快像得了慢性遗忘。苦查了很久才反应过来量化范围太频繁地更新会让离散格点整体漂移。以极端的例子来说如果格点范围跟着新任务数据整体移动了那旧任务知识无论怎么被“钉住”它的数值坐标也已经被平移了。量化范围本身也是记忆的一部分动得太勤等于把锚点拆了重摆。论文的做法在损失函数上做了温和处理但更稳妥的工程方案是每隔一定步数比如几百步才更新一次量化范围训练开始时从一个大致范围估计出发。这不是什么高深技巧但对复现效果影响极大值得留意。5.3 评测指标口径不统一BWT、FGT一片混乱这是纯经验型的坑。有很多论文里BWT的定义略有不同有的按末次任务后对所有旧任务的准确率变化平均有的按任务切换时每个时刻的变化累计做平均。如果不统一口径复现结果跟论文数字对不上会严重怀疑自己的实现。我的建议是复现任何持续学习方向的项目先把论文里的指标公式抄下来再自己写一个独立脚本单独实现指标计算。不要直接拿别人的开源评估代码因为你不知道它用的是哪个口径。等自己的结果能复现论文的趋势比如8位优于FP32且趋势稳定再慢慢把口径对齐。这比一开始就追求数字一模一样要高效得多。最后再补充一个小技巧。做持续学习实验时记得固定随机种子以稳定任务序列这非常重要。持续学习对任务到达顺序极其敏感同一个模型任务A先来还是任务B先来最终性能差别可能非常大。用8位量化做持续学习这个思路最大的价值在于它提醒我们抗遗忘不一定要靠增加机制来达成适当“让模型变钝一点”也可以关键是要找对钝感的位置和程度。这套方法目前最适用的场景依旧是那些内存紧张、样本存储受限或者对隐私高度敏感的持续学习任务尤其是当你根本没有余力把旧数据搬回来重放的时候量化提供的这条“零成本防线”会显得格外香。如果你们也想在项目里验证我建议先挑一个最简单的持续学习基准比如Split MNIST用PyTorch手写一个伪量化层挂到全连接层上跑一遍。整个流程下来几千步就能感受到8位量化和FP32在遗忘曲线上明显的“高度差”。这种亲眼看到差距的体验比读一百遍论文都管用。