fastnlp / fastNLP

fastNLP: A Modularized and Extensible NLP Framework. Currently still in incubation.
https://gitee.com/fastnlp/fastNLP
Apache License 2.0
3.06k stars 450 forks source link

A question in crf.py #365

Closed tyistyler closed 3 years ago

tyistyler commented 3 years ago

您好,我发现在decoder的crf.py的代码中,第263行是这样写的 score = trans_score + emit_score[:seq_len - 1, :] 其中的trans_score大小为[seq_len-1, batch_size],trans_score[0][0]代表第0个句子的第0个字符到第1个字符的转移得分; 而emit_score[:seq_len - 1, :]的大小为[seq_len-1, batch_size],emit_score[0, 0]代表第0个句子第0个字符的发射得分; 但是第0个句子第0个字符的转移得分不应该是start字符到第0个字符的score么?请问这里为什么不写成 score = trans_score + emit_score[1:, :]呢 感谢您的解答~

yhcc commented 3 years ago

start字符和end字符的分数是单独通过start_scores和end_scores来计算的,因为在include_start_end_trans参数为False的时候,我们不考虑start和end字符,如果采用您说的这种方式,实现这个比较麻烦。所以我们就把start和end的分数计算从trans_scores中单独分离出来了。

tyistyler commented 3 years ago

谢谢您的回复。 可能是我没有表述清楚问题, 在score = trans_score + emit_score[:seq_len - 1, :]中 trans_score[0][0]代表第0个句子的第0个字符到第1个字符的转移得分 emit_score[0][0] 代表第0个句子的第0个字符的发射得分 二者相加时,我感觉十分困惑,因为trans_score[0][0]我理解的是第1个字符的转移得分(从位置为0的字符转移到位置为1的字符),将二者相加时,感觉错位了,将0号字符的发射得分与1号字符的转移得分进行了相加,但是第264行的score.sum(0)加法缓解了这个问题。 我个人的看法是,将263和264行的 score = trans_score + emit_score[:seq_len - 1, :] score = score.sum(0) + emit_score[-1].masked_fill(flip_mask[-1], 0)

替换为 score_new = trans_score + emit_score[1:, :] score_new = score1.sum(0) + emit_score[0] 是否更好理解?(二者的结果,我用两个例子验证了一下,是相同的)

yhcc commented 3 years ago

感觉没有错位。这里应该是由于有两种不同的视角造成的,第一个视角是(我们的实现):[第i个字符的发射分数+第i个字符转移到第1个字符的分数]来得到第i个字符的分数,然后sum所有的i,这种做法会在最后一个时刻无法计算,因为最后一个时刻不再有i+1的跳转分数。第二个视角是(您的做法),就是[第i个字符的发射分数+(第i+1个字符的分数+第i个字符跳转到第i+1个字符的分数)],但实作的时候是通过把第0个单独拿出来(也就是您做法里面的emit_score[0]),然后sum所有的第i+1个字符的分数+第i个字符跳转到第i+1个字符的分数。这两种应该是等价的。

choosewhatulike commented 3 years ago

补充一下 @yhcc 的回答。对于一个长度为N的序列,有 N 个发射分数和 N-1 个转移分数 (N个点和中间N-1条边)。而我们求的 score 其实就是这些分数求和。因为是求和,所以先加谁后加谁都是可以的。您这里使用另一种方式实现了这个求和,理论上可以有很多种实现方式,都是等价的。

tyistyler commented 3 years ago

感谢您的解答