信息抽取实战:命名实体识别NER【ALBERT+Bi-LSTM模型 vs. ALBERT+Bi-LSTM+CRF模型】(附代码)

实战:命名实体识别NER

一、命名实体识别(NER)

  本项目将会简单介绍自然语言处理(NLP)中的命名实体识别(NER)。
  命名实体识别Named Entity Recognition,简称NER)是信息抽取、问答系统、句法分析、机器翻译等应用领域的重要基础工具,在自然语言处理技术走向实用化的过程中占有重要地位。一般来说,命名实体识别的任务就是识别出待处理文本中三大类(实体类、时间类和数字类)、七小类(人名、机构名、地名、时间、日期、货币和百分比)命名实体

  举个简单的例子,在句子“小明早上8点去学校上课。”中,对其进行命名实体识别,应该能提取信息

人名:小明,时间:早上8点,地点:学校。

二、BERT的应用

  BERT是谷歌公司于2018年11月发布的一款新模型,它一种预训练语言表示的方法,在大量文本语料(维基百科)上训练了一个通用的“语言理解”模型,然后用这个模型去执行想做的NLP任务。一经公布,它便引爆了整个NLP界,其在11个主流NLP任务中都取得优异的结果,因此成为NLP领域最吸引人的一个模型。简单来说,BERT就是在训练了大量的文本语料(无监督)之后,能够在对英语中的单词(或中文的汉字)给出一个向量表示,使得该单词(或汉字)具有一定的语义表示能力,因此,BERT具有一定的先验知识,在NLP任务中表现十分抢眼。

  给出BERT的几个可能的应用,如下:

  • NLP基本任务
  • 查找相似词语
  • 提取文本中的实体
  • 问答中的实体对齐

NLP基本任务

  BERT公布已经半年多了,现在已经成为NLP中的深度学习模型中必不可少的工具,一般会加载在模型中的Embedding层。由于篇幅原因,笔者不再介绍自己的BERT项目,而是介绍几个BERT在基本任务中的Github项目:

  可以看到,BERT已经广泛应用于NLP基本任务中,在开源项目中导出可以见到它的身影,并且这些项目的作者也写了非常细致的代码工程,便于上手。

查找相似词语

  利用词向量可以查找文章中与指定词语最相近的几个词语。具体的做法为:现将文章分词,对分词后的每个词,查询其与指定词语的相似度,最后按相似度输出词语即可。

提取文本中的实体

  在事件抽取中,我们往往需要抽取一些指定的元素,比如在下面的句子中,

巴基斯坦当地时间2014年12月16日早晨,巴基斯坦塔利班运动武装分子袭击了西北部白沙瓦市一所军人子弟学校,打死141人,其中132人为12岁至16岁的学生。

  我们需要抽取袭击者,也就是恐怖组织这个元素

  直接从句法分析,也许可以得到一定的效果,但由于事件描述方式多变,句法分析会显得比较复杂且效果不一定能保证。这时候,我们尝试BERT词向量,它在一定程度上可以作为补充策略,帮助我们定位到事件的元素。具体的想法如下:

  • 指定事件元素模板
  • 句子分词,对词语做n-gram
  • 查询每个n-gram与模板的相似度
  • 按相似度对n-gram排序,取相似度最高的n-gram

问答中的实体对齐

  在智能问答中,我们往往会采用知识图谱或者数据库存储实体,其中一个难点就是实体对齐。举个例子,我们在数据库中储存的实体如下:

(entities.txt)
 094型/晋级
 052C型(旅洋Ⅱ级)
 辽宁舰/瓦良格/Varyag
 杰拉尔德·R·福特号航空母舰
 052D型(旅洋III级)
 054A型
 CVN-72/林肯号/Lincoln

  这样的实体名字很复杂,如果用户想查询实体“辽宁舰”,就会碰到困难,但是由于实体以储存在数据库或知识图谱中,实体不好直接修改。一种办法是通过关键字匹配定位实体,在这里,我们可以借助BERT词向量来实现。

三、ALBERT

  ALBERT 通过两个参数削减技术克服了扩展预训练模型面临的主要障碍。第一个技术是对嵌入参数化进行因式分解。研究者将大的词汇嵌入矩阵分解为两个小的矩阵,从而将隐藏层的大小与词汇嵌入的大小分离开来。这种分离使得隐藏层的增加更加容易,同时不显著增加词汇嵌入的参数量。
  第二种技术是跨层参数共享。这一技术可以避免参数量随着网络深度的增加而增加。两种技术都显著降低了 BERT 的参数量,同时不对其性能造成明显影响,从而提升了参数效率。ALBERT 的配置类似于 BERT-large,但参数量仅为后者的 1/18,训练速度却是后者的 1.7 倍。这些参数削减技术还可以充当某种形式的正则化,可以使训练更加稳定,而且有利于泛化。

  为了进一步提升 ALBERT 的性能,研究者还引入了一个自监督损失函数,用于句子级别的预测(SOP)。SOP 主要聚焦于句间连贯,用于解决原版 BERT 中下一句预测(NSP)损失低效的问题。
  基于这些设计,ALBERT 能够扩展为更大的版本,参数量仍然小于 BERT-large,但性能可以显著提升。研究者在知名的 GLUE、SQuAD 和 RACE 自然语言理解基准测试上都得到了新的 SOTA 结果:在 RACE 上的准确率为 89.4%,在 GLUE 上的得分为 89.4,在 SQuAD 2.0 上的 F1 得分为 92.2。

ALBERT 的三大改造

  前面已经展示了小模型的优势,以及 ALBERT 的核心思想,那么 ALBERT 具体结构又是怎么样的。在这一部分中,我们将简要介绍 ALBERT 的三大模块,并提供与标准 BERT 的量化对比。
  ALBERT 架构的骨干网络与 BERT 是相似的,即使用 Transformer 编码器和 GELU 非线性激活函数。现在先约定一下 BERT 的表示方式,即指定词嵌入大小为 E、编码器层数为 L、隐藏层大小为 H。与 Devlin 等人的研究一样,这篇论文将前馈网络/滤波器大小设置为 4H,将注意力 Head 的数量设置为 H/64。
如下将介绍 ALBERT 最为独特的三大结果。

  (1)嵌入向量参数化的因式分解
  在 BERT 以及后续的 XLNet 和 RoBERTa 中,WordPiece 词嵌入大小 E 和隐藏层大小 H 是相等的,即 E ≡ H。由于建模和实际使用的原因,这个决策看起来可能并不是最优的。
  从建模的角度来说,WordPiece 词嵌入的目标是学习上下文无关的表示,而隐藏层嵌入的目标是学习上下文相关的表示。通过上下文相关的实验,BERT 的表征能力很大一部分来自于使用上下文为学习过程提供上下文相关的表征信号。因此,将 WordPiece 词嵌入大小 E 从隐藏层大小 H 分离出来,可以更高效地利用总体的模型参数,其中 H 要远远大于 E。
  从实践的角度,自然语言处理使用的词典大小 V 非常庞大,如果 E 恒等于 H,那么增加 H 将直接加大嵌入矩阵的大小,这种增加还会通过 V 进行放大
  因此,对于 ALBERT 而言,研究者对词嵌入参数进行了因式分解,将它们分解为两个小矩阵。研究者不再将 one-hot 向量直接映射到大小为 H 的隐藏空间,而是先将它们映射到一个低维词嵌入空间 E,然后再映射到隐藏空间。通过这种分解,研究者可以将词嵌入参数从 O(V × H) 降低到 O(V × E + E × H),这在 H 远远大于 E 的时候,参数量减少得非常明显。

  (2)跨层参数共享
  对于 ALBERT,研究者提出了另一种跨层参数共享机制来进一步提升参数效率。其实目前有很多方式来共享参数,例如只贡献前馈网络不同层之间的参数,或者只贡献注意力机制的参数,而 ALBERT 采用的是贡献所有层的所有参数。
  这种机制之前也是有的,但研究者的度量发现词嵌入的 L2 距离和余弦相似性是震荡而不是收敛。
  研究者发现 ALBERT 从一层到另一层的转换要比 BERT 平滑得多,结果表明,权重共享有效地提升了神经网络参数的鲁棒性。即使相比于 BERT 这两个指标都有所下降,但在 24 层以后,它们也不会收敛到 0。

  (3)句间连贯性损失
  除了自编码语言建模损失外,BERT 还是用了额外的下一句预测损失。下一句预测损失本来是为了提升下游任务的性能,但是后来很多研究者发现这种机制并不是很高效,因此决定去除它。
  研究者猜测,下一句预测任务低效的原因,主要是它的难度太小。因为下一句预测将主题预测和连贯性预测结合到单个任务中,然而主题预测比连贯性预测简单得多,因此它与语言建模损失函数学到的内容是有重合的。
  研究者表示,句间建模在语言理解中是非常重要的,因此他们提出了一种基于语言连贯性的损失函数。对于 ALBERT,研究者使用了一个句子顺序预测(SOP)损失函数,它会避免预测主题,而只关注建模句子之间的连贯性
具体的损失函数表达式读者可以查阅原论文,但研究者表示,在使用了该损失函数后,ALBERT 能显著提升下游多句子编码任务的性能。

ALBERT 效果如何

  为了进行更公平的对比,研究者在原始 BERT 的配置下训练试验模型效果。研究者使用了 BOOKCORPUS 和 English Wikipedia 共计 16GB 的纯文本作为预训练任务的数据。它们在 Cloud TPU V3 上训练所有的模型,TPU 数量从 64 到 1024 会根据模型大小进行选择。

总结

  在初闻ALBERT时,以为其减少了总的运算量,但实际上是通过参数共享的方式降低了内存,预测阶段还是需要和BERT一样的时间,如果采用了xxlarge版本的ALBERT,那实际上预测速度会更慢。

  ALBERT解决的是训练时候的速度提升,如果要真的做到总体运算量的减少,的确是一个复杂且艰巨的任务,毕竟鱼与熊掌不可兼得。不过话说回来,ALBERT也更加适合采用feature base或者模型蒸馏等方式来提升最终效果。

  ALBERT作者最后也简单提了下后续可能的优化方案,例如采用sparse attention或者block attention,这些方案的确是能真正降低运算量。其次,作者认为还有更多维度的特征需要去采用其他的自监督任务来捕获

四、ALBERT+Bi-LSTM模型

  本项目将会介绍如何利用ALBERT来实现命名实体识别

  本项目的项目结构如下:
在这里插入图片描述

  其中,albert_zh为ALBERT提取文本特征模块,这方面的代码已经由别人开源,我们只需要拿来使用即可。data目录下为我们本次讲解所需要的数据,图中只有example开头的数据集,这是人民日报的标注语料,实体为人名(PER)、地名(LOC)和组织机构名(ORG)。数据集一行一个字符以及标注符号,标注系统采用BIO系统,我们以example.train的第一句为例,标注信息如下:

海 O
钓 O
比 O
赛 O
地 O
点 O
在 O
厦 B-LOC
门 I-LOC
与 O
金 B-LOC
门 I-LOC
之 O
间O
的 O
海 O
域 O
。 O

  在utils.py文件中,配置了一些关于文件路径和模型参数方面的信息,其中规定了输入的文本长度最大为128,代码如下:

# -*- coding: utf-8 -*-
# 数据相关的配置
event_type = "example"

train_file_path = "./data/%s.train" % event_type
dev_file_path = "./data/%s.dev" % event_type
test_file_path = "./data/%s.test" % event_type

# 模型相关的配置
MAX_SEQ_LEN = 128   # 输入的文本最大长度

  在load_data.py文件中,我们将处理训练集、验证集和测试集数据,并将标签转换为id,形成label2id.json文件,代码如下:

# -*- coding: utf-8 -*-
import json
from utils import train_file_path, event_type

# 读取数据集
def read_data(file_path):
    # 读取数据集
    with open(file_path, "r", encoding="utf-8") as f:
        content = [_.strip() for _ in f.readlines()]

    # 添加原文句子以及该句子的标签

    # 读取空行所在的行号
    index = [-1]
    index.extend([i for i, _ in enumerate(content) if ' ' not in _])
    index.append(len(content))

    # 按空行分割,读取原文句子及标注序列
    sentences, tags = [], []
    for j in range(len(index)-1):
        sent, tag = [], []
        segment = content[index[j]+1: index[j+1]]
        for line in segment:
            sent.append(line.split()[0])
            tag.append(line.split()[-1])

        sentences.append(''.join(sent))
        tags.append(tag)

    # 去除空的句子及标注序列,一般放在末尾
    sentences = [_ for _ in sentences if _]
    tags = [_ for _ in tags if _]

    return sentences, tags


# 读取训练集数据
# 将标签转换成id
def label2id():

    train_sents, train_tags = read_data(train_file_path)

    # 标签转换成id,并保存成文件
    unique_tags = []
    for seq in train_tags:
        for _ in seq:
            if _ not in unique_tags:
                unique_tags.append(_)

    label_id_dict = dict(zip(unique_tags, range(
### BP-LSTM 神经网络架构解析 BP-LSTM(Backpropagation through time with Long Short-Term Memory)是一种特殊的循环神经网络结构,它结合了LSTM单元来解决传统RNN中的梯度消失问题,并通过反向传播算法进行训练。这种网络特别适用于处理长时间依赖性的序列数据。 #### LSTM 单元内部机制 LSTM的核心组件是一个记忆细胞(cell state),以及三个门控机制:遗忘门(forget gate)、输入门(input gate) 和 输出门(output gate)[^2]。这些门允许LSTM选择性地保留或丢弃信息,从而有效地捕捉长期依赖关系。 - **遗忘门**决定哪些信息应该被丢弃; - **输入门**控制新信息如何加入到当前的记忆状态中; - **输出门**决定了下一时刻的状态输出是什么样的值; #### BPTT 训练过程 对于BP-LSTM来说,在前馈阶段按照时间步依次计算各个隐藏层的状态并保存下来;而在反馈阶段,则是从最后一个时间点开始逐层向前传递误差信号直至初始时刻,期间依据链式法则调整权重参数以最小化预测误差[^1]。 以下是简化版的BP-LSTM工作原理示意: ```plaintext +-------------------+ | | | 输入 X(t) |-----> [Forget Gate] ----> C'(t) | | (f_t = σ(W_f * [h_(t-1),X(t)] + b_f)) +--------+----------+ | v +--------v----------+ | | | Input Modulation |-----> [Input Gate] ------> C~(t) | Layer | (i_t = σ(W_i *[h_(t-1),X(t)] + b_i)) | | +---------+--------+ | v +---------v--------+ | | | Cell State Update|---> 更新后的Cell State -> C(t)= f_t*C(t-1)+ i_t*tanh(W_c*[h_(t-1),X(t)]+b_c) | | +--+--------+ | v +---------v--------+ | | | Output Generation|---> h(t) = o_t * tanh(C(t)) | | (o_t=σ(W_o*[h_(t-1),X(t)]+b_o)) +------------------+ ``` 此图展示了单个LSTM单元在一个时间步骤内的操作流程,其中包含了四个主要部分:遗忘门、输入调制层、细胞状态更新和输出生成。整个过程中涉及到了多个矩阵乘法运算及激活函数的应用,最终得到该时刻的隐含层输出$h(t)$与新的细胞状态$C(t)$。
评论 42
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

南有芙蕖

你的鼓励将是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值