第七章:文本表示
到目前为止,我们已经使用transformers
库解决了分类和生成问题。文本表示是现代自然语言处理(NLP)中的另一个关键任务,特别是对于无监督任务,如聚类、语义搜索和主题建模。通过使用诸如Universal Sentence Encoder(USE)和带有附加库(如句子转换器)的 Siamese BERT(Sentence-BERT)等各种模型来表示句子将在此处进行解释。还将解释使用 BART 进行零样本学习,并学习如何利用它。还将描述少样本学习方法和无监督使用案例,如语义文本聚类和主题建模。最后,将涵盖一次性学习用例,如语义搜索。
本章将涵盖以下主题:
- 句子嵌入简介
- 句子相似度模型的基准测试
- 使用 BART 进行零样本学习
- 使用 FLAIR 进行语义相似性实验
- 使用 Sentence-BERT 进行文本聚类
- 使用 Sentence-BERT 进行语义搜索
技术要求
我们将使用 Jupyter 笔记本来运行我们的编程练习。为此,您将需要 Python 3.6+和以下软件包:
sklearn
transformers >=4.00
datasets
sentence-transformers
tensorflow-hub
flair
umap-learn
bertopic
本章中编程练习的所有笔记本将在以下 GitHub 链接上提供:
github.com/PacktPublishing/Mastering-Transformers/tree/main/CH07
查看以下链接以查看代码演示视频:bit.ly/2VcMCyI
句子嵌入简介
预训练的 BERT 模型不能产生高效且独立的句子嵌入,因为它们始终需要在端到端的监督设置中进行微调。这是因为我们可以将预训练的 BERT 模型视为一个不可分割的整体,语义分布在所有层中,而不仅仅是最后一层。如果不进行微调,单独使用其内部表示可能是无效的。而且,难以处理无监督任务,如聚类、主题建模、信息检索或语义搜索。例如,在聚类任务中,我们必须评估许多句子对,这导致了巨大的计算开销。
幸运的是,对原始 BERT 模型进行了许多修改,如Sentence-BERT(SBERT),以生成语义有意义且独立的句子嵌入。我们将在接下来讨论这些方法。在自然语言处理文献中,提出了许多神经句子嵌入方法,用于将单个句子映射到一个公共特征空间(向量空间模型),其中通常使用余弦函数(或点积)来衡量相似度,欧氏距离用于衡量不相似度。
以下是一些可以通过句子嵌入有效解决的应用程序:
- 句子对任务
- 信息检索
- 问答
- 重复问题检测
- 释义检测
- 文档聚类
- 主题建模
最简单但最有效的神经句子嵌入操作是对句子中单词的嵌入进行平均池化。为了更好地表示这一点,一些早期的神经方法以无监督方式学习句子嵌入,例如 Doc2Vec、Skip-Thought、FastSent 和 Sent2Vec。Doc2Vec 利用了令牌级的分布理论和一个目标函数来预测相邻的单词,类似于 Word2Vec。该方法注入了一个额外的内存令牌(称为transformers
库),这个额外的令牌充当了表示上下文或文档嵌入的一部分的内存。SkipThought 和 FastSent 被认为是句子级方法,其中目标函数用于预测相邻的句子。这些模型从相邻的句子及其上下文中提取句子的含义,以获取必要的信息。
一些其他方法,例如 InferSent,利用监督学习和多任务迁移学习来学习通用句子嵌入。InferSent 训练各种监督任务以获得更高效的嵌入。基于 RNN 的监督模型,如 GRU 或 LSTM,利用最后的隐藏状态(或堆叠的整个隐藏状态)在监督设置中获取句子嵌入。我们在第一章中涉及了 RNN 方法,从词袋模型到 Transformer。
交叉编码器与双编码器
到目前为止,我们已经讨论了如何训练基于 Transformer 的语言模型,并在半监督和监督环境中对其进行微调。正如我们在前几章中所学到的,多亏了 Transformer 架构,我们取得了成功的结果。一旦在预训练模型的顶部放置了特定于任务的稀疏线性层,在特定于任务的标记数据上对网络的所有权重进行了微调(不仅仅是最后一个特定于任务的稀疏层),我们也经历了 BERT 架构如何在不需要任何架构修改的情况下,对两个不同组的任务(单句或句对)进行微调。唯一的不同之处在于,对于句对任务,句子被连接并用 SEP 标记标记。因此,自注意力应用于连接句子的所有标记。这是 BERT 模型的一个巨大优势,即输入句子可以在每一层从彼此那里获取必要的信息。最终,它们同时被编码。这被称为交叉编码。
然而,关于交叉编码器存在两个缺点,SBERT 作者和Humeau 等人,2019 年已经解决了这些缺点,具体如下:
- 由于需要处理太多可能的组合,交叉编码器设置对许多句子对任务并不方便。例如,要从 1,000 个句子的列表中获取两个最接近的句子,交叉编码器模型(BERT)需要大约 500,000(n(n-1)/2)个推断计算。因此,与 SBERT 或 USE 等替代方案相比,速度会非常慢。这是因为这些替代方案产生独立的句子嵌入,其中相似性函数(余弦相似性)或不相似性函数(欧氏或曼哈顿距离)可以轻松应用。请注意,这些相似性/不相似性函数可以在现代架构上有效执行。此外,借助优化的索引结构,我们可以将比较或聚类许多文档的计算复杂度从许多小时减少到几分钟。
- 由于其监督特性,BERT 模型无法推导出独立的有意义的句子嵌入。很难将预训练的 BERT 模型直接用于无监督任务,例如聚类、语义搜索或主题建模。BERT 模型为文档中的每个标记生成固定大小的向量。在无监督设置中,可以通过对标记向量进行平均或汇总,再加上 SEP 和 CLS 标记,来获得文档级表示。稍后,我们将看到 BERT 的这种表示产生的句子嵌入低于平均水平,并且其性能分数通常比 Word2Vec、FastText 或 GloVe 等词嵌入汇聚技术差。
或者,双编码器(如 SBERT)将一个句子对独立映射到语义向量空间,如下图所示。由于表示是分开的,双编码器可以为每个输入缓存编码的输入表示,从而实现快速推断时间。 BERT 的成功双编码器修改之一是 SBERT。基于孪生网络和三重网络结构,SBERT 微调 BERT 模型以产生语义上有意义且独立的句子嵌入。
以下图显示了双编码器架构:
图 7.1 - 双编码器架构
您可以在public.ukp.informatik.tu-darmstadt.de/reimers/sentence-transformers/v0.2/
找到数百个已经通过不同目标训练的预训练 SBERT 模型。
我们将在下一节中使用其中一些。
对句子相似度模型进行基准测试。
有许多语义文本相似性模型可用,但强烈建议您使用度量标准对它们的能力和差异进行基准测试并加以理解。Papers With Code提供了这些数据集的列表,网址为paperswithcode.com/task/semantic-textual-similarity
。
此外,在每个数据集中有许多模型输出,这些输出是按其结果排名的。这些结果是从上述文章中获取的。
GLUE 提供了大多数这些数据集和测试,但它不仅适用于语义文本相似性。GLUE,代表General Language Understanding Evaluation,是一个用于评估具有不同 NLP 特性的模型的通用基准。有关 GLUE 数据集及其用法的更多详细信息,请参阅第二章,主题的实际介绍。让我们在继续之前先看看它:
- 要从 GLUE 基准加载度量标准和 MRPC 数据集,您可以使用以下代码:
from datasets import load_metric, load_dataset metric = load_metric('glue', 'mrpc') mrpc = load_dataset('glue', 'mrpc')
- 此数据集中的样本标记为
1
和0
,这表示它们是否相似或不相似。您可以使用任何模型,无论其体系结构如何,来为给定的两个句子生成值。换句话说,模型应将这两个句子分类为零和一。 - 假设模型产生值,并且这些值存储在一个名为
predictions
的数组中。您可以轻松地使用这个度量标准与预测一起查看 F1 和准确度值:
labels = [i['label'] for i in dataset['test']] metric.compute(predictions=predictions, references=labels)
- 一些语义文本相似性数据集,如Semantic Textual Similarity Benchmark (STSB),具有不同的度量标准。例如,此基准使用 Spearman 和 Pearson 相关性,因为输出和预测值在 0 到 5 之间,并且是浮点数,而不是在 0 和 1 之间,这是一个回归问题。以下代码显示了此基准的一个示例:
metric = load_metric('glue', 'stsb') metric.compute(predictions=[1,2,3],references=[5,2,2])
- 预测和参考与Microsoft Research Paraphrase Corpus (MRPC)中的相同;预测是模型的输出,而参考是数据集的标签。
- 为了得到两个模型之间的比较结果,我们将使用 RoBERTa 的精简版本,并在 STSB 上测试这两个模型。首先,您必须加载两个模型。以下代码显示了如何在加载和使用模型之前安装所需的库:
pip install tensorflow-hub pip install sentence-transformers
- 正如我们之前提到的,下一步是加载数据集和度量标准:
from datasets import load_metric, load_dataset stsb_metric = load_metric('glue', 'stsb') stsb = load_dataset('glue', 'stsb')
- 然后,我们必须加载两个模型:
import tensorflow_hub as hub use_model = hub.load( "https://tfhub.dev/google/universal-sentence-encoder/4") from sentence_transformers import SentenceTransformer distilroberta = SentenceTransformer( 'stsb-distilroberta-base-v2')
- 这两个模型都为给定的句子提供嵌入。为了比较两个句子之间的相似性,我们将使用余弦相似度。以下函数以批量形式接受句子,并利用 USE 为每对句子提供余弦相似度:
import tensorflow as tf import math def use_sts_benchmark(batch): sts_encode1 = \ tf.nn.l2_normalize(use_model(tf.constant(batch['sentence1'])), axis=1) sts_encode2 = \ tf.nn.l2_normalize(use_model(tf.constant(batch['sentence2'])), axis=1) cosine_similarities = \ tf.reduce_sum(tf.multiply(sts_encode1,sts_encode2),axis=1) clip_cosine_similarities = \ tf.clip_by_value(cosine_similarities,-1.0, 1.0) scores = 1.0 - \ tf.acos(clip_cosine_similarities) / math.pi return scores
- 通过小幅修改,相同的函数也可以用于 RoBERTa。这些小修改仅用于替换嵌入函数,该函数对于 TensorFlow Hub 模型和 transformers 是不同的。以下是修改后的函数:
def roberta_sts_benchmark(batch): sts_encode1 = \ tf.nn.l2_normalize(distilroberta.encode(batch['sentence1']), axis=1) sts_encode2 = \ tf.nn.l2_normalize(distilroberta.encode(batch['sentence2']), axis=1) cosine_similarities = \ tf.reduce_sum(tf.multiply(sts_encode1, sts_encode2), axis=1) clip_cosine_similarities = tf.clip_by_value(cosine_similarities, -1.0, 1.0) scores = 1.0 - tf.acos(clip_cosine_similarities) / math.pi return scores
- 将这些函数应用于数据集将为每个模型生成相似性得分:
use_results = use_sts_benchmark(stsb['validation']) distilroberta_results = roberta_sts_benchmark( stsb['validation'])
- 对两个结果使用度量标准会产生 Spearman 和 Pearson 相关值:
results = { "USE":stsb_metric.compute( predictions=use_results, references=references), "DistillRoberta":stsb_metric.compute( predictions=distilroberta_results, references=references) }
- 您可以简单地使用 pandas 以对比的方式查看结果:
import pandas as pd pd.DataFrame(results)
- 输出如下所示:
图 7.2 – DistilRoberta 和 USE 上的 STSB 验证结果
在本节中,你了解了语义文本相似性的重要基准。无论模型如何,你学会了如何使用这些度量标准之一来量化模型表现。在接下来的部分,你将了解几种少样本学习模型。
使用 BART 进行零样本学习
在机器学习领域,零样本学习指的是可以执行任务而无需明确训练的模型。在 NLP 的情况下,假设有一个模型可以预测一些文本被分配给模型给出的类别的概率。然而,这种学习方式的有趣之处在于模型并没有接受这些类别的训练。
随着许多可以进行迁移学习的高级语言模型的崛起,零样本学习应运而生。在 NLP 的情况下,这种学习是由 NLP 模型在测试时执行的,模型在那里看到属于新类别的样本,以前没有看到过这些样本。
这种学习通常用于分类任务,其中类别和文本都被表示,比较两者的语义相似性。这两者的表现形式是嵌入向量,而相似度度量(如余弦相似度或一个预训练分类器如一个稠密层)输出句子/文本被分类为类别的概率。
我们可以使用许多方法和方案来训练这些模型,但最早使用的方法之一是从包含在元部分中的关键字标签的互联网页面中提取。欲了解更多信息,请阅读以下文章和博文:amitness.com/2020/05/zero-shot-text-classification/
。
而不是使用如此庞大的数据,有像 BART 这样使用多样式自然语言推理(MNLI)数据集对其进行微调并检测两个不同句子之间关系的语言模型。此外,HuggingFace 模型存储库包含许多为零样本学习实现的模型。他们还提供了一个零样本学习流水线,以方便使用。
例如,来自**Facebook AI Research(FAIR)**的 BART 正在以下代码中用于执行零样本文本分类:
from transformers import pipeline import pandas as pd classifier = pipeline("zero-shot-classification", model="facebook/bart-large-mnli") sequence_to_classify = "one day I will see the world" candidate_labels = ['travel', 'cooking', 'dancing', 'exploration'] result = classifier(sequence_to_classify, candidate_labels) pd.DataFrame(result)
结果如下:
图 7.3 – 使用 BART 进行零样本学习的结果
你可以看到,旅行和探索标签的概率最高,但最可能的是旅行。
然而,有时一个样本可能属于多个类别(多标签)。HuggingFace 为此提供了一个名为multi_label
的参数。以下示例使用了这个参数:
result = classifier(sequence_to_classify, candidate_labels, multi_label=True) Pd.DataFrame(result)
因此,它更改为以下内容:
图 7.4 – 使用 BART 进行零样本学习的结果(multi_label = True)
您可以进一步测试结果,看看模型在使用与旅行标签非常相似的标签时的表现。例如,您可以看看在标签列表中添加moving
和going
后,模型的表现如何。
还有其他模型也利用标签和上下文之间的语义相似性来进行零样本分类。在少样本学习的情况下,模型会给出一些样本,但这些样本不足以单独训练一个模型。模型可以利用这些样本来执行诸如语义文本聚类之类的任务,稍后将会解释。
现在您已经学会了如何使用 BART 进行零样本学习,您应该了解它的工作原理。例如,BART 是在旅行
上进行了微调,并将第二个句子的内容(例如有一天我会看到世界
)。根据这一点,如果这两个句子可以相互接续,那么这意味着标签和内容在语义上相关。以下的代码示例展示了如何直接使用 BART 模型,而不需要零样本分类的流程以前的描述:
from transformers \ import AutoModelForSequenceClassification,\ AutoTokenizer nli_model = AutoModelForSequenceClassification\ .from_pretrained( "facebook/bart-large-mnli") tokenizer = AutoTokenizer\ .from_pretrained( "facebook/bart-large-mnli") premise = "one day I will see the world" label = "travel" hypothesis = f'This example is {label}.' x = tokenizer.encode( premise, hypothesis, return_tensors='pt', truncation_strategy='only_first') logits = nli_model(x)[0] entail_contradiction_logits = logits[:,[0,2]] probs = entail_contradiction_logits.softmax(dim=1) prob_label_is_true = probs[:,1] print(prob_label_is_true)
结果如下:
tensor([0.9945], grad_fn=<SelectBackward>)
您也可以将第一个句子称为假设,将包含标签的句子称为前提。根据结果,前提可以蕴涵假设,这意味着假设被标签为前提。
到目前为止,您已经学会了如何使用基于 NLI 微调模型的零样本学习。接下来,您将学习如何利用语义文本聚类和语义搜索来进行少样本/一样本学习。
使用 FLAIR 进行语义相似性实验
在这个实验中,我们将通过flair
库对句子表示模型进行定性评估,这对我们来说真的简化了获取文档嵌入的过程。
我们将采用以下方法进行实验:
- 文档平均池嵌入
- 基于 RNN 的嵌入
- BERT 嵌入
- SBERT 嵌入
在开始实验之前,我们需要安装这些库:
!pip install sentence-transformers !pip install dataset !pip install flair
对于定性评估,我们定义了一组相似的句子对和一组不相似的句子对(每组各五对)。我们期望嵌入模型应该分别度量高分和低分。
句子对是从 SBS Benchmark 数据集中提取的,我们在第六章中已经熟悉了句对回归部分,用于令牌分类的语言模型微调。对于相似的句对,两个句子完全等价,并且它们分享相同的含义。
在 STSB 数据集中,随机抽取了相似分数约为 5 的对,如下所示:
import pandas as pd similar=[ ("A black dog walking beside a pool.", "A black dog is walking along the side of a pool."), ("A blonde woman looks for medical supplies for work in a suitcase. ", " The blond woman is searching for medical supplies in a suitcase."), ("A doubly decker red bus driving down the road.", "A red double decker bus driving down a street."), ("There is a black dog jumping into a swimming pool.", "A black dog is leaping into a swimming pool."), ("The man used a sword to slice a plastic bottle.", "A man sliced a plastic bottle with a sword.")] pd.DataFrame(similar, columns=["sen1", "sen2"])
输出如下:
图 7.5 – 相似对列表
这是来自 STS-B 数据集的相似度得分约为 0 的不相似句子列表:
import pandas as pd dissimilar= [ ("A little girl and boy are reading books. ", "An older child is playing with a doll while gazing out the window."), ("Two horses standing in a field with trees in the background.", "A black and white bird on a body of water with grass in the background."), ("Two people are walking by the ocean.", "Two men in fleeces and hats looking at the camera."), ("A cat is pouncing on a trampoline.", "A man is slicing a tomato."), ("A woman is riding on a horse.", "A man is turning over tables in anger.")] pd.DataFrame(dissimilar, columns=["sen1", "sen2"])
输出如下:
图 7.6 – 不相似对列表
现在,让我们准备好评估嵌入模型所需的函数。以下sim()
函数计算两个句子之间的余弦相似度;即,s1
,s2
:
import torch, numpy as np def sim(s1,s2): s1=s1.embedding.unsqueeze(0) s2=s2.embedding.unsqueeze(0) sim=torch.cosine_similarity(s1,s2).item() return np.round(sim,2)
在这个实验中使用的文档嵌入模型都是预训练模型。我们将文档嵌入模型对象和句子对列表(相似或不相似)传递给以下evaluate()
函数,一旦模型编码了句子嵌入,它将计算列表中每对的相似度得分,以及列表的平均值。函数的定义如下:
from flair.data import Sentence def evaluate(embeddings, myPairList): scores=[] for s1, s2 in myPairList: s1,s2=Sentence(s1), Sentence(s2) embeddings.embed(s1) embeddings.embed(s2) score=sim(s1,s2) scores.append(score) return scores, np.round(np.mean(scores),2)
现在,是时候评估句子嵌入模型了。我们将从平均池化方法开始!
平均词嵌入
平均词嵌入(或文档池化)对句子中的所有单词应用均值池化操作,其中所有单词嵌入的平均值被视为句子嵌入。以下执行实例化了基于 GloVe 向量的文档池嵌入。请注意,虽然我们这里只使用了 GloVe 向量,但 flair API 允许我们使用多个单词嵌入。以下是代码定义:
from flair.data import Sentence from flair.embeddings\ import WordEmbeddings, DocumentPoolEmbeddings glove_embedding = WordEmbeddings('glove') glove_pool_embeddings = DocumentPoolEmbeddings( [glove_embedding] )
让我们评估 GloVe 池模型的相似对,如下所示:
>>> evaluate(glove_pool_embeddings, similar) ([0.97, 0.99, 0.97, 0.99, 0.98], 0.98)
结果似乎很好,因为那些得到的值非常高,这是我们期望的。然而,模型也产生了高得分,例如对于不相似列表的平均得分为 0.94。我们的期望值应该小于 0.4。我们稍后在本章将讨论为什么会得到这个值。以下是执行情况:
>>> evaluate(glove_pool_embeddings, dissimilar) ([0.94, 0.97, 0.94, 0.92, 0.93], 0.94)
接下来,让我们对同一问题评估一些 RNN 嵌入。
基于 RNN 的文档嵌入
让我们基于 GloVe 嵌入实例化一个 GRU 模型,默认的DocumentRNNEmbeddings
模型是 GRU:
from flair.embeddings \ import WordEmbeddings, DocumentRNNEmbeddings gru_embeddings = DocumentRNNEmbeddings([glove_embedding])
运行评估方法:
>>> evaluate(gru_embeddings, similar) ([0.99, 1.0, 0.94, 1.0, 0.92], 0.97) >>> evaluate(gru_embeddings, dissimilar) ([0.86, 1.0, 0.91, 0.85, 0.9], 0.9)
同样,我们得到了不相似列表的高分。这并不是我们从句子嵌入中想要的。
基于 Transformer 的 BERT 嵌入
以下执行实例化了一个池化最终层的bert-base-uncased
模型:
from flair.embeddings import TransformerDocumentEmbeddings from flair.data import Sentence bert_embeddings = TransformerDocumentEmbeddings( 'bert-base-uncased')
运行评估,如下所示:
>>> evaluate(bert_embeddings, similar) ([0.85, 0.9, 0.96, 0.91, 0.89], 0.9) >>> evaluate(bert_embeddings, dissimilar) ([0.93, 0.94, 0.86, 0.93, 0.92], 0.92)
这更糟糕!不相似列表的得分高于相似列表的得分。
句子-BERT 嵌入
现在,让我们将 Sentence-BERT 应用于区分相似对和不相似对的问题,如下所示:
- 首先,警告:我们需要确保
sentence-transformers
包已经被安装:
!pip install sentence-transformers
- 正如我们之前提到的,Sentence-BERT 提供了各种预训练模型。我们将选择
bert-base-nli-mean-tokens
模型进行评估。以下是代码:
from flair.data import Sentence from flair.embeddings \ import SentenceTransformerDocumentEmbeddings sbert_embeddings = SentenceTransformerDocumentEmbeddings( 'bert-base-nli-mean-tokens')
- 让我们评估模型:
>>> evaluate(sbert_embeddings, similar) ([0.98, 0.95, 0.96, 0.99, 0.98], 0.97) >>> evaluate(sbert_embeddings, dissimilar) ([0.48, 0.41, 0.19, -0.05, 0.0], 0.21)
- 干得好!SBERT 模型产生了更好的结果。模型为不相似列表产生了较低的相似度得分,这是我们所期望的。
- 现在,我们将进行一个更难的测试,我们将向模型传递相互矛盾的句子。我们将定义一些棘手的句子对,如下所示:
>>> tricky_pairs=[ ("An elephant is bigger than a lion", "A lion is bigger than an elephant") , ("the cat sat on the mat", "the mat sat on the cat")] >>> evaluate(glove_pool_embeddings, tricky_pairs) ([1.0, 1.0], 1.0) >>> evaluate(gru_embeddings, tricky_pairs) ([0.87, 0.65], 0.76) >>> evaluate(bert_embeddings, tricky_pairs) ([1.0, 0.98], 0.99) >>> evaluate(sbert_embeddings, tricky_pairs) ([0.93, 0.97], 0.95)
- 有趣!分数非常高,因为句子相似性模型类似于主题检测,并且衡量内容相似性。当我们看句子时,它们分享相同的内容,尽管它们彼此矛盾。内容是关于狮子和大象或猫和垫子。因此,模型产生了高相似度分数。由于 GloVe 嵌入方法池化了单词的平均值而不关心单词顺序,它将两个句子视为相同。另一方面,GRU 模型产生了较低的值,因为它关心单词顺序。令人惊讶的是,即使是 SBERT 模型也没有产生有效的分数。这可能是由于 SBERT 模型中使用的基于内容相似性的监督。
- 要正确检测具有三个类别(即中性、矛盾和蕴含)的两个句子对的语义,我们必须在 MNLI 上使用一个经过微调的模型。以下代码块显示了一个示例,使用了在 XNLI 上进行了微调的 XLM-Roberta,使用相同的例子:
from transformers \ Import AutoModelForSequenceClassification, AutoTokenizer nli_model = AutoModelForSequenceClassification\ .from_pretrained( 'joeddav/xlm-roberta-large-xnli') tokenizer = AutoTokenizer\ .from_pretrained( 'joeddav/xlm-roberta-large-xnli') import numpy as np for permise, hypothesis in tricky_pairs: x = tokenizer.encode(premise, hypothesis, return_tensors='pt', truncation_strategy='only_first') logits = nli_model(x)[0] print(f"Permise: {permise}") print(f"Hypothesis: {hypothesis}") print("Top Class:") print(nli_model.config.id2label[np.argmax( logits[0].detach().numpy()). ]) print("Full softmax scores:") for i in range(3): print(nli_model.config.id2label[i], logits.softmax(dim=1)[0][i].detach().numpy()) print("="*20)
- 输出将显示每个正确的标签:
Permise: An elephant is bigger than a lion Hypothesis: A lion is bigger than an elephant Top Class: contradiction Full softmax scores: contradiction 0.7731286 neutral 0.2203285 entailment 0.0065428796 ==================== Permise: the cat sat on the mat Hypothesis: the mat sat on the cat Top Class: entailment Full softmax scores: contradiction 0.49365467 neutral 0.007260764 entailment 0.49908453 ====================
在某些问题中,NLI 比语义文本更优先,因为它旨在找到矛盾或蕴含,而不是原始的相似度得分。对于下一个样本,同时使用两个句子进行蕴含和矛盾。这有点主观,但对于模型来说,第二个句子对似乎是在蕴含和矛盾之间的非常微妙的选择。
精通 Transformers(三)(2)https://developer.aliyun.com/article/1510706