Quora重复问题¶
此文件夹包含用于展示如何训练SentenceTransformers进行信息检索的脚本。作为一个简单的示例,我们将使用Quora重复问题数据集。该数据集包含超过50万个句子,并带有超过40万个成对注释,标注两个问题是否重复。
基于此数据集训练的模型可用于挖掘重复问题,即给定一组大量句子(在此情况下为问题),识别所有重复的成对句子。有关如何使用句子转换器挖掘重复问题/释义的示例,请参见释义挖掘。这种方法可以扩展到数十万个句子。
训练¶
选择合适的损失函数对于微调有用模型至关重要。对于给定任务,有两种损失函数特别适用:OnlineContrastiveLoss
和 MultipleNegativesRankingLoss
。
对比损失¶
完整的训练示例,请参见training_OnlineContrastiveLoss.py。
Quora重复问题数据集有一个`成对分类子集 <https://huggingface.co/datasets/sentence-transformers/quora-duplicates/viewer/pair-class>`_,其中包含问题对和标签:1表示重复,0表示不同。
正如我们的`损失概述 <../../../docs/sentence_transformer/loss_overview.md>`_所示,这使我们能够使用:class:~sentence_transformers.losses.ContrastiveLoss。标签为1的相似对被拉近,使它们在向量空间中接近,而距离小于定义的边界的不同对则在向量空间中被推远。
改进的版本是:class:~sentence_transformers.losses.OnlineContrastiveLoss。这种损失查看哪些负对距离小于最大正对的距离,以及哪些正对距离大于负对的最小距离。即,这种损失自动检测批次中的困难情况,并仅针对这些情况计算损失。
损失可以这样使用:
from datasets import load_dataset
train_dataset = load_dataset("sentence-transformers/quora-duplicates", "pair-class", split="train")
# => Dataset({
# features: ['sentence1', 'sentence2', 'label'],
# num_rows: 404290
# })
print(train_dataset[0])
# => {'sentence1': 'What is the step by step guide to invest in share market in india?', 'sentence2': 'What is the step by step guide to invest in share market?', 'label': 0}
train_loss = losses.OnlineContrastiveLoss(model=model, margin=0.5)
MultipleNegativesRankingLoss¶
完整的示例,请参见training_MultipleNegativesRankingLoss.py。
MultipleNegativesRankingLoss
特别适用于信息检索/语义搜索。一个优点是它只需要正对,即我们只需要重复问题的示例。有关损失如何工作的更多信息,请参见`NLI > MultipleNegativesRankingLoss <../nli/README.html#multiplenegativesrankingloss>`_。
使用损失很简单,不需要调整任何超参数:
from datasets import load_dataset
train_dataset = load_dataset("sentence-transformers/quora-duplicates", "pair", split="train")
# => Dataset({
# features: ['anchor', 'positive'],
# num_rows: 149263
# })
print(train_dataset[0])
# => {'anchor': 'Astrology: I am a Capricorn Sun Cap moon and cap rising...what does that say about me?', 'positive': "I'm a triple Capricorn (Sun, Moon and ascendant in Capricorn) What does this say about me?"}
train_loss = losses.MultipleNegativesRankingLoss(model)
由于'is_duplicate'是一个对称关系,我们不仅可以使用(锚点,正样本),还可以使用(正样本,锚点)到我们的训练样本集中:
from datasets import concatenate_datasets
train_dataset = concatenate_datasets([
train_dataset,
train_dataset.rename_columns({"anchor": "positive", "positive": "anchor"})
])
# Dataset({
# features: ['anchor', 'positive'],
# num_rows: 298526
# })
备注
通常增加批次大小会得到更好的结果,因为任务的难度增加了。从100个问题中识别出正确的问题副本比从10个问题中识别要难得多。因此,建议将训练批次大小设置得尽可能大。我在32 GB GPU内存上以350的批次大小进行了训练。
备注
:class:`~sentence_transformers.losses.MultipleNegativesRankingLoss`只有在 (a_i, b_j) 中 j != i 时,实际上是一个负样本,即非重复问题对时才能正常工作。在少数情况下,这个假设是错误的。但在大多数情况下,如果我们随机抽取两个问题,它们不是重复的。如果你的数据集不能满足这个特性,:class:`~sentence_transformers.losses.MultipleNegativesRankingLoss`可能效果不佳。
多任务学习¶
ContrastiveLoss
对于成对分类非常有效,即给定两对文本,它们是否是重复的。它将负样本对在向量空间中推远,从而使得区分重复与非重复对的效果良好。
MultipleNegativesRankingLoss
另一方面主要减少了从大量可能的候选中正样本对的距离。然而,非重复问题之间的距离并不那么大,因此这种损失函数在成对分类中效果不佳。
在 training_multi-task-learning.py 中,我展示了如何使用这两种损失函数来训练网络。关键代码是定义这两种损失,并将其传递给 fit 方法。
from datasets import load_dataset
from sentence_transformers.losses import ContrastiveLoss, MultipleNegativesRankingLoss
from sentence_transformers import SentenceTransformerTrainer, SentenceTransformer
model_name = "stsb-distilbert-base"
model = SentenceTransformer(model_name)
# https://huggingface.co/datasets/sentence-transformers/quora-duplicates
mnrl_dataset = load_dataset(
"sentence-transformers/quora-duplicates", "triplet", split="train"
) # The "pair" subset also works
mnrl_train_dataset = mnrl_dataset.select(range(100000))
mnrl_eval_dataset = mnrl_dataset.select(range(100000, 101000))
mnrl_train_loss = MultipleNegativesRankingLoss(model=model)
# https://huggingface.co/datasets/sentence-transformers/quora-duplicates
cl_dataset = load_dataset("sentence-transformers/quora-duplicates", "pair-class", split="train")
cl_train_dataset = cl_dataset.select(range(100000))
cl_eval_dataset = cl_dataset.select(range(100000, 101000))
cl_train_loss = ContrastiveLoss(model=model, margin=0.5)
# 创建训练器并开始训练
trainer = SentenceTransformerTrainer(
model=model,
train_dataset={
"mnrl": mnrl_train_dataset,
"cl": cl_train_dataset,
},
eval_dataset={
"mnrl": mnrl_eval_dataset,
"cl": cl_eval_dataset,
},
loss={
"mnrl": mnrl_train_loss,
"cl": cl_train_loss,
},
)
trainer.train()
预训练模型¶
目前,以下在Quora重复问题数据集上训练的模型可用:
distilbert-base-nli-stsb-quora-ranking: 我们扩展了distilbert-base-nli-stsb-mean-tokens模型,并在Quora重复问题数据集上使用OnlineContrastiveLoss和MultipleNegativesRankingLoss对其进行了训练。代码见training_multi-task-learning.py。
distilbert-multilingual-nli-stsb-quora-ranking: distilbert-base-nli-stsb-quora-ranking的多语言扩展。在50种语言的平行数据上进行了训练。
你可以像这样加载和使用预训练模型:
from sentence_transformers import SentenceTransformer
model = SentenceTransformer("distilbert-base-nli-stsb-quora-ranking")