通过本文你将了解如何训练一个人名、地址、组织、公司、产品、时间,共6个实体的命名实体识别模型。

准备训练样本

下面的链接中提供了已经用brat标注好的数据文件以及brat的配置文件,因为标注内容较多放到brat里加载会比较慢,所以拆分成了10份,每份包括3000多条样本数据,将这10份文件和相应的配置文件放到brat目录/data/project路径下,然后就可以从浏览器访问文件内容以及相应的标注情况了。

如果你还不知道什么是brat,或还不清楚如何使用brat,强烈建议先阅读前两篇文章《用深度学习做命名实体识别(二):文本标注工具brat》、《用深度学习做命名实体识别(三):文本数据标注过程》。

标注数据虽然有了,但是还不能满足我们的训练要求,因为我们需要根据ann和txt,将其转成训练所需的数据格式,格式如下:

可以看到,每一行一个字符,字符后面跟上空格,然后跟上该字符的标注, 每个样本之间用空行分隔。
另外,也可以看到这里采用的是BIO的标注方式:

  • B,即Begin,表示开始
  • I,即Intermediate,表示中间
  • O,即Other,表示其他,用于标记无关字符

转换代码如下:

# -*- coding: utf-8 -*-  """ 数据格式转化 """ import codecs import os  __author__ = '程序员一一涤生'  tag_dic = {"时间": "TIME",            "地点": "LOCATION",            "人名": "PERSON_NAME",            "组织名": "ORG_NAME",            "公司名": "COMPANY_NAME",            "产品名": "PRODUCT_NAME"}   # 转换成可训练的格式,最后以"END O"结尾 def from_ann2dic(r_ann_path, r_txt_path, w_path):     q_dic = {}     print("开始读取文件:%s" % r_ann_path)     with codecs.open(r_ann_path, "r", encoding="utf-8") as f:         line = f.readline()         line = line.strip("\n\r")         while line != "":             line_arr = line.split()             print(line_arr)             cls = tag_dic[line_arr[1]]             start_index = int(line_arr[2])             end_index = int(line_arr[3])             length = end_index - start_index             for r in range(length):                 if r == 0:                     q_dic[start_index] = ("B-%s" % cls)                 else:                     q_dic[start_index + r] = ("I-%s" % cls)             line = f.readline()             line = line.strip("\n\r")      print("开始读取文件:%s" % r_txt_path)     with codecs.open(r_txt_path, "r", encoding="utf-8") as f:         content_str = f.read()         # content_str = content_str.replace("\n", "").replace("\r", "").replace("//////", "\n")     print("开始写入文本%s" % w_path)     with codecs.open(w_path, "w", encoding="utf-8") as w:         for i, str in enumerate(content_str):             if str is " " or str == "" or str == "\n" or str == "\r":                 print("===============")             elif str == "/":                 if i == len(content_str) - len("//////") + 1:  # 表示到达末尾                     # w.write("\n")                     break                 # 连续六个字符首尾都是/,则表示换一行                 elif content_str[i + len("//////") - 1] == "/" and content_str[i + len("//////") - 2] == "/" and \                         content_str[i + len("//////") - 3] == "/" and content_str[i + len("//////") -