抄自 Frank Tian 李宏毅 Life Long Learning
Life Long Learning (LLL)说的是,用同一个模型进行持续不断的学习。
在我的理解中这个LLL有不同层次的含义。
用分类问题举例,模型在最开始学习的时候可以用不同类别的图片,但是接下来,如果我们又拿到了一些训练数据,这些训练数据和之前的图片有些差别,我们想让模型通过学习新的数据提升能力,但是又不想让模型降低处理原来问题的能力。
例如开始时见到的手写数字是有背景噪音的:
![](https://i-blog.csdnimg.cn/blog_migrate/470a21de7083e5d7ed12d72852702694.png)
![](https://i-blog.csdnimg.cn/blog_migrate/01c1d16c99451026de2d6a3833764e52.png)
后来新增加的训练数据是没有背景噪音的:
![](https://i-blog.csdnimg.cn/blog_migrate/ee20c10a7052660880595c1c803c39c0.png)
![](https://i-blog.csdnimg.cn/blog_migrate/9f528ec2ddba713bbe270a624e136b28.png)
在不考虑LLL方法的时候,我们先通过第一个数据集训练,让模型在第一个数据集和第二个数据集上分类,这时模型是没有见过第二个数据集的:
![](https://i-blog.csdnimg.cn/blog_migrate/d1333ae546acbdd8462a6d7510e7b179.jpeg)
![](https://i-blog.csdnimg.cn/blog_migrate/51f6dec890bf659ff7b64b022851085e.jpeg)
这时候模型在第二个任务上表现的也可以,然后我们让我们在第二个数据集上学习,期待它在第二个数据集上表现的更好。
但是,结果显示,模型忘记了第一个任务:
![](https://i-blog.csdnimg.cn/blog_migrate/5d482562b3a051c731155c40dc69343a.jpeg)
![](https://i-blog.csdnimg.cn/blog_migrate/8da1b79610c1f8d8c8ee2722cc166d39.jpeg)
这感觉有点像模型过分的专精于第二个任务这种比较简单的任务,失去了处理第一种任务的能力。
但是,模型能不能把两个任务都做的很好的呢?
我们在最开始就同时那这两个数据集训练,得到的结果如下:
![](https://i-blog.csdnimg.cn/blog_migrate/3f61bee6404fc8f318a4cd3e3e7b6e13.jpeg)
![](https://i-blog.csdnimg.cn/blog_migrate/0e786048e1d8c4da6acde29a72754159.jpeg)
这说明,模型是有能力同时学好两个任务的,也就是说模型的容量是足够大的。
不仅是在CV中,在NLP中也有类似的例子,用模型训练一个自动问答系统,让它处理不同的任务,往往训练到下一个任务的时候他就忘记了之前的:
另一方面,在类似分类器这样的模型中,我们可能期望有后续的数据后,可以增加样本的类别。
从理论上讲这是可行的,例如使用DNN分类,如果原来有N个类别,神经网络的Dense层,也就是经过了Softmax的Output层会有N个神经元。
那么只要增加了一个神经元,就可以增加一个类别了,然后用新的类别的数据去训练,应该就可以识别新的类别了。
当然这里面还有一个小细节,我们倒数第二层连接Dense层新添加的神经元的权重应该初始化为0,这样当DNN识别原来的类别时,预测的结果不会改变。
但是,这往往是理想状态的结果,如果我们只调整“倒数第二层连接Dense层新添加的神经元的权重”,分类效果可能不理想,而如果进一步更改前面的权重,又可能影响其他类别的分类。
这些都是LLL要解决的问题。
这样的问题又被称为Catastrophic Forgetting。
回到LLL本身,我们之所以需要LLL的技术,是因为我们不希望在学习新的任务的时候还要保留旧的任务的数据集。同时我们也希望“学习一个新的任务”这件事情能够更快的完成。
在传统的参数化DNN中,模型重要的部分就是结构和参数。可以说结构是骨架,参数是肌肉,而一个模型能不能处理好一个任务也是依靠这两者的。
现在我们希望模型学习了新的任务之后没有忘记旧的任务,那么就需要保护和旧任务相关的架构和参数。
在最开始手写数字识别的例子中,模型的结构没有发生改变,那么我们就需要保护参数。
一种保护参数的方法被称为Elastic Weight Consolidation (EWC),它的想法是给每一个参数设计一个guard b i b_i bi 用来衡量这个参数值不值得保护。
我们设
θ
b
\theta^b
θb 是之前模型的参数,新的任务的损失函数为
L
(
θ
)
L(\theta)
L(θ) ,那么EWC的损失函数应该为:
L
′
(
θ
)
=
L
(
θ
)
+
λ
∑
i
b
i
(
θ
i
−
θ
i
b
)
2
L^{\prime}(\theta)=L(\theta)+\lambda \sum_{i} b_{i}\left(\theta_{i}-\theta_{i}^{b}\right)^{2}
L′(θ)=L(θ)+λ∑ibi(θi−θib)2
这意味这我们确实通过调整 θ \theta θ 去让模型适应新的数据了,但是又不希望参数改变的过于剧烈。
至于那些参数只能小幅度的改变,甚至不应该改变,而哪些参数可以较大幅度的改变,由参数的guard b b b 决定。
EWC的想法是很朴素的,而重点在于怎么找到合适的 b b b 。
EWC的想法是, b b b 可以是 L ( θ ) L(\theta) L(θ) 关于每个 θ \theta θ 的二阶导数。
这个想法是十分amazing的,但是确实很有道理。
我们期望模型的参数修改后依旧能能很好的处理之前的任务,那就是能保持 L ( θ ) L(\theta) L(θ) 不会变得太大。
看下面的例子:
在
θ
1
\theta _ 1
θ1 方向上,最低点的二阶微分很小,因此最低点附近的曲线比较缓,这表示我们即便在 <
θ
1
\theta _1
θ1 方向上修改参数值,也不会太大的改变
L
(
θ
)
L(\theta)
L(θ) 。
相反,在 θ 2 \theta _ 2 θ2 方向上,最低点的二阶微分比较大,因此最低点附近的曲线比较陡,这意味这我们不能大幅度的修改参数值。
EWC在MNIST上的表现如下:
可以看到SGD这种fine-tuning的方法学会了新的任务之后旧的就忘得一干二净了。
而 L 2 L_2 L2 对参数做了约束,但是因为没有guard这种“选择上的倾向”,能很好的记住旧的任务,但是新的任务学的都不太好。
其他的方法和EWC类似,例如Synaptic Intelligence (SI),把海森矩阵换成了曲率,Memory Aware Synapses (MAS)的想法也是类似的。
接下来,我们讨论第二种LLL,也就是像增加了类别的分类器这样的网络,也就是改变了网络结构的终身学习。
有一种想法被称为Learning without Forgetting(LwF),来自下面的论文:
Learning without Forgetting
在这片论文中,作者讲参数分成了不同的类别,分为共享参数 θ s \theta _s θs ,Dense层的旧参数 θ o \theta_o θo 和新添加的参数 θ n \theta _ n θn 。
通过把这些参数分类,针对不同的参数添加不同的约束,比如是完全固定住,可以小幅度调整,还是可以随机初始化重新调整,从而适应网络结构的改变。
图示:
红色代表要初始化并训练的层,蓝色的是要微调的层,白色的是固定住不变的层。
文章中对比了不同的在线学习的方法,原模型是
从
1
1
1 到
m
m
m 都是之前训练好的任务。
微调则是用小的学习率修改前面的层,但是涉及到最后分类的Dense层不变。这样的方法存在弊端,就是往往能比较好的处理新的任务,但是在旧的任务上表现欠佳。
Feature Extraction则是不改变
θ
s
\theta _s
θs 和
θ
o
\theta_o
θo,把前面的层输出当作特征提取,在前面的层的基础之上训练新的层去分类。
当然,这样的方法对旧任务完全没有影响,但是新任务上的变现欠佳。这是因为这个“特征提取器”是针对原来的任务设计的,并不能很好的提取新的类别的特征。
至于Joint Training,就是把新的和旧的训练数据都输入到网络中,这相当于重新训练一个网络。
我们常常把Joint Training的结果当作在线学习的上届。但是这并不实际,因为没有那么多存储资源保留数据,也没有那么多时间训练新的模型。
而我们使用的LwF也更改了所有的参数,但是只需要输入新的任务的数据。
LwF的算法如下:
它首先是随机初始化了新的参数
θ
n
\theta _ n
θn ,同时记录了旧的模型对于新的数据的输出。
接下来,它同时训练所有参数,并且设 Y ^ o \hat{Y}_{o} Y^o 为 θ o \theta _o θo 这个模型的输出,设 Y ^ n \hat{Y}_{n} Y^n 为 θ n \theta _n θn 这个模型的输出,注意他们的输入是一样的,都是新的数据集。
优化目标是:
θ
s
∗
,
θ
o
∗
,
θ
n
∗
←
argmin
θ
^
s
,
θ
^
θ
,
θ
^
n
(
λ
o
L
o
l
d
(
Y
o
,
Y
^
o
)
+
L
n
e
w
(
Y
n
,
Y
^
n
)
+
R
(
θ
^
s
,
θ
^
o
,
θ
^
n
)
)
\theta_{s}^{*}, \theta_{o}^{*}, \theta_{n}^{*} \leftarrow \underset{\hat{\theta}_{s}, \hat{\theta}_{\theta}, \hat{\theta}_{n}}{\operatorname{argmin}}\left(\lambda_{o} \mathcal{L}_{o l d}\left(Y_{o}, \hat{Y}_{o}\right)+\mathcal{L}_{n e w}\left(Y_{n}, \hat{Y}_{n}\right)+\mathcal{R}\left(\hat{\theta}_{s}, \hat{\theta}_{o}, \hat{\theta}_{n}\right)\right)
θs∗,θo∗,θn∗←θ^s,θ^θ,θ^nargmin(λoLold(Yo,Y^o)+Lnew(Yn,Y^n)+R(θ^s,θ^o,θ^n))
也就是让 Y ^ o \hat{Y}_{o} Y^o 和 Y o {Y}_{o} Yo 尽可能近,让 Y ^ n \hat{Y}_{n} Y^n 和 Y n {Y}_{n} Yn 尽可能近。
这样既保证了之前任务的表现,又保证了新任务的表现。
接下来还有更多的LLL的前沿进展,比如LLL和迁移学习的相似性。
迁移学习希望模型在学习了Task 1之后,用更短的时间或者更少的数据集就能学习Task 2,但是此时迁移学习就不再要求模型在Task 1上的性能了。
但是LLL希望模型依旧能在Task 1上表现的很好。
还有当LLL进行下去,有限的参数肯定没办法处理所有的任务,这时候可能需要扩张网络。
同时,让模型学习多个任务的时候,这些任务的前后顺序也十分重要,一个合适的顺序应该能让模型在前面学到的技能对后面的任务有所帮助。
这项技术被称为Curriculum Learning: