文章目录
1.什么是pointer network
如上图所示,
P
1
,
P
2
,
P
3
,
P
4
P_1,P_2,P_3,P_4
P1,P2,P3,P4的坐标分别为(
x
1
,
y
1
x_1,y_1
x1,y1),(
x
2
,
y
2
x_2,y_2
x2,y2),(
x
3
,
y
3
x_3,y_3
x3,y3),(
x
4
,
y
4
x_4,y_4
x4,y4),我们想从这些点中找出几个点,这几个点的坐标连起来后,能涵盖所有点。
以上面这幅图为例,将各个点的坐标输入encoder后,decoder依次输出1、4、2、1。
P
1
,
P
4
,
P
2
P_1,P_4,P_2
P1,P4,P2连起来的点正好是我们想要的结果。
pointer network具体是如何工作的:
pointer是指针的意思
step1
:
decoder的第一个cell输入encoder的结果以及begin(本例中为"→")后,输出一个和encoder的cell数相同(4)的向量,各个元素的大小代表了这四个点的权重,假设为(0.5,0.1,0.3,0.1),那么
P
1
P_1
P1的权重最大,指针就指向
P
1
P_1
P1。
step2
:
decoder的第二个cell输入第一个cell的结果以及
P
1
P_1
P1(因为pointer第一个指向的是
P
1
P_1
P1)的坐标后,同样输出一个包含4个元素的向量(0.1,0.2,0.1,0.6),
P
4
P_4
P4的权重最大,所以指针指向
P
4
P_4
P4。
后面的步骤都是一样,直到输出end(本例中为"←")。
可以看出,pointer network的最后的输出(
P
1
,
P
4
,
P
2
P_1,P_4,P_2
P1,P4,P2),都来自最开始的输入(
P
1
,
P
2
,
P
3
,
P
4
P_1,P_2,P_3,P_4
P1,P2,P3,P4),即相当于把部分输入信息copy到输出。
2.OOV问题
OOV问题(Out Of Vocablaury)指,词典不够大,不能涵盖source中的所有单词。一般我们创建词典的时候,都是选择出现频率较高的词,比如经过分词,一共有2.1万个单词,选择出现频率最高的2万个单词建立vocab,那1000个出现频率较低的词就属于OOV,虽然在输入神经网络前会给这部分低频词统一赋一个’'的编码,但是这多多少少会影响模型整体效果,因为这部分单词全部用来表示了,信息有所丢失。
一个处理该问题的思想就是:直接把这个低频词从输入copy到输出,那么信息就不会丢失了。
那么pointer network就可以完成copy这个步骤。
3. LM with pointer network
假设我们现在要做一个总结摘要的工作,比如输入“Germany emerge victorious 2-0 win against Argentina on Saturday”,我们希望输出“Germany beat Argentina”.
3.1 传统的seq2seq with attention:
decoder中’Germany’的hid + encoder的output → context
context + decoder中’Germany’的hid → vocab distribution(即右上角绿色的部分)
vocab distribution是一个长度为vocab size的向量,每个元素代表了vocab中对应单词的权重,此时代表"beat"的那个元素的权重最大,所以这个cell的结果应该就是"beat".
3.2 LM with pointer net work
从vocab distribution中可以看出,vocab中的词汇为’a’一直到‘zoo’,所以source text中的‘2-0’在vocab中是以‘unk’存在的,虽然在本例最后的输出中不涉及‘2-0’,但是我们还是希望这个信息在输出部分(final distribution)有所体现。
因此我们可以在上述传统模型中加入pointer network。
P
g
P_g
Pg代表传统模型输出的vocab distribution,也就是final distribution中的绿色部分;
P
c
P_c
Pc代表pointer network输出的distribution,也就是final distribution中的蓝色部分。
参照第一节中我们介绍的pointer network的具体工作流程,我们知道,我们使用pointer network就是想知道source text中每个单词的权重,哪个单词的权重最大就copy哪个单词。而attention机制中的attention distribution正好代表了source text中每个单词的权重,所以我们可以直接用attention distribution表示
P
c
P_c
Pc.
因此整个的思路如下:
1.decoder中’Germany’的hid + encoder的output → Attention distribution(即
P
c
P_c
Pc)
2.encoder中每个cell的输出以attention distribution做weight进行加权平均得到context
3.decoder中’Germany’的hid + context → vocab distribution(即
P
g
P_g
Pg)
4.decoder中’Germany’的hid + context →
P
g
e
n
P_{gen}
Pgen(
P
g
e
n
P_{gen}
Pgen是一个scalar)
5.
P
g
e
n
∗
P
g
+
(
1
−
P
g
e
n
)
∗
P
c
P_{gen}*P_g+(1-P_{gen})*P_c
Pgen∗Pg+(1−Pgen)∗Pc 得到final distribution
从最后的final distribution中可以看出,‘2-0’虽然没有在
P
g
P_g
Pg(绿色部分)中体现,但是在
P
c
P_c
Pc中得到了体现(图片放大看,‘zoo’后面那个单词就是‘2-0’)
4.pytorch代码实现LM with pointer network
def get_final_distribution( x, p_gen, p_vocab, attention_weights,batch_oov_num):
batch_size = x.size()[0]
p_gen = torch.clamp(p_gen, 0.001, 0.999)
p_vocab_weighted = p_gen * p_vocab
attention_weighted = (1 - p_gen) * attention_weights
# attention_weighted表示source中每个单词的权重,size为(b,seq_len) 可以看成有b个句子,每个句子长度为seq_len
# 比如(2,5),第一行为[[0.4,0.1,0.2,0.1,0.2]] 就表示第一句中各个单词的权重分别为0.4,0.1 ...
extension = torch.zeros((batch_size,batch_oov_num)).float()
p_vocab_extended = torch.cat([p_vocab_weighted, extension], dim=1)
final_distribution = p_vocab_extended.scatter_add_(dim=1,index=x,src=attention_weighted)
# final_distribution的size为(batch_size,vocab_size+batch_oov_num)
return final_distribution
vocab = {'pad':0
,'unk':1
,'wyb':2
,'and':3
,'xz':4
,'are':5
,'good':6
,'friends':7}
seq1 = 'wyb and xz are actors' # => [2,3,4,5,1,0]
seq2 = 'wyb and xz are dedicated actors' # => [2,3,4,5,1,1]
batch_size = 2
seq_len = 6
vocab_size = 8
x = torch.tensor([[2,3,4,5,8,0],[2,3,4,5,9,8]]) # 8代表‘actors’,9代表‘dedicated’
p_gen = torch.rand((batch_size,1))
p_vocab = torch.rand((batch_size,vocab_size))
attention_weights = torch.rand((batch_size,seq_len))
batch_oov_num = 2 # actors和dedicated这两个单词
final_distribution = get_final_distribution(x, p_gen, p_vocab, attention_weights,batch_oov_num)
final_distribution
tensor([[0.5410, 0.0142, 0.2903, 0.8483, 0.7934, 0.5476, 0.0270, 0.0879, 0.7804,0.0000],
[0.0525, 0.2674, 0.7799, 0.8531, 0.6568, 0.6961, 0.1096, 0.0833, 0.2051,0.2947]])
0.7804就表示第一个句子该cell输出的结果为‘actors’的概率为0.7804(相对概率,还没经过softmax处理)
0.2051表示第二个句子该cell输出的结果为‘actors’的概率为0.2051,0.2947表示第二个句子该cell输出的结果为‘dedicate’的概率为0.2947。