好久没有写博客了,这一次就将最近看的pytorch 教程中的lstm+crf的一些心得与困惑记录下来。
参考了很多其他大神的博客,https://blog.youkuaiyun.com/cuihuijun1hao/article/details/79405740
https://www.jianshu.com/p/97cb3b6db573
至于原理,非常建议读这篇英文博客,写的非常非常非常好!!!!!!值得打印出来细细品读!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!https://createmomo.github.io/2017/09/12/CRF_Layer_on_the_Top_of_BiLSTM_1/
在这位大神的基础上,根据自己的debug又添加了一些注释pytorch版的bilstm+crf实现sequence label
为了方便理解:
注意,
self.transitions = nn.Parameter(torch.randn(self.tagset_size, self.tagset_size)) 说明了转移矩阵是随机的!!!随机的!!!随机的!!!,而且放入了网络中,会更新的!!!会更新的!!!会更新的!!!
解释一下重点的函数功能:
def log_sum_exp(vec) 这个函数,是一个封装好的数学公式,里面先做减法的原因在于,减去最大值可以避免e的指数次,计算机上溢。
def _forward_alg(self, feats): 这个函数,只是根据 随机的transitions ,前向传播算出的一个score,用到了动态规划的思想,但是因为用的是随机的转移矩阵,算出的值很大 score>20
def _get_lstm_features(self, sentence): 可以看出,函数里经过了embedding,lstm,linear层,是根据LSTM算出的一个矩阵。这里是11x5的一个tensor,而这个11x5的tensor,就是发射矩阵!!!发射矩阵!!!发射矩阵!!!(emission matrix)
def _score_sentence(self, feats, tags):是根据真实的标签算出的一个score,这与上面的def _forward_alg(self, feats)有什么不同的地方嘛?共同之处在于,两者都是用的随机的转移矩阵算的score,但是不同地方在于,上面那个函数算了一个最大可能路径,但是实际上可能不是真实的 各个标签转移的值。例如说,真实的标签 是 N V V,但是因为transitions是随机的,所以上面的函数得到的其实是N N N这样,两者之间的score就有了差距。而后来的反向传播,就能够更新transitions,使得转移矩阵逼近真实的“转移矩阵”。(个人理解)
def _viterbi_decode(self, feats):维特比解码,实际上就是在预测的时候使用了,输出得分与路径值。
这个函数是重点:
def neg_log_likelihood(self, sentence, tags):
feats = self._get_lstm_features(sentence)#11*5 经过了LSTM+Linear矩阵后的输出,之后作为CRF的输入。
forward_score = self._forward_alg(feats) #0维的一个得分,20.*来着
gold_score = self._score_sentence(feats, tags)#tensor([ 4.5836])
return forward_score - gold_score #这是两者之间的差值,后来直接根据这个差值,反向传播。。。神奇!!!!!!
def forward(self, sentence):forward函数只是用来预测了,train的时候没用调用它,这让我感到很震惊,还有这种操作?
import torch
import torch.autograd as autograd
import torch.nn as nn
import torch.optim as optim
def to_scalar(var): #var是Variable,维度是1
# returns a