🚩🚩🚩Hugging Face 实战系列 总目录
有任何问题欢迎在下面留言
本篇文章的代码运行界面均在Pycharm中进行
本篇文章配套的代码资源已经上传
中篇内容:
下篇内容:
1 NER概念
1.1 NER概念解释
命名实体识别(Named Entity Recognition,NER)是自然语言处理领域的一项关键任务,旨在从文本中识别和分类特定的命名实体,如人名、地名、组织机构名等。NER的目标是标记文本中的实体,并将其归类到预定义的实体类型中。
NER通常使用机器学习和深度学习技术来完成任务。以下是一种常见的NER流程:
-
数据收集和标注:收集包含命名实体的文本数据,并为每个实体标注相应的标签(实体类型)。
-
特征提取:从文本数据中提取有用的特征,如词性、词形、上下文等。这些特征将作为输入提供给模型。
-
模型训练:使用标注好的数据和提取的特征来训练NER模型。常用的模型包括条件随机场(CRF)、循环神经网络(RNN)、长短期记忆网络(LSTM)、卷积神经网络(CNN)和注意力机制(Attention)等。
-
模型评估和调优:使用评估数据集来评估训练得到的模型性能,并进行调优以提高准确性和召回率。
-
实体识别:使用训练好的NER模型对新的文本进行实体识别。模型将识别并标记文本中的命名实体,使其易于提取和理解。
NER在许多应用中起着重要作用,例如信息抽取、问答系统、文本摘要、机器翻译等。它可以帮助自动化处理大量文本数据,并提供有关实体的结构化信息,为后续的分析和应用提供基础。
1.2 NER任务
对这句话进行一个词的抽取:今天晚上我吃了一只鸭
- 今天 是一个时间
- 我 是一个人
- 鸭 是一个动物
我想对一个文本数据中抽取出一个关键知识
我现在将(时间,人,动物)构建一个三元组行分类,最终定为几类是你在任务中自己定义的,这里的三分类只是举例而已。
分别表示(什么时间,谁,对谁),进行关键信息抽取,那我们解决这个任务的模型就需要知道哪些词是关键信息。那今天这个词是一个时间还是人还是动物就是一个三分类,然后后面的每个词晚上、我、吃了、一只都需要进行三分类。所以虽然是叫NER,但是实际上就是一个对Token的分类任务。
Token可以这么理解,在NLP中,拿到一句话无论做什么预处理的工作,第一件事都需要做分词。
那前面那句话举例:
今天晚上我吃了一只鸭
1今天 2晚上 3我 4吃了 5一只 6鸭
这句话进行分词处理就应该是这个结果。对Token进行分类就是把每个词对应的类别是什么做一个映射。Token分类就是对每一个词都进行类别标注,这个过程就叫做一个命名体识别。
所以文本的分类需要人工进行标注。
其实大部分的文本标注工具都自己搭建一个在线的或者离线的,我们今天用一个开源的工具。
2 Doccano工具安装
Doccano是一个标签标注的工具,标注完成后的数据再经过模型设计、调用、训练,安装教程我专门放在了我的这篇文章:
Doccano工具安装教程/文本标注工具/文本标注自己的项目/NLP分词器工具/自然语言处理必备工具/如何使用文本标注工具_会害羞的杨卓越的博客-CSDN博客
3 Doccano工具使用
安装好Doccano工具后,可以创建项目,对自己的数据集进行标注,标注的教程我放在了这篇文章:
4 BIO处理
4.1 BIO
在第3部分中,我们已经拿到了已经标注了3个标签的数据。
打开下载后的文件:
前面是数据,后面是标签,记录的是标签的起始位置信息和对应的标签名。
在文本标注中,我们一般使用BIO的处理流程,B表示开始,I表示中间和结尾,O代表没有标注的内容
比如拿我们刚刚的时间标签举例:
08年考研暑期英语复习全指南
0表示为B-time,8表示为I-time,年表示为I-time,后面其他的词全部表示为O。如果标签就只有时间的这个任务,那就是一个三分类。分别为时间的开头、时间的中间和结尾、其他。如果是刚刚标注三个标签的那个任务,就是3*2+1=7,一个7分类。
所以我们刚刚那个三个标签的任务还没完,还需要把O标出来。在本篇文章中的资源,我们给出了脚本,自动帮你完成这个工作。所以创建了三个标签的任务是一个7分类的任务。
4.2 BIO处理脚本
在本文配套的资源中,这是我们专门处理的脚本,具体的文件位置是ner/ner-labels/convert.py
简单介绍一个ner-labels这个文件夹的内容:
- admin.json:Doccano处理后的数据
- convert.py:当前提到的脚本
- train.txt:原始数据
- train_BIO.txt:脚本处理后的数据
- unknow.jsonl:原始数据中没有参与标注的文本
4.3 BIO解读
我们删除项目中原有的train_BIO.txt,执行一遍脚本后,就会生成train_BIO.txt
打开这个train_BIO.txt看看:
现在的文件竟然包含567行了,每一个字都对应一个标签。
这个是我们这个任务我们定义这样的做法,实际上没有一个确定的做法,最后都是要进行分词的处理。你想怎么做标签都是可以的,只要能达到最终的任务。
5、数据读取
在我们的文件中data文件夹有三个数据,我这里就直接偷懒了,训练、验证、测试全都是一样的数据,都和BIO脚本的处理产生的文件相同:
看我们的train.py的代码,首先指定一下数据的位置:
data_dir = '.\data'
将训练、验证、测试的数据集的数据都读进来:
train_texts, train_tags = read_data(data_dir + '\\train.txt')
test_texts, test_tags = read_data(data_dir + '\\val.txt')
val_texts, val_tags = read_data(data_dir + '\\test.txt')
这里有一个专门读数据的函数read_data,进入到这个函数中,首先是将数据读取进来:
file_path = Path(file_path)
raw_text = file_path.read_text(encoding='UTF-8').strip()
raw_docs = re.split(r'\n\t?\n', raw_text)
这里解释一下,在我们的数据中,我们用空行为间隔将每一行的样本隔开。然后我们开始遍历样本:
token_docs = []
tag_docs = []
for doc in raw_docs:
tokens = []
tags = []
for line in doc.split('\n'):
token, tag = line.split(' ')
tokens.append(token)
tags.append(tag)
token_docs.append(tokens)
tag_docs.append(tags)
第一个for循环是遍历每一个样本,第二个for循环是遍历每一个样本的每一个字。最后的返回值:
return token_docs, tag_docs
- token_docs存的是所有的数据
- tag_docs存的是所有的标签
6、encoding
训练、测试、验证三个数据集都进行了read_data函数的处理,现在将处理的数据进行封装:
unique_tags = set(tag for doc in train_tags for tag in doc)
tag2id = {tag: id for id, tag in enumerate(unique_tags)}
id2tag = {id: tag for tag, id in tag2id.items()}
label_list = list(unique_tags)
所有的标签是什么存在了unique_tags
- unique_tags :整个标签
- tag2id:标签名字对应的id
- id2tag: id对应的标签名字(预测的时候,预测0-6的数字,再用这个字典转换成标签名字)
- label_list :将所有的标签转换成list
此时我们已经完成了分词了,后面做tokenizer只需要记住对应的id就行了
from transformers import AutoTokenizer, BertTokenizerFast #is_split_into_words表示已经分词好了
tokenizer = BertTokenizerFast.from_pretrained('bert-base-chinese')
train_encodings = tokenizer(train_texts, is_split_into_words=True, return_offsets_mapping=True, padding=True, truncation=True,max_length=512)
val_encodings = tokenizer(val_texts, is_split_into_words=True, return_offsets_mapping=True, padding=True, truncation=True,max_length=512)
- 第一行:导入Hugging Face提供的自动分词器的包、词嵌入向量的预训练模型包
- 第二行:导入一个中文的预训练的词嵌入模型
- 第三行:对训练集进行词嵌入操作
- 第四行:对验证集集进行词嵌入操作
tokenizer参数解析:
tokenizer(train_texts, is_split_into_words=True, return_offsets_mapping=True, padding=True, truncation=True,max_length=512)
- train_texts:训练数据变量名
- is_split_into_words:当前输入文本是否已经完成了分词,tokenizer只需要完成id的映射
- return_offsets_mapping:返回一个offset,后面会解释我们为什么需要一个偏移的offset
- padding:补长
- truncation:截断
- max_length:bert定义的最大长度
如果你对这些参数都完全不明白的话,你应该先阅读一下这篇文章:
Hugging Face实战(NLP实战/Transformer实战/预训练模型/分词器/模型微调/模型自动选择/PyTorch版本/代码逐行解析)上篇之模型调用_会害羞的杨卓越的博客-CSDN博客
现在我们有很多变量,进入pycharm的debug界面,看看有哪些变量,都是什么意思:
我们的每一个样本都会转换成input_ids:
这个token_type是什么意思?就是当前的词属于那句话
我们的这个任务,每个文本都是一句话,所以全是0
而这个attention_mask是我们在做self_attention的时候,是记录那些话需要计算attention的
1表示是一个实际的词,为0的表示加的padding。
offset_mapping是偏移量是表示标签应该如何对应的,这个很有用,但是我们还是先不解释,后面会解释。
这几行代码就是把文本转换成对应的id,等下要输入模型的东西。
中篇内容:
下篇内容: