920232796 / bert_seq2seq

pytorch实现 Bert 做seq2seq任务,使用unilm方案,现在也可以做自动摘要,文本分类,情感分析,NER,词性标注等任务,支持t5模型,支持GPT2进行文章续写。

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

UNILM的Attention Mask设置问题。

lierik opened this issue · comments

楼主你好,我对于这个attention的mask还有一点小问题。
目前我在处于测试阶段,生成任务就是简单的复制,给5个数字,然后生成相同的5个数字。这个任务应该很简答, 所以我就用了bert和一个全连接softmax就结束了。

在训练过程中我对这个attention的mask设置有了点问题,如下:
举个例子,batch_size=1,我的5个数字是12345。
我在训练的过程中设置了最大长度是15,我给的输入是:
[[CLS],1,2,3,4,5,[SEP],1,2,3,4,5, [PAD],[PAD]]
7个字符的segment_0,6个segment_1,还有2个pad。
这里我不知道第二个句子要不要加SEP,因为我们是生成任务,如果给了[SEP],那到最后一个SEP的时候我生成出来的应该是啥。。

第二个就是attention mask, 如上文,我的输入是size:[1,15]
所以这个attention mask我就设置的是size[1,15,15]
和楼主图里的设置一样,segment_0的mask全部为1,这样mask矩阵的前7行就是7个1加上8个0
之后segment_1,第一个数字的生成,attention不到自己,也是7个1加上8个0,么?
之后第二个数字,就是8个1加上7个0,以此类推。
最后两行的PAD就全部0.
具体的矩阵就是下面这样的,有点大,辛苦楼主了。

  ([[1., 1., 1., 1., 1., 1., 1., 0., 0., 0., 0., 0., 0., 0., 0.],
    [1., 1., 1., 1., 1., 1., 1., 0., 0., 0., 0., 0., 0., 0., 0.],
    [1., 1., 1., 1., 1., 1., 1., 0., 0., 0., 0., 0., 0., 0., 0.],
    [1., 1., 1., 1., 1., 1., 1., 0., 0., 0., 0., 0., 0., 0., 0.],
    [1., 1., 1., 1., 1., 1., 1., 0., 0., 0., 0., 0., 0., 0., 0.],
    [1., 1., 1., 1., 1., 1., 1., 0., 0., 0., 0., 0., 0., 0., 0.],
    [1., 1., 1., 1., 1., 1., 1., 0., 0., 0., 0., 0., 0., 0., 0.],
    [1., 1., 1., 1., 1., 1., 1., 0., 0., 0., 0., 0., 0., 0., 0.],
    [1., 1., 1., 1., 1., 1., 1., 1., 0., 0., 0., 0., 0., 0., 0.],
    [1., 1., 1., 1., 1., 1., 1., 1., 1., 0., 0., 0., 0., 0., 0.],
    [1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 0., 0., 0., 0., 0.],
    [1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 0., 0., 0., 0.],
    [1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 0., 0., 0.],
    [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
    [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]])

不知道这样的attentionmask对不对,因为我最后生成出来的效果不好,经常是全5,全7,全PAD,不会完整的复制。

首先,第二个句子结束应该加SEP,这是bert的标准输入。预测啥不用管,计算loss的时候会用特殊的mask让这个地方的预测值不起作用。

就是这个attention mask的话,你去看bert源码,行是表示的输出,列代表输入,比如a[0, 0]这个值,如果是1,表示的是CLS这个位置的输出,是会受到CLS这个输入的影响。再往后推一步,a[1, 1]这个值为1,表示数字1这个位置的输出,会受到数字1这个输入的影响。

你预测PAD其实很可能是你计算loss的时候,没有把不应该加入loss的部分给去掉,还得需要一个mask,专门计算loss的,而且你如果第二个句子没有SEP标志,模型是不知道什么时候预测结束的。最后beam-search解码的时候,必须是需要模型预测到SEP标志,才停止解码。

好的,我先给第二个句子也加上SEP。
之后attentionmask,正常的bert输入应该是和句子一样维度,比如我这里是input是[1,15],attention也应该是[1,15]这样才能表示位置的一一对应,但是在训练过程中,我设置的这个attentionmask是[1,15,15],也就是说一个15的长度的句子,我给的attentionmask矩阵是[15,15],我想的是训练过程中的应该是并行的,在我这个复制任务条件下,就是走了一次decoder,但是对每个位置生成,这样想是对的么?这个是我看了Transformers的源码得到的结论,训练过程每个batch只有一次decoder,生成过程则是生成多长字符走多少次decoder,如果不对,希望楼主指出。。

如果是对的话,那我想的就是,生成第一个字符,也就是segment_0的第一个字符,上面的假设就是数字1,这个生成考虑的是[15,15]的attentionmatrix中的[:1,:],就是第一行,这里我用切片表示了。
然后第二个数字2,使用的是[15,15]的attentionmaskmatrix中的[1:2,:],就是第二行。
以此类推,不知道我这样的操作对UNLIM的理解对不对。

我在坐loss的时候对输出进行了切片,只计算生成的1,2,3,4,5,[SEP]这六个字符的交叉熵。
我还没有进行inference,因为训练时loss降不下去,然后发现loss降不下去是因为模型对每一个字符都是相同的生成,就是全1,全sep等等。

谢谢楼主,又长篇大论的一通,这个问题已经困扰我一个星期了,我都没有解决。。

对 训练的时候 因为提前构造好了mask 所以走一次就会预测所有字符 计算loss。 但是预测的时候,由于不知道输出是啥,因此需要一个一个字符这样预测~

其实unilm 你别想太复杂 bert 本身不是有个attention mask 么 unilm 其实只是改变了这个mask 而已 decoder方式跟bert一样呀 没有啥区别

那我这样设置attentionmask矩阵对么,我看官方实例给的代码都是attentionmask张量和input张量同纬度,这里我是给了个方阵。。而且loss的时候我通过切片,只输出了生成的那6个字符(1,2,3,4,5,SEP),就这6个字符和标准的做loss,这个也没问题么。。
我确实没想的复杂, 所以就先做个小测试,但是不知道为什么,它就是输出全一样的字符,这个字符是啥都可能,我根本想不通哪里不对,都是按照论文的思路来的并且还看过好多别人写的心得啥的。。

如果楼主方便,能不能麻烦你针对我这个情况给一个attentionmask的输入呢,如果5个字符太长,2个也行,能意思一下就可以。。谢谢了。。

我在坐loss的时候对输出进行了切片,只计算生成的1,2,3,4,5,[SEP]这六个字符的交叉熵。 你这句话有问题哈,你计算错了,loss。

应该是计算 SEP 1, 2, 3, 4, 5 这六个字符的交叉熵

预测到5以后,5这个位置应该预测SEP,往后就通通不要计算loss了。因为最后的SEP预测的是PAD了,你如果计算了这个loss,模型就会预测PAD。

就是segment_0的SEP和segment_1的所有有效字符么?

是的。

好的,我去改改试试,那attentionmask我的设置有问题么,我心里总是有点没底。。

输入如果是 cls , 1, 2, sep, 1, sep pad, mask应该是:

1, 1, 1, 1, 0, 0, 0
1, 1, 1, 1, 0, 0, 0
1, 1, 1, 1, 0, 0, 0
1, 1, 1, 1, 0, 0, 0
1, 1, 1, 1, 1, 0, 0
1, 1, 1, 1, 1, 1, 0

最后一行不用关心,只要保证最后一列为0就ok,最后一行因为以后计算loss会有个mask把让数值不产生作用。

好的,感谢!我这就去试试

没事没事,加油咯~

奥利给!

楼主不好意思我又来问个问题,我这里有了一点进展,有了一定的结果。但是还有点疑惑:

  1. 比如输入的是[cls,1,2,sep,1,2,sep],如果我的输入正确的话,训练过程中经过模型之后应该是输出[cls,1,2,sep,1,2,sep],还是应该输出[1,2,sep,1,2,pad]呢?

  2. 就是我在算的时候loss仅仅是后面的,前面的没有考虑,是不是最后会导致模型前面的输出是混乱的,仅仅segment_1是输出了1,2,但是segment_0是随便输出的数字呢?

因为我目前loss已经降了,可以完成复制,但是我看了中间的输出结果,是[4,4,4,4,1,2,sep]这种,而不是[cls,1,2,sep,1,2,sep]或者是[1,2,sep,1,2,sep,pad]

前面是你的输入,所以不用管阿,管它输出啥,反正你已经知道输入是什么了,不是么。

输出: [#,#,#,#,1,2,sep], #代表无所谓,输出啥也不用管,loss也不用去计算。

好的,谢谢楼主,我成功了,万分感谢!

给个star呗,哈哈 多谢啦!

忘记了,忘记了,应该的!