Transformers 抽取式问答实战用 Trainer 微调 DistilBERT 并完成推理【免费下载链接】transformers Transformers: the model-definition framework for state-of-the-art machine learning models in text, vision, audio, and multimodal models, for both inference and training.项目地址: https://gitcode.com/GitHub_Trending/tra/transformers本文以仓库中 日语版问答任务指南 为主体讲解如何基于 Transformers 在 SQuAD 数据集上微调 DistilBERT 完成抽取式问答Extractive Question Answering并给出可直接运行的训练配置、数据预处理方案与推理代码。读完本文你将掌握如何构造问答数据集与答案起止位置标签、如何用Trainer一键微调并推送模型到 Hub以及如何从模型的start_logits/end_logits中解码出最终答案。任务概览什么是抽取式问答问答Question Answering任务根据输入问题返回一个答案可分为两类抽取式Extractive直接从给定的上下文context中抽取答案片段模型输出的本质是答案在上下文中从第几个 token 开始、到第几个 token 结束生成式Abstractive基于上下文生成一段能回答问题的文本答案未必逐字出现在原文中。本文聚焦第一类在 SQuAD 数据集上微调 DistilBERT并在微调完成后用同一模型做推理。SQuAD 的每条样本包含context背景信息、question问题和answers答案文本及其在 context 中的起始字符位置answer_start这正是抽取式问答的标准数据形态。环境准备与数据集加载训练前需要安装依赖库datasets用于加载与批量处理数据集evaluate用于后续评估pip install transformers datasets evaluate推荐先登录 Hugging Face 账号以便训练完成后把模型推送到 Hub 与社区共享 from huggingface_hub import notebook_login notebook_login()登录时按提示输入 token 即可。随后用 Datasets 加载 SQuAD 的子集先取 5000 条训练数据便于快速实验验证流程再用train_test_split划分出训练集与测试集 from datasets import load_dataset squad load_dataset(squad, splittrain[:5000]) squad squad.train_test_split(test_size0.2)查看一条样本可以确认数据字段结构 squad[train][0] {answers: {answer_start: [515], text: [Saint Bernadette Soubirous]}, context: Architecturally, the school has a Catholic character. ..., id: 5733be284776f41900661182, question: To whom did the Virgin Mary allegedly appear in 1858 in Lourdes France?, title: University_of_Notre_Dame}三个关键字段的含义answers答案 token 的起始位置字符级偏移与答案文本context模型需要从中抽取答案的背景信息question需要模型回答的问题。数据预处理截断上下文与答案位置映射预处理是问答任务中最关键、也最容易出错的环节。先用AutoTokenizer加载 DistilBERT 对应的 tokenizer from transformers import AutoTokenizer tokenizer AutoTokenizer.from_pretrained(distilbert/distilbert-base-uncased)问答任务的预处理有三个要点只截断 context 而非 question数据集里部分样本的context会超过模型最大输入长度设置truncationonly_second可以只对第二个序列即 context做截断保证问题信息不丢失返回偏移映射设置return_offsets_mappingTrue得到每个 token 在原始文本中的字符起止区间这是把答案从字符位置换算成 token 位置的基础用sequence_ids区分 question 与 contextsequence_ids(i)返回第 i 个 token 属于哪个序列0 表示 question1 表示 context据此定位 context 的 token 起止下标。下面的预处理函数完整实现了截断 答案位置映射 def preprocess_function(examples): ... questions [q.strip() for q in examples[question]] ... inputs tokenizer( ... questions, ... examples[context], ... max_length384, ... truncationonly_second, ... return_offsets_mappingTrue, ... paddingmax_length, ... ) ... ... offset_mapping inputs.pop(offset_mapping) ... answers examples[answers] ... start_positions [] ... end_positions [] ... ... for i, offset in enumerate(offset_mapping): ... answer answers[i] ... start_char answer[answer_start][0] ... end_char answer[answer_start][0] len(answer[text][0]) ... sequence_ids inputs.sequence_ids(i) ... ... # 找到 context 的起始与结束 token 下标 ... idx 0 ... while sequence_ids[idx] ! 1: ... idx 1 ... context_start idx ... while sequence_ids[idx] 1: ... idx 1 ... context_end idx - 1 ... ... # 若答案不在截断后的 context 范围内则标记为 (0, 0) ... if offset[context_start][0] end_char or offset[context_end][1] start_char: ... start_positions.append(0) ... end_positions.append(0) ... else: ... # 否则定位答案起止 token ... idx context_start ... while idx context_end and offset[idx][0] start_char: ... idx 1 ... start_positions.append(idx - 1) ... ... idx context_end ... while idx context_start and offset[idx][1] end_char: ... idx - 1 ... end_positions.append(idx 1) ... ... inputs[start_positions] start_positions ... inputs[end_positions] end_positions ... return inputs关键细节说明答案的字符区间由answer_start与答案文本长度共同算出end_char answer_start len(text)当答案因为截断而完全落在 context 之外时将其标签设为(0, 0)——这并非真实答案位置而是让模型在该样本上忽略答案源码中通过start_positions.clamp(0, ignored_index)与CrossEntropyLoss(ignore_indexignored_index)处理这类越界样本见 modeling_distilbert.py偏移映射offset_mapping在送入模型前必须从inputs中弹出因为它只是字符级别的辅助信息不是模型输入。将预处理函数应用到整个数据集batchedTrue可以一次性批量处理多条样本以加快速度同时移除不再需要的原始列 tokenized_squad squad.map(preprocess_function, batchedTrue, remove_columnssquad[train].column_names)最后创建数据收集器data collator。与 Transformers 中其他 collator 不同DefaultDataCollator不做任何额外的预处理例如补 padding 到等长它只是把批量样本简单地堆叠成张量。这是因为预处理阶段已经用paddingmax_length统一了序列长度 from transformers import DefaultDataCollator data_collator DefaultDataCollator()从源码看DefaultDataCollator 是一个dataclass包装其__call__委托给default_data_collator默认以return_tensorspt返回 PyTorch 张量并对label/label_ids等键做特殊处理本任务中的start_positions、end_positions属于普通键会被直接torch.tensor(...)堆叠成 batch见 data_collator.py。使用 Trainer 微调参数解析与训练一切就绪后用AutoModelForQuestionAnswering加载带问答头QA head的 DistilBERT from transformers import AutoModelForQuestionAnswering, TrainingArguments, Trainer model AutoModelForQuestionAnswering.from_pretrained(distilbert/distilbert-base-uncased)AutoModelForQuestionAnswering是一个自动映射类定义于 modeling_auto.py它会根据 checkpoint 的架构配置自动挑选对应的*ForQuestionAnswering实现类。该映射覆盖了大量架构例如BertForQuestionAnswering、DistilBertForQuestionAnswering、BartForQuestionAnswering、BigBirdForQuestionAnswering、MobileBertForQuestionAnswering等完整列表见 MODEL_FOR_QUESTION_ANSWERING_MAPPING_NAMES因此训练脚本无需针对具体模型写分支。接下来只需三步在TrainingArguments中定义训练超参数把训练参数连同模型、数据集、tokenizer、数据收集器一起传给Trainer调用trainer.train()开始微调。 training_args TrainingArguments( ... output_dirmy_awesome_qa_model, ... eval_strategyepoch, ... learning_rate2e-5, ... per_device_train_batch_size16, ... per_device_eval_batch_size16, ... num_train_epochs3, ... weight_decay0.01, ... push_to_hubTrue, ... )各参数含义与取值建议参数作用说明output_dir模型保存目录唯一必填参数训练产物checkpoint、配置都会写入该目录eval_strategy评估策略epoch表示每个 epoch 结束时在验证集上计算一次评估损失对应旧版evaluation_strategy本仓库已更名为eval_strategylearning_rate学习率微调场景常用2e-5这类较小的值避免破坏预训练权重per_device_train_batch_size单设备训练 batch 大小本文取 16需根据显存调整per_device_eval_batch_size单设备评估 batch 大小本文取 16num_train_epochs训练轮数本文取 3weight_decay权重衰减0.01 为常见取值用于正则化push_to_hub是否推送 Hub设为True时训练结束后可把模型上传到 Hugging Face Hub需要已登录随后构造Trainer。注意当前仓库的Trainer使用processing_class参数接收 tokenizer trainer Trainer( ... modelmodel, ... argstraining_args, ... train_datasettokenized_squad[train], ... eval_datasettokenized_squad[test], ... processing_classtokenizer, ... data_collatordata_collator, ... )训练完成后用trainer.push_to_hub()把模型分享到 Hub社区任何人都可以直接加载使用 trainer.train() trainer.push_to_hub()关于评估的说明问答任务的评估需要大量后处理例如对答案起止概率做非极大值抑制、对齐原始字符偏移、与标准答案比较等。为了让指南聚焦核心流程本文省略了完整评估步骤但Trainer在训练过程中仍然会计算评估损失这得益于eval_strategyepoch与传入的eval_dataset因此你不会对模型表现完全无感知。推理从 logits 到答案微调完成后即可用于推理。先准备一个问题与一段上下文 question How many programming languages does BLOOM support? context BLOOM has 176 billion parameters and can generate text in 46 languages natural languages and 13 programming languages.把问题与上下文一起送入 tokenizer 并返回 PyTorch 张量 from transformers import AutoTokenizer tokenizer AutoTokenizer.from_pretrained(my_awesome_qa_model) inputs tokenizer(question, context, return_tensorspt)加载微调后的模型并在torch.no_grad()下前向传播得到logits import torch from transformers import AutoModelForQuestionAnswering model AutoModelForQuestionAnswering.from_pretrained(my_awesome_qa_model) with torch.no_grad(): ... outputs model(**inputs)从模型输出中取start_logits与end_logits各自概率最高的位置 answer_start_index outputs.start_logits.argmax() answer_end_index outputs.end_logits.argmax()最后切出对应的 token 序列并解码为文本 predict_answer_tokens inputs.input_ids[0, answer_start_index : answer_end_index 1] tokenizer.decode(predict_answer_tokens) 176 billion parameters and can generate text in 46 languages natural languages and 13源码原理问答头如何输出答案理解推理代码背后的原理有助于排查问题。以 DistilBERT 为例其问答实现位于 modeling_distilbert.py核心流程是distilbert(...)前向编码得到hidden_states形状为(batch_size, seq_len, hidden_dim)经过dropout后送入qa_outputs线性层输出(batch_size, seq_len, 2)的 logits沿最后一维split成start_logits与end_logits形状均为(batch_size, seq_len)分别表示每个 token 作为答案起始位置与作为答案结束位置的打分训练阶段传入start_positions/end_positions时用两个CrossEntropyLoss分别计算起始与结束位置的损失取平均作为总损失返回。因此在推理阶段对start_logits.argmax()和end_logits.argmax()即可得到模型认为最可能的答案起止 token 下标再通过input_ids切片与tokenizer.decode还原为可读文本。输出的结构化封装为QuestionAnsweringModelOutput其中同时携带loss、start_logits、end_logits以及可选的hidden_states、attentions方便训练与调试。延伸与注意事项完整英文原版本文对应的英文完整版指南见 docs/source/en/tasks/question_answering.md其中包含与本文一致的 SQuAD 加载、预处理、训练、评估与推理全流程可作为交叉参考。更多模型选择AutoModelForQuestionAnswering的映射表modeling_auto.py覆盖数十种架构只需替换 checkpoint 名称即可迁移到 BERT、BigBird、Longformer、DeBERTa 等模型预处理与训练代码无需改动。长文本场景truncationonly_second只截断 context 的策略同样适用于长文档问答若上下文远超max_length384可考虑滑动窗口切分后再拼接各窗口的答案分数。答案合法性本文演示直接取argmax实际生产环境建议约束answer_end_index answer_start_index并可结合squad_convert等后处理过滤无意义答案例如答案落在 context 之外的情形在训练时已被标记为(0, 0)并通过ignore_index处理。部署微调完成后push_to_hub上传的模型既可通过AutoModelForQuestionAnswering.from_pretrained本地加载也可结合仓库中的 pipelines 模块以pipeline(question-answering, model...)方式快速封装为服务接口。【免费下载链接】transformers Transformers: the model-definition framework for state-of-the-art machine learning models in text, vision, audio, and multimodal models, for both inference and training.项目地址: https://gitcode.com/GitHub_Trending/tra/transformers创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考