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

相关推荐
HPC_fac130520678162 分钟前
科研深度学习:如何精选GPU以优化服务器性能
服务器·人工智能·深度学习·神经网络·机器学习·数据挖掘·gpu算力
猎嘤一号1 小时前
个人笔记本安装CUDA并配合Pytorch使用NVIDIA GPU训练神经网络的计算以及CPUvsGPU计算时间的测试代码
人工智能·pytorch·神经网络
天润融通1 小时前
天润融通携手挚达科技:AI技术重塑客户服务体验
人工智能
Elastic 中国社区官方博客3 小时前
使用 Elastic AI Assistant for Search 和 Azure OpenAI 实现从 0 到 60 的转变
大数据·人工智能·elasticsearch·microsoft·搜索引擎·ai·azure
江_小_白4 小时前
自动驾驶之激光雷达
人工智能·机器学习·自动驾驶
yusaisai大鱼5 小时前
TensorFlow如何调用GPU?
人工智能·tensorflow
珠海新立电子科技有限公司8 小时前
FPC柔性线路板与智能生活的融合
人工智能·生活·制造
IT古董8 小时前
【机器学习】机器学习中用到的高等数学知识-8. 图论 (Graph Theory)
人工智能·机器学习·图论
曼城周杰伦8 小时前
自然语言处理:第六十三章 阿里Qwen2 & 2.5系列
人工智能·阿里云·语言模型·自然语言处理·chatgpt·nlp·gpt-3
余炜yw9 小时前
【LSTM实战】跨越千年,赋诗成文:用LSTM重现唐诗的韵律与情感
人工智能·rnn·深度学习