使用 DistilBERT 和 Transformers 构建问答系统

问答(Question Answering)是一项至关重要的自然语言处理任务,它使机器能够通过从给定的上下文中提取相关信息来理解和响应人类的问题。DistilBERT,作为 BERT 的蒸馏版本,在构建问答系统时提供了性能和计算效率之间的绝佳平衡。

在本教程中,您将学习如何使用 DistilBERT 和 transformers 库构建一个强大的问答(Q&A)系统。您将学习从基本实现到高级功能的方方面面。特别是,您将学习:

  • 如何使用 DistilBERT 实现基本的问答系统
  • 用于提高答案质量的高级技术

通过我的书籍《Hugging Face Transformers中的NLP》快速启动您的项目。它提供了带有工作代码的自学教程

让我们开始吧。

使用 DistilBERT 和 Transformers 构建问答系统
照片来源:Ana Municio。部分权利保留。

概述

这篇文章分为三个部分;它们是

  • 构建一个简单的问答系统
  • 处理长上下文
  • 构建专家系统

构建一个简单的问答系统

问答系统不仅仅是将问题抛给模型并获得答案。您希望答案准确且有充分的依据。做到这一点的方法是提供一个“上下文”来查找答案。虽然这可以防止模型回答开放式问题,但也能防止它**凭空捏造**答案。能够完成此任务的模型将能够理解问题和上下文,这比仅仅一个语言模型要强大得多。

能够执行此任务的模型是 BERT。下面,您将使用 DistilBERT 模型构建一个简单的问答系统。

您将看到的输出是:

我们使用的模型是 distilbert-base-uncased-distilled-squad,这是一个使用 SQuAD 数据集微调的 DistilBERT 模型。它是一个“不区分大小写”的模型,这意味着它将输入视为不区分大小写。这是一个经过微调的模型,可以在知识蒸馏方面表现更好。因此,它特别适用于需要理解问题和上下文的问答任务。

要使用它,您创建了一个使用 transformers 库的 pipeline。您请求它成为一个问答管道,但指定了要使用的模型和分词器,而不是让 pipeline() 函数为您选择一个。

当您调用管道时,您会提供问题和上下文。模型将在上下文中找到答案并返回答案。但是,它返回的不是一个简单的答案,而是答案在上下文中出现的位置以及答案的分数(介于 0 和 1 之间)。由于 top_k 设置为 3,因此返回了三个这样的答案。

从输出中,您可以发现得分最高的答案只是“Paris”(在上下文字符串中的字符位置 54 到 59),但其他答案也并非错误,只是表述方式不同。您可以修改上面的代码,根据分数选择最佳答案。

处理长上下文

这个简单的问答系统的问题在于它只能处理短上下文。模型对它能接受的最大序列长度有限制,对于这个特定模型是 512 个 token。

通常,这个限制的问题不在于问题,而在于上下文,因为您通常有一大段文本作为背景信息,而问题是您想从中找到答案的单个句子。要解决这个问题,您可以“分块”,即,将长上下文字符串拆分成更小的块,然后逐个馈送给问答模型。您应该重复使用问题,但遍历不同的块来查找答案。

使用 top_k=3,您可以期望从每个块中获得 3 个答案。由于每个答案都有一个分数,您可以简单地选择得分最高的答案。您也可以在找到最佳答案之前丢弃得分低的答案。这样,您就可以判断上下文是否提供了足够的信息来回答问题。

让我们看看如何实现这一点。

这会将工作流程封装到一个类中,使其更易于使用。您将问题和上下文传递给 get_answer() 方法,它将返回得分最高的答案。

get_answer() 方法中,如果答案已在缓存中,它将立即返回。否则,它将通过空格分割上下文,将每个块保持在长度限制以下。然后,将每个块与问题进行匹配,从问答模型中获取答案(及分数)。只有得分高于阈值的答案才被认为是有效的。然后选择最佳答案。可能找不到得分足够高的答案。在这种情况下,您将其标记为“未找到答案”。

为了方便语法,使用的参数存储在 dataclass 对象中。请注意,它将 max_sequence_length 设置为 512。这是一个保守的选择,因为模型可以处理多达 512 个 token,大约相当于 1500 个字符。但是,设置较低的序列长度可以帮助模型更有效地运行,因为 Transformer 模型的时空复杂性与序列长度呈二次方关系。

此代码的输出是

您可能会注意到,上述实现可能存在一个问题,即一个块被分割在一个句子中间,而最合适的答案可能就在其中。在这种情况下,您可能会发现问答模型找不到答案,或者返回了一个次优的答案。这是 preprocess_context() 方法算法中的一个问题。您可以考虑使用更长的块大小或创建带有重叠词的块。您可以尝试将其作为一项练习来实现。

构建专家系统

有了上述问答系统作为构建块,您可以自动化构建问题上下文的过程。通过一个可以用作问答上下文的文档数据库,您可以构建一个专家系统,该系统可以回答各种各样的问题。

构建一个好的专家系统是一项复杂的任务,涉及许多考虑因素。但是,高级框架并不难理解。这与 RAG(检索增强生成)的想法相似,其中上下文是从文档数据库中检索的,然后由模型生成答案。一个关键的组成部分是能够检索与问题最相关上下文的数据库。让我们看看如何构建一个。

这个类名为 ContextManager。您可以使用上下文 ID 向其中添加一段文本,上下文管理器将只保留有限数量的上下文。您可以使用上下文 ID 来检索文本。但最重要的函数是 search_relevant_context(),它将根据提供的问句搜索最相关的上下文。您可以使用不同的算法来计算相关性得分。这里使用了一个简单的算法,即计算重叠词的数量,或者使用 Jaccard 相似度。

有了这个类,您可以构建一个专家系统,该系统可以回答各种各样的问题。下面是如何使用它的示例

您首先将一些上下文添加到上下文管理器中。根据所需的上下文管理器最大大小,您可以向系统中添加大量文本。然后,您可以根据问题搜索最相关的上下文。然后,您可以像前一节一样,将问题和上下文馈送到问答系统中以获取答案,其中块状化和迭代查找最佳答案是在后台完成的。

您可以扩展此功能,尝试使用前几个上下文来查找更广泛的上下文中的答案。这是一种避免在上下文中找不到最佳答案的简单方法。但是,如果您有更好的方法来评估上下文的相关性,例如使用神经网络模型来计算相关性得分,您可能不需要尝试许多上下文。

上述输出将是

总而言之,以下是完整的代码

进一步阅读

以下是一些您可能会觉得有用的资源:

总结

在本教程中,您使用 DistilBERT 构建了一个全面的问答系统。特别是,您学习了如何

  • 使用 transformers 中的 pipeline 函数构建问答系统
  • 通过分块处理大型上下文
  • 使用上下文管理器管理上下文并在其之上构建专家系统

想在您的NLP项目中使用强大的语言模型吗?

NLP with Hugging Face Transformers

在您自己的机器上运行最先进的模型

...只需几行Python代码

在我的新电子书中探索如何实现
使用 Hugging Face Transformers 进行自然语言处理

它涵盖了在以下任务上的实践示例实际用例文本分类、摘要、翻译、问答等等...

最终将高级NLP带入
您自己的项目

没有理论。只有实用的工作代码。

查看内容

暂无评论。

发表回复

Machine Learning Mastery 是 Guiding Tech Media 的一部分,Guiding Tech Media 是一家领先的数字媒体出版商,专注于帮助人们了解技术。访问我们的公司网站以了解更多关于我们的使命和团队的信息。