基于python BiLSTM-CRF的命名实体识别 附完整代码

简介: 基于python BiLSTM-CRF的命名实体识别 附完整代码

完整代码:https://download.csdn.net/download/qq_38735017/87427497


实验一、中文分词实现


1.1 问题描述


中文分词指的是将一个汉字序列切分成一个一个单独的词。中文分词是文本挖掘的基础,对于输入的一段中文,成功的进行中文分词,可以达到电脑自动识别语句含义的效果。它是信息提取、信息检索、机器翻译、文本分类、自动文摘、语音识别、文本语音转换、自然语言理解等中文信息处理领域的基础。


1.1.1 基础任务

实现基于词典的分词算法


实验一资料包下的“Dictionary_based”文件夹中提供了基础词典和分词算法的大致框架。分词算法的核心部分需要大家完成,实验中提供了若干测试样本用以帮助大家判断算法是否正确实现。


实现基于统计学习的分词算法


实验中给出 Bi-LSTM+CRF 模型的基础实现,相关代码及说明文档位于实验一资料包下的“Bi-LSTM+CRF”文件夹下。请根据给定的实验资料中 README.md 文件配置相应实验环境,说明:(1)提供源码 PyTorch 语言编写(可根据个人掌情况用其他语言编写),默认运行版本是 CPU 版本;(2)如希望运行 NPU 版本,大家可跟任课老师联系,申请华为云资源运行(需提前统计名单:姓名 + 学号 + 个人手机号码 + 邮箱);


1.1.2 选做任务


优化基础任务中实现的分词器,可考虑的优化方案有:


  • 修改网络结构,例如引入 BERT 等预训练语言模型;
  • 与命名实体识别算法相互配合,减少对命名实体的错误分割;
  • 构造合适的词典集(可扩充 + 人工整理);
  • 实现新词发现(登录)功能,识别测试集中的新词(未登录词);
  • 调整、优化模型训练过程中的超参数。


完成优化后对测试文件“Bi-LSTM+CRF/data/test.txt”进行分词,分词结果保存到.txt 文件中 utf-8 编码,词与词之间以空格分隔,每个测试样本占一行。文件“Bi-LSTM+CRF/cws_result.txt”中给出了输出示例。提交分词结果后,依据单词级别的 F1-score 进行评判,决定选做部分的实验分数。


单词级别的 F1-score 的计算方式如下:


  • Gold: 共同 创造 美好 的 新 世纪 —— 二 ○○ 一年 新年 贺词
  • Hypothesis: 共同 创造 美 好 的 新 世纪 —— 二 ○○ 一年 新年 贺词
  • Precision = 9 / 11 = 0.818
  • Recall = 9 / 10 = 0.9
  • F1-score = 2PrecisionRecall/(Precision+Recall)=0.857


1.2 模块设计-基于词典


1.2.1 前向最大匹配


从待分词句子的左边向右边搜索,寻找词的最大匹配。我们需要规定一个词的最大长度,每次扫描的时候寻找当前开始的这个长度的词来和字典中的词匹配,如果没有找到,就缩短长度继续寻找,直到找到字典中的词或者成为单字。

算法流程如下:


  • (1)从待分词子串中从前往后取出 max_len 个字,然后扫描分词字典,测试该 max_len 个字的子串是否在字典中;
  • (2)如果存在,则从待分词子串中删除掉该 max_len 个字的子串,重新按照规则取子串,重复(1);
  • (3)如果不存在于字典中,则减少该子串的最右一个字,之后重复(1)。


1.2.2 后向最大匹配


从待分词句子的右边向左边搜索,寻找词的最大匹配。同样,我们也需要规定一个词的最大长度,每次扫描的时候寻找当前开始的这个长度的词来和字典中的词匹配,如果没有找到,就缩短长度继续寻找,直到找到字典中的词或者成为单字。


算法流程如下:


  • (1)从待分词子串中从后往前取出 max_len 个字,然后扫描分词字典,测试该 max_len 个字的子串是否在字典中;
  • (2)如果存在,则从待分词子串中删除掉该 max_len 个字的子串,重新按照规则取子串,重复(1);
  • (3)如果不存在于字典中,则减少该子串的最左一个字,之后重复(1)。


1.2.3 双向最大匹配


将前向最大匹配算法和后向最大匹配算法进行比较,从而确定正确的分词方法。

算法流程如下:

  • (1)比较前向最大匹配和后向最大匹配结果;
  • (2)如果分词结果相同,返回其中任意一个;
  • (3)如果分词结果不同:
  • 比较两者分词总数量,数量高者罚分;
  • 比较两者分词中单字词数量,单字词多者罚分;
  • 比较两者分词中非字典词数量,非字典词多者罚分;
  • 选择罚分最少的作为最终结果。


1.3 模块设计-基于统计学习


1.3.1 data_u.py


  • getist:单个分词转换成 tag 序列。按行读入数据,并分析各个字对应的标签,然后返回分析结果。
  • handle_data:处理数据,并保存至 save_path。按行读取对应文件中的数据,并做相应的处理,然后把处理的结果保存到 data_save.pkl 中。


1.3.2 dataloader.py

读取通过 data_u.py 处理完后的文件 data_save.pkl,并将其向量化。

1.3.3 infer.py

通过已经训练好的模型,完成对测试文件的分析,并将分词结果保存到 cws_result.txt 文件中。

1.3.4 model.py


  • init_hidden:通过 torch.randn 函数进行初始化操作。
  • _get_lstm_features:获取 LSTM 框架。
  • forward:预测每个标签的 loss 值,以减少无效预测。
  • infer:采用 Bi-LSTM+CRF 的基础结构的分析结果。


1.3.5 run.py

采用小批量梯度下降法,对模型进行训练,使得 loss 值降低。

小批量梯度下降,是对批量梯度下降以及随机梯度下降的一个折中办法。其思想是:每次迭代 使用 batch_size 个样本来对参数进行更新,每次使用一个 batch 可以大大减小收敛所需要的迭代次数,同时可以使收敛到的结果更加接近梯度下降的效果。


1.4 代码实现-基于词典

1.4.1 前向最大匹配


defforward_mm_split(self,fmm_text):"""
正向最大匹配分词算法
:param fmm_text:待分词字符串
:return:分词结果,以list形式存放,每个元素为分出的词
"""# 字词列表,存放分词结果word_list=[]# 用于记录分词的起始位置count=0# 字或词当前的长度word_len=self.max_lenwhileword_len>0andcount<len(fmm_text):word=fmm_text[count:count+word_len]word_len=len(word)if(wordinself.words)or(wordinself.delimiter):word_list.append(word)count=count+word_lenword_len=self.max_lenelse:word_len=word_len-1returnword_list

1.4.2 后向最大匹配

defreverse_mm_split(self,rmm_text):"""
逆向最大匹配分词算法
:param rmm_text:待分词字符串
:return:分词结果,以list形式存放,每个元素为分出的词
"""# 字词列表,存放分词结果word_list=[]# 用于记录分词的末尾位置count=len(rmm_text)# 字或词当前的长度word_len=self.max_lenwhileword_len>0andcount>0:ifcount<=word_len:word=rmm_text[:count]else:word=rmm_text[(count-word_len):count]word_len=len(word)if(wordinself.words)or(wordinself.delimiter):word_list.insert(0,word)count=count-word_lenword_len=self.max_lenelse:word_len=word_len-1returnword_list

1.4.3 双向最大匹配

defbidirectional_mm_split(self,bi_text):"""
双向最大匹配分词算法
:param bi_text:待分词字符串
:return:分词结果,以list形式存放,每个元素为分出的词
"""# 前向最大匹配得到的分词结果forward=self.forward_mm_split(bi_text)# 后向最大匹配得到的分词结果reverse=self.reverse_mm_split(bi_text)# 总词数forward_total_words=len(forward)reverse_total_words=len(reverse)# 单字词个数forward_single_words=0reverse_single_words=0# 非字典词数forward_illegal_words=0reverse_illegal_words=0# 罚分,分值越低,表明结果越好forward_score=0reverse_score=0ifforward==reverse:returnforwardelse:# 统计前向匹配的各个词情况
  forwordinforward:iflen(word)==1:forward_single_words+=1ifwordnotinself.words:forward_illegal_words+=1# 统计后向匹配的各个词情况
  forwordinreverse:iflen(word)==1:reverse_single_words+=1ifwordnotinself.words:reverse_illegal_words+=1# 计算罚分
  ifforward_total_words<reverse_total_words:reverse_score+=1
  else:forward_score+=1
  ifforward_illegal_words<reverse_illegal_words:reverse_score+=1
  else:forward_score+=1
  ifforward_single_words<reverse_single_words:reverse_score+=1
  else:forward_score+=1# 比较罚分情况,罚分最小的选做最终结果
  ifforward_score<reverse_score:
    returnforward
  else:
    returnreverse

1.5 运行结果


利用实验包已给出的代码框架,实现完对应的匹配函数后,运行测试样例。

(1)基于词典的中文分词,得到输出结果如下:


f44eb08f68a7f969468d0f0a1246673f.png

(2)基于统计学习的中文分词,将输出的分词文件进行在线测评,结果如下:59cd443afae87ef6c3015fbe5661eae9.png



1.6 实验小结


实验中总体的代码框架已给出,需要实现的部分为前向最大匹配、后向最大匹配和双向最大匹配三个核心函数。通过相关资料的参考以及对中文分词的个人理解,能够顺利实现各个匹配模式的实现。


基于统计学习的中文分词代码,由于已经给出了代码框架,所以只是在其基础上做了部分优化,并增加了一部分的训练数据。

相关文章
|
19天前
|
开发框架 数据建模 中间件
Python中的装饰器:简化代码,增强功能
在Python的世界里,装饰器是那些静悄悄的幕后英雄。它们不张扬,却能默默地为函数或类增添强大的功能。本文将带你了解装饰器的魅力所在,从基础概念到实际应用,我们一步步揭开装饰器的神秘面纱。准备好了吗?让我们开始这段简洁而富有启发性的旅程吧!
26 6
|
1月前
|
存储 缓存 测试技术
Python中的装饰器:功能增强与代码复用的利器
在Python编程中,装饰器是一种强大而灵活的工具,它允许开发者以简洁优雅的方式增强函数或方法的功能。本文将深入探讨装饰器的定义、工作原理、应用场景以及如何自定义装饰器。通过实例演示,我们将展示装饰器如何在不修改原有代码的基础上添加新的行为,从而提高代码的可读性、可维护性和复用性。此外,我们还将讨论装饰器在实际应用中的一些最佳实践和潜在陷阱。
|
1月前
|
人工智能 数据挖掘 Python
Python编程基础:从零开始的代码旅程
【10月更文挑战第41天】在这篇文章中,我们将一起探索Python编程的世界。无论你是编程新手还是希望复习基础知识,本文都将是你的理想之选。我们将从最基础的语法讲起,逐步深入到更复杂的主题。文章将通过实例和练习,让你在实践中学习和理解Python编程。让我们一起开启这段代码之旅吧!
|
17天前
|
Python
Python中的函数是**一种命名的代码块,用于执行特定任务或计算
Python中的函数是**一种命名的代码块,用于执行特定任务或计算
42 18
|
12天前
|
数据可视化 Python
以下是一些常用的图表类型及其Python代码示例,使用Matplotlib和Seaborn库。
通过这些思维导图和分析说明表,您可以更直观地理解和选择适合的数据可视化图表类型,帮助更有效地展示和分析数据。
54 8
|
19天前
|
API Python
【Azure Developer】分享一段Python代码调用Graph API创建用户的示例
分享一段Python代码调用Graph API创建用户的示例
41 11
|
21天前
|
测试技术 Python
探索Python中的装饰器:简化代码,增强功能
在Python的世界中,装饰器是那些能够为我们的代码增添魔力的小精灵。它们不仅让代码看起来更加优雅,还能在不改变原有函数定义的情况下,增加额外的功能。本文将通过生动的例子和易于理解的语言,带你领略装饰器的奥秘,从基础概念到实际应用,一起开启Python装饰器的奇妙旅程。
34 11
|
17天前
|
Python
探索Python中的装饰器:简化代码,增强功能
在Python的世界里,装饰器就像是给函数穿上了一件神奇的外套,让它们拥有了超能力。本文将通过浅显易懂的语言和生动的比喻,带你了解装饰器的基本概念、使用方法以及它们如何让你的代码变得更加简洁高效。让我们一起揭开装饰器的神秘面纱,看看它是如何在不改变函数核心逻辑的情况下,为函数增添新功能的吧!
|
17天前
|
程序员 测试技术 数据安全/隐私保护
深入理解Python装饰器:提升代码重用与可读性
本文旨在为中高级Python开发者提供一份关于装饰器的深度解析。通过探讨装饰器的基本原理、类型以及在实际项目中的应用案例,帮助读者更好地理解并运用这一强大的语言特性。不同于常规摘要,本文将以一个实际的软件开发场景引入,逐步揭示装饰器如何优化代码结构,提高开发效率和代码质量。
42 6
|
22天前
|
Python
如何提高Python代码的可读性?
如何提高Python代码的可读性?
34 4