赞
踩
Datawhale打卡小程序使用
Transformer图解
Bert&GPT图解
Bert知识笔记
Bert实践
Transformers解决文本分类
提示:原文点这里
本篇文章主要内容:
本文主要解决的是抽取式问答任务:给定一个问题和一段文本,从这段文本中找出能回答该问题的文本片段(span) 。通过使用Trainer API和dataset包,我们将轻松加载数据集,然后微调transformers。
提示:下载点这里
斯坦福问答数据集 (SQuAD) 是一个阅读理解数据集,由众包工作者对一组维基百科文章提出的问题组成,其中每个问题的答案都是来自相应阅读段落或问题的一段文本或跨度可能无法回答。
SQuAD 1.1
SQuAD数据集的先前版本,包含500多篇文章的100,000多个问答对。
SQuAD2.0
将 SQuAD1.1 中的 100,000 个问题与众包工作人员以对抗方式编写的 50,000 多个无法回答的问题相结合,使其看起来类似于可回答的问题。为了在 SQuAD2.0 上做得好,系统不仅要在可能的情况下回答问题,还要确定段落不支持答案并放弃回答。
这里仍然使用Datasets库来加载数据和对应的评测方式,数据加载和评测方式加载只需要简单使用load_dataset和load_metric即可。
# squad_v2等于True或者False分别代表使用SQUAD v1 或者 SQUAD v2。
# 如果您使用的是其他数据集,那么True代表的是:模型可以回答“不可回答”问题,也就是部分问题不给出答案,而False则代表所有问题必须回答。
squad_v2 = False
model_checkpoint = "distilbert-base-uncased"
batch_size = 16
from datasets import load_dataset, load_metric
# 下载数据(确保有网络)
datasets = load_dataset("squad_v2" if squad_v2 else "squad")
无论是训练集、验证集还是测试集,对于每一个问答数据样本都会有“context", "question"和“answers”三个key,下面是一个样本的标注情况。注意 answers 的标注,answers 除了给出了文本片段里的答案文本之外,还给出了该answer所在位置。
{'answers': {'answer_start': [515], 'text': ['Saint Bernadette Soubirous']},
'context': 'Architecturally, the school has a Catholic character. Atop the Main Building\'s gold dome is a golden statue of the Virgin Mary. Immediately in front of the Main Building and facing it, is a copper statue of Christ with arms upraised with the legend "Venite Ad Me Omnes". Next to the Main Building is the Basilica of the Sacred Heart. Immediately behind the basilica is the Grotto, a Marian place of prayer and reflection. It is a replica of the grotto at Lourdes, France where the Virgin Mary reputedly appeared to Saint Bernadette Soubirous in 1858. At the end of the main drive (and in a direct line that connects through 3 statues and the Gold Dome), is a simple, modern stone statue of Mary.',
'id': '5733be284776f41900661182',
'question': 'To whom did the Virgin Mary allegedly appear in 1858 in Lourdes France?',
'title': 'University_of_Notre_Dame'}
我们需要对数据进行预处理后,再喂入模型。还是使用Tokenizer首先对输入进行tokenize,然后将tokens转化为预模型中需要对应的token ID,再转化为模型需要的输入格式。
1、Tokenizer的使用点这里
2、更多预处理知识点这里
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained(model_checkpoint)
输入截断问题注意点1:
本例子模型所要求的最大输入是384,因此对于超过该长度的输入文本需要进行阶段操作。一般来说,我们只对【context】进行切片,不会对问题进行切片,由于【context】是拼接在【question】后面的,对应着第2个文本,所以使用【only_second】控制【.tokenizer】使用【doc_stride】控制切片之间的重合长度。
tokenized_example = tokenizer(
example["question"],
example["context"],
max_length=max_length,
truncation="only_second",
return_overflowing_tokens=True,
stride=doc_stride
)
输入截断问题注意点2:
由于我们对超长文本进行了切片,我们需要重新寻找答案所在位置。机器问答模型将使用答案的位置(答案的起始位置和结束位置,start和end)作为训练标签(而不是答案的 token ids)。所以切片需要和原始输入有一个对应关系,每个token在切片后context的位置和原始超长context里位置的对应关系。在tokenizer里可以使用return_offsets_mapping参数得到这个对应关系的map:
tokenized_example = tokenizer(
example["question"],
example["context"],
max_length=max_length,
truncation="only_second",
return_overflowing_tokens=True,
return_offsets_mapping=True,
stride=doc_stride
)
# 打印切片前后位置下标的对应关系
print(tokenized_example["offset_mapping"][0][:100])
输入截断问题注意点3:
第一个token是[CLS]设定为(0, 0)是因为这个token不属于qeustion或者answer的一部分。第2个token对应的起始和结束位置是0和3。我们可以根据切片后的token id转化对应的token;然后使用offset_mapping参数映射回切片前的token位置,找到原始位置的tokens。由于question拼接在context前面,所以直接从question里根据下标找就行了。
first_token_id = tokenized_example["input_ids"][0][1]
offsets = tokenized_example["offset_mapping"][0][1]
print(tokenizer.convert_ids_to_tokens([first_token_id])[0], example["question"][offsets[0]:offsets[1]])
输入截断问题注意点3:
通过上述的操作,我们得到了切片前后的位置对应关系。我们还需要使用sequence_ids参数来区分question和context。
如下所示:
None对应了special tokens,然后0或者1分表代表第1个文本和第2个文本,由于我们qeustin第1个传入,context第2个传入,所以分别对应question和context。最终我们可以找到标注的答案在预处理之后的features里的位置:
sequence_ids = tokenized_example.sequence_ids()
print(sequence_ids)
# -----------------------------------------------输出--------------------------------------------------------------
[None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, None, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 1, 1, 1, 1, 1, 1, 1, None]
输入截断问题注意点4:
经过阶段处理之后,我们需要对答案的位置进行验证,验证方式是:使用答案所在位置下标,取到对应的token ID,然后转化为文本,然后和原始答案进行但对比。
1、处理好训练/微调需要的数据后,下载预训练的模型。由于我们要做的是机器问答任务,于是我们使用这个类【AutoModelForQuestionAnswering】,和tokenizer相似,model也是使用from_pretrained方法进行加载。
from transformers import AutoModelForQuestionAnswering, TrainingArguments, Trainer
model = AutoModelForQuestionAnswering.from_pretrained(model_checkpoint)
2、为了能够得到一个Trainer训练工具,我们还需要3个要素,其中最重要的是训练的设定/参数TrainingArguments。这个训练设定包含了能够定义训练过程的所有属性。
args = TrainingArguments(
f"test-squad",
evaluation_strategy = "epoch",
learning_rate=2e-5, #学习率
per_device_train_batch_size=batch_size,
per_device_eval_batch_size=batch_size,
num_train_epochs=3, # 训练的论次
weight_decay=0.01,
)
3、我们使用一个default_data_collator将预处理好的数据喂给模型
from transformers import default_data_collator
data_collator = default_data_collator
此部分内容较为繁琐,不再赘述。建议去原文中配合代码进行理解。原文点这里
以上就是本篇博客的全部内容了,主要是针对抽取式问答任务的模型构建方法进行了记录,内容难度较大,代码部分仍需努力。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。