增量学习笔记

借这篇博客记录增量学习的笔记。

概念

Ie0eFs.png

增量学习研究的是在一个连续的信息流中持续进行学习的问题,它的目标是将吸收新知识的同时要保留甚至整合、优化旧知识。之所以要研究增量学习,是因为在机器学习领域,模型训练有一个普遍缺陷,称为「灾难性遗忘」,即一个模型在新任务上训练时,在旧任务上的表现会显著下降。

造成灾难性遗忘的一个主要原因是「传统模型假设数据分布是固定或平稳的,训练样本是独立同分布的」,所以模型可以一遍又一遍地看到所有任务相同的数据,但当数据变为连续的数据流时,训练数据的分布就是非平稳的,模型从非平稳的数据分布中持续不断地获取知识时,新知识会干扰旧知识,从而导致模型性能的快速下降,甚至完全覆盖或遗忘以前学习到的旧知识。

做法

增量学习的方法大体上可以分为如下三个类别:

回放

回放类方法的思想是「温故而知新」,也就是在训练新任务时,模型会保留一部分具有代表性的旧数据来避免对旧任务的遗忘。因此这类方法的核心是「保留旧任务的哪部分数据,以及如何利用旧数据与新数据一起训练模型」

iCaRL[CVPR’17]

iCaRL是回放类方法的代表,它为每个旧任务保留了一部分有代表性的数据(iCaRL假设越接近类别特征均值的样本越具有代表性)。给定一个包含不同类别的数据流$X^1,X^2,\dots$其中$X^y=\{x_1^y,\dots\}$中的样本都属于同一个类别。iCaRL学习的是一个分类器和一种特征表示的映射方法。iCaRL对一个新输入的待分类样本的流程如下:

关键在于第二行的样本集$P$和第三行的特征映射方法$\phi$。样本集$P$中包含$t$个类别各自的代表性样本,将一个类别中的所有样本都经过$\phi$得到它们的特征表示,然后取平均作为这个类别的特征表示,随后将新输入的样本也经过$\phi$得到它的特征表示,将这个特征表示与所有类别的特征表示进行比较,将最相近的作为新样本的分类标签。

其中$X^s,…,X^t $表示新增加每一类对应的样本集;$K$表示存储的大小,即所有样本集的样本总数;$θ$表示当前的模型参数;$P$为当前的样本集。算法2代表的样本集的构建步骤如下:

  1. 将新得到新类样本和之前存储的旧类样本集共同加到卷积神经网络中训练,来更新当前的模型参数$θ$
  2. $K$是固定值,增加新类别后,样本集中每个类别应该保留的图片数应该进行调整,对旧任务$1,…,s-1$每个类别的图片数减少到$m$
  3. 对新任务构建新的样本集$P_y$,其中$y = s,…,t$,每个类别分别选择$m$张,最后将其加入到总的样本集$P$中

第一步中的卷积神经网络仅是用做表征学习的,而不是做最后的分类任务。

IeB9AJ.png

算法3代表的特征学习步骤如下:

  1. 首先将新任务的数据集$X_s,…,X_t$和$P$一起进行数据增广,构建最终的训练集$D$
  2. 然后将增广后的数据集$D$中旧任务的部分通过神经网络,提取它们的特征向量并存储
  3. 网络在$D$中新任务的部分上训练,loss函数前半部分为新任务的分类损失,后半部分为旧任务的蒸馏损失。

通过算法3得到一个用于特征表示的映射的网络,通过算法2构建了旧任务的样本集,最后的步骤就是通过算法1对新样本进行分类。

GEM[NIPS’17]

iCaRL可能会对保留的旧任务的样本产生过拟合,GEM通过一个约束优化问题改善了这种情况。GEM以不等式约束的方式修正新任务的梯度更新方向,从而希望模型在不增大旧任务的损失的同时尽量最小化新任务的损失值,只更新新任务的参数而不干扰旧任务的参数。

正则化

正则化类方法的思想是「通过给新任务的损失函数施加约束的方法来保护旧知识不被新知识覆盖」,这类方法在学习新任务时不需要旧任务的数据。

LWF[ECCV’16]

LWF是正则化类方法的典型代表。下面以一张不同增量学习方法之间的对比来说明LWF:

IeBaNj.png

图(a)是一个CNN网络,它的参数分别以$θ_s$和$θ_o$来表示。$θ_s$表示网络的卷积层 + 全连接层,它与特定的任务无关,是网络的共享参数。而最后一层是与类别相关的输出层,其参数单独用$θ_o$表示。若加入一个有新类别的分类任务,就将新任务新增的参数先随机初始化,表示为$θ_n$。

目前基于已有的$θ_s$来学习$θ_n$主要有以下三种方法:

  • 微调(Fine-tuning):$θ_s$和$θ_o$都可以进行更新,在新任务上一般采用一个较小的学习率对在旧任务上训练的网络进行调整,有时$\theta_s$会被固定防止过拟合等。微调的方法会因为没有旧任务样本的指导而在旧任务上表现变差。
  • 特征提取(Feature Extraction):$θ_s$和$θ_o$都不变,从网络中的一个或多个中间层的输出被用来训练新任务的参数$θ_n$。特征提取通常在新任务上表现不佳,因为共享参数不能表示一些新任务独有的特征表示。
  • 联合训练(Joint Training):所有的参数可以都进行学习优化,通常这个方法产生的结果是最优的,所以一般视为增量学习方法的性能上界(upper bound)。

而LWF可以看作知识蒸馏与微调的结合。它只使用新任务的训练样本和标签,通过学习$\theta_n$来使得网络在新旧任务上都有好的表现。微调是使用一个已经训练完成的网络参数来对新的网络进行初始化,并在一个低的学习率下,更新参数,在新任务数据中重新找到一个局部最优解。而知识蒸馏则可以训练一个小的网络在源数据集上或者大量无标签的数据集上达到一个复杂网络的性能。

IeB2E4.png

LWF的步骤如下:

  1. 将新样本通过由旧样本训练好的网络并记录网络的输出$y_o$,新类别中的样本被添加到输出层,权重随机初始化为$\theta_n$,这里新加入的参数量等于新的类别数乘上其中的样本数。
  2. 首先固定$\theta_s$和$\theta_o$来更新$\theta_n$直到收敛,然后再一起更新所有参数直到收敛。避免新任务的训练过分调整旧模型的参数而导致新模型在旧任务上性能的下降。

LWF中的损失函数同样由新任务的分类损失以及旧任务的知识蒸馏损失组成,分类损失是多分类任务常见的logistic损失,而旧任务的知识蒸馏损失是一个交叉熵的形式,它使得新网络在新任务上的预测和旧网络在新任务上的预测相近:

我们知道对于一个复杂网络来说往往能够得到很好的分类效果,错误的概率比正确的概率会小很多很多,但是对于一个小网络来说它是无法学成这个效果的。我们为了去帮助小网络进行学习,就在小网络的softmax加一个T参数,加上这个T参数以后错误分类再经过softmax以后输出会变大,同样的正确分类会变小。这就人为的加大了训练的难度,一旦将T重新设置为1,分类结果会非常的接近于大网络的分类效果。

LWF的缺点是,它很依赖新旧任务之间的相关性,而当数据分布的相关性很弱时,并不能保证不丢失先前任务的重要信息。而且将新样本通过由旧样本训练好的网络并记录网络的输出会带来额外的开销。

EBLL[ICCV’17]

EBLL在LWF的基础上保留旧任务中重要的特征从而保留其中的重要信息,来达到避免遗忘的目的。LWF中使用知识蒸馏的思路不代表没有信息的丢失,因此,提出通过auto-encoder,来学习一个新的子特征空间,包含旧任务中中最重要的特征表示。

MAS[ECCV’18]

MAS的核心思路是对每个任务,在训练完该任务之后,计算网络中每个参数$\theta_{ij}$对于该任务的重要性$\Omega_{ij}$并沿用到训练后续的任务中去。

每当进来一个新任务对其进行训练时,对于$\Omega_{ij}$大的参数$\theta_{ij}$,在梯度下降时尽量减少它的改变幅度,因为该参数对过去的某个任务很重要,需要保留它的值来避免遗忘。对于$\Omega_{ij}$比较小的参数$\theta_{ij}$,我们可以以较大的幅度对其进行梯度更新,以得到在该新任务上较好的性能或者准确率。在具体训练过程中,重要性$\Omega_{ij}$以正则项的形式添加到损失函数中。

关键在于如何计算每个参数$\theta_{ij}$对于该任务的重要性$\Omega_{ij}$。对于一个网络模型来说,它收敛以后我们可以将它的前向传递过程视为对一个真实函数$F$的近似,在此每个参数对于一个任务的重要性相当于该函数对于该参数的敏感程度。比如当一个$\theta$进行很小的改变后,却引起了网络输出很大的变化,就可以认为该参数是重要的,或者当前函数对该参数敏感。对于每个数据点$x_k$,有:

这就是函数在该数据点上对每个参数的偏导数。随后对于每个数据点,MAS求得它们的偏导的均值作为最后的重要性$\Omega_{ij}$,其中$N$是当前任务中的样本总数:

当函数$F$的输出是多维度的时候,这时候对于每个维度都需要进行一次计算,才能得到最终的$\Omega_{ij}$。这里MAS用L2范数的平方作为代替,相当于把输出的所有维度合为一个标量,最终只需要进行一次计算即可:

MAS的损失函数为如下的形式,每当新进来一个任务时,在其任务的原损失函数上添加一个正则项来限制各个参数的更新幅度。其中$\theta_{ij}^*$是由前n-1个任务训练得到的模型,同时也是用于训练第n个任务的初始模型的参数。每当训练完一个任务之后, $\Omega_{ij}$都会进行更新,先计算对最新的任务(刚训练完成的任务)的重要性,然后累加到之前的重要性上。

该方法的优点包括:

  1. Constant Memory:模型占用的内存不随着任务的数量进行增加。

  2. Problem Agnostic:MAS方法是场景无关的,因为在具体代码中,该模型只对网络的backbone部分计算重要性,对于每个新的任务来说,模型会新建一个head(比如在分类中就是最后一个全连接层)进行训练。

  3. On Pretrained:给定一个预训练好的模型,可以在其top上再进行改动,然后添加新任务。

  4. Unlabelled Data:能够从无标签数据中学习,这个属性使得该方法能用应用在没有训练数据的场景下。

参数分离

参数分离类方法的思想是「训练不同任务时使用模型的不同参数」,来达到避免遗忘的目的。通常的做法是模型的大小保持不变,不随任务数量的增加而变大,而在训练新任务时对旧任务的参数进行mask。

PackNet[CVPR’18]

PackNet是参数分离方法的典型代表,也是这篇survey中表现最好的方法。它最基本的想法就是在固定网络大小不变的情况下,通过剪枝使一些参数成为 free parameters,以便能使它们被用来训练新的任务。

IeBTKK.png

以一个 5×5 的 filter 为例说明PackNet的训练过程。(a) 在任务 I 上进行初始训练,学习得到一个完整的filter;(b) 裁剪掉 60% (15/25) 再重新训练,得到了一个对应于任务 I 的稀疏的 filter,其中白圆圈代表0值权重,对应于任务 I 的权重将被固定,并且不会在后续过程中被裁剪;© 被剪枝的权重可以用于学习任务 II;(d) 再减枝33%(5/15)并且重新训练,橘色的圆圈即代表对应于任务 II 的权重,随即也被固定,并且之后不会被剪枝。这个过程将会随着学习完所有任务或者使用完所有filter 而终止。在推断时,根据所选的任务使用对应的mask。

例图已经说明了PackNet的步骤:

  1. 我们从为初始任务学习的一个标准网络开始,称作 Task I。filter 的初始权重在 (a) 中用灰色表示。然后,我们裁剪掉一部分网络权重(即:将其置为0)。由于网络连接的突然变化,裁剪网络会导致性能下降。当裁剪率很高时,这一点尤其明显。为了在裁剪后恢复准确率,我们需要对网络进行重新训练,所需的 迭代次数要比初始训练时所需的少。经过一轮裁剪和重新训练后,我们获得了一个具有稀疏 filter 的网络,并且对 Task I 的性能影响降到了最低。Task I的surviving parameters(未被裁剪的参数,即 (b) 中灰色的参数)此后保持不变。

  2. 下一步,我们为新任务 Task II 训练网络,使裁剪后的权重从0恢复,获得 (c) 所示的橙色权重。注意,Task II的 filters 同时使用了灰色和橙色权重——即,重复使用了属于先前任务的权重。我们再次裁剪网络,释放掉一些仅用于 Task II 的参数,并重新训练 Task II 以从裁剪中恢复。 最终的 filters 如 (d) 所示。此后,Task I 和 Task II 的权重保持固定,然后将可被裁剪的参数用于学习又一个新任务,从而得到如 (e) 所示的绿色权重。重复此过程,直到完成了所有任务或没有更多可用的 free parameters 为止。

值得注意的是,PackNet每次裁剪的比例是固定的,而不是自适应的;在每一轮裁剪中,从每个卷积层和全连接层中删除固定百分比的可被裁剪的权重。同一层中的权重按其绝对大小排序,并选择最低的50%或75%予以裁剪。