目前我的研究方向是持续学习。本文汇总了持续学习的基础知识体系,可以看作一篇综述吧,希望这篇笔记能带你进入我的研究领域。本文涉及的方法都是我觉得有代表性的,只介绍思想,不会非常详细地讲细节。
目录
一、相关概念
持续学习(Continual Learning, CL)是多个任务的机器学习的一种学习范式。持续学习又称终身学习(Lifelong Learning)、序列学习(Sequential Learning),终身学习的概念很早就提出了,进入深度学习时代后研究者逐渐改叫持续学习;还有人把持续学习叫做增量学习(Incremental Learning)。
持续学习从大面来说定义为:多个任务数据依次交付给持续学习算法学习(每次只有当前任务数据),使得最终学到的模型能够胜任所有任务。“依次”和“所有”是持续学习的核心,缺一者就与只有单任务的机器学习无差别了:
- 缺“依次”:每次算法能用之前所有任务数据学习,则最后一个任务时就能学习所有任务,就不“持续”了。在实际场景中,旧数据主要是由于存储限制或隐私保护等原因而不可用的。
- 缺“所有”:若不要求在所有任务上表现都好(例:只要求当前任务),则就是当前任务的单任务的机器学习。
另外,持续学习也不允许每个任务都单独学习一个独立的模型,这样相当于多个单任务的机器学习。这种称为独立式学习(isloated learning)。(参考下面讲解的模型容量分配问题)
持续学习与其他学习范式的主要区别如下,
- 在线学习:数据都是同一个任务来的,一定是独立同分布的;持续学习划出多个任务,数据不一定(不是一定不,但通常不是)是独立同分布的。且它的研究重点是“在线”与“离线”的区别;
- 迁移学习:重点关注的是“迁移”——如何利用旧任务的学习成果帮助新任务的学习;
- 多任务学习:数据是一次给完的,强调同时学习多个任务;
- 元学习:“学会学习”的角度更高,不只关注如何解决当前所有任务,还试图提取学习经验,泛化到新的任务。
二、持续学习关心的问题
以下先从较抽象的角度介绍持续学习关心的问题,之后再给出形式化定义和具体的例子。
灾难性遗忘
上面已经说过,在持续学习中,使用新任务数据训练模型使其在该新任务上效果好,是很容易做到的,只需应用成熟的单任务机器学习的算法即可;相反,很多时候学习新任务后,模型在旧任务上的效果会变差,这就是灾难性遗忘(Catastrophic Forgetting, CF),也是持续学习关心的核心问题。
灾难性遗忘是神经网络模型固有的特性,实际上是不能完全解决掉的,只要用的神经网络。可以这样的简单地理解:它们的信息是记在网络参数中的,学习新任务后,就会覆盖之前的参数。但我们仍然可以缓解这一问题,方法就是引入防遗忘机制,使模型保持旧任务上的效果。设计各种防遗忘机制也是持续学习的主要目标。
从“哲学”上来说,假设模型的学习能力是固定的,模型在新任务上效果好,则在旧任务上效果会变差;反之,模型保持了旧任务上的效果,则在新任务上效果就不会好。前者是模型学习新知识的能力,称为可塑性(plasticity);后者是旧知识的记忆能力,称为稳定性(stability)。可塑性与稳定性是内在相互矛盾的,术语叫可塑性-稳定性困境(Stability-Plasticity Dilemma),这是机器学习的一个天然的哲学约束,类似于 “没有免费午餐定理”。持续学习的目标是在所有任务上表现都好,即同时追求可塑性和稳定性;但这个困境说明了实现这一目标没有捷径,持续学习场景不是伪命题,并不是无脑加防遗忘机制、加强防遗忘的力度(例如调大防遗忘正则项超参数)就可以了,必须切实地提高模型的真本领。
后向迁移与前向迁移
除了灾难性遗忘作为核心问题,持续学习还关心算法是否具备:
- 后向迁移(backward transfer)能力:学习后面的任务时,能否帮助到前面的任务;
- 前向迁移(forward transfer)能力:学习前面的任务时,能否帮助到后面的任务。
请注意用词:在后向迁移和前向迁移术语中,“前”是指旧任务方向,“后”是指新任务方向。而我平时习惯说“后”是指新任务。
拥有后向迁移能力是比克服灾难性遗忘还要厉害的事情。克服灾难性遗忘仅仅是学习后面的任务不会给前面的任务帮倒忙,而后向迁移还要求能帮正忙。按照我的理解,后向迁移能力与灾难性遗忘是同一种能力的两种程度。
拥有前向迁移能力意味着,在还没有见到要学习的任务时,就已经在积累该任务的知识,并且在训练该任务时用到。由于没有该任务的信息,这种能力也是最难拥有的,目前持续学习的研究基本无法触碰这个话题。
模型容量分配问题
持续学习的一大特点是学习任务的类型和数量没有预定义。在学习每个任务的期间,永远不知道未来有多少个任务、它们是什么样子的。对于之前所说的“独立式学习”(每个任务学习一个独立的模型,其模型大小随任务量线性地增加),模型尝试学习、记下每个任务所有的知识,对应的算法也是与普通机器学习没有差别,是持续学习不允许的。
我们不希望模型大小无序地膨胀,而是固定模型容量(capacity),让算法在固定容量的模型下完成持续学习(偶尔也会允许少量的膨胀)。(这里所说的模型容量更多的是一个抽象概念,指模型的表示能力。当然,对于深度学习,模型的表示能力也与参数量成正相关。)
很显然,固定容量的模型,随着任务越来越多,模型也不能容纳所有的知识,会出现模型容量饱和(capacity saturation)问题。知识必须有所舍弃,各任务上的效果也会打折扣,遗忘也就越严重。
由于深度学习基于的是参数化的神经网络模型,这个问题是不可能解决的,因为参数是会被覆写的,模型的表示能力是有限的。目前持续学习的研究致力于缓解这个问题,而不是彻底解决它。一个好的持续学习算法能让模型尽量记住任务重要的知识,在需要舍弃知识时舍弃不重要的,减少模型表示上的重叠或冗余,从而减缓遗忘的速度。
在持续学习中,每个任务会占据模型的一部分容量,任务之间也会共用部分容量(根据任务相似的程度)。但是如果不加限制,每个任务学习后就会很自然地占满所有模型容量,这样不仅容易导致任务的过拟合(因为通常适合持续学习多个任务的模型要比适合某个任务的模型要大很多),也让后面的(与该任务不太相似的)任务无处占据模型容量,导致后面的任务效果都变差。所以,需要在算法中加入一些稀疏化(sparsity)机制来解决模型容量不够的问题。我们在下面的参数隔离方法中可以显式地看到这方面的研究。
三、任务:分类问题
持续学习也分监督学习、无监督学习等,也有判别模型、生成模型。目前大家研究最多的是监督学习,且更多地关心分类问题。本文只讨论分类问题。
在分类问题中,持续学习场景按照如下两个分类维度划分:
- 任务类别是否相同:有所有任务完全相同的、完全不相同的(每个任务来的都是新类),也有既有相同也有不相同的;
- 数据是否包含任务 ID:任务 ID 是指数据来自第几个任务的“几”。分训练数据与测试数据讨论:
- 训练数据与测试数据都有任务 ID 信息:在测试时知道数据来自第几个任务;
- 训练数据有任务 ID 信息,测试数据没有:在测试时不知道数据来自第几个任务,这样需要算法能够自行显式或隐式地判断任务 ID,更加困难;
- 训练数据与测试数据都没有任务 ID 信息:没有任务 ID 信息就是没有明确的任务边界(task boundary),数据随任务是流式地进入算法的。
根据此分类,某些常见场景有习惯性叫法:
- 类别增量学习(Class Incremental Learning, CIL):每个任务包含若干不重复的类别,训练数据有而测试数据没有任务 ID 信息;
- 任务增量学习(Task Incremental Learning, TIL):训练数据与测试数据都有任务 ID 信息,对任务类别是否相同无要求;
- 领域增量学习(Domain Incremental Learning, DIL):从形式上看,只有“每个任务包含的类别相同”一个要求。但它强调的是每个任务的具体数据集中数据输入 \(\mathbf{x}\) 领域的不同。
形式化定义
下面给出几个场景的形式化定义。设有任务 \(t=1,2,\cdots\),每个任务的数据集为 \(\mathcal{D}^{(t)}\),其中 \(\mathcal{D}^{(t)} =\{(\mathbf{x}_i,y_i)\}_{i=1}^{N_t} \in (\mathcal{X}^{(t)},\mathcal{Y}^{(t)})\)。算法在每个时刻 \(t\) 利用 \(\mathcal{D}^{(t)}\) 将 \(f^{(t-1)}\) 更新 \(f^{(t)}\),希望 \(f^{(t)}\) 能完成目前涉及到的所有分类任务,即输入 \(\mathbf{x} \in \mathcal{X}^{(1)}\cup\cdots\cup\mathcal{X}^{(t)}\),输出所有涉及到的类别 \(\hat{y} \in \mathcal{Y}^{(1)}\cup \cdots \cup \mathcal{Y}^{(t)}\)。
- 类别增量学习:\(\mathcal{Y}^{(t)}\) 之间互不相交。可以记 \(\mathcal{Y}_1 = \{C_1,\cdots,C_{k_1}\}, \mathcal{Y}_2 = \{C_{k_1 + 1}, \cdots, C_{k_2}\}, \cdots\);
- 任务增量学习:知道了输入的任务 ID \(t_{\mathbf{x}}\),即目标简化为输入 \(\mathbf{x}\in \mathcal{X}^{(t_\mathbf{x})}\),输出 \(\hat{y} \in \mathcal{Y}^{(t_\mathbf{x})}\);
- 领域增量学习:\(\mathcal{Y}^{(1)}=\cdots=\mathcal{Y}^{(t)}\),但强调 \(\mathcal{X}^{(1)},\cdots,\mathcal{X}^{(t)}\) 的不同。
一定要强调上面加粗的“所有”二字,这对理解 TIL 与 CIL 的区别非常关键。对于 CIL,很多人的误区是以为任务 \(t\) 训练时只在 \(\mathcal{Y}^{(t)}\) 中分类就可以了,而事实是在 \(\mathcal{Y}^{(1)}\cup\cdots\cup\mathcal{Y}^{(t)}\) 中分类(就是下图多头模型有无灰色箭头的区别),也就是说训练任务越来越难,成包含关系。所以 CIL 场景是比 TIL 场景要困难不少的。
注意点:
- 之前说过,持续学习过程中永远不知道之后有多少个任务。但在实际实验中,持续学习数据集是固定的,总任务数是固定的 \(T\) 个(也为了计算指标方便),以上 \(t=1,\cdots,T\),但是持续学习算法在任何时刻都禁止使用 \(T\) 这个信息。
- CIL 第一个任务至少要包含 2 个类,之后的任务没有限制。
与其他学习范式在具体定义上的区别可以参考下图1,不再详述:
Baseline:多头模型
对于非每个任务类别相同的场景,类是越来越多的。而且系统不知道未来有哪些类,无法在一开始就把所有类包括进来,构造出输出头固定的分类器;只能每当出现新类,临时加入该类的输出头。
所谓的多头模型是指模型的主要部分(特征提取器 \(\varphi\))由各任务共用,但输出端不固定,随着新类别的引入,随时会引入新的输出头。因此模型参数会包含共享参数和类别独有的参数两部分,后者的比例应该是非常小的,所以即使它的数量线性增长问题也不大,是允许的。
下面介绍以多头模型为基础的持续学习最简单的算法,算是所有持续学习算法的 baseline。
微调算法
最简单的学习方式,并不是每个新任务都从头开始训练,而是用上一个任务的训练结果作为下一个任务的初始化。具体来说,上图模型参数分为网络共享权重 \(\mathbf{w}_0\) 和每个类别独有的权重 \(\mathbf{w}_1,\mathbf{w}_2,\cdots\)。每遇到新类别都会引入新的 \(\mathbf{w}_i\),都作(随机)初始化。\(\mathbf{w}_0\) 在算法的最开始(随机)初始化,且在每个时刻 \(\mathbf{w}^{(t)}_0\) 都会用 \(\mathbf{w}^{(t-1)}_0\) 初始化。
这个算法在持续学习论文里习惯叫做微调(fine-tuning),因为直接拿上一个任务初始化的方式有微调上一个任务的意思。直观上看这种方式直接覆盖了上个任务的成果,重新把所有的模型容量让新任务占满,很容易灾难性遗忘。(尽管有类别独有的参数能防止遗忘,但它们占的比例太小,起的作用是远远不够的。)因此这个算法可以认为没有任何防遗忘机制,是一个白板算法,大家研究的持续学习算法都是在其基础上引入自己的防遗忘机制的。
下图2描述了持续学习算法与微调白板模型参数更新路径的对比,图中展示的是参数空间,上面的点是参数,两个圈分别代表任务 1、任务 2 的分类损失函数(等高线)。训练任务 1 后参数位于右上方点,在训练任务 2 时,采用微调白板算法参数会直接更新到左上方点,而采用有防遗忘机制的持续学习算法(图中为 OWM)会更新到下方点。
需要注意的是,对于 CIL 这样的新任务中没有旧类的场景,由于没有旧类数据作为起对照作用的负样本,微调算法学到的模型一定会将所有输入预测为最后一个任务的类,导致旧任务不仅全部忘掉,还会使其准确率降为0(此时的遗忘,真的称得上是“灾难性”了)。所以这个微调算法只对不会出现新类的 TIL 场景有意义,对 CIL 是没有任何效果的。事实上,即使独立式学习也无法解决 CIL 场景。对 CIL,必须加入一定的防遗忘机制。
固定特征提取器
固定特征提取器走了另一个极端,在第一个任务训练结束后,特征提取器再也不动,遇到新任务时就只更新对应类别的输出头。这样固然不会忘记第一个任务,但是会导致后面的任务知识无法被学到(因为输出头的表示能力是不够的),最终导致第一个任务准确率很高,之后的任务很低,实际上和微调模型效果是类似的。
数据集
持续学习分类问题的常用数据集是通过机器学习的标准数据集划分、构造出来的。标准数据集例如常用的 MNIST、CIFAR、ImageNet 等。划分方式主要有两种:
- 分割(split):按照类别划分数据集为任务,用于 CIL;
- 置换(permute):对原数据集所有数据做一次相同的变换,得到一个任务,可以用于 TIL、DIL 等每个任务类别相同的场景。
以 MNIST 为例,可以构造 Split MNIST、Permuted MNIST 两种数据集。Split MNIST 按类别划分成(以 5 个任务为例)0v1, 2v3, 4v5, 6v7, 8v9;Permuted MNIST 每构造一个任务时就按相同方式打乱各图片像素的顺序。
四、持续学习的指标
总体指标
持续学习的主要目标是让模型在所有任务上表现都好,因此持续学习的指标首先是各任务平均指标,其次关注其他关心问题上的表现,如后向迁移能力、前向迁移能力。这些指标都是持续学习过程训练的各模型在各任务上的单个指标计算出来的1:记 \(R_{\tau,t}\) 表示时刻 \(\tau\) 训出的模型在第 \(t\) 个任务上的指标(例,对分类问题是准确率),注意每个任务都有自己的测试集 \(\mathcal{D}^{(t)}_{test}\),\(R_{\tau,t}\) 是用 \(\mathcal{D}^{(t)}_{test}\) 做测试的。可以得到以下总体指标:
- 各任务平均指标
- \(ACC = \frac1T \sum_{t=1}^T R_{T,t}\),即最后得到的模型在所有任务上的平均表现;
- 平均后向迁移
- \(BWT = \frac1{T-1} \sum_{t=1}^{T-1} (R_{T,t}- R_{t,t})\),即任务刚开始学(\(t\) 时刻)与学到最后(\(T\) 时刻)效果之差,对所有非最后一个任务取平均。这个指标只衡量了最后一个任务的后向迁移情况。
- 平均后向迁移指标可正可负。若为负,则代表没有后向迁移能力。
- 平均前向迁移
- \(FWT = \frac1{T-1} \sum_{t=1}^{T-1} (R_{t-1,t} - \bar{b}_t)\)。\(\bar{b}_t\) 是随机初始化并用 \(\mathcal{D}_t\) 训练的模型效果(多次实验取平均),有点 \(R_{0,t}\) 的意思,但不太一样。指标表示到在任务刚开始学但还没有学(\(t-1\) 时刻)期间累积的知识(比较的对象是不使用 \(\mathcal{D}_1,\cdots, \mathcal{D}_{t-1}\) 前向迁移的知识、而只使用 \(\mathcal{D}_t\) 自己知识的结果 \(\bar{b}_t\)),对所有非第一个任务取平均。
- 平均后前向迁移指标可正可负。若为负,则代表没有前向迁移能力。
各任务平均指标有上界:将所有任务一起学习的指标,或各任务独立式学习的指标。
第一个指标的定义方式是公认的,后两者可能还有待探索。举个例子,FWT 中的 \(R_{t-1,t}\) 在 CIL 场景下是无法计算的,因为在 \(t-1\) 时刻压根就没有 \(t\) 时刻新出现的类别,FWT 需要另外定义。
以上指标都是以任务为单位作算数平均计算出来的,通常要求任务划分得比较均衡(事实上多数数据集是这样的,例如 CIL 每个任务的类数量相等),否则最好根据任务规模/难易加权平均,例如有些文章使用调和平均(harmonic mean)。还有的指标转而以类别为单位算平均。
曲线图
在持续学习实验中,最常见的观察对象是 \(R_{T,t}\)(横坐标为 \(t \in 1:T\)),即最后学到的模型在各任务上的指标折线图。这个图相当于总体指标 ACC 的展开,更加具体:曲线越高,效果越好。
还有一种是 \(R_{t,t0}\)(横坐标为 \(t \in t_0:T\),\(t_0\) 一般为第一个任务),即某个任务学习后,继续学习其他的任务对它的影响,也能反映遗忘的程度:下降得越慢,说明防遗忘效果越好。
还有人会观察总体指标随 \(T\) 的变化曲线。也就是说,测试过程通常是每训练完一个新任务就对已涉及的所有任务测试一遍。
训练过程中的学习曲线
在训练过程中需要监视学习曲线,持续学习有多个任务,就有多个独立的学习曲线(下图对角线上的图)。但持续学习的目标不只是让当前任务学好,更关注是否会灾难性遗忘,所以还需要监视模型在旧任务上的表现,于是得到更多的学习曲线(下图对角线上方的图)。下图是一个例子,来自持续学习算法 EWC 论文[^footnote EWC],我暂且称为 “三角图”:
注意这些图画的是模型于各训练阶段在整个测试集上的表现。为了画这张图,需要每隔一段时间(横坐标单位)就做一次完整的测试,其实很耗时间,但这时间不是算在训练时间内的,无所谓。
一个好的持续学习算法应当在任务切换后(并不是瞬间)在旧任务上效果不变差太快,例如图中对任务 A,在训练结束切换至 B 时,准确率曲线 EWC 几乎不下降,而不加防遗忘机制的 SGD 就会迅速下降,说明 EWC 防遗忘性能比较优秀。
其他
分类问题常常讨论混淆矩阵,它实际上是准确率的展开,反映了哪些类分对、分错。对于所有任务类别相同的 TIL 场景,可以画每个任务的混淆矩阵;但多用于 CIL 场景,因为可以把所有任务画在一个矩阵里。以下是一个例子,来自持续学习算法 iCaRL 论文:
五、防遗忘机制概论
目前防遗忘机制可以概括为几类:重演数据法、正则化法、梯度操控法、网络结构法。(注意它们并不是互斥关系,持续学习算法可以结合多种防遗忘机制。)下面我将展开讨论每种机制的原理并介绍代表算法。在开始之前,首先说一下防遗忘机制有的共同元素。
持续学习算法防止遗忘不是凭空的,总是要记住一些旧任务的知识或信息。持续学习算法一般都有一个对象在随新任务的到来不断地积累知识或信息,这个对象统称为记忆(memory),记为 \(\mathcal{M}\)。这个记忆当然也是有限制的:
- 当然不能记下旧任务的所有训练数据,否则就变成了多任务学习,这种情况是坚决不允许的;
- 但记下旧任务训练的整个模型,如果它们不是直接用于测试,在目前持续学习的研究中,也是被允许的,因为从逻辑上讲这不构成独立式学习。
持续学习算法的记忆存的信息是多样的,例如在重演数据法中存的是旧任务的部分数据,在其他方法中存的有梯度、mask 等非数据信息。相比于存整个数据,这种信息往往可以忽略不计,即使随任务数线性增加也没有关系。即使是存一个任务的整个模型,也比存整个数据小得多。
来新任务时:
- 如何在新任务上使用旧任务的记忆;
- 如何迭代地积累新任务的知识; 是大部分防遗忘机制的设计要素,下面介绍各算法时也主要说清楚这两点就可以了。
在防遗忘机制中,通常有一个支配防遗忘程度的超参数可供人工调节,例如正则化法中的正则项系数。介绍算法是也会额外指出这个算法中调节防遗忘程度的超参数是什么。
重演数据法
防止遗忘最直接的方式是在记忆中旧任务的训练数据,称为重演(replay 或 experience replay)数据。此时这块记忆通常称为情节记忆(episodic memory,模仿心理学术语)。
由于存的是数据本身,占用的空间是巨大的,记忆容量需要有更严格的限制,因此此方法一定要涉及记忆空间的管理,通常需要考虑如何选择有代表性的重演样本、空间不够时如何舍弃等问题。受记忆空间的限制,重演数据与真实训练数据相比太少,是重演数据法面临的主要问题。
对应地,重演数据法的两个设计要素是:
- 如何在新任务上使用重演数据;
- 如何选择或构造重演数据,重演数据空间如何管理。
iCaRL
iCaRL1 是最早提出的重演数据法,也是 CIL 场景的最经典的算法。它只适用于 CIL 场景。
非参数分类器
上文说过,微调模型不适用于 CIL 场景,因为缺少旧任务的负样本。这主要影响的其实不是特征提取器,而是分类器。微调模型的分类器是带参数的一层网络,缺少负样本会让正样本对应的权重尽可能大,负样本权重尽可能小。因此,改成非参数的分类器,是解决问题的一种方法。
在介绍之前,首先提一个关于神经网络的事实——最后一层作为线性层的分类器学习到的权重向量 \(\mathbf{w}_k\)(与特征维度一致)可以作为特征空间上该类 \(k\) 的代表点,或者叫原型(prototype)。道理比较简单(但是没见过的话不一定会想到),因为对于训练数据 \((\mathbf{x}, y=k)\),交叉熵损失函数是让 \(\phi(\mathbf{x})\) 与 \(\mathbf{w}_k\) 的内积尽量为 1,也就是说让 \(\mathbf{w}_k\) 尽量与见过的训练数据 \(\mathbf{x} \in \mathcal{D}_{train}\) 相等。因此,普通的线性层分类器测试时就是在比较 \(\phi(\mathbf{x})\) 与哪个原型 \(\mathbf{w}_k\) 内积更大(更接近),因此可以看成一种原型最近邻分类器,只不过这些原型是可学习的参数。
iCaRL 使用的是非参数的原型最近邻分类器,原型不是通过反向传播算法学习出来的,而是在 t 任务时直接使用该任务类的训练样本的均值作为原型。这种非参数分类器的坏处是,特征提取器无法与它一起训练(它没有参数,梯度流受阻),因此 iCaRL 采取的策略是训练时用参数分类器(它只是为了训练特征提取器),测试时改用非参数分类器。
重演数据
上面的设计只是间接地规避了没有负样本给训练带来的“逻辑”错误,不能看作一种防遗忘机制。缺少旧任务的负样本仍然是事实,是导致灾难性遗忘的原因。重演数据就是用于填补缺少的负样本。
- 重演数据的使用方法
- 可以简单地将其看做普通的训练数据,混到新任务数据中一起训练。iCaRL 采取了另一种方式:对重演数据使用的不是真实标签,而是通过上一个任务模型预测的蒸馏标签(准确来说,是得分)。在新任务训练开始前,先计算出蒸馏得分,再将它与新任务得分(全 0)拼起来作为重演数据交叉熵损失的参考对象。
用蒸馏得分的原因是,它比标签更容易保存低频信息。
- 重演数据的选择与空间管理
- 重演数据选择的逻辑是,离原型(均值)越近的越有代表性,因此选择的是(在特征空间上)离原型最近的前若干个点(注:原文有些许差别,但这里为了方便不计较了)。本文也要求重演数据的总量固定为 K,每个旧任务平均分配这个空间:一开始第一个任务占据了所有 K 个,之后第二个任务占据 K/2 个,第一个任务则舍弃掉 K/2 个(依据的也是离原型的远近),不需要重新选择;以此类推。记忆容量 K 是此算法唯一调节防遗忘程度的超参数。
正则化法
正则化法是对损失函数下手,对任务 \(t\) 的分类损失函数加防遗忘正则项,引导训练过程考虑防遗忘。
防遗忘正则项不是普通的深度学习正则项,例如 L2 正则项等,因为这种正则项不包含旧任务的任何信息,只是漫无目的地防遗忘,而不是防止特定旧任务的遗忘。(EWC 论文中讨论过它们的效果差异,可以参考)
正则项不能直接是旧任务的损失函数(因为无法获取旧任务的数据),而是某种代理损失(proxy loss)。引导的方向不同,就导致了不同的正则化法。
\[\min_{\theta} L^{(t)}(\theta) = L_{FINETUNE}^{(t)}(\theta) + \lambda L_{REVIEW}^{(t)}(\theta)\]其中 \(\theta\) 指代持续学习的所有参数;\(L_{FINETUNE}^{(t)}(\theta) = \sum_{(\mathbf{x},y)\in \mathcal{D}_{train}^{(t)}} L(f(\mathbf{x};\theta),y)\) 即任务 \(t\) 正常的分类损失;\(L^{(t)}_{REVIEW}(\theta)\) 是需要设计的防遗忘正则项。这里调节防遗忘程度的超参数是正则化系数 \(\lambda\)。
防遗忘正则项的构造方式有很多,可以是来自旧任务的各种信息,此时记忆存储的就是这些用于构造防遗忘正则项的信息。记忆这些信息的空间代价往往比重演数据要小很多。
正则项的构造甚至可以用重演数据构造,但一般把使用重演数据的归为重演数据法。例如 iCaRL 中的重演数据用于蒸馏损失,其实本质上就是正则项。
LwF
LwF(Learning without Forgetting)1是一个非常简单的防遗忘机制:在任务 t 训练开始前,先让任务 t 的数据 \(\mathcal{D}_{train}^{(t)}\) 过一遍旧模型,得到旧模型分类的结果;在正式训练时,引导分类结果与旧模型分类结果靠近,模仿旧模型,达成防遗忘的作用。即加正则项:
\[L_{REVIEW}^{(t)}(\theta) = \sum_{\mathbf{x}\in \mathcal{D}_{train}^{(t)}} L(f(\mathbf{x};\theta),f(\mathbf{x};\theta^{(t-1)}))\]注意,在这个过程中没有用过重演的旧数据,用的是任务 \(t\) 训练之初自然继承下来的旧模型。整个算法唯一要记忆的是上一个任务学习的模型参数。
这种简单的方法缺陷是致命的:旧模型的信息全部浓缩到了分类结果这个小小的标签中,信息量太少——因为达成一个分类结果的方式有很多,这样最终可能使得模型与旧模型只有 “形似” 而没有 “神似”。另外一个角度,模型会对同一个数据参考两个标签(旧模型的分类标签、真实标签),若二者不同,这种冲突不太合理;若相同,就没有引入正则项的必要了。
EWC
EWC(Elastic Weight Consolidation)1是正则化法中第一个产生重要影响的算法。它限制每个参数的值与旧任务尽量接近,并根据参数(对旧任务)的重要程度决定限制的程度(加上的每个参数的重要程度是 EWC 与 L2 正则化的本质区别):
\[L_{REVIEW}^{(t)}(\theta) = \sum_{\tau=1}^{t-1} \sum_p^{#params} F_{\tau,p} (\theta_p - \theta_{\tau\star,p})^2\]\(\theta_{\tau\star,p}\) 是学习了 \(\tau\) 任务后的模型参数,\(F_{\tau,p}\) 是 Fisher 信息量,它度量的是 \(\tau\) 任务的样本对第 p 个模型参数所能提供的信息量,因此可以作为参数 \(\theta_{\tau\star,p}\) 的重要程度。Fisher 信息量定义为似然函数对参数导数平方的期望,可以估计为用 \(\tau\) 任务各样本计算的损失函数对参数导数平方的均值,它就是 \(\tau\) 任务训练时梯度平方的累加,可以随着 \(\theta_{\tau\star,p}\) 一起计算得到。
记忆存放的信息是之前所有任务的模型参数 \(\{\theta^{(\tau)}_{\star}\}_{\tau=1}^{t-1}\) 以及计算得到的 \(\{F_\tau\}_{\tau=1}^{t-1}\)。要注意存的旧模型是不允许用于测试的,只允许辅助训练,这是它不属于独立式学习的原因。
梯度操控法
正则化法通过修改损失函数影响反向传播,间接地改变了参数更新过程。我们也直接规定、操控训练的更新过程。
最常用的做法是直接操纵梯度,修改梯度的计算、梯度下降公式等,这里我称为 “梯度操控法”。一般流程为根据某种防遗忘的需要推导出修改梯度原梯度 \(\mathbf{g}\) 的算法,再用修改后的梯度 \(\tilda{\mathbf{g}}\) 套用梯度下降公式跟新:
\[\theta = \theta - \alpha \tilda{\mathbf{g}}\]我将在这篇笔记中讨论梯度操控法的经典论文。
网络结构法
网络结构法从网络结构下手,将网络划分成各部分并按某种机制分配给各任务,构成某种子网络,因此又称参数隔离法(Parameter Isolation)。它显式地体现了模型容量分配问题,将模型容量这一概念显化到模型各部分参数了。这也是一种直接规定、操控更新过程的方法。
注意,
- 对网络划分的意思并不是为每个任务使用单独的模型,各模型之间完全独立的独立式学习。各部分之间一定有着某种联系;
- 划分不是数学概念上的划分(split),可以重叠也可以不重叠;
- 一般是对网络的特征提取器部分进行划分,输出头部分总是共用的。
这类持续学习算法只适用于 TIL 场景。在测试时,需要根据测试数据的任务 ID \(t\) 的信息,选取对应的网络划分部分作预测。
对于这类方法,如果各部分能做到不相互重叠,那真的是可以显式地达到各任务互不干扰,它防遗忘方法中的最强者。某些论文里甚至声称能做到零遗忘(zero-forgetting)。
模型扩张法:Progressive NN
论文链接:Progressive Neural Networks, arXiv 2016
该方法不固定模型大小,即模型大小可以随任务线性增加。它是每来一个新任务,就将网络(指特征提取器部分的网络,不算输出头)扩充一列(一列包括每层若干个神经元),如图:
该方法主要的问题是模型大小线性增长,它以此为代价来解决模型容量问题,其实是很像独立式学习了。但它与独立式学习的区别是多了图中斜向右上箭头代表的权重,使新的一列网络与旧网络建立了联系——旧知识(旧网络的输出)可以通过该权重迁移过来。训练时,固定旧网络部分的参数(虚线)不动,训练新加入的参数(实线)。图中 \(a\) 为论文额外加入的非线性函数,可以更加强调斜向右上箭头权重的特殊性。测试时,使用测试数据任务 ID \(t\) 对应的部分网络作预测。
Mask 机制
如果要固定模型大小,参数隔离方法就是对固定数量的网络参数按任务进行划分,可以归结为引入加在模型上的遮罩(mask),它用来规定对模型某部分的选择,遮盖其他部分。Mask 用于不同的任务上,每个任务都有自己的 mask。持续学习中有大量的工作是基于 mask 机制的,例如 PackNet、HAT 等等,我不打算对着几篇代表性论文讲解,而是根据 mask 的实现方式、构造方式与在训练过程中的指导作用,对这些工作分分类。我将在这篇笔记中详细讨论一些工作应用 mask 机制的细节。
Mask 的实现方式
Mask 是遮在模型上的指示性变量,有两种形式:
- 加在参数上的(weight mask):直接在每个参数上规定,对第 l 层与第 l+1 层之间的参数,\(\mathbf{M}^l\) 为矩阵;
- 加在神经元上的(feature mask):在每个神经元上规定,对第 l 层神经元,\(\mathbf{m}^l\) 为向量,间接地影响与神经元相连接的参数。这种 mask 数量会大大减少。
各任务的 mask 需要存储在记忆 \(\mathbf{M}\) 中。对于 weight mask,每个任务占用空间是参数量级的;对于 feature mask,每个任务占用空间与神经元数目一致(相比 weight mask 成平方级地减少)。虽然记忆是随任务数线性增长的,但不用担心,它们比重演数据小多了。另外再次强调,mask 覆盖的参数不包括输出头的参数,因为不能直接影响输出头的输出结果(例如可能会让输出值变为 0)。
Mask 变量的取值,可以是:
- 二元的 0,1:称为 hard mask,只有 2 种状态:被遮住与不被遮住;
- 实数值:称为 soft mask。
以下不特别说明,都是指二元 mask。
Mask 如何规定训练过程与测试过程
Mask 如何影响新任务的训练过程(包括前向传播和反向传播)与最终的测试过程(前向传播),把这两件事定义清楚,mask 的作用就定义清楚了。以下是通常的选择:
- Mask 可以选择是否作用新任务训练过程的前向传播,若选择作用:
- 对于 weight mask:将 \(\mathbf{W}_l\) 乘以 mask,即 \(\mathbf{W}_l \odot \mathbf{M}_l\);
- 对于 feature mask:将神经元输出(激活前后都一样)\(\mathbf{o}_l\) 乘以 mask,即 \(\mathbf{o}_l \odot \mathbf{m}_l\);
- Mask 可以选择是否作用新任务训练过程的反向传播,若选择作用,指的是修改反向传播公式,在梯度流中阻塞:
- 对于 weight mask:将计算的 \(\frac{\partial L}{\partial \mathbf{W}_l}\) 乘以 mask,即被遮住的参数不更新;
- 对于 feature mask:将神经元输出(指激活后)\(\mathbf{o}_{l-1}\) 乘以 mask,根据反向传播公式 \(\frac{\partial L}{\partial w_{i j}^{l}}=\delta_{j}^{l} o_{i}^{l-1}=g^{\prime}\left(a_{j}^{l}\right) o_{i}^{l-1} \sum_{k=1}^{r^{l+1}} w_{j k}^{l+1} \delta_{k}^{l+1}\),被遮住的神经元发射的参数都不更新;
- 对于测试过程的前向传播,mask 通常都是作用的(一般没有例外),将 \(\mathbf{W}_l\) 乘以 mask,即 \(\mathbf{W}_l \odot \mathbf{M}_l\),即对于任务 ID 为 \(t\) 的测试输入,使用任务 \(t\) 的 mask 选择的子网络作预测。
如果 mask 对训练过程的前向传播和反向传播有独立的作用,那么一个二元 mask 是不够表示的,需要两个二元 mask,表示四个状态。但大多数论文只会涉及一个,所以只用一个二元 mask。
如何构造 mask
训练任务 \(t\) 时,不仅要将旧任务的 mask 作用到(如果选择作用的话)网络上,还要构造出新任务 \(t\) 的 mask。构造 mask 可使用固定算法(例如按照某种指标选择一定比例的重要程度较高的参数),也可将 mask 看成可学习的参数融进训练过程学习,即将 mask 代入到模型中当作参数随模型参数正常训练,也就是对如下计算图(以一层为例)作反向传播:
- 对于 weight mask: \(f(\mathbf{o}_l;\mathbf{W}_l,\mathbf{M}_l) = (\mathbf{W}_l \odot \mathbf{M}_l)\cdot \mathbf{o}_l\)
- 对于 feature mask: \(f(\mathbf{o}_l;\mathbf{W}_l,\mathbf{m}_l) = \mathbf{W}_l \cdot (\mathbf{o}_l \odot \mathbf{m}_l)\)
注意:
- 如果 mask 融进训练过程来学习,每个任务的训练过程不仅要考虑训练新 mask,还要将旧任务 mask 的作用考虑进来,最终训练的反向传播过程形式更麻烦(并不只是上式);
- 根据不同的构造方式,各任务的 mask 可以设计为允许重叠,也可以不重叠。如上所述,mask 不重叠(参数硬隔离)可以实现零遗忘,但也要面临模型容量问题;
- 二元 mask 是无法直接融进训练过程的(因为不连续不可导),需要采取一些训练技巧处理不可导。
对于融进训练过程与模型参数一起训练的 mask,一个重要的事情是使其稀疏化,即尽量让 mask 少占用剩余可用的位置,防止模型容量过快用完。稀疏化也是必须的,因为如果不加任何限制,每个任务总会倾向于学到一个全 1 的 mask(因为为了在当前任务上效果好,学习算法会试图占据一切可能利用的模型容量资源的),导致从第一个任务开始,模型容量就快用完了。这是模型容量分配问题在 mask 机制上实际的表现,每篇使用可学习 mask 的论文都应设计恰当的稀疏化机制。
稀疏化的方法通常是对 mask 加约束,如正则项,论文 HAT 中的正则项就是一个典型。
Mask 机制实际上就是一种注意力机制,注意力机制对输入(或者中间层)的每个元素考虑赋予不同的注意力得分,让模型更加关注输入中得分高的部分,得分低的则看作无用信息被抑制。重要的是,这个得分可以通过梯度下降自动地学习出来,而不用手动规定。
记住,注意力机制是一种思想的统称,可以与各种模型混合,不单单用在 RNN 中的 Encoder-Decoder 结构。这里的 mask 机制可能是比较简单的一种用法。
优缺点讨论
- 重演数据法最大的缺点是重演数据量不够;
- 直接操控更新过程的方法(包括梯度操控法、参数隔离法)有更好的可解释性,但也会带来僵硬的问题。(二者有冲突)
六、前沿方向
这里列举一些持续学习的其他前沿方向,不作详细介绍。
- 小样本持续学习:
- 持续异常检测;(换问题)
- 带粗细粒度的持续学习;(造新场景)
- 持续学习 + Transformer(ViT):DyTox。
- …
参考资料
以下列举一些持续学习相关的参考资料与学习资源。
- 课程 Continual Learning(比萨大学):https://course.continualai.org
- 持续学习社区 Continual AI:https://www.continualai.org
Gradient Episodic Memory for Continual Learning
M. De Lange et al., “A Continual Learning Survey: Defying Forgetting in Classification Tasks,” IEEE TPAMI 2021, vol. 44, no. 7, pp. 3366–3385, Jul. 2022, doi: 10.1109/TPAMI.2021.3057446. ↩ ↩2 ↩3 ↩4 ↩5
G. Zeng, Y. Chen, B. Cui, and S. Yu, “Continual learning of context-dependent processing in neural networks,” Nat Mach Intell, vol. 1, no. 8, Art. no. 8, Aug. 2019, doi: 10.1038/s42256-019-0080-x. ↩