Lasertagger
Lasertagger出自论文Encode, Tag, Realize: High-Precision Text Editing,本文提供了一种简单的实现思路,并开源在https://github.com/hanggun/lasertagger-chinese
模型结构
文章一共提出了2种模型结构,分别为
L
a
s
e
r
t
a
g
g
e
r
A
R
Lasertagger_{AR}
LasertaggerAR和
L
a
s
e
r
t
a
g
g
e
r
F
F
Lasertagger_{FF}
LasertaggerFF,其主要区别点在于解码器的不同,
L
a
s
e
r
t
a
g
g
e
r
A
R
Lasertagger_{AR}
LasertaggerAR采用自回归的方式进行解码,而
L
a
s
e
r
t
a
g
g
e
r
F
F
Lasertagger_{FF}
LasertaggerFF直接采用全连接输出。出于高效生成文本的需求与目标,本文仅对
L
a
s
e
r
t
a
g
g
e
r
F
F
Lasertagger_{FF}
LasertaggerFF进行了实现。
L
a
s
e
r
t
a
g
g
e
r
Lasertagger
Lasertagger可以简单的认为是判别模型,其输入为句子,输出为句子中每个单词的标签类别,由图3中可以知道,作者采用Bert对句子进行编码,再用一个全连接层与Softmax层输出标签的概率。因此Lasertagger的主要贡献点在于标签的设计。
Lasertagger一共设计了4种标签,包括KEEP,DELETE,SWAP,DELETE|word
,KEEP
意味着保留当前字符,DELETE
代表删除当前字符,SWAP
代表将SWAP
前后句子进行互换,DELETE|word
代表删除当前字符并添加新的字符Word。在添加字符这个标签中有2个选择,一是在KEEP前面添加字符,二是在DELETE前面添加字符,作者在实验过程中发现,在DELETE前面添加字符拥有更高的准确率,并且添加的字符始终在第一个被删除的字前面。例如只会出现DELETE|"what is",DELETE,KEEP
,而不会出现DELETE|"what", DELETE|"is",KEEP
添加的word来自于词汇表,有多少word就代表我们最终需要预测的类别数有多大,词汇表太大会使模型变大,训练与预测变慢,因此我们希望尽可能地减小词汇表的大小,同时又希望最大化源语句重组成目标语句的量,因此作者提出使用longest common subsequence (LCS)最长公共子序列的方式获取所需添加的词汇。首先获取source 与 target之间的LCS,然后比较LCS与target,将target中不存在于LCS的n-grams添加到词汇表中并进行统计,最终选择出现次数top-k的的词汇作为最终的词汇表。
LCS算法寻找最长子序列中的子序列可以是非连续的,例如abcdefg中的abc,abd,abe都是子序列,可以使用动态规划来进行寻找,假设两个序列为source和target,定义dp矩阵,则
d
p
[
i
]
[
j
]
=
d
p
[
i
−
1
]
[
j
−
1
]
+
1
i
f
(
t
a
r
g
e
t
[
i
−
1
]
=
=
s
o
u
r
c
e
[
j
−
1
]
)
dp[i][j] = dp[i-1][j-1] + 1 \quad if \quad (target[i-1] == source[j-1])
dp[i][j]=dp[i−1][j−1]+1if(target[i−1]==source[j−1])
d
p
[
i
]
[
j
]
=
m
a
x
(
d
p
[
i
−
1
]
[
j
]
,
d
p
[
i
]
[
j
−
1
]
)
e
l
s
e
dp[i][j] = max(dp[i-1][j], dp[i][j-1]) \quad else
dp[i][j]=max(dp[i−1][j],dp[i][j−1])else
当
t
a
r
g
e
t
[
i
−
1
]
target[i-1]
target[i−1]等于
s
o
u
r
c
e
[
j
−
1
]
source[j-1]
source[j−1]时,最长子序列取上一位置最大子序列数+1,当
t
a
r
g
e
t
[
i
−
1
]
target[i-1]
target[i−1]不等于
s
o
u
r
c
e
[
j
−
1
]
source[j-1]
source[j−1]时,最长子序列取
d
p
[
i
−
1
]
[
j
]
dp[i-1][j]
dp[i−1][j]和
d
p
[
i
]
[
j
−
1
]
dp[i][j-1]
dp[i][j−1]中最大的。当完成最长子序列的dp表格后,可以采用回溯的方式输出最长子序列。具体方式为:从最后一位开始,若当前位置的字符相等,则输出,若不相等,则往
d
p
[
i
−
1
]
[
j
]
dp[i-1][j]
dp[i−1][j],
d
p
[
i
]
[
j
−
1
]
dp[i][j-1]
dp[i][j−1]中最大的的方向走。
得到词汇表后,我们需要为source语句生成标签,实现的算法伪代码如下:
其思想如下:从source与target的起点开始,遍历source与target,当source当前位置字符与target当前字符相等时,将source当前位置的标签从DELETE变更为KEEP,当source当前位置字符与target当前字符不相等时,向target往后找np个字符,并添加到待添加列表p,若存在其中一个字符与source当前字符相同,则可以认为source中不存在待添加词汇,因此需要将待添加列表作为添加词汇。需要注意的是,当match_found存在时,
x
(
i
s
)
x(i_s)
x(is)首先等于
p
K
E
E
P
p_{KEEP}
pKEEP,在之后会找到第一个DELETE的标签,并将
p
K
E
E
P
p_{KEEP}
pKEEP变为
K
E
E
P
KEEP
KEEP,将第一个DELETE标签变为
p
D
E
L
E
T
E
p_{DELETE}
pDELETE。
当我们构建完成标签后,就可以开始训练判别模型了,预测时,仅需按照标签进行增,删,保留即可。本文对CSL中文标签生成数据集进行了测试,实验结果如下:
100%|██████████| 698/698 [00:47<00:00, 14.54it/s]
{‘main’: 0.5333193455638408, ‘rouge-1’: 0.6020930159841356, ‘rouge-2’: 0.46388364783442765, ‘rouge-l’: 0.5683682080831056, ‘best’: 0.5333193455638408}