自然语言处理中的实体识别技术

实体识别自然语言处理(NLP)领域中的一项重要任务,它用于检测文本中的实体,以便在后续任务中使用。由于某些文本/词汇对于特定上下文比其他文本/词汇更具信息量和重要性,实体识别有时也被称为信息检索。通过实体识别,可以提取一般文本中的人员、地点、组织等信息,也可以针对特定领域提取临床术语、药物、疾病等信息,以提高医疗记录的诊断准确性。

要进行实体识别,需要具备以下先决条件:熟练掌握Python语言和使用PyTorch训练神经网络的知识;了解Transformers和BERT架构;熟悉Transformers中的双向编码器表示(BERT)。BERT是一个通用的语言预训练模型,它在大型数据集上进行预训练,可以微调后用于情感分析、问答系统、命名实体识别等不同任务。BERT是NLP领域中迁移学习的最先进方法。

为了详细了解BERT架构,可以参考以下链接:。此外,如果想要了解如何使用Transformers进行情感分析,可以查看前一篇博客。

在实现实体识别任务时,首先需要在Google Colab中启用GPU支持,然后安装必要的库以使用HuggingFace的transformer。这些库包括datasets用于获取数据,tokenizers用于预处理数据,transformers用于微调模型,seqeval用于计算模型指标。将使用HuggingFace datasets模块中的英语NER数据集,该数据集遵循BIO(开始、内部、外部)格式,用于标记句子中的命名实体识别任务。数据集包含训练集、验证集和测试集,包含tokens、ner_tags、langs和spans。ner_tags有与BIO格式对应的ID,I-TYPE表示单词是TYPE类型的短语内部的一部分。如果两个相同类型的短语紧挨着,第二个短语的第一个单词将有B-TYPE标签,表示它开始了一个新的短语。带有O标签的单词不属于任何短语。总共有四个类别:Person(PER)、Organization(ORG)、Location(LOC)和其他(O)。训练集有20000个样本,验证集和测试集各有10000个样本。

数据需要被处理成transformers模型所需的格式。BERT期望输入格式为input_ids、token_type_ids和attention_mask。标签也需要根据BERT使用的子词分词进行调整。将使用distilbert-base-uncased预训练模型的tokenizer来处理tokens。

from transformers import AutoTokenizer tokenizer = AutoTokenizer.from_pretrained("distilbert-base-uncased")

为什么需要根据分词输出调整标签?以下是一个示例,其中id 2和5由于子词分词而重复了两次,因此需要为子词重复标签。将为特殊标记设置标签为-100,因为它们的word id为None,这将在损失函数中自动忽略。

def tokenize_adjust_labels(samples): tokenized_samples = tokenizer.batch_encode_plus(samples["tokens"], is_split_into_words=True, truncation=True) total_adjusted_labels = [] for k in range(0, len(tokenized_samples["input_ids"])): prev_wid = -1 word_ids_list = tokenized_samples.word_ids(batch_index=k) existing_label_ids = samples["ner_tags"][k] i = -1 adjusted_label_ids = [] for word_idx in word_ids_list: if(word_idx is None): adjusted_label_ids.append(-100) elif(word_idx != prev_wid): i = i + 1 adjusted_label_ids.append(existing_label_ids[i]) prev_wid = word_idx else: label_name = label_names[existing_label_ids[i]] adjusted_label_ids.append(existing_label_ids[i]) total_adjusted_labels.append(adjusted_label_ids) tokenized_samples["labels"] = total_adjusted_labels return tokenized_samples

将使用map函数将tokenize_adjust_labels应用于整个数据集,并使用remove_columns参数移除不需要的列。现在,让看看tokenized_dataset包含的内容。由于不同的样本长度不同,因此需要对tokens进行填充以使它们具有相同的长度。为此,将使用DataCollatorForTokenClassification,它将对输入和标签进行填充。

from transformers import DataCollatorForTokenClassification data_collator = DataCollatorForTokenClassification(tokenizer)

将使用Distillbert-base-uncased模型进行微调,并指定数据集中存在的标签数量。

model = AutoModelForTokenClassification.from_pretrained("distilbert-base-uncased", num_labels=len(label_names))

需要定义一个函数来处理模型预测并计算所需的指标。将使用seqeval指标,这是用于标记分类的常用指标。

import numpy as np from datasets import load_metric metric = load_metric("seqeval") def compute_metrics(p): predictions, labels = p predictions = np.argmax(predictions, axis=2) true_predictions = [[label_names[p] for (p, l) in zip(prediction, label) if l != -100] for prediction, label in zip(predictions, labels)] true_labels = [[label_names[l] for (p, l) in zip(prediction, label) if l != -100] for prediction, label in zip(predictions, labels)] results = metric.compute(predictions=true_predictions, references=true_labels) return { "precision": results["overall_precision"], "recall": results["overall_recall"], "f1": results["overall_f1"], "accuracy": results["overall_accuracy"], }

compute_metrics函数的输入是包含模型预测和相应标签的命名元组。将为每个标记选择最大logit,并忽略特殊标记(-100)作为在预处理部分设置的标签。最后,将返回包含精确度、召回率、F1分数和准确度指标的字典。

现在,数据处理和指标函数已经准备好了,可以使用Trainer API对模型进行微调。

from transformers import TrainingArguments, Trainer batch_size = 16 logging_steps = len(tokenized_dataset['train']) // batch_size epochs = 2 training_args = TrainingArguments( output_dir="results", num_train_epochs=epochs, per_device_train_batch_size=batch_size, per_device_eval_batch_size=batch_size, evaluation_strategy="epoch", disable_tqdm=False, logging_steps=logging_steps ) trainer = Trainer( model=model, args=training_args, train_dataset=tokenized_dataset["train"], eval_dataset=tokenized_dataset["validation"], data_collator=data_collator, tokenizer=tokenizer, compute_metrics=compute_metrics ) trainer.train() predictions, labels, _ = trainer.predict(tokenized_dataset["test"]) predictions = np.argmax(predictions, axis=2) true_predictions = [[label_names[p] for (p, l) in zip(prediction, label) if l != -100] for prediction, label in zip(predictions, labels)] true_labels = [[label_names[l] for (p, l) in zip(prediction, label) if l != -100] for prediction, label in zip(predictions, labels)] results = metric.compute(predictions=true_predictions, references=true_labels) results
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485