Advertisement

Bi-LSTM-CRF实现中文命名实体识别工具(TensorFlow)

阅读量:

获取项目的源码途径位于文章末尾。

请回复暗号13以便获得600多个深度学习项目的资料,并欢迎加入我们的学习社群。

复制代码
                    **《------往期经典推荐------》**
    
    
      
    
    代码解释

MobileNetV2用于实时口罩检测的TensorFlow框架

更多干货内容持续更新中…


1. 项目简介

本项目旨在开发一个基于深度学习技术的中文命名实体识别(NER)系统作为自然语言处理(NLP)领域中的核心任务之一 该系统将广泛应用于信息抽取 文本分类 以及知识图谱构建等多个应用场景中 该研究工作采用了双向长短时记忆网络(BiLSTM)与条件随机场(CRF)模型的组合架构 基于这一架构 利用深度学习技术实现对文本中实体边界及其类型的学习 研究重点包括人名 地名 和组织名三种类型的命名实体识别 该模型不仅能够精准识别指定类型的命名实体 还能通过TensorFlow框架实现其功能 中文NER面临显著的技术挑战 包括缺少明显的词汇分界线的同时 entity 的语境关联性较强 本研究通过优化上下文信息捕捉机制与序列标注方法 来提升NER系统的准确性 最终目标是构建一个性能稳定 具备扩展性和易部署性的中文命名实体识别系统 为中文信息处理提供可靠的基础模块

2.技术创新点摘要

  1. 基于双层长短时记忆网络与条件随机场结合的优化架构:项目采用了基于双层长短时记忆网络(BiLSTM)与条件随机场(CRF)相结合的优化架构。BiLSTM用于提取输入文本的深层语义信息并捕捉中文字符间的依赖关系;而CRF则在输出层进行全局序列标注优化以保证实体标注的一致性与完整性。该架构在命名实体识别任务中展现出显著优越性较传统LSTM和CNN模型更能捕捉复杂的上下文模式。
  2. 支持预训练字符嵌入或随机初始化嵌入的选择:在嵌入层设计上, 本项目支持选择使用预训练字符嵌入或随机初始化嵌入向量, 并提供了动态更新嵌入的功能(update_embedding)。这种灵活的设计使得模型能够根据具体任务需求选择最优的特征表示方式, 更好地适应不同数据源。
  3. 采用梯度裁剪策略以防止梯度爆炸:模型训练过程中, 项目采用了梯度裁剪(gradient clipping)策略, 有效抑制了梯度爆炸问题, 确保了模型训练过程中的数值稳定性;同时提供了多种优化器选择(如Adam、SGD等)并采用自适应学习率调节机制(learning rate scheduling)以实现损失函数变化下的动态学习率微调, 提升了模型收敛效率。
  4. 根据输入序列长度动态调整填充策略:在输入层设计中, 项目采用了根据输入序列实际长度进行动态填充处理的设计思路(batch dynamic)。这种设计使得模型能够高效地处理不同长度的输入序列, 减少了不必要的计算开销并提升了整体处理效率。
在这里插入图片描述

3. 数据集与预处理

本项目采用自公开CoNLL-2003标准的数据格式作为中文命名实体识别任务的数据来源。该集合中每一行都包含具体的词汇及其对应标签信息。这些标记遵循BIO格式,在标记时会使用'B-'表示名称的起始位置,'I-'代表名称的持续部分,'O'则代表非名称字段。这些标记不仅用于分类人名、地名及组织名称等三种基本类型,同时还会根据具体语境区分名词的所有格形式以及代词指代关系,从而保证了对复杂语义关系的有效捕捉。整个集合被系统性地划分为训练样本、验证样本与测试样本三个互不重叠的部分

数据集特点

  • 数据中包含汉字、英文字符以及数字等多种字符类型,在处理混合类型的文本时需要特别留意。
  • 在不同语言交织或者字符类型交替的情况下,识别命名实体的边界较为困难。
  • 各类实体标签分布不均的问题尤其明显,在组织名(ORG)这类标签数量较少的情况下容易导致分类失衡的问题。

数据预处理流程

  1. 数据清洗与分词 :首先,对原始文本进行数据清洗,去除无效字符和标点符号,并使用自定义分词工具对文本进行分词处理。分词后,每个词会被转换为唯一的词ID以便输入模型。
  2. 字典构建与标签转换 :在数据清洗和分词后,项目根据所有出现的词汇生成词汇表(Vocabulary),并为每个标签创建对应的标签索引(tag2label)。所有句子中的词汇将根据该词汇表转换为词索引,标签也会被转换为标签ID。
  3. 特征工程与填充处理 :针对中文文本中的词汇信息,本项目还引入了词嵌入(Word Embeddings)作为附加特征,以提升模型对不同字符含义的理解。同时,针对不同长度的句子,使用了序列填充(Padding)处理,使其能够统一输入到模型中进行训练。
  4. 数据集划分与增强 :将原始数据集分为训练集、验证集和测试集,并通过数据增广技术(如随机替换同义词或删除非必要词语)来提升模型的泛化能力。

4. 模型架构

模型结构的逻辑

本项目基于 双向长短时记忆网络(BiLSTM)和条件随机场(CRF) 的命名实体识别模型架构的核心部分设计了几个主要组件。

输入嵌入层(Embedding Layer)

该层将输入的词汇序列映射为相应的词向量表示,并进一步通过预训练或随机初始化的词嵌入矩阵完成每个词项的具体对应。
数学表示:E = W_{\text{embedding}}[X] 其中,Wembedding 是预训练或随机初始化的嵌入矩阵(英语单词),X 为输入的词序列(Chinese word sequence),E 为对应的词向量结果(Vector representation)。

BiLSTM 层

该系统采用了双向 LSTM 组合(包含前向 LSTM 和后向 LSTM),以识别或解析序列中的前后依赖关系,并为每个词提供更全面的理解。
数学表示:

\text{BiLSTM}(x) = [\overrightarrow{\text{LSTM}}(x), \overleftarrow{\text{LSTM}}(x)]

复制代码
   
$$\overrightarrow{h_t} = \text{LSTM}_{\text{fw}}(E_t, \overrightarrow{h_{t-1}})$$

    
        
               
    代码解释
  1. 左向h_t等于通过双向LSTM模型(记为\text{LSTM}_{\text{bw}})处理当前输入E_t以及左向h_{t+1}

  2. 输入空间H_t由前向h_t和后向h_{t}通过水平连接组成。

  3. 其中,前向h_{t}和后向h_{t}分别代表前馈与反馈方向上的状态信息;而BiLSTM层的输出则整合了这两者的信息。

投影层(Projection Layer)

该层通过线性变换将 BiLSTM 层的隐状态映射到相应的评分空间中,并由此计算出每个时间步上各个标签对应的分数(即 logits)。数学表示如下:

P_t = H_t \times W + b

其中,

  • W 表示权重矩阵,

  • b 表示偏置项,

  • P_t 表示第t个时间步上各个标签对应的分数。

条件随机场层(CRF Layer)

该方法旨在处理序列标注问题中的标注关联性。通过计算整个序列的分数来确定最优路径的位置,并确保输出标签的一致性。
损失函数定义为:

\text{log\_likelihood} = \sum_{i=1}^{N} \left( S(X, y) - \log \sum_{y'} e^{S(X, y')} \right)

其中S(X,y)表示输入序列X与标签y之间的评分函数;N表示总的序贯数据条数;\text{log\_likelihood}则代表模型在训练集上的对数似然估计。

模型的整体训练流程与评估指标

模型训练流程

  1. 输入准备:将文本数据转换为索引表示并进行序列填充与标签转换。

  2. 构建图计算模型:通过调用 add_placeholders() 方法创建输入占位符后,在以下操作中依次完成嵌入层运算 (lookup_layer_op()) 以及后续的 BiLSTM 层运算 (biLSTM_layer_op()) ,接着执行投影层操作并最终完成 CRF 层操作。

  3. 前向传播:在模型训练过程中,在输入数据经过 BiLSTM 层以及投影层后会生成预测结果(称为 logits)。

  4. 损失计算:利用 CRF 的 crf_log_likelihood 方法来评估真实标签与预测标签之间的差异程度,并在此基础上进行优化以降低损失值。

  5. 梯度裁剪与优化:采用指定优化器(例如 Adam 优化器)来进行参数更新操作的同时配合梯度裁剪技术以防止出现梯度爆炸问题。

  6. 模型保存与验证:在整个训练周期结束后对模型进行性能评估并在验证集的基础上记录最优模型参数以便后续使用。

评估指标

  1. 准确性(Accuracy):该指标用于衡量模型在实体边界识别和类别预测方面的准确性。
  2. 精确率(Precision)、召回率(Recall)与F1值:这些指标包括精确率(Precision)、召回率(Recall)和F1值。其中,在多标签分类任务中,默认使用F1值作为关键性能指标。
复制代码
   
$$\text{Precision} = \frac{TP}{TP + FP}$$

    
        
               
    代码解释
  1. 利用 \text{Recall} 的计算公式可得:\text{Recall} = \frac{\text{TP}}{\text{TP} + \text{FN}}
  2. 基于上述公式可得 F1 指标:F1 = \frac{2 × \text{Precision} × \text{Recall}}{\text{Precision} + \text{Recall}}
  3. 通过 conlleval 脚本对命名实体识别的结果进行详细分析,并输出一份详细的性能评估报告。

5. 核心代码详细讲解

数据预处理和特征工程

代码段:

复制代码
    parser.add_argument('--train_data', type=str, default='data_path', help='train data source')
    parser.add_argument('--epoch', type=int, default=40, help='#epoch of training')
    parser.add_argument('--update_embedding', type=str2bool, default=True, help='update embedding during training')
    parser.add_argument('--pretrain_embedding', type=str, default='random', help='use pretrained char embedding or init it randomly')
    
    
      
      
      
      
    
    代码解释

解释:

这些参数用于模型的初始化和数据处理:

  • --train_data: 指定训练数据文件的位置,以便于后续顺利加载和处理这些数据。
  • --epoch: 设置完整的训练循环次数,默认设置为40次循环。
  • --update_embedding: 确定在模型训练过程中是否更新模型中的嵌入矩阵参数?
  • --pretrain_embedding: 选择使用预先训练好的词向量还是随机生成新词向量来初始化模型参数。

代码段:

复制代码
    word2id = read_dictionary(os.path.join('.', args.train_data, 'word2id.pkl'))
    if args.pretrain_embedding == 'random':
    embeddings = random_embedding(word2id, args.embedding_dim)
    
    
      
      
      
    
    代码解释

解释:

  • 该函数用于加载词汇表,并创建一个字典以记录每个单词与其对应的词ID之间的对应关系。

    • 如果参数 pretrain_embedding 被设置为 random ,则会调用 random_embedding 函数生成随机初始化的词向量矩阵(即随机分配每个单词的向量表示)。
模型架构构建

代码段:

复制代码
    def build_graph(self):
    self.add_placeholders()
    self.lookup_layer_op()
    self.biLSTM_layer_op()
    self.softmax_pred_op()
    self.loss_op()
    self.trainstep_op()
    
    
      
      
      
      
      
      
      
    
    代码解释

解释:

此函数作为模型的核心架构构成函数,在系统中按照顺序调用各个子模块,并实现计算图的构建过程

  • 初始化占位符节点以支持输入、标签及序列长度等必要参数。
  • 生成词嵌入表示层以将输入数据转换为低维向量表示。
  • 基于双向 LSTM 的特征提取模块用于捕捉序列中的前后文信息。
  • 执行非标签分类预测任务以确定最可能的标签输出。
  • 定义损失计算机制(支持 CRF 或 Softmax 失误率)以衡量模型预测与真实标签之间的差异。
  • 配置优化器并执行训练更新步骤以最小化损失并调整模型参数。

代码段:

复制代码
    def biLSTM_layer_op(self):with tf.variable_scope("bi-lstm"):
        cell_fw = LSTMCell(self.hidden_dim)
        cell_bw = LSTMCell(self.hidden_dim)
        (output_fw_seq, output_bw_seq), _ = tf.nn.bidirectional_dynamic_rnn(
            cell_fw=cell_fw,
            cell_bw=cell_bw,
            inputs=self.word_embeddings,
            sequence_length=self.sequence_lengths,
            dtype=tf.float32)
        output = tf.concat([output_fw_seq, output_bw_seq], axis=-1)
        output = tf.nn.dropout(output, self.dropout_pl)
    
    
      
      
      
      
      
      
      
      
      
      
      
    
    代码解释

解释:

biLSTM_layer_op 是模型的双向 LSTM 层,用于提取序列上下文特征。

  • cell_fwcell_bw 分别对应前向与后向的 LSTM 结构。

    • 利用 tf.nn.bidirectional_dynamic_rnn 这一函数实现对输入嵌入矩阵 self.word_embeddings 的处理,并依据输入序列长度进行自适应地计算。
    • 将前向与后向方向的隐状态通过连接操作进行整合,并通过Dropout操作进行正则化处理以防止过拟合。
模型的损失函数与训练步骤

代码段:

复制代码
    def loss_op(self):if self.CRF:
        log_likelihood, self.transition_params = crf_log_likelihood(
            inputs=self.logits,
            tag_indices=self.labels,
            sequence_lengths=self.sequence_lengths)
        self.loss = -tf.reduce_mean(log_likelihood)else:
        losses = tf.nn.sparse_softmax_cross_entropy_with_logits(
            logits=self.logits,
            labels=self.labels)
        mask = tf.sequence_mask(self.sequence_lengths)
        losses = tf.boolean_mask(losses, mask)
        self.loss = tf.reduce_mean(losses)
    tf.summary.scalar("loss", self.loss)
    
    
      
      
      
      
      
      
      
      
      
      
      
      
      
    
    代码解释

解释:

loss_op 函数用于定义模型的损失计算方法。

  • 如果使用 CRF 层:执行 crf_log_likelihood 函数以求取条件随机场的对数似然值,并输出转移参数 self.transition_params 以及相应的对数值。
  • 如果不使用 CRF:利用 sparse_softmax_cross_entropy_with_logits 函数计算交叉熵损失,并对序列长度施加掩码处理(应用 sequence_mask)。
  • 最终经过 tf.reduce_mean 运算以求取平均值,从而获得整体损失。

代码段:

复制代码
    def trainstep_op(self):with tf.variable_scope("train_step"):
        self.global_step = tf.Variable(0, name="global_step", trainable=False)
        optim = tf.train.AdamOptimizer(learning_rate=self.lr_pl)
        grads_and_vars = optim.compute_gradients(self.loss)
        grads_and_vars_clip = [[tf.clip_by_value(g, -self.clip_grad, self.clip_grad), v] for g, v in grads_and_vars]
        self.train_op = optim.apply_gradients(grads_and_vars_clip, global_step=self.global_step)
    
    
      
      
      
      
      
      
    
    代码解释

解释:

trainstep_op 定义了模型的训练步骤:

  • 通过 tf.train.AdamOptimizer 定义 Adam 优化器,并基于损失函数 self.loss 计算其对应的梯度。

  • 执行梯度裁剪操作(采用 clip_by_value 方式)以避免出现梯度爆炸现象。

  • 将优化后的梯度应用到模型参数上,并同步更新全局训练步骤 global_step。

模型训练与评估

代码段:

复制代码
    def train(self, train, dev):
    saver = tf.train.Saver(tf.global_variables())with tf.Session(config=self.config) as sess:
        sess.run(self.init_op)
        self.add_summary(sess)for epoch in range(self.epoch_num):
            self.run_one_epoch(sess, train, dev, self.tag2label, epoch, saver)
    
    
      
      
      
      
      
    
    代码解释

解释:

train 函数是模型的核心训练流程:

启动 TensorFlow 会话以执行 self.init_op ,以进行变量初始化。
通过调用 run_one_epoch 函数,在每个 epoch 完成一次完整的训练过程。

6. 模型优缺点评价

模型优点:

  1. 双向 LSTM 与 CRF 结合实现高效性能:该模型通过提取并整合文本中的前后语境信息,并利用全局标注机制优化分类结果,在实体识别中有效解决实体识别中的边界模糊及标签间的依存关系等问题。特别地,在面对长文本以及复杂的语义依存关系时,在保持较高计算效率的同时实现了较高的识别准确率和召回率。
  2. 支持预训练词向量与随机初始化矩阵的选择:该模型架构允许用户根据实际需求选择不同的嵌入方案,并提供可调节的嵌入更新策略以满足不同数据特性和多样化应用场景的需求。
  3. 采用动态批次机制适应不同长度输入序列:通过梯度裁剪抑制爆炸性增长这一技术手段,在保证训练效果的同时降低了计算资源消耗成本。
  4. 提供多维度超参数调节方案:从优化器选择到学习率调度策略再到正则化手段等多维度超参数均提供灵活设置选项,在提升分类效果的同时显著提升了模型泛化能力。

模型缺点:

  1. 模型训练耗时较长:由于 BiLSTM 涉及前后向序列并行处理,在大规模数据集上会导致较高的计算开销。
  2. 模型对类别分布不平衡较为敏感:当某些标签样本数量较少时,在预测过程中可能会倾向于识别频次较高的类别。
  3. 模型引入了较多参数可能导致模型容易过拟合:若数据量不足或缺乏有效的正则化手段,则可能加剧过拟合现象的发生。

改进方向:

  1. 模型架构优化:可尝试采用自注意力机制(Self-Attention)或Transformer层来改进模型架构设计,并进一步提升对长距离依赖关系的捕捉能力进而提高训练效率。
  2. 超参数调节:通过超参数搜索(如Grid Search或Bayesian Optimization)来自动选择最佳的学习速率以及LSTM隐层维度等关键超参数。
  3. 数据增强策略:引入同义词替换策略并配合随机删除操作以增强数据多样性的同时有助于提升模型的泛化性能。

↓↓↓更多热门推荐:
基于opencv答题卡识别判卷

🙏感谢小伙伴们点赞、关注! 若有其他项目需求,请在评论区留言,并抽空制作更新。
✌粉丝福利:点击下方名片 ↓↓↓ ,回复暗号:13, 免费获取600多个深度学习项目资料, 请问您是否已经成功加入我们的社群?

全部评论 (0)

还没有任何评论哟~