基于 Transformers 实现问答

前言

问答是一个经典的 NLP 任务,有多种实际应用的形式。 如下面列举出来的两种常见形式:

  • 每个问题都提供可能答案的列表,模型只需要返回答案选项的概率分布,这种一般比较简单。
  • 给定一个输入文档(俗称上下文)和一个有关该文档的问题,并且它必须提取文档中包含答案的文本范围。 在这种情况下,模型不是计算答案选项的概率分布,而是计算文档文本中标记的两个概率分布,对应表示包含答案的范围的开始位置结束位置。这种问答称为"提取式问答"。

一般来说提取式问答的模型需要非常庞大的数据来从头训练,但是使用强大的预训练基础模型开始可以将数据集大小减少多个数量级,并且能取得令人满意的效果。本文介绍的是在轻量级 BERT 模型 distilbert 模型上进行微调来完成简单的问答任务。

数据

在将这些文本输入模型之前,我们需要对它们进行预处理。 这是由 Transformers Tokenizer 完成的,它将输入的文本转化为 token id ,并生成其他输入供 bert 模型使用。为此,我们使用 AutoTokenizer.from_pretrained 方法从 distilbert-base-cased 实例我们的分词器,这将确保我们得到一个与我们想要使用的预训练模型模型 distilbert 架构相对应的分词器。

下面代码主要是数据处理过程,每个样本将 contextquestion 作为输入,将 answer 在输入的 token 序列中的起始位置 start_positions 和结束位置 end_positions 标记出来,如果 answer 在输入的 token 序列中不存在,则将起始位置 start_positions 和结束位置 end_positions 都标记为 cls_token_id 在序列中的索引位置。

ini 复制代码
def prepare_train_feature(examples):
    examples["question"] = [q.lstrip() for q in examples["question"]]
    examples["context"] = [c.lstrip() for c in examples["context"]]
    tokenized_examples = tokenizer(examples["question"], examples["context"], truncation="only_second",  max_length=max_length, stride=doc_stride, return_overflowing_tokens=True, return_offsets_mapping=True, padding="max_length")
    sample_mapping = tokenized_examples.pop("overflow_to_sample_mapping")
    offset_mapping = tokenized_examples.pop("offset_mapping")
    tokenized_examples["start_positions"] = []
    tokenized_examples["end_positions"] = []
    for i, offsets in enumerate(offset_mapping):
        input_ids = tokenized_examples["input_ids"][i]
        cls_index = input_ids.index(tokenizer.cls_token_id)
        sequence_ids = tokenized_examples.sequence_ids(i)
        sample_index = sample_mapping[i]
        answers = examples["answers"][sample_index]
        if len(answers["answer_start"]) == 0:
            tokenized_examples["start_positions"].append(cls_index)
            tokenized_examples["end_positions"].append(cls_index)
        else:
            start_char = answers["answer_start"][0]
            end_char = start_char + len(answers["text"][0])
            token_start_index = 0
            while sequence_ids[token_start_index] != 1:
                token_start_index += 1
            token_end_index = len(input_ids) - 1
            while sequence_ids[token_end_index] != 1:
                token_end_index -= 1
            if not (offsets[token_start_index][0] <= start_char and offsets[token_end_index][1] >= end_char):
                tokenized_examples["start_positions"].append(cls_index)
                tokenized_examples["end_positions"].append(cls_index)
            else:
                while token_start_index < len(offsets) and offsets[token_start_index][0] <= start_char:
                    token_start_index += 1
                tokenized_examples["start_positions"].append(token_start_index - 1)
                while offsets[token_end_index][1] >= end_char:
                    token_end_index -= 1
                tokenized_examples["end_positions"].append(token_end_index + 1)
    return tokenized_examples
tokenized_datasets = datasets.map(prepare_train_feature, batched=True, remove_columns=datasets["train"].column_names)
train_set = tokenized_datasets["train"].with_format("numpy")[:]
validation_set = tokenized_datasets["validation"].with_format("numpy")[:]

模型

我们选择了轻量级的distilbert,它是著名的 BERT 语言模型的一个较小的蒸馏版本。 但是如果任务需要更高的准确率,并且有足够 GPU 来处理它,那么可以使用更大的模型,如 roberta-large

使用 TFAutoModelForQuestionAnswering 类从 Hugging Face Transformers 库中加载预训练的问答模型 distilbert-base-cased。使用 TensorFlow 的混合精度 mixed_float16 进行训练,这有助于在相同计算资源下加速模型的训练。另外配置 Adam 优化器,设置学习率为 5e-5,然后使用 compile 方法将模型编译,最后将模型权重保存成 h5 模型,以供测试需要。

训练需要 16G 作用的显存,耗时总共 20 分钟左右。

ini 复制代码
model = TFAutoModelForQuestionAnswering.from_pretrained(model_checkpoint)
keras.mixed_precision.set_global_policy("mixed_float16")
optimizer = keras.optimizers.Adam(learning_rate=5e-5)
model.compile(optimizer=optimizer)
model.fit(train_set, validation_data=validation_set, epochs=2)
model.save_weights("QA.h5")

模型输入:

vbnet 复制代码
question: 'Keras is an API designed for human beings, not machines. Keras follows best practices for reducing cognitive load: it offers consistent & simple APIs, it minimizes the number of user actions required for common use cases, and it provides clear & actionable error messages. It also has extensive documentation and developer guides. '
answer: What is Keras?

预测结果为:

复制代码
it offers consistent & simple APIs

可以看出,模型的问答效果初具效果。

发展

当前的问答任务,主要已经逐渐放弃了 BERT 这种"小模型",而是使用参数量越来越大的大模型,其中以 ChatGPT 最为出色,但是究其架构细节,仍然是在 Transformer 基础上搭建而成的,只是额外加入了 SFT 和强化学习的步骤来使其更加符合人类的问答习惯而已。

参考

github.com/wangdayaya/...

相关推荐
广州灵眸科技有限公司1 分钟前
瑞芯微(EASY EAI)RV1126B display
开发语言·数据库·人工智能·科技·嵌入式硬件
极客互动API4 分钟前
企业微信 AI 智能客服实战:Spring Boot+Vue 接入豆包、扣子、DeepSeek
java·人工智能·微信·企业微信
今天AI了吗5 分钟前
Codex使用技巧:深度解析 Plan Mode 与 Goal Mode
java·网络·人工智能·架构·java-ee
FX1317887KP_8 分钟前
AI陪练正在重塑KET PET FCE口语备考,传统外教课还有必要吗?
人工智能·小程序·ket口语·pet口语·fce备考·剑桥英语
天远Date Lab8 分钟前
零信任架构实战:基于天远全能个人大数据报告构建自动化核心KYC网关
大数据·人工智能·架构·自动化
智购科技智能售货柜9 分钟前
2026自动售货机商品掉落声学计数方案:从麦克风到频谱识别的工程实践~YH
人工智能·算法
QXWZ_IA10 分钟前
输电线路沉降监测用什么技术?三种高精度路线对比与精度解析
人工智能·科技
盛世宏博智慧档案12 分钟前
基于PLC与物联网网关的档案库房温湿度超标自动联动控制实现思路(含拓扑图与协议对接)
大数据·人工智能·物联网
CV山月13 分钟前
《DPO 算法详解:不训练奖励模型,如何让大模型直接学会人类偏好?》
人工智能·经验分享·python·大模型·强化学习·研究生
狂奔solar14 分钟前
让AI学会“看见“手指的遮挡 —— Hand Visibility Detector 深度解读
人工智能·手势识别