本篇博文继续参考:

【实战篇】是时候彻底弄懂BERT模型了(收藏,已修复)_bert-base-uncased-CSDN博客https://helloai.blog.csdn.net/article/details/120232707

目录

导入依赖

 下载并加载模型和分词器

增加[CLS]和[SEP]标记到问题和段落中

对问题和段落进行分词

组合问题和段落标记,并将它们转换为input_ids

 定义segment_ids

把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_idssegment_ids转换为Tensor

input_ids = torch.tensor([input_ids])
segment_ids = torch.tensor([segment_ids])

获取答案

input_idssegment_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_indexend_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 中提取对应片段
│
└── 输出自然语言形式的答案

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐