自然语言处理【NLP】系列——实战自然语言推理中的问答任务(小白级入门教程)
本篇博文继续参考:
目录
把input_ids和segment_ids转换为Tensor
自然语言推理(Natural Language Inference,简称 NLI)是自然语言处理中的一个任务,其目标是判断两个自然语言句子之间的逻辑关系。这两个句子分别是:
- 前提(Premise):一个已知的句子。
- 假设(Hypothesis):一个需要验证的句子。
模型的任务是根据前提判断假设是否成立,并将其分类为以下三种关系之一:
- 1. 蕴涵(Entailment / True):如果从前提可以推断出假设是正确的,则两者的关系是“蕴涵”。比如:
前提:一只狗正在草地上奔跑。 假设:有一只动物在户外活动。 关系:蕴涵(因为狗是动物,草地属于户外) - 2. 矛盾(Contradiction / False):如果前提与假设之间存在冲突或不可能同时成立,则两者的关系是“矛盾”。比如:
前提:她穿着红色的衣服。 假设:她的衣服是绿色的。 关系:矛盾(红与绿不同) - 3. 中性/不确定(Neutral / Neutral):如果前提既不支持也不否定假设,即无法确定真假,则两者的关系是“中性”或“不确定”。
前提:他在图书馆里看书。 假设:他喜欢历史小说。 关系:中性(看书不一定看的是历史小说)在本节中将学习如何使用一个预训练的问答BERT模型来做问答任务,注意并不是微调哦!!
导入依赖
from transformers import BertForQuestionAnswering, BertTokenizer
import torch
下载并加载模型和分词器
因为本次实验的目的是梳理流程,并不是提升精度,因此仍旧使用bert的预训练模型uncased_L-12_H-768_A-12,也可以使用ert-large-uncased-whole-word-masking-finetuned-squad模型,它是在SQUAD数据集上微调过的模型。
model = BertForQuestionAnswering.from_pretrained('./uncased_L-12_H-768_A-12')
tokenizer = BertTokenizer.from_pretrained('./uncased_L-12_H-768_A-12')
定义BERT的输入,为问题和文本段落
question = "What is the immune system?"
paragraph = "The immune system is a system of many biological structures and processes within an organism that protects against disease. To function properly, an immune system must detect a wide variety of agents, known as pathogens, from viruses to parasitic worms, and distinguish them from the organism's own healthy tissue."
增加[CLS]和[SEP]标记到问题和段落中
question = '[CLS] ' + question + '[SEP]'
paragraph = paragraph + '[SEP]'
对问题和段落进行分词
question_tokens = tokenizer.tokenize(question)
paragraph_tokens = tokenizer.tokenize(paragraph)
组合问题和段落标记,并将它们转换为input_ids
BERT 在自然语言推理任务中表现非常出色。通常的做法是将前提和假设拼接成一个句子对
[CLS] 前提内容 [SEP] 假设内容 [SEP]
tokens = question_tokens + paragraph_tokens
input_ids = tokenizer.convert_tokens_to_ids(tokens)
定义segment_ids
构建 token_type_ids(也叫 segment_ids) 的一个常见方式,用于告诉模型哪些 token 是问题(question),哪些是段落(paragraph)。question赋值为0,paragraph赋值为1。
segment_ids = [0] * len(question_tokens)
segment_ids += [1] * len(paragraph_tokens)
结果示例:
# 假设 question_tokens 有 8 个 token,paragraph_tokens 有 25 个 token
segment_ids = [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, ..., 1]
把input_ids和segment_ids转换为Tensor
input_ids = torch.tensor([input_ids])
segment_ids = torch.tensor([segment_ids])
获取答案
将input_ids和segment_ids输入到模型中,它会返回所有标记作为答案开始位置和结束位置的得分:
start_scores, end_scores = model(input_ids, token_type_ids = segment_ids, return_dict = False)
获取start_index最高答案开始位置得分对应的标记索引,和end_index最高答案结束位置得分对应的标记索引:
start_index = torch.argmax(start_scores)
end_index = torch.argmax(end_scores)
# 打印结果
print("起始位置索引:", start_index.item()) # 示例输出: 起始位置索引: 14
print("结束位置索引:", end_index.item()) # 示例输出: 结束位置索引: 30
输出结果
将 tokens 列表中从 start_index 到 end_index 的 token 用空格连接成一个字符串,并打印输出。
print(' '.join(tokens[start_index:end_index+1]))
#输出结果
a system of many biological structures and processes within an organism that protects against disease
总结
在问答任务(Question Answering)中,BERT 等模型通过给定一个问题和一段段落,预测出段落中最有可能作为答案的子串。
输入:问题 + 段落
│
├── 编码成 token ID 和 token_type_ids
│
├── 模型推理 → 得到 start_scores 和 end_scores
│
├── 找到得分最高的 start_index 和 end_index
│
├── 从 tokens 中提取对应片段
│
└── 输出自然语言形式的答案
更多推荐
所有评论(0)