本次论文是来自2016年一篇基于动态架构的文章,应该算是最早的一篇文章了。
论文地址点这里
一. 介绍
本文介绍了渐进式网络,这是一种新的模型体系结构,明确支持跨任务序列的传输。虽然微调仅在初始化时包含先验知识,但渐进式网络在整个训练过程中保留预处理模型,并从中学习横向连接,以提取新任务的有用特征。通过以这种方式组合先前学习的特征,渐进式网络实现了更丰富的组合性,其中先前的知识不再是瞬时的,可以在特征层次的每一层进行集成。此外,在预处理网络旁边添加新容量,使这些模型具有重用旧计算和学习新计算的灵活性。正如我们将要展示的,进步的网络自然会积累经验,并且不会因设计而产生灾难性的遗忘。
二. 渐进式网络
持续学习是机器学习的一个长期目标,在机器学习中,模型需哟处理一系列按顺序经历的任务,而且有能力从以前的任务中转移知识,以提高收敛速度[20]。渐进式网络将这些迫切需要直接集成到模型架构中:通过为每个正在解决的任务实例化一个新的神经网络(一列)来防止灾难性遗忘,而通过与先前学习的列特征的横向连接来实现传递。
渐进网络开始于一个单独的列:一个神经网络共有
L
L
L层隐藏层:
h
i
(
1
)
∈
R
n
i
h^{(1)}_i \in \mathbb{R}^{n_i}
hi(1)∈Rni,其中
n
i
n_i
ni表示为这一层的每个单元,参数
Θ
(
1
)
\Theta^{(1)}
Θ(1)经过训练而收敛。当切换到另一个任务时,参数
Θ
(
1
)
\Theta^{(1)}
Θ(1)被冻结,新的参数
Θ
(
2
)
\Theta^{(2)}
Θ(2)进行初始化,同时层
h
i
(
2
)
h^{(2)}_i
hi(2)同时从
h
i
−
1
(
2
)
h^{(2)}_{i-1}
hi−1(2)和
h
i
−
1
(
1
)
h^{(1)}_{i-1}
hi−1(1)接收。具体来说,生成
K
K
K个任务的模型表示为:
h
i
(
k
)
=
f
(
W
i
(
k
)
h
i
−
1
(
k
)
+
∑
j
<
k
U
i
(
k
:
j
)
h
i
−
1
(
j
)
)
h_i^{(k)}=f\left(W_i^{(k)} h_{i-1}^{(k)}+\sum_{j<k} U_i^{(k: j)} h_{i-1}^{(j)}\right)
hi(k)=f⎝
⎛Wi(k)hi−1(k)+j<k∑Ui(k:j)hi−1(j)⎠
⎞
其中
W
i
(
k
)
∈
R
n
i
×
n
i
−
1
W_i^{(k)} \in \mathbb{R}^{n_i \times n_{i-1}}
Wi(k)∈Rni×ni−1表示在第
k
k
k列上的第
i
i
i个权重,
U
i
(
k
:
j
)
∈
R
n
i
×
n
j
U_i^{(k: j)} \in \mathbb{R}^{n_i \times n_j}
Ui(k:j)∈Rni×nj表示为从第
j
j
j列上第
i
−
1
i-1
i−1横向连接的权重。
f
f
f表示为一个非线性的元件:
f
(
x
)
=
max
(
0
,
x
)
f(x)=\max(0,x)
f(x)=max(0,x)。下图展示的是
K
=
3
K=3
K=3的时候的工作流程:
Adapters(适应器): 在上图中可以发现,从之前的列传入新的列的时候需要经过一个适应器地调整,此处的作用是添加一下MLP层,进行加强版的非线性连接,因此,忽略掉bias,那么可以得到:
h
i
(
k
)
=
σ
(
W
i
(
k
)
h
i
−
1
(
k
)
+
U
i
(
k
:
j
)
σ
(
V
i
(
k
:
j
)
α
i
−
1
(
<
k
)
h
i
−
1
(
<
k
)
)
)
h_i^{(k)}=\sigma\left(W_i^{(k)} h_{i-1}^{(k)}+U_i^{(k: j)} \sigma\left(V_i^{(k: j)} \alpha_{i-1}^{(<k)} h_{i-1}^{(<k)}\right)\right) \text { }
hi(k)=σ(Wi(k)hi−1(k)+Ui(k:j)σ(Vi(k:j)αi−1(<k)hi−1(<k)))
其中
V
i
(
k
:
j
)
∈
R
n
i
−
1
×
n
i
−
1
(
<
k
)
V_i^{(k: j)} \in \mathbb{R}^{n_{i-1} \times n_{i-1}^{(<k)}}
Vi(k:j)∈Rni−1×ni−1(<k)表示为投影地矩阵。
(其实这里的新的列你可以理解为是一个全新的网络,在代码中就是和原本网络保持一致的神经网络层,这个列的添加也代表新任务过来,相当于就是从旧的输出直接和新网络的输出相加进行传播。)
三. 代码解析
本次代码我没找到官方的,但在github找到了一个比较简洁易懂,代码链接点这里
首先是构建一个基本的PNN块:
这里需要注意的地方就是在进行传播的时候需要加上之前的输出(多个)。接下来就是PNN的构成:
这是一个简单的PNN网络,关键地方有两个:添加新的列以及冻结参数。添加新的列的话,直接在创建一个列表存新的PNN块。
(其实有更简单的方法,你可以在每次新任务结束的时候存下新增加的model放到一个list里面,之后对list遍历传入新的列作为输入即可。)