基于Bi-LSTM与CRF实现中文命名实体识别任务

一、基于Bi-LSTM与CRF实现中文命名实体识别任务

命名实体识别是指识别文本中具有特定意义的实体,主要包括人名、地名、机构名、专有名词等。本项目实现一个简单的命名实体识别方法,该方法通过BiLSTM+CRF模型预测出文本中文字所对应的标签,再根据标签提取出文本中的实体。

在这里插入图片描述

二、数据集介绍

本数据集共包含约2.7万中文文本,其中包括约2.08万训练集,0.23万验证集和0.46万测试集。数据集分别命名为example.train,example.dev,example.test,保存在datasets目录下。

  • 1.训练集:包含文本和对应的标签,用于模型训练。
  • 2.验证集:包含文本和对应的标签,用于模型训练和参数调试。
  • 3.测试集:包含文本和对应的标签,用于预测结果、验证效果。

数据集中标注有三种实体,分别为人名、地名、机构名,标注集合为{‘O’,‘B-PER’,‘I-PER’,‘B-ORG’,‘I-ORG’,‘B-LOC’,‘I-LOC’}。
其中’O’表示非实体,'B-'表示实体的首字,'I-'表示实体的其他位置的字,'PER’表示人名,'ORG’表示机构名,'LOC’表示地名。IOB(Inside–outside–beginning)是用于标记标志的通用标记格式。

三、BiLSTM+CRF模型介绍

首先,句中的每个单词是一条包含词嵌入和字嵌入的词向量,词嵌入通常是事先训练好的,字嵌入则是随机初始化的。所有的嵌入都会随着训练的迭代过程被调整。其次,BiLSTM-CRF的输入是词嵌入向量,输出是每个单词对应的预测标签。即使没有CRF层,我们照样可以训练一个基于BiLSTM的命名实体识别模型。但是CRF层可以加入一些约束来保证最终预测结果是有效的。这些约束可以在训练数据时被CRF层自动学习得到。
可能的约束条件有:

  • 句子的开头应该是“B-”或“O”,而不是“I-”。
  • “B-label1 I-label2 I-label3…”,在该模式中,类别1,2,3应该是同一种实体类别。比如,“B-Person I-Person” 是正确的,而“B-Person I-Organization”则是错误的。
  • “O I-label”是错误的,命名实体的开头应该是“B-”而不是“I-”。
    有了这些有用的约束,错误的预测序列将会大大减少。

img

四、定义Bi-LSTM网络

def __init__(self, vocab_size, tag_to_ix, embedding_dim, hidden_dim):super(BiLSTM_CRF, self).__init__()self.vocab_size = vocab_sizeself.tag_to_ix = tag_to_ixself.embedding_dim = embedding_dimself.hidden_dim = hidden_dimself.tagset_size = len(tag_to_ix)self.word_embeds = nn.Embedding(self.vocab_size + 1, self.embedding_dim)self.BiLSTM = nn.LSTM(embedding_dim, hidden_size=hidden_dim//2,bidirectional=True, num_layers=1)self.hidden2tag = nn.Linear(hidden_dim, self.tagset_size)self.transitions = nn.Parameter(torch.randn([self.tagset_size, self.tagset_size]))self.hidden = self.init_hidden()

五、定义CRF层

def neg_log_likelihood(self, sentence, tags):feats = self._get_lstm_features(sentence)forward_score = self._forward_alg(feats)gold_score = self._score_sentence(feats, tags)return forward_score - gold_score

六、优化思路

  1. 统计学习方法之间或内部层叠融合。

  2. 规则、词典和机器学习方法之间的融合,其核心是融合方法技术。
    在基于统计的学习方法中引入部分规则,将机器学习和人工知识结合起来。

  3. 将各类模型、算法结合起来,将前一级模型的结果作为下一级的训练数据,并用这些训练数据对模型进行训练,得到下一级模型。

这种方法在具体实现过程中需要考虑怎样高效地将两种方法结合起来,采用什么样的融合技术。由于命名实体识别在很大程度上依赖于分类技术,在分类方面可以采用的融合技术主要包括如Voting, Grading等。

完整源码

import pickleimport numpy as np
import pandas as pd
import torch
import torch.nn as nn
from keras.preprocessing.sequence import pad_sequences
from sklearn.model_selection import train_test_split
from torch.utils.data import TensorDataset
from torch import optim
from torchnet import meter
from tqdm import tqdmnum_layers = 1 # LSTM的层数
hidden_dim = 100 # LSTM中的隐层大小
epochs = 50 # 迭代次数
batch_size = 32 # 每个批次样本大小
embedding_dim = 15 # 每个字形成的嵌入向量大小
lr = 0.01 # 学习率
device = 'cpu' # 加载文本数据 
def load_data():def get_vocab_list(path_list):vocab_set = set()vocab_list = list()for path in path_list:with open(path,'r',encoding = 'utf-8') as f:for line in f:if len(line.strip()) == 0:continue;if line[0] not in vocab_set:vocab_set.add(line[0])vocab_list.append(line[0])return vocab_listdef save_vocab(path,vocab_list):output = ''.join([vocab+'\n' for vocab in vocab_list])with open(path,'w',encoding = 'utf-8') as f:f.write(output)def get_string2id(path):string2id = {}id2string = []with open(path,'r',encoding = 'utf-8') as f:for line in f:string2id[line.strip()] = len(string2id)id2string.append(line.strip())return id2string,string2iddef get_sequence_len(path):sequence_len = list()tmp_len = 0with open(path,'r',encoding = 'utf-8') as f:for line in f:line = line.strip()if len(line) == 0:  #句子的间隔,说明前一个句子已经结束,长度为tmp_lensequence_len.append(tmp_len)tmp_len = 0else:tmp_len += 1return np.array(sequence_len)def read_data(path,vocab2id,label2id,max_len):data_x = list()data_y = list()tmp_text = list()tmp_label = list()with open(path,'r',encoding = 'utf-8') as f:for line in f:line = line.strip()if len(line) == 0:tmp_text += [len(vocab2id)] * (max_len - len(tmp_text))tmp_label += [0] * (max_len - len(tmp_label))data_x.append(tmp_text)data_y.append(tmp_label)tmp_text = list()tmp_label = list()else:tmp_text.append(vocab2id[line[0]])tmp_label.append(label2id[line[2:]])print(u'{} include sequences {}'.format(path,len(data_x)))return np.array(data_x),np.array(data_y)vocab_list = get_vocab_list(['./datasets/example.train', './datasets/example.dev','./datasets/example.test'])save_vocab('./vocab.txt',vocab_list)id2label,label2id = get_string2id('./datasets/labels.txt')id2word,word2id = get_string2id('./vocab.txt')print(len(label2id),len(word2id))train_sequence_len = get_sequence_len('./datasets/example.train')dev_sequence_len = get_sequence_len('./datasets/example.dev')test_sequence_len = get_sequence_len('./datasets/example.test')max_len = max(max(train_sequence_len),max(dev_sequence_len),max(test_sequence_len)) print(max_len)train_text,train_label = read_data('./datasets/example.train',word2id,label2id,max_len)dev_text,dev_label = read_data('./datasets/example.dev',word2id,label2id,max_len)test_text,test_label = read_data('./datasets/example.test',word2id,label2id,max_len)return train_text, train_label, test_text, test_label, id2label, id2word# 1.加载数据集
train_text, train_label, test_text, test_label, id2label, id2word = load_data()
print('训练集', train_text.shape, train_label.shape)# 2.将numpy转成tensor
x_train = torch.from_numpy(train_text).to(torch.long)
y_train = torch.from_numpy(train_label).to(torch.long)
x_test = torch.from_numpy(test_text).to(torch.long)
y_test = torch.from_numpy(test_label).to(torch.long)# x_train = x_train[:32]
# y_train = y_train[:32]# 3.形成训练数据集
train_data = TensorDataset(x_train, y_train)
test_data = TensorDataset(x_test, y_test)# 4.将数据加载成迭代器
train_loader = torch.utils.data.DataLoader(train_data,batch_size,True)test_loader = torch.utils.data.DataLoader(test_data,batch_size,False)START_TAG = "O"
STOP_TAG = "O"# 5.定义相关函数
def argmax(vec):_, idx = torch.max(vec, 1)return idx.item()def prepare_sequence(seq, to_ix):idxs = [to_ix[word] for word in seq]return torch.tensor(idxs, dtype=torch.long)def log_sum_exp(vec):max_score = vec[0, argmax(vec)]max_score_broadcast = max_score.view([1, -1]).expand([1, vec.size()[1]])return max_score + torch.log(torch.sum(torch.exp(vec - max_score_broadcast)))# 6.定义模型
class BiLSTM_CRF(nn.Module):def __init__(self, vocab_size, tag_to_ix, embedding_dim, hidden_dim):super(BiLSTM_CRF, self).__init__()self.vocab_size = vocab_sizeself.tag_to_ix = tag_to_ixself.embedding_dim = embedding_dimself.hidden_dim = hidden_dimself.tagset_size = len(tag_to_ix)self.word_embeds = nn.Embedding(self.vocab_size + 1, self.embedding_dim)self.BiLSTM = nn.LSTM(embedding_dim, hidden_size=hidden_dim//2,bidirectional=True, num_layers=1)self.hidden2tag = nn.Linear(hidden_dim, self.tagset_size)self.transitions = nn.Parameter(torch.randn([self.tagset_size, self.tagset_size]))self.hidden = self.init_hidden()def init_hidden(self):# [num_layers * num_directions, batch, hidden_size]return (torch.randn([2, 1, self.hidden_dim//2]),torch.randn([2, 1, self.hidden_dim//2]))def _get_lstm_features(self, sentence):self.hidden = self.init_hidden()embeds = self.word_embeds(sentence).view([len(sentence), 1, -1])BiLSTM_out, self.hidden = self.BiLSTM(embeds, self.hidden)BiLSTM_out = BiLSTM_out.view([len(sentence), self.hidden_dim])BiLSTM_feats = self.hidden2tag(BiLSTM_out)return BiLSTM_featsdef _score_sentence(self, feats, tags):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]]return scoredef _forward_alg(self, feats):forward_var = torch.full([1, self.tagset_size], -10000.)for feat in feats:forward_var_t = []for next_tag in range(self.tagset_size):emit_score = feat[next_tag].view([1, -1]).expand([1, self.tagset_size])trans_score = self.transitions[next_tag].view([1, -1])next_tag_var = forward_var + trans_score + emit_scoreforward_var_t.append(log_sum_exp(next_tag_var).view([1]))forward_var = torch.cat(forward_var_t).view([1, -1])forward_var = log_sum_exp(forward_var)return forward_vardef neg_log_likelihood(self, sentence, tags):feats = self._get_lstm_features(sentence)forward_score = self._forward_alg(feats)gold_score = self._score_sentence(feats, tags)return forward_score - gold_scoredef _viterbi_decode(self, feats):forward_var = torch.full([1, self.tagset_size], -10000.)forward_var[0][self.tag_to_ix[START_TAG]] = 0backpointers = []for feat in feats:backpointers_t = []forward_var_t = []for next_tag in range(self.tagset_size):next_tag_var = forward_var + self.transitions[next_tag]best_tag_id = argmax(next_tag_var)backpointers_t.append(best_tag_id)forward_var_t.append(next_tag_var[0][best_tag_id].view([1]))forward_var = (torch.cat(forward_var_t) + feat).view([1, -1])backpointers.append(backpointers_t)forward_var += self.transitions[self.tag_to_ix[STOP_TAG]]best_tag_id = argmax(forward_var)path_score = forward_var[0][best_tag_id]best_path = [best_tag_id]for backpointers_t in reversed(backpointers):best_tag_id = backpointers_t[best_tag_id]best_path.append(best_tag_id)start = best_path.pop()assert self.tag_to_ix[START_TAG] == startbest_path.reverse()return path_score, best_pathdef forward(self, sentence):BiLSTM_feats = self._get_lstm_features(sentence)score, best_path = self._viterbi_decode(BiLSTM_feats)return score, best_path# 7.模型训练
model = BiLSTM_CRF(vocab_size=len(id2word),tag_to_ix=label2id,embedding_dim=embedding_dim,hidden_dim=hidden_dim)
optimizer = optim.Adam(model.parameters(), lr=lr)
for epoch in range(10):test_data = tqdm(test_data)for sentence, tags in test_data:model.zero_grad()targets = torch.tensor([tags[t] for t in tags], dtype=torch.long)loss = model.neg_log_likelihood(sentence, targets)loss.backward()optimizer.step()print("【EPOCH: 】%s" % str(epoch + 1))print("训练损失为%s" % (str(loss.item())))

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/19706.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

前沿技术揭秘:云原生-展望容器、自动化和DevOps的发展趋势

2023年最火热的就是ChatGPT,当然还有5G技术、AI、机器学习、区块链等技术。另外还有一个现象就是网上热点及企业招聘JD,都会出现一个词汇那就是“云原生”。云原生究竟是上帝的宠儿还是时代的骄子呢,我们来盘一盘 1、什么是云原生技术? 云原生…

一键安装langchain-ChatGLM

最近开源大模型层出不穷,非常火爆。好多小伙伴跃跃欲试,但是,大模型本地搭建,就算是只做推理也需要性能强悍的机器,更不要说微调和全参数训练,没有几十万的显卡投入是搞不定的。chatGLM推理可以在cpu上运行…

重磅!GPT-4发布,目前最先进人工智能系统

今天OpenAI发布了GPT-4,ChatGPT Plus订阅用户(20美元/月)可以使用最新的GPT-4,免费用户不变。 根据OpenAI官方对GPT-4新特性的介绍,这里总结有下面5个特性: GPT-4 可以更准确地解决难题,这要归功…

火爆的GPT-4来了!

3月14日,人工智能公司OpenAI发布了ChatGPT(GPT-3.5阶段)的升级版GPT-4,让原本已经略显沉寂的ChatGPT话题再次迎来了“爆炸式热议”,毫无悬念地冲上了社交平台热搜。“AI 终将取代人类”、“GPP-4考试能力强国90%的人类…

ChatGPT的公司CEO:Altman 认为的优秀人才品质

Altman 认为的优秀人才品质 Sam Altman认为下面这些是优秀创业者的共有品质: 1 清晰的愿景 能准确地阐明他们在做什么以及原因。如果创业者不能够清晰的阐明,也就没有真正理解自己的创业。在Airbnb申请时,他们做了绝大部人永远不会做的事情——在陌生人的客厅睡充气床。…

Python+Socket实现多人聊天室,功能:好友聊天、群聊、图片、表情、文件等

一、项目简介 本项目主要基于python实现的多人聊天室,主要的功能如下: 登录注册添加好友与好友进行私聊创建群聊邀请/申请加入群聊聊天发送图片聊天发送表情聊天发送文件聊天记录保存在本地中聊天过程中发送的文件保存本地 二、环境介绍 python3.8my…

Linux-Socket实现模拟群聊(多人聊天室)

Linux-Socket实现模拟群聊&#xff08;多人聊天室&#xff09; 简单版本 服务端源码 #include<stdio.h> #include<stdlib.h> #include<pthread.h> #include<unistd.h> #include<string.h> #include<sys/socket.h> #include<arpa/ine…

不要拿 ChatGPT 干这 6 件事

虽然 ChatGPT 是一个强大的 AI 工具&#xff0c;能够生成连贯和相关性极强的回复&#xff0c;但它也有其局限性。它不是敏感信息的安全渠道&#xff0c;也不是法律或医疗咨询的可靠来源&#xff0c;不能替代人类的决策或专业的心理健康支持&#xff0c;也不是事实信息的权威来源…

宽客挑战赛: 量化投资基础知识12题

跨界知识聚会系列文章&#xff0c;“知识是用来分享和传承的”&#xff0c;各种会议、论坛、沙龙都是分享知识的绝佳场所。我也有幸作为演讲嘉宾参加了一些国内的大型会议&#xff0c;向大家展示我所做的一些成果。从听众到演讲感觉是不一样的&#xff0c;把知识分享出来&#…

为了做宽客选择读一个PhD值得吗

转 为了做宽客选择读一个PhD值得吗&#xff1f; 编者按语&#xff1a;接触不少想往quant方向走的童鞋,对于量化交易是很感兴趣也觉得未来大有可为&#xff0c;但是quant由于其行业性质其门槛具有一定的专业要求。现在很多投行、银行、公募、私募等招聘职位基本都要求硕士学历&…

“宽客鼻祖”的诞生——爱德华·索普

本文摘自《算法交易员&#xff1a;会赚钱的人工智能》 1961 年某个炎热的夜晚&#xff0c;美国拉斯维加斯赌场里有个男人正在玩“21点”&#xff0c;他的身后围着数十名看客。虽然这个男人已经淡定地玩了整整 6 小时&#xff0c;但从他戴着的大黑框眼镜和淋漓的汗水中还是可以…

克里夫·阿斯内斯:量化天才的宽客人生

克里夫阿斯内斯 &#xff08;Clifford Asness&#xff09;&#xff0c;1966年10月1日出生在美国纽约皇后区的一个普通中产阶级家庭。父亲是一名律师&#xff0c;母亲独立经营一家医疗教育公司。在宾夕法尼亚大学取得商学院和工程与应用科学院的两个学士学位之后&#xff0c;他进…

宽客人物事件图谱

看完了《宽客》这本书&#xff0c;描述的是20世纪美国华尔街对冲基金、股票市场、证券市场从早期的投资者靠直觉交易进化为数学家、物理学家靠数学模型进行交易的发展历程&#xff0c;这些进入金融界的数学家、物理学家依靠大数据分析、自动化交易找到市场中稍纵即逝的交易机会…

量化交易创干合送给每一位爱习宽客quat

原 量化交易原创干货合集&#xff0c;送给每一位爱学习的宽客quant 序号标题传送链接1双均线策略(期货) 量化策略源码https://www.myquant.cn/docs/python_strategyies/1532alpha对冲(股票期货) 量化策略源码https://www.myquant.cn/docs/python_strategyies/1013集合竞价选股…

量化交易创干货合送每位爱习宽客quan

原 量化交易原创干货合集,送给每一位爱学习的宽客quant 序号标题传送链接1双均线策略(期货) 量化策略源码https://www.myquant.cn/docs/python_strategyies/1532alpha对冲(股票+期货) 量化策略源码https://www.myquant.cn/docs/python_strategyies/1013集合竞价选股(股票)

惊恐 !ChatGPT通过谷歌L3入职面试,拿到18万美元offer,人类码农危?

上一篇&#xff1a;单男福利&#xff1f;程序猿用ChatGPT创造的虚拟老婆&#xff0c;被真女友强制「安乐死」 来源&#xff1a;新智元 【导读】ChatGPT已经通过谷歌面试&#xff0c;拿下offer了。看来&#xff0c;替代全部码农它还做不到&#xff0c;但替代一部分&#xff0c;已…

18.3 万美元offer到手!ChatGPT 通过谷歌 L3 面试:留给谷歌的时间不多了

微软投资、OpenAI 发布的 ChatGPT 去年底爆红后&#xff0c;“传统搜索引擎要亡”的言论甚嚣尘上&#xff0c;搜索巨头谷歌也拉响了“红色代码”警报&#xff0c;内部正在进行各种开发测试&#xff0c;应对这个看起来可能是几十年来谷歌价值 1490 亿美元搜索业务的第一个显著威…

ChatGPT助力校招----面试问题分享(十一)

1 ChatGPT每日一题&#xff1a;PCB布线&#xff0c;高速信号线走直角的后果 问题&#xff1a;PCB布线&#xff0c;高速信号线走直角的后果 ChatGPT&#xff1a;对于高速信号线来说&#xff0c;最好避免使用直角布线。直角布线会引入反射和信号损耗&#xff0c;从而导致信号完…

chatgpt赋能python:Python教程:如何打开和读取文件

Python教程&#xff1a;如何打开和读取文件 作为一名具有10年Python编程经验的工程师&#xff0c;我经常会发现自己需要处理和操作文件。因此&#xff0c;在本文中&#xff0c;我将向你展示如何使用Python在程序中打开和读取文件。 1. 文件路径 在打开文件之前&#xff0c;我…

ChatGPT+Midjourney融合

&#x1f31f;亲爱的小伙伴们&#xff01;今天我要向大家强烈推荐一种绝妙的工具&#xff0c;它将会给你的生活带来巨大的改变和便利。就是——ChatGPTMidjourney融合&#xff01;&#x1f525;&#x1f525;&#x1f525; ✨让我们来探索一下这个神奇的组合带来的惊喜吧&…