基于 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/...

相关推荐
nju_spy几秒前
周志华《机器学习导论》第8章 集成学习 Ensemble Learning
人工智能·随机森林·机器学习·集成学习·boosting·bagging·南京大学
静心问道24 分钟前
TrOCR: 基于Transformer的光学字符识别方法,使用预训练模型
人工智能·深度学习·transformer·多模态
说私域25 分钟前
基于开源AI大模型、AI智能名片与S2B2C商城小程序源码的用户价值引导与核心用户沉淀策略研究
人工智能·开源
亲持红叶27 分钟前
GLU 变种:ReGLU 、 GEGLU 、 SwiGLU
人工智能·深度学习·神经网络·激活函数
说私域27 分钟前
线上协同办公时代:以开源AI大模型等工具培养网感,拥抱职业变革
人工智能·开源
群联云防护小杜29 分钟前
深度隐匿源IP:高防+群联AI云防护防绕过实战
运维·服务器·前端·网络·人工智能·网络协议·tcp/ip
摘星编程34 分钟前
构建智能客服Agent:从需求分析到生产部署
人工智能·需求分析·智能客服·agent开发·生产部署
不爱学习的YY酱37 分钟前
信息检索革命:Perplexica+cpolar打造你的专属智能搜索中枢
人工智能
whaosoft-1432 小时前
51c自动驾驶~合集7
人工智能
刘晓倩5 小时前
Coze智能体开发实战-多Agent综合实战
人工智能·coze