前言

在中文分词领域,已经有着很多优秀的工具,例如:

  • jieba分词
  • SnowNLP
  • 北京大学PKUse
  • 清华大学THULAC
  • HanLP
  • FoolNLTK
  • 哈工大LTP
  • 斯坦福分词器CoreNLP
  • BaiduLac

这里,我们不使用上述的工具,而是利用bert训练一个自己的分词器。

数据预处理

首先我们查看下初始的数据:data/sighan2005/raw_data/training.txt

1998年  ,  中国  人民  将  满怀信心  地  开创  新  的  业绩  。  尽管  我们  在  经济社会  发展  中  还  面临  不少  困难  ,  但  我们  有  *理论  的  指引  ,  有  改革  开放  近  20  年  来  取得  的  伟大  成就  和  积累  的  丰富  经验  ,  还有  其他  的  各种  有利  条件  ,  我们  一定  能够  克服  这些  困难  ,  继续  稳步前进  。  只要  我们  进一步  解放思想  ,  实事求是  ,  抓住  机遇  ,  开拓进取  ,  建设  有  中国  特色  社会主义  的  道路  就  会  越  走  越  宽广  。
实现 祖国 的 完全 统一 , 是 海内外 全体 中国 人 的 共同 心愿 。 通过 中 葡 双方 的 合作 和 努力 , 按照 “ 一国两制 ” 方针 和 澳门 《 基本法 》 , 1999年 12月 澳门 的 回归 一定 能够 顺利 实现 。
台湾 是 中国 领土 不可分割 的 一 部分 。 完成 祖国 统一 , 是 大势所趋 , 民心所向 。 任何 企图 制造 “ 两 个 中国 ” 、 “ 一中一台 ” 、 “ 台湾 独立 ” 的 图谋 , 都 注定 要 更 失败 。 希望 台湾 当局 以 民族 大义 为重 , 拿 出 诚意 , 采取 实际 的 行动 , 推动 两岸 经济 文化 交流 和 人员 往来 , 促进 两岸 直接 通邮 、 通航 、 通商 的 早日 实现 , 并 尽早 回应 我们 发出 的 在 一个 中国 的 原则 下 两岸 进行 谈判 的 郑重 呼吁 。
环顾 全球 , 日益 密切 的 世界 经济 联系 , 日新月异 的 科技 进步 , 正在 为 各国 经济 的 发展 提供 历史 机遇 。 但是 , 世界 还 不 安宁 。 南北 之间 的 贫富 差距 继续 扩大 ; 局部 冲突 时有发生 ; 不 公正 不 合理 的 旧 的 国际 政治经济 秩序 还 没有 根本 改变 ; 发展中国家 在 激烈 的 国际 经济 竞争 中 仍 处于 弱势 地位 ; 人类 的 生存 与 发展 还 面临 种种 威胁 和 挑战 。 和平 与 发展 的 前景 是 光明 的 , 21 世纪 将 是 充满 希望 的 世纪 。 但 前进 的 道路 不 会 也 不 可能 一帆风顺 , 关键 是 世界 各国 人民 要 进一步 团结 起来 , 共同 推动 早日 建立 公正 合理 的 国际 政治经济 新 秩序 。
中国 政府 将 继续 坚持 奉行 独立自主 的 和平 外交 政策 , 在 和平共处 五 项 原则 的 基础 上 努力 发展 同 世界 各国 的 友好 关系 。 中国 愿意 加强 同 联合国 和 其他 国际 组织 的 协调 , 促进 在 扩大 经贸 科技 交流 、 保护 环境 、 消除 贫困 、 打击 国际 犯罪 等 方面 的 国际 合作 。 中国 永远 是 维护 世界 和平 与 稳定 的 重要 力量 。 中国 人民 愿 与 世界 各国 人民 一道 , 为 开创 持久 和平 、 共同 发展 的 新 世纪 而 不懈努力 !
在 这 辞旧迎新 的 美好 时刻 , 我 祝 大家 新年 快乐 , 家庭 幸福 !
谢谢 ! ( 新华社 北京 12月 31日 电 )
在 十五大 精神 指引 下 胜利 前进 —— 元旦 献辞

这里面每一行是一段文本。一段文本中不同的词是以两个空格进行分隔的。接下来,我们要将数据处理成我们需要的样子。在data/sighan2005/raw_data/下新建一个process.py

import json
from pprint import pprint max_seq_len= 512
# -1:索引为0-511,-2:去掉CLS和SEP,+1:词索引到下一位
max_seq_len = max_seq_len - 1 - 2 + 1 with open("training.txt", "r", encoding="utf-8") as fp:
data = fp.readlines() res = []
i = 0
for d in data:
d = d.strip().split(" ")
dtype = "word"
start = 0
tmp = []
labels = []
j = 0
for word in d:
start = len("".join(tmp))
tmp.append(word)
end = start + len(word)
labels.append(["T{}".format(j), dtype, start, end, word])
j += 1
if end > max_seq_len:
sub_tmp = tmp[:-1]
sub_labels = labels[:-1]
end = start + len("".join(sub_tmp))
text = "".join(sub_tmp)
res.append({
"id": i,
"text": text,
"labels": sub_labels
}) start = 0
tmp = [word]
end = len("".join(tmp))
labels = [["T{}".format(0), dtype, 0, end, word]]
i += 1 if tmp:
text = "".join(tmp)
res.append({
"id": i,
"text": text,
"labels": labels
})
i += 1 with open("../mid_data/train.json", 'w', encoding="utf-8") as fp:
json.dump(res, fp, ensure_ascii=False) labels = ["word"]
with open("../mid_data/labels.json", 'w', encoding="utf-8") as fp:
json.dump(labels, fp, ensure_ascii=False) nor_ent2id = {"O":0, "B-word":1, "I-word":2, "E-word":3, "S-word":4}
with open("../mid_data/nor_ent2id.json", 'w', encoding="utf-8") as fp:
json.dump(nor_ent2id, fp, ensure_ascii=False) with open("test.txt", "r", encoding="utf-8") as fp:
data = fp.readlines() res = []
i = 0
for d in data:
d = d.strip().split(" ")
dtype = "word"
start = 0
tmp = []
labels = []
j = 0
for word in d:
start = len("".join(tmp))
tmp.append(word)
end = start + len(word)
labels.append(["T{}".format(j), dtype, start, end, word])
j += 1
if end > max_seq_len:
sub_tmp = tmp[:-1]
sub_labels = labels[:-1]
end = start + len("".join(sub_tmp))
text = "".join(sub_tmp)
res.append({
"id": i,
"text": text,
"labels": sub_labels
}) start = 0
tmp = [word]
end = len("".join(tmp))
labels = [["T{}".format(0), dtype, 0, end, word]]
i += 1 if tmp:
text = "".join(tmp)
res.append({
"id": i,
"text": text,
"labels": labels
})
i += 1 with open("../mid_data/test.json", 'w', encoding="utf-8") as fp:
json.dump(res, fp, ensure_ascii=False)

上述需要我们自己定义一个max_seq_len,然后会对句子进行切分,最后会在data/sighan2005/mid_data/下生成以下文件:train.json、test.json、labels.json、nor_ent2id.json。其中train.json部分数据如下:

[{"id": 0, "text": "迈向充满希望的新世纪——一九九八年新年讲话(附图片1张)", "labels": [["T0", "word", 0, 2, "迈向"], ["T1", "word", 2, 4, "充满"], ["T2", "word", 4, 6, "希望"], ["T3", "word", 6, 7, "的"], ["T4", "word", 7, 8, "新"], ["T5", "word", 8, 10, "世纪"], ["T6", "word", 10, 12, "——"], ["T7", "word", 12, 17, "一九九八年"], ["T8", "word", 17, 19, "新年"], ["T9", "word", 19, 21, "讲话"], ["T10", "word", 21, 22, "("], ["T11", "word", 22, 23, "附"], ["T12", "word", 23, 25, "图片"], ["T13", "word", 25, 26, "1"], ["T14", "word", 26, 27, "张"], ["T15", "word", 27, 28, ")"]]},]

labels.json是实体标签,这里就是一个["word"]。nor_ent2id是实体对应的BIOES标签,这里是:{"O": 0, "B-word": 1, "I-word": 2, "E-word": 3, "S-word": 4}。

有了这些数据之后,就可以生成bert所需要的数据了,具体代码在preprocess.py里面。这里面我们要定义以下参数:

dataset = "sighan2005"
args.max_seq_len = 512 # 和之前process.py里面保持一致

运行之后部分样例如下:

*** train_example-1 ***
[CLS] 迈 向 充 满 希 望 的 新 世 纪 [UNK] [UNK] 一 九 九 八 年 新 年 讲 话 ( 附 图 片 1 张 ) [SEP]
text: [CLS] 迈 向 充 满 希 望 的 新 世 纪 — — 一 九 九 八 年 新 年 讲 话 ( 附 图 片 1 张 ) [SEP]
token_ids: [101, 6815, 1403, 1041, 4007, 2361, 3307, 4638, 3173, 686, 5279, 100, 100, 671, 736, 736, 1061, 2399, 3173, 2399, 6382, 6413, 8020, 7353, 1745, 4275, 8029, 2476, 8021, 102, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
attention_masks: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
token_type_ids: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
labels: [0, 1, 3, 1, 3, 1, 3, 4, 4, 1, 3, 1, 3, 1, 2, 2, 2, 3, 1, 3, 1, 3, 4, 4, 1, 3, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
length: 512

实际上我们会将每一个词转换为B(词的开头)I(词的中间)E(词的结尾)S(单独的一个字)标签,比如针对于"迈向",其对应的标签就是B-word,E-word,如果是单个的字,则是S-word。最后会在data/sighan2005/final_data下生成train.pkl和dev.pkl。

训练、验证、测试和预测

主代码在main.py里面,其中:

bertForNer = BertForNer(args, train_loader, dev_loader, dev_loader, id2query)
bertForNer.train() model_path = './checkpoints/{}_{}/model.pt'.format(model_name, args.data_name)
bertForNer.test(model_path)
"""
{"id": 5, "text": "在1998年来临之际,我十分高兴地通过中央人民广播电台、中国国际广播电台和中央电视台,向全国各族人民,向香港特别行政区同胞、澳门和台湾同胞、海外侨胞,向世界各国的朋友们,致以诚挚的问候和良好的祝愿!", "labels": [["T0", "word", 0, 1, "在"], ["T1", "word", 1, 6, "1998年"], ["T2", "word", 6, 8, "来临"], ["T3", "word", 8, 10, "之际"], ["T4", "word", 10, 11, ","], ["T5", "word", 11, 12, "我"], ["T6", "word", 12, 14, "十分"], ["T7", "word", 14, 16, "高兴"], ["T8", "word", 16, 17, "地"], ["T9", "word", 17, 19, "通过"], ["T10", "word", 19, 21, "中央"], ["T11", "word", 21, 23, "人民"], ["T12", "word", 23, 25, "广播"], ["T13", "word", 25, 27, "电台"], ["T14", "word", 27, 28, "、"], ["T15", "word", 28, 30, "中国"], ["T16", "word", 30, 32, "国际"], ["T17", "word", 32, 34, "广播"], ["T18", "word", 34, 36, "电台"], ["T19", "word", 36, 37, "和"], ["T20", "word", 37, 39, "中央"], ["T21", "word", 39, 42, "电视台"], ["T22", "word", 42, 43, ","], ["T23", "word", 43, 44, "向"], ["T24", "word", 44, 46, "全国"], ["T25", "word", 46, 48, "各族"], ["T26", "word", 48, 50, "人民"], ["T27", "word", 50, 51, ","], ["T28", "word", 51, 52, "向"], ["T29", "word", 52, 54, "香港"], ["T30", "word", 54, 56, "特别"], ["T31", "word", 56, 59, "行政区"], ["T32", "word", 59, 61, "同胞"], ["T33", "word", 61, 62, "、"], ["T34", "word", 62, 64, "澳门"], ["T35", "word", 64, 65, "和"], ["T36", "word", 65, 67, "台湾"], ["T37", "word", 67, 69, "同胞"], ["T38", "word", 69, 70, "、"], ["T39", "word", 70, 72, "海外"], ["T40", "word", 72, 74, "侨胞"], ["T41", "word", 74, 75, ","], ["T42", "word", 75, 76, "向"], ["T43", "word", 76, 78, "世界"], ["T44", "word", 78, 80, "各国"], ["T45", "word", 80, 81, "的"], ["T46", "word", 81, 83, "朋友"], ["T47", "word", 83, 84, "们"], ["T48", "word", 84, 85, ","], ["T49", "word", 85, 87, "致以"], ["T50", "word", 87, 89, "诚挚"], ["T51", "word", 89, 90, "的"], ["T52", "word", 90, 92, "问候"], ["T53", "word", 92, 93, "和"], ["T54", "word", 93, 95, "良好"], ["T55", "word", 95, 96, "的"], ["T56", "word", 96, 98, "祝愿"], ["T57", "word", 98, 99, "!"]]}
""" raw_text = "在1998年来临之际,我十分高兴地通过中央人民广播电台、中国国际广播电台和中央电视台,向全国各族人民,向香港特别行政区同胞、澳门和台湾同胞、海外侨胞,向世界各国的朋友们,致以诚挚的问候和良好的祝愿!"
logger.info(raw_text)
bertForNer.predict(raw_text, model_path)

分别是训练、测试和预测,如需只运行相关功能,注释掉其它代码即可。运行指令:

!python main.py \
--bert_dir="../model_hub/chinese-bert-wwm-ext/" \
--data_dir="./data/sighan2005/" \
--data_name='sighan2005' \
--log_dir="./logs/" \
--output_dir="./checkpoints/" \
--num_tags=5 \
--seed=123 \
--gpu_ids="0" \
--max_seq_len=512 \
--lr=3e-5 \
--crf_lr=3e-2 \
--other_lr=3e-4 \
--train_batch_size=16 \
--train_epochs=3 \
--eval_batch_size=16 \
--lstm_hidden=128 \
--num_layers=1 \
--use_lstm='False' \
--use_crf='True' \
--dropout_prob=0.3 \
--dropout=0.3

最后我们来看看结果:

precision:0.9667 recall:0.9549 micro_f1:0.9608
precision recall f1-score support word 0.97 0.95 0.96 104371 micro-f1 0.97 0.95 0.96 104371 在1998年来临之际,我十分高兴地通过中央人民广播电台、中国国际广播电台和中央电视台,向全国各族人民,向香港特别行政区同胞、澳门和台湾同胞、海外侨胞,向世界各国的朋友们,致以诚挚的问候和良好的祝愿!
Load ckpt from ./checkpoints/bert_crf_sighan2005/model.pt
Use single gpu in: ['0']
{'word': [('在', 0), ('1998年', 1), ('来临', 6), ('之际', 8), (',', 10), ('我', 11), ('十分', 12), ('高兴', 14), ('地', 16), ('通过', 17), ('中央', 19), ('人民', 21), ('广播', 23), ('电台', 25), ('、', 27), ('中国', 28), ('国际', 30), ('广播', 32), ('电台', 34), ('和', 36), ('中央', 37), ('电视台', 39), (',', 42), ('向', 43), ('全国', 44), ('各族', 46), ('人民', 48), (',', 50), ('向', 51), ('香港', 52), ('特别', 54), ('行政区', 56), ('同胞', 59), ('、', 61), ('澳门', 62), ('和', 64), ('台湾', 65), ('同胞', 67), ('、', 69), ('海外', 70), ('侨胞', 72), (',', 74), ('向', 75), ('世界各国', 76), ('的', 80), ('朋友', 81), ('们', 83), (',', 84), ('致以', 85), ('诚挚', 87), ('的', 89), ('问候', 90), ('和', 92), ('良好', 93), ('的', 95), ('祝愿', 96), ('!', 98)]}

到此,我们的基于bert的分词就全部完成了。

补充

代码地址:https://github.com/taishan1994/pytorch_bert_bilstm_crf_ner

要先下载预训练模型和项目同级的model_hub下,这里使用的是hugging face上面的roberta。

基于bert训练自己的分词系统的更多相关文章

  1. 基于BERT预训练的中文命名实体识别TensorFlow实现

    BERT-BiLSMT-CRF-NERTensorflow solution of NER task Using BiLSTM-CRF model with Google BERT Fine-tuni ...

  2. 在TensorFlow中基于lstm构建分词系统笔记

    在TensorFlow中基于lstm构建分词系统笔记(一) https://www.jianshu.com/p/ccb805b9f014 前言 我打算基于lstm构建一个分词系统,通过这个例子来学习下 ...

  3. 基于Bert的恶意软件多分类

    基于Bert从Windows API序列做恶意软件的多分类 目录 基于Bert从Windows API序列做恶意软件的多分类 0x00 数据集 0x01 BERT BERT的模型加载 从文本到ids ...

  4. php 分词 —— PHPAnalysis无组件分词系统

    分词,顾名思义就是把词语分开,从哪里分开?当然是一大堆词语里了,一大堆词语是什么?是废话或者名言.这在数据库搜索时非常有用. 官方网站 http://www.phpbone.com/phpanalys ...

  5. 基于word2vec训练词向量(二)

    转自:http://www.tensorflownews.com/2018/04/19/word2vec2/ 一.基于Hierarchical Softmax的word2vec模型的缺点 上篇说了Hi ...

  6. NLPIR(北理工张华平版中文分词系统)的SDK(C++)调用方法

    一.本文内容简介 二.具体内容 1. 中文分词的基本概念 2.关于NLPIR(北理工张华平版中文分词系统)的基本情况 3.具体SDK模块(C++)的组装方式 ①准备内容: ②开始组装 三.注意事项 一 ...

  7. 深度学习与计算机视觉(11)_基于deep learning的快速图像检索系统

    深度学习与计算机视觉(11)_基于deep learning的快速图像检索系统 作者:寒小阳 时间:2016年3月. 出处:http://blog.csdn.net/han_xiaoyang/arti ...

  8. 基于深度学习的中文语音识别系统框架(pluse)

    目录 声学模型 GRU-CTC DFCNN DFSMN 语言模型 n-gram CBHG 数据集 本文搭建一个完整的中文语音识别系统,包括声学模型和语言模型,能够将输入的音频信号识别为汉字. 声学模型 ...

  9. 分词系统简介:PHPAnalysis分词程序

    分词系统简介:PHPAnalysis分词程序使用居于unicode的词库,使用反向匹配模式分词,理论上兼容编码更广泛,并且对utf-8编码尤为方便. 由于PHPAnalysis是无组件的系统,因此速度 ...

随机推荐

  1. 分享一款自带工作流引擎的NodeJS全栈框架,接单快手、创业神器

    CabloyJS是什么 CabloyJS是一款自带工作流引擎的Node.js全栈框架, 接单快手.创业神器, 基于koa + egg + vue + framework7 + mysql 在线演示 场 ...

  2. AtCoder ABC 250 总结

    AtCoder ABC 250 总结 总体 连续若干次一样的结果:30min 切前 4 题,剩下卡在 T5 这几次卡在 T5 都是一次比一次接近, 什么 dp 前缀和打挂,精度被卡,能水过的题连水法都 ...

  3. Tomcat部署接口环境遇到的问题,有没有人能帮忙解决指导一下

    1.在虚拟机中用Tomcat部署一个接口环境:linux+jdk+Tomcat 前提条件:代码包啥的别人都用过,可以部署成功 2.具体部署: a. 利用xftp把所有的代码包war包传送到tomcat ...

  4. 写了个基于 MacOS + iTerm2 自动打开窗口执行命令的工具

    大家好,我是秋风,今天要给大家带来的这个工具是我最近写的 一个 npm 工具.mmt 是基于 MacOS + iTerm2 ,目的主要是为了提高日常生活中的效率,接下来我带大家看看一些常用的一些场景. ...

  5. Sentiment analysis in nlp

    Sentiment analysis in nlp The goal of the program is to analysis the article title is Sarcasm or not ...

  6. HMS Core音频编辑服务3D音频技术,助力打造沉浸式听觉盛宴

    2022年6月28日,HDD·HMS Core.Sparkle影音娱乐沙龙在线上与开发者们见面.HMS Core音频编辑服务(Audio Editor Kit)专家为大家详细分享了基于分离的3D音乐创 ...

  7. CPI教程-异步接口创建及使用

    CPI教程-异步接口创建及使用 create by yi 转载请注明出处 先简单介绍一下同步接口和异步接口 什么是同步接口 同步接口的意思就是发送方发送Message后,接口方处理完成后会立刻返回执行 ...

  8. 【FAQ】华为帐号服务报错 907135701的常见原因总结和解决方法

    很多开发者在接入华为帐号服务时,经常会出现907135701的报错.根据官网文档说明,错误码907135701表示: 这个错误码在安卓和鸿蒙上都会出现,导致该报错的原因有很多,开发者可以按照下面几点进 ...

  9. Redis如何实现多可用区?

    在如今的业务场景下,高可用性要求越来越高,核心业务跨可用区已然成为标配.腾讯云数据库高级工程师刘家文结合腾讯云数据库的内核实战经验,给大家分享Redis是如何实现多可用区,内容包含Redis主从版.集 ...

  10. Optional 类

    @Test public void test2(){ Girl girl = new Girl(); // girl = null; //ofNullable(T t):t可以为null Option ...