精华内容
下载资源
问答
  • biLSTM-CRF
    千次阅读
    2021-10-09 19:37:57

    BILSTM-CRF代码

    代码来源于命名实体识别(NER):BiLSTM-CRF原理介绍+Pytorch_Tutorial代码解析
    第一部分:导包
    1.torch.nn包中主要包含了用来搭建各个层的模块(Modules),比如全连接、二维卷积、池化等;torch.nn包中还包含了一系列有用的loss函数。
    2.torch.optim包则主要包含了用来更新参数的优化算法,比如SGD、AdaGrad、RMSProp、 Adam等。
    3.import torch.autograd as autograd这是求自动微分的

    第二部分
    用于设置随机初始化的种子,即上述的编号,编号固定,每次获取的随机数固定。

    1.设置标签与BILSTM隐藏层
    首先确定标签个数:SBIOE
    BILSTM的隐藏特征个数4,单向为2。

    START_TAG = "<START>"
    STOP_TAG = "<STOP>"
    EMBEDDING_DIM = 5  # 由于标签一共有B\I\O\START\STOP 5个,所以embedding_dim为5
    HIDDEN_DIM = 4  # 这其实是BiLSTM的隐藏层的特征数量,因为是双向所以是2倍,单向为2
    

    2.数据集
    这里用两个句子来测试,每一个句子对应的词性都有正确的标签。

    training_data = [(
        "the wall street journal reported today that apple corporation made money".split(),
        "B I I I O O O B I O O".split()
    ), (
        "georgia tech is a university in georgia".split(),
        "B I O O O O B".split()
    )]
    

    3.处理数据集中句子的词,不重复的将句子中的词拿出来并标号。
    设置一个word_to_ix存储句子中每一个单词。
    首先我们拿出每一个句子跟其对应的标签,用sentence与tag循环每一个句子,比如第0次抽出来的就是第一个句子"the wall …money",与他的标签"B I I …0"。
    现在我们只存储出现过的单词(不管标签),下面代码解释:

    word_to_ix = {}
    for sentence, tags in training_data:
        for word in sentence:
            if word not in word_to_ix: #word_to_ix是否包含左边的内容
                word_to_ix[word] = len(word_to_ix)
    

    if word not in word_to_ix:
    word_to_ix[word] = len(word_to_ix)

    这句就是说word_to ix没有word这句单词时候,就存储进去,并且给每一个新的word赋值,赋的值就是长度。

    最终的结果为都在word_to_ix中:
    word_to_ix: {‘the’: 0, ‘wall’: 1, ‘street’: 2, ‘journal’: 3, ‘reported’: 4, ‘today’: 5, ‘that’: 6, ‘apple’: 7, ‘corporation’: 8, ‘made’: 9, ‘money’: 10, ‘georgia’: 11, ‘tech’: 12, ‘is’: 13, ‘a’: 14, ‘university’: 15, ‘in’: 16}

    4.将5个标签存到tag_to_ix的字典中。

    tag_to_ix = {"B": 0, "I": 1, "O": 2, START_TAG: 3, STOP_TAG: 4}
    

    5.几个实用的小函数

    def prepare_sequence(seq, to_ix):
        idxs = [to_ix[w] for w in seq]  #  将句子”w1 w2 w3”(词序列)[w1,w2,w3..]中的词w转化为在词表中的索引值 to_ix [w] 
        return torch.tensor(idxs, dtype=torch.long)
    def argmax(vec):
        # 得到最大的值的索引
        _, idx = torch.max(vec, 1)
        return idx.item()
    def log_sum_exp(vec):
        max_score = vec[0, argmax(vec)]  # max_score的维度为1
        max_score_broadcast = max_score.view(1, -1).expand(1, vec.size()[1])  # 维度为1*5
        return max_score + torch.log(torch.sum(torch.exp(vec - max_score_broadcast)))
    

    6.接下来,我们将我们的句子输入到BILSTM-CRF模型,

    model = BiLSTM_CRF(len(word_to_ix), tag_to_ix, EMBEDDING_DIM, HIDDEN_DIM)
    

    第三部分.重点讲解BILSTM-CRF模型
    那么我们先看一下BILSTM_CRF模型:

    class BiLSTM_CRF(nn.Module):
        def __init__(self, vocab_size, tag_to_ix, embedding_dim, hidden_dim):
            super(BiLSTM_CRF, self).__init__()
            self.embedding_dim = embedding_dim # 嵌入维度
            self.hidden_dim = hidden_dim  # 隐藏层维度
            self.vocab_size = vocab_size # 词汇大小
            self.tag_to_ix = tag_to_ix  # 标签转为下标
            self.tagset_size = len(tag_to_ix)  # 目标取值范围大小
    
            self.word_embeds = nn.Embedding(vocab_size, embedding_dim)  # 嵌入层
            self.lstm = nn.LSTM(embedding_dim, hidden_dim // 2, num_layers=1, bidirectional=True)   # 双向LSTM
            self.hidden2tag = nn.Linear(hidden_dim, self.tagset_size)
            # 转移矩阵,transitions[i][j]表示从label_j转移到label_i的概率,虽然是随机生成的但是后面会迭代更新
            self.transitions = nn.Parameter(torch.randn(self.tagset_size, self.tagset_size))
    
            self.transitions.data[tag_to_ix[START_TAG], :] = -10000  # 从任何标签转移到START_TAG不可能
            self.transitions.data[:, tag_to_ix[STOP_TAG]] = -10000  # 从STOP_TAG转移到任何标签不可能
    
            self.hidden = self.init_hidden()  # 随机初始化LSTM的输入(h_0, c_0)
    

    1.定义模型def_init_():

    class BiLSTM_CRF(nn.Module):
    def init(self, vocab_size, tag_to_ix, embedding_dim, hidden_dim):

    描述class XX(nn.Module):def _init_的操作,可以看这个链接。
    vocab_size就是len(word_to_ix)的长度,也就是所有的词(不重复)。将tag_to_ix也穿过来,embedding_dim就是标签数量,hidden_dim是bilstm层隐藏数量。

    super(BiLSTM_CRF, self).init()

    和自定义模型一样,这句话就是调用父类的构造函数。
    (2)定义一些模型参数,下面解释一点自己不会的

    self.word_embeds = nn.Embedding(vocab_size, embedding_dim) # 嵌入层

    这里是nn.Embedding的理解
    简单来说就是把词向量放入网络,词向量的输出应该是什么样子,输出是:(vocab_size,embedding_dim)。

    self.lstm = nn.LSTM(embedding_dim, hidden_dim // 2, num_layers=1, bidirectional=True)

    这是nn.LSTM的理解
    输入的是词向量纬度embedding_dim=5,hidden_dim的纬度为4/2=2,循环神经网络的层数为1,bidirecton代表使用双向LSTM。

    同理,PyTorch的nn.Linear()是用于设置网络中的全连接层的。

    下面这行代码就是看转移概率的,也就是从一个tag->tag:
    transition矩阵是随机生成的,他会进行更新迭代。

    self.transitions = nn.Parameter(torch.randn(self.tagset_size, self.tagset_size))
    self.transitions.data[tag_to_ix[START_TAG], :] = -10000 # 从任何标签转移到START_TAG不可能
    self.transitions.data[:, tag_to_ix[STOP_TAG]] = -10000 # 从STOP_TAG转移到任何标签不可能

    (1)定义def init_hidden()函数:

        def init_hidden(self):
            return (torch.randn(2, 1, self.hidden_dim // 2),
                    torch.randn(2, 1, self.hidden_dim // 2))
    

    这应该就是双层lstm隐藏层,因为是双向的,所以生成2个,每一个纬度为(1,self.hidden_dim//2),随机初始化隐藏层的输入,这个函数用self.hidden = self.init_hidden()之后:

        (tensor([[[ 1.1456, -0.0378]],[[ 0.9321,  0.5295]]]), 
        tensor([[[-1.5295,  0.2228]],[[-1.4066, -0.2268]]]))
    

    (2)应该是计算总路径的分数

        def _forward_alg(self, feats):  #前向算法,feats是LSTM所有时间步的输出
            '''
            输入:发射矩阵(emission score),实际上就是LSTM的输出——sentence的每个word经BiLSTM后,对应于每个label的得分
            输出:所有可能路径得分之和/归一化因子/配分函数/Z(x)
            '''
            init_alphas = torch.full((1, self.tagset_size), -10000.)#初始化得分值全部为-10000,并置start_tag的值为0,这个思想类似于dijkstra计算最短路径的第一步
            init_alphas[0][self.tag_to_ix[START_TAG]] = 0. # start位置的alpha为0
    
            # 包装到一个变量里面以便自动反向传播
            forward_var = init_alphas
            for feat in feats:  # w_i
                alphas_t = []
                for next_tag in range(self.tagset_size):  # tag_j  next_tag有target_size个可能的取值
                    # t时刻tag_i emission score(1个)的广播。需要将其与t-1时刻的5个previous_tags转移到该tag_i的transition scors相加
                    emit_score = feat[next_tag].view(1, -1).expand(1, self.tagset_size)  # 1*5: 遍历标签集 发射分数emission_score[i][j]是词i被标注为词性j的概率 两层for循环里第一层为词序列中的第i个特征(词性),第二层为标签集中的第j种标签(词性)
                    # t-1时刻的5个previous_tags到该tag_i的transition scors
                    trans_score = self.transitions[next_tag].view(1, -1)  # 维度是1*5 转移分数transitions_socre[m1][m2]是序列中当前词的前一个词被标注为m1下,当前词被标注为m2的概率 . 即由m1转移到下一个状态为m2的概率
    
                    next_tag_var = forward_var + trans_score + emit_score
                    # 求和,实现w_(t-1)到w_t的推进
                    alphas_t.append(log_sum_exp(next_tag_var).view(1))
                forward_var = torch.cat(alphas_t).view(1, -1)  # 1*5 forward_var size:[1][标签集大小]
                # 每个时间步标注为词性j j->[1-len(tags)] 的分数 每个时间步都更新 for循环遍历结束后 forward_var就是遍历词序列末尾时的最后一个分数
    
            # 最后将最后一个单词的forward var与转移 stop tag的概率相加
            terminal_var = forward_var + self.transitions[self.tag_to_ix[STOP_TAG]]
            alpha = log_sum_exp(terminal_var)
            return alpha
    

    这个函数,只是根据 随机的transitions ,前向传播算出的一个score,用到了动态规划的思想,但是因为用的是随机的转移矩阵,算出的值很大 score>20。这是计算总路径之和,这篇知乎介绍了方法,看懂这个方法才能读懂代码。BiLSTM-CRF中CRF计算细节
    或者看这篇博客的代码解析:pytorch中biLSTM_CRF模型源码学习
    或者BILSTM_CRF代码解析

    分析代码,:

    init_alphas = torch.full((1, self.tagset_size), -10000.)

    torch.full就是说,我创建一个(1,self.tagset_size)的纬度的矩阵,每一个都是-10000:
    这个意思可能是:初始化得分值全部为-10000,并置start_tag的值为0,这个思想类似于dijkstra计算最短路径的第一步。

    for feat in feats:

    遍历句子 feats是一个[句长][标签集大小]的矩阵,总时间步==句长,这个循环就是循环11个词。(第一句话有11个词),第一个词的5个标签概率如下图:

        tensor([-0.2095,  0.1737, -0.3876,  0.4378, -0.3475]
    

    for next_tag in range(self.tagset_size):

    再循环5个标签中的第一个标签,在上面链接的知乎可以知道,我们需要将1个标签概率扩成(1,5)纬度。计算

    next_tag_var = forward_var + trans_score + emit_score

    纬度如下:

     tensor([[-10000., -10000., -10000.,      0., -10000.]]) 
     trans_score: tensor([[-1.1811e-01, -1.4420e+00, -1.1108e+00, -1.1187e+00, -1.0000e+04]],grad_fn=<ViewBackward>)
     emit_score: tensor([[-0.2095, -0.2095, -0.2095, -0.2095, -0.2095]],grad_fn=<ExpandBackward>)
    

    alphas_t.append(log_sum_exp(next_tag_var).view(1))

    将每一个Pmt(1,5)维(3个1,5维矩阵加起来的之和),经过log_sum_exp变成一个数字,逐步添加到alphas_t,最终aphps是(1,5)维。
    将alphas_t是保存Pmt,(m是标签个数,t是第几个词),这个其实就到第t个词的路径分数。m个标签,他当前就有m个路径。

    forward_var = torch.cat(alphas_t).view(1, -1)

    这时候已经出标签循环了,第t个词所有m个标签概率已经循环结束,f
    forward_var size:[1][标签集大小]每个时间步标注为词性j j->[1-len(tags)] 的分数 每个时间步都更新 for循环遍历结束后 forward_var就是遍历词序列末尾时的最后一个分数。
    紧接着进入第二个词的循环,不断的用forward_var_size,当一个句子所有的词循环结束,跳出循环。

    terminal_var = forward_var +self.transitions[self.tag_to_ix[STOP_TAG]]
    alpha = log_sum_exp(terminal_var)

    最后加上句子最后一个词转移到STOP_TAG的分数,得到所有可能路径的得分总和。

    (3)其中得到lstm层得到feats:

    def _get_lstm_features(self, sentence):
    	self.hidden = self.init_hidden()#初始化状态向量
    	embeds = self.word_embeds(sentence) #获取句向量:用相应的词向量替换每一个词
        embeds = embeds.unsqueeze(1)#在1的位置加上一个维数为1的维度
     	lstm_out, self.hidden = self.lstm(embeds, self.hidden)#lstm层 输入句向量和状态向量,输出一个输出向量和状态向量 
    	lstm_out = lstm_out.view(len(sentence), self.hidden_dim)#reshape 输出向量扁平化为[句长,隐藏层维度]
    	lstm_feats = self.hidden2tag(lstm_out) #全连接层 将扁平化的词向量映射到类别的编号
    	return lstm_feats
    

    可以看出,函数里经过了embedding,lstm,linear层,是根据LSTM算出的一个矩阵。这里是11x5的一个tensor,而这个11x5的tensor,就是发射矩阵!!!发射矩阵!!!发射矩阵!!!(emission matrix)
    (4)计算标签序列在当前模型的得分

    def _score_sentence(self, feats, tags):
            # Gives the score of a provided tag sequence
            score = torch.zeros(1)
            tags = torch.cat([torch.tensor([self.tag_to_ix[START_TAG]], dtype=torch.long), tags])
            for i, feat in enumerate(feats):
                score = score + \
                    self.transitions[tags[i + 1], tags[i]] + feat[tags[i + 1]] #递推计算路径分数:转移分数+发射分数
            score = score + self.transitions[self.tag_to_ix[STOP_TAG], tags[-1]]#加上句子最后一个词转移到STOP_TAG的转移分数
            return score
    

    根据真实的标签算出的一个score,这与上面的def _forward_alg(self, feats)有什么不同的地方嘛?共同之处在于,两者都是用的随机的转移矩阵算的score,但是不同地方在于,上面那个函数算了一个最大可能路径,但是实际上可能不是真实的 各个标签转移的值。例如说,真实的标签 是 N V V,但是因为transitions是随机的,所以上面的函数得到的其实是N N N这样,两者之间的score就有了差距。而后来的反向传播,就能够更新transitions,使得转移矩阵逼近真实的“转移矩阵”。(个人理解)。
    (5)维特比算法

        #解码,得到预测的序列,以及预测序列的得分
        def _viterbi_decode(self, feats):
            backpointers = []
     
            # Initialize the viterbi variables in log space
            init_vvars = torch.Tensor(1, self.tagset_size).fill_(-10000.)
            init_vvars[0][self.tag_to_ix[START_TAG]] = 0
     
            # forward_var at step i holds the viterbi variables for step i-1
            forward_var = autograd.Variable(init_vvars)
            for feat in feats:
                bptrs_t = []  # holds the backpointers for this step
                viterbivars_t = []  # holds the viterbi variables for this step
     
                for next_tag in range(self.tagset_size):
                    # next_tag_var[i] holds the viterbi variable for tag i at the
                    # previous step, plus the score of transitioning
                    # from tag i to next_tag.
                    # We don't include the emission scores here because the max
                    # does not depend on them (we add them in below)
                    next_tag_var = forward_var + self.transitions[next_tag] #其他标签(B,I,E,Start,End)到标签next_tag的概率
                    best_tag_id = argmax(next_tag_var)
                    bptrs_t.append(best_tag_id)
                    viterbivars_t.append(next_tag_var[0][best_tag_id].view(1))
                # Now add in the emission scores, and assign forward_var to the set
                # of viterbi variables we just computed
                forward_var = (torch.cat(viterbivars_t) + feat).view(1, -1)#从step0到step(i-1)时5个序列中每个序列的最大score
                backpointers.append(bptrs_t) #bptrs_t有5个元素
     
            # Transition to STOP_TAG
            terminal_var = forward_var + self.transitions[self.tag_to_ix[STOP_TAG]]#其他标签到STOP_TAG的转移概率
            best_tag_id = argmax(terminal_var)
            path_score = terminal_var[0][best_tag_id]
     
            # Follow the back pointers to decode the best path.
            best_path = [best_tag_id]
            for bptrs_t in reversed(backpointers):#从后向前走,找到一个best路径
                best_tag_id = bptrs_t[best_tag_id]
                best_path.append(best_tag_id)
            # Pop off the start tag (we dont want to return that to the caller)
            start = best_path.pop()
            assert start == self.tag_to_ix[START_TAG]  # Sanity check
            best_path.reverse()# 把从后向前的路径正过来
            return path_score, best_path
    

    维特比解码,实际上就是在预测的时候使用了,输出得分与路径值。
    (6)loss函数-非常重要!!!这就是利用了用"真实路径”-总路径的loss,从而迭代更新!应该就是下面这个公式:
    在这里插入图片描述

    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 #这是两者之间的差值,后来直接根据这个差值,反向传播
    

    (7)forward函数

        def forward(self, sentence):
            '''
            解码过程,维特比解码选择最大概率的标注路径
            '''
            lstm_feats = self._get_lstm_features(sentence)
    
            score, tag_seq = self._viterbi_decode(lstm_feats)
            return score, tag_seq
    

    def forward(self, sentence):forward函数只是用来预测了,train的时候没用调用它。

    第四部分.训练数据集
    (1)梯度下降

    optimizer = optim.SGD(model.parameters(), lr=0.01, weight_decay=1e-4)
    
    for epoch in range(300):
        for sentence, tags in training_data:
            model.zero_grad()
    
            # 输入
            sentence_in = prepare_sequence(sentence, word_to_ix)
            targets = torch.tensor([tag_to_ix[t] for t in tags], dtype=torch.long)
    
            # 获取loss
            loss = model.neg_log_likelihood(sentence_in, targets)
    
            # 反向传播
            loss.backward()
            optimizer.step()
    
    更多相关内容
  • 为解决该问题, 本文提出了一种基于BERT-BiLSTM-CRF模型的研究方法. 首先通过BERT模型预处理生成基于上下文信息的词向量, 其次将训练出来的词向量输入BiLSTM-CRF模型做进一步训练处理. 实验结果表明, 该模型在MSRA...
  • BERT-BiLSTM-CRF-master.zip

    2020-07-17 10:58:56
    # BERT-BiLSTM-CRF BERT-BiLSTM-CRF的Keras版实现 ## BERT配置 1. 首先需要下载Pre-trained的BERT模型,本文用的是Google开源的中文BERT模型: - ...
  • 将MOOC课程评论评价对象和评价词的抽取问题看作序列标注问题,利用BiLSTM模型获取MOOC课程评论中评价对象和评价词的上下文信息,利用CRF模型获取MOOC课程评论中评价对象和评价词的整体信息,从而标注出MOOC课程评论...
  • NER的BERT-BILSTM-GCN-CRF在原本BERT-BILSTM-CRF上融合GCN和词性标签等做NER任务数据格式高B-剧种B-名词腔I-剧种I-名词:OO马B-人名B-名词平I-人名I-名词所OO着O B动词扶O B动词贫O I动词小O B -名词I O-名词运行
  • Bert-BiLSTM-CRF-pytorch-master (1).zip,Bert-BiLSTM-CRF-pytorch-master,crf.py,crf_predict.py,main.py,utils.py,data,example.train,example.test,example.dev,data_process.ipynb,LICENSE,model.py,.gitignore,...
  • BERT-BiLSTM-CRF-NER-master.zip,BERT-BiLSTM-CRF-NER-master,setup.py,terminal_predict.py,run.py,requirement.txt,data_process.py,pictures,service_1.png,predict.png,server_help.png,service_2.png,03E18A6A9...
  • BERT-BiLSTM-CRF-NERTensorflow solution of NER task Using BiLSTM-CRF model with Google BERT Fine-tuning使用谷歌的BERT模型在BLSTM-CRF模型上进行预训练用于中文命名实体识别的Tensorflow代码'中文文档请查看 ...
  • BiLSTM + CRF用于顺序标记任务 :rocket: :rocket: :rocket: BiLSTM + CRF模型的TensorFlow实现,用于序列标记任务。项目特色基于Tensorflow API。 高度可扩展; 一切都是可配置的。 模块化,结构清晰。 对初学者非常...
  • BI-LSTM-CRF模型的PyTorch实现。特征: 与相比,执行了以下改进: 全面支持小批量计算完全矢量化的实现。 特别是,删除了“得分句”算法中的所有循环,从而极大地提高了训练效果支持CUDA 用于非常简单的API START / ...
  • 下载即可运行 1、data文件夹(数据) 2、bilstm_crf_model.py(模型) 3、process_data.py(数据预处理文件) 4、train.py(模型训练文件) 5、val.py(测试文件) 6、model.png(模型结构图)
  • 使用BiLSTM-CRF模型的NER任务的PyTorch解决方案。 此存储库包含BiLSTM-CRF模型的PyTorch实现,用于命名实体识别任务。 代码结构 在项目的根目录,您将看到: ├── pyner | └── callback | | └── ...
  • 站点小号ELF-细心BiLSTM-ÇRF瓦特第I和T ransferredËmbeddings为因果关系提取。 arXiv论文链接: : 免费... 在此基础上,我们提出了一种以BiLSTM-CRF模型为骨干的神经因果提取器,称为SCITE(自注意力BiLSTM-CRF传递嵌
  • 因此本文针对财产纠纷审判案件,提出了一种基于SVM-BiLSTM-CRF的神经网络模型.首先利用SVM筛选出包含关键命名实体的句子,然后将正确包含此类实体的句子转化为字符级向量作为输入,构建适合财产纠纷裁判文书命名实体...
  • 中文命名实体识别任务下的Keras解决方案,下游模型支持BiLSTM-CRF/BiGRU-CRF/IDCNN-CRF/single-CRF,预训练语言模型采用BERT系列(谷歌的预训练语言模型:支持BERT/RoBERTa/ALBERT)。如果对您有帮助,欢迎点Star呀~...
  • 命名实体识别代码,BiLSTM-CRF代码,Tensorflow框架
  • 任务使用BiLSTM-CRF/BiGRU-CRF/IDCNN-CRF模型和预训练语言模型的Keras解决方案:支持BERT/RoBERTa/ALBERT )。 更新日志 2020年2月27日重构的代码keras_bert_ner并删除了一些多余的文件。 bert4keras == 0.2.5现在已...
  • Improving sentiment analysis via sentence type classification using BiLSTM-CRF and CNN
  • 用于中文命名实体识别的简单BiLSTM-CRF模型 该存储库包含用于为中文命名实体识别任务构建非常简单的基于字符的BiLSTM-CRF序列标签模型的代码。 其目标是识别三种类型的命名实体:PERSON,LOCATION和ORGANIZATION。 ...
  • BILSTM-CRF

    2020-11-22 18:24:10
    介绍——在命名实体识别任务中,BiLSTM模型中CRF层的通用思想 详细的实例——通过实例来一步步展示CRF的工作原理 实现——CRF层的一步步实现过程 谁可以读本文——本文适用与NLP初级入门者或者AI其他相关领域 ...

    本文框架如下:

    介绍——在命名实体识别任务中,BiLSTM模型中CRF层的通用思想

    详细的实例——通过实例来一步步展示CRF的工作原理

    实现——CRF层的一步步实现过程

    谁可以读本文——本文适用与NLP初级入门者或者AI其他相关领域

    需要有的基础知识:你只需要知道什么是命名实体识别,如果你不懂神经网络,条件随机场(CRF)或者其它相关知识,不必担心,本文将向你展示CRF层是如何工作的。本文将尽可能的讲的通俗易懂。

    1.介绍

            基于神经网络的方法,在命名实体识别任务中非常流行和普遍。在文献【1】中,作者提出了Bi-LSTM模型用于实体识别任务中,在模型中用到了字嵌入和词嵌入。本文将向你展示CRF层是如何工作的。

            如果你不知道Bi-LSTM和CRF是什么,你只需要记住他们分别是命名实体识别模型中的两个层。

    1.1开始之前

            我们假设我们的数据集中有两类实体——人名和地名,与之相对应在我们的训练数据集中,有五类标签:

            B-Person, I- Person,B-Organization,I-Organization, O

           假设句子x由五个字符w1,w2,w3,w4,w5组成,其中【w1,w2】为人名类实体,【w3】为地名类实体,其他字符标签为“O”。

    1.2BiLSTM-CRF模型

            以下将给出模型的结构:

            第一,句子x中的每一个单元都代表着由字嵌入或词嵌入构成的向量。其中,字嵌入是随机初始化的,词嵌入是通过数据训练得到的。所有的嵌入在训练过程中都会调整到最优。

            第二,这些字或词嵌入为BiLSTM-CRF模型的输入,输出的是句子x中每个单元的标签。

     

    图1. Bi-LSTM结构图

            尽管一般不需要详细了解BiLSTM层的原理,但是为了更容易知道CRF层的运行原理,我们需要知道BiLSTM的输出层。

     

    图2.Bi-LSTM标签预测原理图

            如上图所示,BiLSTM层的输出为每一个标签的预测分值,例如,对于单元w0,BiLSTM层输出的是1.5 (B-Person), 0.9 (I-Person), 0.1 (B-Organization), 0.08 (I-Organization) and 0.05 (O). 这些分值将作为CRF的输入。

    1.3 如果没有CRF层会怎样

            你也许已经发现了,即使没有CRF层,我们也可以训练一个BiLSTM命名实体识别模型,如图3.所示:

     

    图3.去除CRF的BiLSTM命名实体识别模型

            由于BiLSTM的输出为单元的每一个标签分值,我们可以挑选分值最高的一个作为该单元的标签。例如,对于单元w0,“B-Person”有最高分值—— 1.5,因此我们可以挑选“B-Person”作为w0的预测标签。同理,我们可以得到w1——“I-Person”,w2—— “O” ,w3——“B-Organization”,w4——“O”。

            虽然我们可以得到句子x中每个单元的正确标签,但是我们不能保证标签每次都是预测正确的。例如,图4.中的例子,标签序列是“I-Organization I-Person” and “B-Organization I-Person”,很显然这是错误的。

     

    图4. 去除CRF层的BiLSTM模型

    1.4CRF层能从训练数据中获得约束性的规则

            CRF层可以为最后预测的标签添加一些约束来保证预测的标签是合法的。在训练数据训练过程中,这些约束可以通过CRF层自动学习到。

    这些约束可以是:

    I:句子中第一个词总是以标签“B-“ 或 “O”开始,而不是“I-”

    II:标签“B-label1 I-label2 I-label3 I-…”,label1, label2, label3应该属于同一类实体。例如,“B-Person I-Person” 是合法的序列, 但是“B-Person I-Organization” 是非法标签序列.

    III:标签序列“O I-label” is 非法的.实体标签的首个标签应该是 “B-“ ,而非 “I-“, 换句话说,有效的标签序列应该是“O B-label”。

    有了这些约束,标签序列预测中非法序列出现的概率将会大大降低。



    作者:御风之星
    链接:https://www.jianshu.com/p/97cb3b6db573
    来源:简书
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

    展开全文
  • 基于Bi-LSTM-CRF的公交下车站点推断方法 杨鑫,左兴权 北京邮电大学计算机学院 Bi-LSTM-CRF based approach to estimate the stations of passengers' getting o the bus YANG Xin,ZUO Xing-Quan
  • 基于注意力的BiLSTM-CRF模型在中国临床命名实体识别中的应用
  • 命名实体识别BiLSTM-CRF代码实现 – 潘登同学的NLP笔记 文章目录命名实体识别BiLSTM-CRF代码实现 -- 潘登同学的NLP笔记条件随机场概述直观的例子CRF的特征函数们举些例子对比逻辑回归对比HMMBilstm-CRF命名实体识别...

    命名实体识别BiLSTM-CRF代码实现 – 潘登同学的NLP笔记

    条件随机场概述

    条件随机场(Conditional Random Fields),是在给定一组输入随机变量条件下另外一组输出随机变量的条件概率分布模型,它是一种判别式的概率无向图模型,既然是判别式,拿就是对条件概率分布建模;

    之前也在BiLSTM-CRF中聊过,判别式模型就是给定x计算y,生成式模型就是计算联合分布的参数;

    设有线性链结构的随机变量序列 X = ( X 1 , X 2 , . . . , X n ) , Y = ( Y 1 , Y 2 , . . . , Y N ) X=(X_1,X_2,...,X_n),Y=(Y_1,Y_2,...,Y_N) X=(X1,X2,...,Xn),Y=(Y1,Y2,...,YN),在给定观察序列 X X X 的条件下,随机变量序列 Y Y Y 的条件概率分布为 P ( Y ∣ X ) P(Y|X) P(YX),若其满足马尔科夫特性,即
    P ( Y i ∣ X , Y 1 , Y 2... Y n ) = P ( Y i ∣ X , Y i − 1 , Y i + 1 ) P(Yi|X,Y1,Y2...Yn)=P(Yi|X,Yi−1,Yi+1) P(YiX,Y1,Y2...Yn)=P(YiX,Yi1,Yi+1)
    这时 P ( Y ∣ X ) P(Y|X) P(YX) 则为线性链条件随机场

    条件随机场(ConditionalRandom Field,CRF)是经典 NER 的主流模型。

    • 它的目标函数不仅考虑输入的状态特征函数,而且还包含了标签转移特征函数。
    • 在训练时可以使用 SGD 学习模型参数。
    • 在已知模型时,给输入序列求预测输出序列即求使目标函数最大化的最优序列,是一个动态规划问题,可以使用 Viterbi 算法解码来得到最优标签序列。
    • CRF 的优点在于其为一个位置进行标注的过程中可以利用丰富的内部及上下文特征信息。

    直观的例子

    假设你有许多小明同学一天内不同时段的照片,从小明提裤子起床到脱裤子睡觉各个时间段都有(小明是照片控!)。现在的任务是对这些照片进行分类。比如有的照片是吃饭,那就给它打上吃饭的标签;有的照片是跑步时拍的,那就打上跑步的标签;有的照片是开会时拍的,那就打上开会的标签。问题来了,你准备怎么干?

    一个简单直观的办法就是,不管这些照片之间的时间顺序,想办法训练出一个多元分类器。就是用一些打好标签的照片作为训练数据,训练出一个模型,直接根据照片的特征来分类。例如,如果照片是早上 6:00 拍的,且画面是黑暗的,那就给它打上睡觉的标签;如果照片上有车,那就给它打上开车的标签。这样可行吗?

    乍一看可以!但实际上,由于我们忽略了这些照片之间的时间顺序这一重要信息,我们的分类器会有缺陷的。举个例子,假如有一张小明闭着嘴的照片,怎么分类?显然难以直接判断,需要参考闭嘴之前的照片,如果之前的照片显示小明在吃饭,那这个闭嘴的照片很可能是小明在咀嚼食物准备下咽,可以给它打上吃饭的标签;如果之前的照片显示小明在唱歌,那这个闭嘴的照片很可能是小明唱歌瞬间的抓拍,可以给它打上唱歌的标签。所以,为了让我们的分类器能够有更好的表现,在为一张照片分类时,我们必须将与它相邻的照片的标签信息考虑进来。这——就是条件随机场(CRF)大显身手的地方!

    CRF的特征函数们

    我们正式地定义一下什么是 CRF 中的特征函数,所谓特征函数,就是这样的函数,它接受四个参数:

    • 句子 s s s(就是我们要标注词性的句子)
    • i i i,用来表示句子 s s s 中第 i i i 个单词
    • l i l_i li,表示要评分的标注序列给第 i i i 个单词标注的词性
    • l i − 1 l_i-1 li1,表示要评分的标注序列给第 i − 1 i-1 i1 个单词标注的词性
      它的输出值是 0 或者 1,0 表示要评分的标注序列不符合这个特征,1 表示要评分的标注序列符合这个特征

    注意: 这里,我们的特征函数仅仅依靠当前单词的标签和它前面的单词的标签对标注序列进行评判,这样建立的 CRF 也叫作线性链 CRF,这是 CRF 中的一种简单情况。为简单起见,本文中我们仅考虑线性链 CRF

    最终算法的预测值 y i ^ \hat{y_i} yi^受很多个特征函数的影响,写为数学表达式
    P ( y ∣ x ) = P R e a l P a t h T o t a l P a t h = e S i Z ( x ) = 1 Z ( x ) exp ⁡ ( ∑ i , k λ k ⋅ t k ( y i , y i − 1 , x , i ) + ∑ i , l μ k ⋅ e l ( y i , x , i ) ) \begin{aligned} P(y|x) &= \frac{P_{RealPath}}{TotalPath} = \frac{e^{S_i}}{Z(x)} \\ &= \frac{1}{Z(x)}\exp(\sum_{i,k} \lambda_k \cdot t_k (y_i,y_{i-1},x,i) + \sum_{i,l} \mu_k \cdot e_l (y_i,x,i)) \end{aligned} P(yx)=TotalPathPRealPath=Z(x)eSi=Z(x)1exp(ikλktk(yi,yi1,x,i)+ilμkel(yi,x,i))

    其中 x x x s s s表达意思一致, λ k \lambda_k λktransition scores矩阵的一个元素, t k t_k tk为特征函数,特征函数个数与 λ k \lambda_k λk都是 l a b e l 2 label^2 label2个; 既然前面是transition scores的一个表达,那么后面自然是Emission scores的表达, e l e_l el也理解为特征函数;exp中的是某一条路径中的表达式; Z ( x ) Z(x) Z(x)则是所有路径的加和…

    举些例子

    f 1 ( s , i , l i , l i − 1 ) = 1 f_1(s,i,l_i,l_{i-1}) = 1 f1(s,i,li,li1)=1
    l i l_i li 是“副词”并且第 i i i 个单词以“ly”结尾时,我们就让 f 1 = 1 f_1 = 1 f1=1,其他情况 f1 为 0。不难想到, f 1 f_1 f1 特征函数的权重 λ 1 \lambda_1 λ1 应当是正的。而且 λ 1 \lambda_1 λ1 越大,表示我们越倾向于采用那些把以“ly”结尾的单词标注为“副词”的标注序列;

    f 2 ( s , i , l i , l i − 1 ) = 1 f_2(s,i,l_i,l_{i-1}) = 1 f2(s,i,li,li1)=1
    如果 i = 1 i=1 i=1 l i = 动 词 l_i=动词 li=,并且句子 s s s 是以“?”结尾时, f 2 = 1 f_2=1 f2=1,其他情况 f 2 = 0 f_2=0 f2=0。同样, λ 2 \lambda_2 λ2 应当是正的,并且 λ 2 \lambda_2 λ2 越大,表示我们越倾向于采用那些把问句的第一个单词标注为“动词”的标注序列;

    f 3 ( s , i , l i , l i − 1 ) = 1 f_3(s,i,l_i,l_{i-1}) = 1 f3(s,i,li,li1)=1
    l i − 1 l_{i-1} li1 是介词, l i l_i li 是名词时, f 3 = 1 f_3 = 1 f3=1,其他情况 f 3 = 0 f_3=0 f3=0 λ 3 \lambda_3 λ3 也应当是正的,并且 λ 3 \lambda_3 λ3 越大,说明我们越认为介词后面应当跟一个名词;

    f 3 ( s , i , l i , l i − 1 ) = 1 f_3(s,i,l_i,l_{i-1}) = 1 f3(s,i,li,li1)=1
    如果 l i l_i li l i − 1 l_{i-1} li1 都是介词,那么 f 4 f_4 f4 等于 1,其他情况 f 4 = 0 f_4=0 f4=0。这里,我们应当可以想到 λ 4 \lambda_4 λ4 是负的,并且 λ 4 \lambda_4 λ4 的绝对值越大,表示我们越不认可介词后面还是介词的标注序列;

    对比逻辑回归

    CRF的概率形式与softmax很像,softmax又是逻辑回归的推广
    p ( l ∣ s ) = exp ⁡ [ ∑ j = 1 m ∑ i = 1 n f j ( l i , l i − 1 , s , i ) ] ∑ exp ⁡ [ ∑ j = 1 m ∑ i = 1 n f j ( l i , l i − 1 , s , i ) ] p(l|s) = \frac{\exp{[\sum_{j=1}^m \sum_{i=1}^n f_j (l_i,l_{i-1},s,i)}]}{\sum \exp{[\sum_{j=1}^m \sum_{i=1}^n f_j (l_i,l_{i-1},s,i)]}} p(ls)=exp[j=1mi=1nfj(li,li1,s,i)]exp[j=1mi=1nfj(li,li1,s,i)]
    那是因为 CRF 确实基本上是逻辑回归的序列版本,鉴于逻辑回归是一个对数线性模型用于分类,CRF 是一个对数线性模型用于序列打标签

    对比HMM

    HMM 采用生成式方法去打标签,数学表达为
    p ( l , s ) = p ( l 1 ) ∏ i p ( l i ∣ l i − 1 ) p ( w i ∣ l i ) p(l,s) = p(l_1)\prod_i p(l_i|l_{i-1})p(w_i|l_i) p(l,s)=p(l1)ip(lili1)p(wili)
    CRF 更强大,它可以做 HMM 可以完成的一切,并且还能做 HMM 不能做的, 我们将HMM的表达式往CRF上靠
    log ⁡ p ( l , s ) = log ⁡ p ( l 1 ) + ∑ i log ⁡ p ( l i ∣ l i − 1 ) + ∑ i log ⁡ p ( w i ∣ l i ) \log p(l,s) = \log p(l_1) + \sum_i\log p(l_i|l_{i-1}) + \sum_i\log p(w_i|l_i) logp(l,s)=logp(l1)+ilogp(lili1)+ilogp(wili)
    如果我们考虑这些对数概率为相对应的二元的转化和发射指标特征的权重。即,我们可以构建一个 CRF 等同于任意 HMM, 对于每个HMM的转移概率 log ⁡ p ( l i = y ∣ l i − 1 = x ) \log p(l_i=y|l_{i-1}=x) logp(li=yli1=x),可以理解为只有两个输入的特征函数,每个特征函数的权重为 w x , y = log ⁡ p ( l i = y ∣ l i − 1 = x ) w_{x,y} = \log p(l_i=y|l_{i-1}=x) wx,y=logp(li=yli1=x)每个特征函数的输出都是1;

    类似地,对于每个 HMM 的发射概率 log ⁡ p ( w i ∣ l i ) \log p(w_i|l_i) logp(wili),也可以视作特征函数,每个特征函数的权重为 w x , z = log ⁡ p ( w i = z ∣ l i = x ) w_{x,z} = \log p(w_i=z|l_{i}=x) wx,z=logp(wi=zli=x);

    因此,由 CRF 计算的分数 p(l|s)使用这些特征函数是精确地成比例的对应于 HMM 计算的分数,所以每一个 HMM 是等同于一些 CRF的特征函数;

    CRFs 可以建模更丰富的标签分布,这里有两个原因:

    1. CRFs 可以定义更大的特征集合。然后 HMMs 必然是局部在本质上(因为它们被限制到二元的转换和发射特征函数,强迫每个单词仅依赖于当前的标签和每个标签仅依赖于之前的标签),CRFs 可以使用更多全局的特征。例如,一个特征在我们的 POS 标签的概率增长,一个句子首个单词标注为动词如果句子最后包含一个问号符号。
    2. CRFs可以有任意的权重 。 鉴于 HMM 的概率必须满足某些限制, 例如 0 < = p ( w i ∣ l i ) < = 1 , ∑ w P ( w i = w ∣ l i ) = 1 0<=p(w_i|l_i)<=1,\sum_w P(w_i=w|l_i)=1 0<=p(wili)<=1,wP(wi=wli)=1,但CRF 的权重是不限制的;

    HMM模型存在两个严格假设:

    • 输出观察值之间严格独立(之前概率图中的head-to-tail)
    • 状态的转移过程中当前状态只与前一状态有关(一阶马尔科夫模型)

    除此之外,HMM还会出现标注偏置问题:

    • 假设有三个状态(标签)a,b,c
    • 在语料库训练中,a转移到b的概率,大于a转移到c的概率(统计出来的),所以很受语料库统计的影响,可能会造成HMM在测试的时候只出现a到b的状态

    Bilstm-CRF命名实体识别代码实现

    数据预处理

    在这里插入图片描述

    训练模型

    在这里插入图片描述

    模型应用(维特比算法)

    在这里插入图片描述

    展开全文
  • BI-LSTM,BILSTM-CRF,Lattice-LSTM基本原理以及在NER中的应用 连大赵露思 喜欢这篇文章可以关注公众号GoAI哟,都是感兴趣的在读研究生共同经营的,目前已收录计算机视觉和NLP的文章多篇 目录: ①BI-LSTM,BILSTM-CRF...

    BI-LSTM,BILSTM-CRF,Lattice-LSTM基本原理以及在NER中的应用

    连大赵露思

    目录:
    ①BI-LSTM,BILSTM-CRF,Lattice-LSTM的基本原理
    ②BI-LSTM,BILSTM-CRF,Lattice-LSTM在NER中的作用

    BI-LSTM,BILSTM-CRF,Lattice-LSTM的基本原理

    BI-LSTM:
    LSTM(long-short term memory)是RNN(recurrent neural network)的一种非常适合对时序数据(如文本数据)建模的算法。
    Bi-LSTM(Bi-directional long-short term memory)由前项LSTM和后项LSTM组合而成的,两者在自然语言处理任务中都常被用来建模上下文信息。

    Bi-LSTM由两个LSTM上下叠加在一起组成。输出由这两个LSTM的隐藏层的状态决定。
    注意:Forward layer和Backward layer是不相连的,即x->y不会同时经过F和B层。
    在这里插入图片描述

    为什么选择BI-LSTM而不是LSTM
    虽然LSTM相较于RNN已经有明显的改进,在一定程度上解决了梯度消失和梯度爆炸的问题。
    但是,LSTM无法编码从后到前的信息,而BILSTM可以更好地捕捉双向的语义依赖。
    举一个栗子,“这个火锅店脏得不行,没有隔壁好”,这里的“不行”是对“脏”的程度的一种修饰,通过BiLSTM可以更好的捕捉双向的语义依赖。

    在这里插入图片描述

    前向的依次输入“我”,“爱”,“中国”得到三个向量{ hL0, hL1, hL2 };
    后向的依次输入“中国”,“爱”,“我”得到三个向量{ hR0, hR1, hR2 };
    最后将前向和后向的隐向量进行拼接得到{ [hL0, hR2], [hL1, hR1], [hL2, hR0] },即{ h0, h1, h2 }。

    在这里插入图片描述

    对于情感分类任务来说,我们采用的句子的表示往往是[hL2, hR2]。因为其包含了前向与后向的所有信息。上图中softmax函数是神经网络的最后一层,又称归一化指数函数,它是二分类函数sigmoid在多分类上的推广,目的是将多分类的结果以概率的形式展现出来,使神经网络的输出由原本的不具有概率分布特性, 变为了具有概率分布的特性, 这样可以对神经网络的性能进行评估。

    BILSTM-CRF

    在我们开始了解BILSTM-CRF之前,我们假定在我们的数据集里有两个实体类型:Person和Organization。实际上在我们的数据集里,我们有五种标签类别:B-Person,I-Person,B-Organization,I-Organization和O这五种。

    虽然,理解BILSTM层的细节并不是很重要,但是为了更容易理解CRF层,我们需要了解BILSTM层输出的含义。
    首先,句子x中的每一个词都会被表示成一个向量,这个向量包含单词的character embedding 以及word embedding。这里的character embedding随机初始化,word embedding通常来自一个预训练的word embedding文件,所有的embeddings都会在训练过程中微调。
    然后,BiLSTM-CRF模型的输入是这些embeddings,输出是句子x的所有单词的预测标签。

    【embedding就是用一个低维的向量表示一个物体,可以是一个词,或是一个商品,或是一个电影等等。embedding向量的性质是能使距离相近的向量对应的物体有相近的含义,比如 Embedding(复仇者联盟)和Embedding(钢铁侠)之间的距离就会很接近,但 Embedding(复仇者联盟)和Embedding(乱世佳人)的距离就会远一些。】

    BiLSTM的输出是该单词对应每一个类别的score,这些score作为CRF layer的输入。
    CRF layer中,在所有的label sequence选择预测得分最高的序列作为最佳答案。
    CRF layer 可以对最终的预测labels添加一些限制来确保结果是有效的。
    这些限制可以由CRF layer在训练过程中自动的训练数据集中学到。

    这些限制可以是:
    句子的第一个单词应该是“B-”或 “O”,不可能是 “I-”;
    Eg: “B-Person I-Person”是可以的,“B-Person I-Organization”无效,“O I-label” 不合法,命名实体的开始应该是“B-”而不是“I-”。添加了这些限制之后,预测结果中的无效序列会大幅减少。

    在这里插入图片描述

    为什么我们需要CRF这层,直接挑出最大的概率的那个不行吗?
    还真不行,CRF会学习到合适的表达。
    你或许会发现,尽管不加CRF层,我们依然可以训练得到一个BILSTM命名实体识别模型作为结果。

    在这里插入图片描述

    因为BILSTM每个词的输出都是标签的分数,我们选择每个词最高分数的的标签。

    举个栗子,对于w0的最高分数是1.5即B-Person类别,因此我们选择B-Person作为w0的最好的预测标签。同理,我们选择I-Person作为w1的最好的预测标签,O作为w2的最好的预测标签,B-Organization作为w3的最好的预测标签,O作为w4的最好的预测标签。

    虽然在这个例子里我们可以得到句子x的正确标签,但是结果并不总是好的。让我们用下面这张图片上的例子再试一次。

    在这里插入图片描述

    显然,此时的输出是无效的。I-Organization不能作为开头,开头应该以B或者O开头。而且I-Organization和I-Person是不能相邻的。

    CRF layer
    在 CRF 层的损失函数中,我们有两种类型的分数。这两个分数是 CRF 层的关键概念。
    第一个是 emission 分数。这些 emission 分数来自 BiLSTM 层。如标记为 B-Person 的 w0 的分数为 1.5。
    我们使用tyi,yj来表示 transition 分数。例如tB−Person,I−person= 0.9 表示标签的 transition,即B−Persion−>I−Person得分为 0.9。因此,我们有一个 transition 得分矩阵,它存储了所有标签之间的所有得分。为了使 transition 评分矩阵更健壮,我们将添加另外两个标签,START 和 END。START 是指一个句子的开头,而不是第一个单词。END 表示句子的结尾。
    下面是一个 transition 得分矩阵的例子,包括额外添加的 START 和 END 标签。
    在这里插入图片描述

    如上表所示,我们可以发现 transition 矩阵已经学习了一些有用的约束。

    你可能想问一个关于矩阵的问题。在哪里或如何得到 transition 矩阵?
    实际上,该矩阵是 BiLSTM-CRF 模型的一个参数。在训练模型之前,可以随机初始化矩阵中的所有 transition 分数。所有的随机分数将在你的训练过程中自动更新。换句话说,CRF 层可以自己学习这些约束。我们不需要手动构建矩阵。随着训练迭代次数的增加,分数会逐渐趋于合理。

    CRF损失函数
    CRF 损失函数由真实路径得分和所有可能路径的总得分组成。在所有可能的路径中,真实路径的得分应该是最高的。
    假设我们有一个 5 个单词的句子。可能的路径是:
    在这里插入图片描述

    假设每条可能的路径都有一个分数 Pi​,并且总共有 N 条可能的路径,所有路径的总分数是 Ptotal=P1​+P2​+…+PN​

    如果我们说第 10 条路径是真正的路径,换句话说,第 10 条路径是我们的训练数据集提供的黄金标准标签。在所有可能的路径中,得分P10应该是百分比最大的。

    在这里插入图片描述

    在训练过程中,我们的 BiLSTM-CRF 模型的参数值将会一次又一次的更新,以保持增加真实路径的分数百分比。

    Lattice-LSTM

    Lattice-LSTM(网格结构-长短期记忆网络)模型是在基于字的LSTM-CRF模型的基础上,加入潜在的多粒度词语的信息。将分词信息带入LSTM,能够将字符级别序列信息和该序列对应的词信息同时编码供模型自动取用,相较于字粒度(字符级)的编码,Lattice-LSTM加入了词信息,丰富了语义表达;相较于词粒度的编码,Lattice-LSTM可以避免分词错误带来的影响。以句子“支气管哮喘”为例:

    在这里插入图片描述


    BI-LSTM,BILSTM-CRF,Lattice-LSTM在NER中的作用


    NER(Named Entity Recognition,命名实体识别)又称作专名识别,是自然语言处理中常见的一项任务,使用的范围非常广。命名实体通常指的是文本中具有特别意义或者指代性非常强的实体,通常包括人名、地名、机构名、时间、专有名词等。

    NER系统就是从非结构化的文本中抽取出上述实体,并且可以按照业务需求识别出更多类别的实体,比如产品名称、型号、价格等。因此实体这个概念可以很广,只要是业务需要的特殊文本片段都可以称为实体。

    在中文命名实体识别中,目前的主流方法是基于字符的BILSTM-CRF模型。词语为命名实体识别提供了重要的边界信息,越来越多的研究利用单词信息提高识别的准确率,而在特定领域的命名实体识别中,由于专业术语的特殊性,未登录词常常会因为歧义造成识别错误。

    目前,常用中文分词方法主要分为基于词典的方法、基于传统机器学习的方法和基于深度学习的方法。由于基于词典的方法简单高效,在一些实际应用中常常使用该方法。其中,基于词典的方法主要以词典为主,结合少量的词法、语法规则和语义解析。基于统计的方法来处理命名实体识别任务需要手动定义特征模版,基于深度学习的方法,由于不需要人为设定特征,能够从原始数据中自主的学习,因此可以减少人为对数据的干扰,找到更深层次和更加抽象的特征,近年来成为研究热点,但是深度学习的方法也存在特征学习不足的问题。

    随着时代的进步,一些新词不断涌现,词典的规模也相应扩大,还会面临存在未登录词的问题。所以,越来越多的学者研究如何发现新词去扩充词典。

    BILSTM-CRF

    BILSTM-CRF将中文命名实体识别任务分为 2 步:先通过CRF进行分词,在分词的基础上再利用双向LSTM模型进行命名实体识别。在进行中文分词的时候使用CRF模型,CRF模型分词从“字组成词” 的构词思想,通过分析大规模的语料库,统计字在词中的相应位置出现的可能性。由于同时考虑词语出现的频率和上下文语境,因此具备了较好的上下文融合能力,同时CRF对于歧义词和未登录词也具有良好的识别效果。BILSTM 能够对任何长度的序列数据进行处理,适用于文本数据。因此,CRF分词和 BI- LSTM 实体识别相融合的方法可以有效地提升命名实体识别的性能。中文分词实质上就是序列标注的问题。

    Lattice-LSTM
    中文NER和分词有关,特别是实体的边界就是词的边界,一个lattice中的字-词会有指数级别的路径,所以构建了一个lattice-lstm结构自动控制信息流从句子开始流到句子结尾。
    在传统的基于字的 LSTM 模型中加入潜在的粒度多样化的词语信息作为特征,并构建 Lattice-LSTM 来对这些词语进行建模。

    多粒度中文分词的优势在于其应用于信息检索和机器翻译等任务时具有一定的容错性,可以减少分词错误对后续任务的影响。不同粒度的分词结果可以起到分词作用:一方面,粗粒度词语可以使模型更加准确地捕获信息从而进行分析;另一方面,细粒度词语可以减少数据稀疏性并且体现出对语言更深层次的理解,为后续任务打下良好的基础。

    命名实体识别效果的评判主要看实体的边界是否划分正确以及实体的类型是否标注正确。(实体边界的识别更加困难)

    展开全文
  • pytorch lstm+crfbilstm+crf 、LSTM CRF 命名实体识别代码 代码和数据可以直接运行
  • BiLSTM-CRF代码实现

    2022-06-30 17:18:57
    BiLSTM-CRF代码实现Bidirectional LSTM-CRF Models for Sequence Tagging解读CRF+BiLSTM代码分步骤解读本次数据集来源:NER数据集 解压后的数据集包含两个文件,一个是source_BIO.txt,另一个是target_BIO.txt,...
  • 论文《End-to-end Sequence Labeling via Bi-directional LSTM-CNNs-CRF》的代码实现
  • 首先使用BERT语言模型进行文本特征提取获取字粒度向量矩阵, BiLSTM用于上下文信息的提取, 同时结合CRF模型提取全局最优序列, 最终得到景点命名实体. 实验表明, 提出的模型性能提升显著, 在实际旅游领域内景点识别的...
  • 命名实体识别BiLSTM-CRF

    2022-05-05 23:49:26
    文章目录命名实体识别BiLSTM-CRF -- 潘登同学的NLP笔记标注策略早期方法基于统计学习的方法深度学习方法BiLSTM-CRF如果不加CRFCRF 层可以从训练数据学习限制CRF层Emission score(发射分数)Transition score(转移...
  • 最通俗易懂的BiLSTM-CRF模型中的CRF层介绍 本文转载自知乎最通俗易懂的BiLSTM-CRF模型中的CRF层介绍 本文翻译自GitHub博客上的原创文章,结尾有原文链接。文章没有晦涩的数学公式,而是通过实例一步一步讲解CRF的...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 4,378
精华内容 1,751
关键字:

biLSTM-CRF