说明文档
multi-qa-MiniLM-distill-onnx-L6-cos-v1
这是一个 sentence-transformers 模型:它将句子和段落映射到 384 维的稠密向量空间,专为语义搜索而设计。它在来自多种来源的 2.15 亿个(问题,答案)对上进行了训练。有关语义搜索的介绍,请参阅:SBERT.net - 语义搜索
使用方法(ONNX 运行时)
使用 optimum
from optimum.onnxruntime import ORTModelForFeatureExtraction
from transformers import AutoTokenizer
from transformers import Pipeline
import torch.nn.functional as F
import torch
# copied from the model card
def mean_pooling(model_output, attention_mask):
token_embeddings = model_output[0] #First element of model_output contains all token embeddings
input_mask_expanded = attention_mask.unsqueeze(-1).expand(token_embeddings.size()).float()
return torch.sum(token_embeddings * input_mask_expanded, 1) / torch.clamp(input_mask_expanded.sum(1), min=1e-9)
class SentenceEmbeddingPipeline(Pipeline):
def _sanitize_parameters(self, **kwargs):
# we don't have any hyperameters to sanitize
preprocess_kwargs = {}
return preprocess_kwargs, {}, {}
def preprocess(self, inputs):
encoded_inputs = self.tokenizer(inputs, padding=True, truncation=True, return_tensors='pt')
return encoded_inputs
def _forward(self, model_inputs):
outputs = self.model(**model_inputs)
return {"outputs": outputs, "attention_mask": model_inputs["attention_mask"]}
def postprocess(self, model_outputs):
# Perform pooling
sentence_embeddings = mean_pooling(model_outputs["outputs"], model_outputs['attention_mask'])
# Normalize embeddings
sentence_embeddings = F.normalize(sentence_embeddings, p=2, dim=1)
return sentence_embeddings
# load optimized model
model_name = "rawsh/multi-qa-MiniLM-distill-onnx-L6-cos-v1"
model = ORTModelForFeatureExtraction.from_pretrained(model_name, file_name="model_quantized.onnx")
# create optimized pipeline
tokenizer = AutoTokenizer.from_pretrained(model_name, use_fast=True)
optimized_emb = SentenceEmbeddingPipeline(model=model, tokenizer=tokenizer)
pred1 = optimized_emb("Hello world!")
pred2 = optimized_emb("I hate everything.")
print(pred1[0].dot(pred2[0]))
使用方法(Sentence-Transformers)
安装 sentence-transformers 后,使用此模型变得非常简单:
pip install -U sentence-transformers
然后你可以像这样使用该模型:
from sentence_transformers import SentenceTransformer, util
query = "How many people live in London?"
docs = ["Around 9 Million people live in London", "London is known for its financial district"]
#Load the model
model = SentenceTransformer('sentence-transformers/multi-qa-MiniLM-L6-cos-v1')
#Encode query and documents
query_emb = model.encode(query)
doc_emb = model.encode(docs)
#Compute dot score between query and all document embeddings
scores = util.dot_score(query_emb, doc_emb)[0].cpu().tolist()
#Combine docs & scores
doc_score_pairs = list(zip(docs, scores))
#Sort by decreasing score
doc_score_pairs = sorted(doc_score_pairs, key=lambda x: x[1], reverse=True)
#Output passages & scores
for doc, score in doc_score_pairs:
print(score, doc)
PyTorch 使用方法(HuggingFace Transformers)
如果不使用 sentence-transformers,你可以这样使用该模型:首先,将输入通过 transformer 模型,然后在上下文化的词嵌入之上应用正确的池化操作。
from transformers import AutoTokenizer, AutoModel
import torch
import torch.nn.functional as F
#Mean Pooling - Take average of all tokens
def mean_pooling(model_output, attention_mask):
token_embeddings = model_output.last_hidden_state
input_mask_expanded = attention_mask.unsqueeze(-1).expand(token_embeddings.size()).float()
return torch.sum(token_embeddings * input_mask_expanded, 1) / torch.clamp(input_mask_expanded.sum(1), min=1e-9)
#Encode text
def encode(texts):
# Tokenize sentences
encoded_input = tokenizer(texts, padding=True, truncation=True, return_tensors='pt')
# Compute token embeddings
with torch.no_grad():
model_output = model(**encoded_input, return_dict=True)
# Perform pooling
embeddings = mean_pooling(model_output, encoded_input['attention_mask'])
# Normalize embeddings
embeddings = F.normalize(embeddings, p=2, dim=1)
return embeddings
# Sentences we want sentence embeddings for
query = "How many people live in London?"
docs = ["Around 9 Million people live in London", "London is known for its financial district"]
# Load model from HuggingFace Hub
tokenizer = AutoTokenizer.from_pretrained("sentence-transformers/multi-qa-MiniLM-L6-cos-v1")
model = AutoModel.from_pretrained("sentence-transformers/multi-qa-MiniLM-L6-cos-v1")
#Encode query and docs
query_emb = encode(query)
doc_emb = encode(docs)
#Compute dot score between query and all document embeddings
scores = torch.mm(query_emb, doc_emb.transpose(0, 1))[0].cpu().tolist()
#Combine docs & scores
doc_score_pairs = list(zip(docs, scores))
#Sort by decreasing score
doc_score_pairs = sorted(doc_score_pairs, key=lambda x: x[1], reverse=True)
#Output passages & scores
for doc, score in doc_score_pairs:
print(score, doc)
TensorFlow 使用方法(HuggingFace Transformers)
与上面的 PyTorch 示例类似,要在 TensorFlow 中使用该模型,你需要将输入通过 transformer 模型,然后在上下文化的词嵌入之上应用正确的池化操作。
from transformers import AutoTokenizer, TFAutoModel
import tensorflow as tf
#Mean Pooling - Take attention mask into account for correct averaging
def mean_pooling(model_output, attention_mask):
token_embeddings = model_output.last_hidden_state
input_mask_expanded = tf.cast(tf.tile(tf.expand_dims(attention_mask, -1), [1, 1, token_embeddings.shape[-1]]), tf.float32)
return tf.math.reduce_sum(token_embeddings * input_mask_expanded, 1) / tf.math.maximum(tf.math.reduce_sum(input_mask_expanded, 1), 1e-9)
#Encode text
def encode(texts):
# Tokenize sentences
encoded_input = tokenizer(texts, padding=True, truncation=True, return_tensors='tf')
# Compute token embeddings
model_output = model(**encoded_input, return_dict=True)
# Perform pooling
embeddings = mean_pooling(model_output, encoded_input['attention_mask'])
# Normalize embeddings
embeddings = tf.math.l2_normalize(embeddings, axis=1)
return embeddings
# Sentences we want sentence embeddings for
query = "How many people live in London?"
docs = ["Around 9 Million people live in London", "London is known for its financial district"]
# Load model from HuggingFace Hub
tokenizer = AutoTokenizer.from_pretrained("sentence-transformers/multi-qa-MiniLM-L6-cos-v1")
model = TFAutoModel.from_pretrained("sentence-transformers/multi-qa-MiniLM-L6-cos-v1")
#Encode query and docs
query_emb = encode(query)
doc_emb = encode(docs)
#Compute dot score between query and all document embeddings
scores = (query_emb @ tf.transpose(doc_emb))[0].numpy().tolist()
#Combine docs & scores
doc_score_pairs = list(zip(docs, scores))
#Sort by decreasing score
doc_score_pairs = sorted(doc_score_pairs, key=lambda x: x[1], reverse=True)
#Output passages & scores
for doc, score in doc_score_pairs:
print(score, doc)
技术细节
以下是关于如何使用此模型的一些技术细节:
| 设置 | 值 |
|---|---|
| 维度 | 384 |
| 生成归一化嵌入 | 是 |
| 池化方法 | 平均池化 |
| 适用的评分函数 | 点积(util.dot_score)、余弦相似度(util.cos_sim)或欧氏距离 |
注意:当使用 sentence-transformers 加载时,此模型会生成长度为 1 的归一化嵌入。在这种情况下,点积和余弦相似度是等效的。点积更推荐使用,因为它速度更快。欧氏距离与点积成比例,也可以使用。
背景
该项目旨在使用自监督对比学习目标在超大规模句子级数据集上训练句子嵌入模型。我们使用对比学习目标:给定一对句子中的一个句子,模型应该预测出在我们数据集中与其实际配对的句子是哪一句(从一组随机采样的其他句子中)。
我们在 Hugging Face 组织的 使用 JAX/Flax 进行 NLP 和 CV 的社区周 期间开发了此模型。我们作为以下项目的一部分开发了此模型:使用 10 亿训练对训练史上最佳句子嵌入模型。我们受益于高效的硬件基础设施来运行该项目:7 个 TPU v3-8,以及 Google Flax、JAX 和 Cloud 团队成员关于高效深度学习框架的指导。
预期用途
我们的模型旨在用于语义搜索:它将查询/问题和文本段落编码到稠密向量空间中。它为给定的段落找到相关文档。
请注意,输入长度限制为 512 个词元:超过此长度的文本将被截断。另请注意,该模型仅在最长 250 个词元的输入文本上进行训练。对于更长的文本,效果可能不佳。
训练过程
完整的训练脚本可在此当前仓库中访问:train_script.py。
预训练
我们使用预训练的 nreimers/MiniLM-L6-H384-uncased 模型。有关预训练过程的更多详细信息,请参阅模型卡片。
训练
我们使用多个数据集的拼接来微调我们的模型。总共有约 2.15 亿个(问题,答案)对。
我们根据加权概率对每个数据集进行采样,具体配置详见 data_config.json 文件。
该模型使用 MultipleNegativesRankingLoss 进行训练,采用平均池化、余弦相似度作为相似度函数,缩放因子为 20。
| 数据集 | 训练元组数量 |
|---|---|
| WikiAnswers 来自 WikiAnswers 的重复问题对 | 77,427,422 |
| PAQ 为维基百科中每个段落自动生成的(问题,段落)对 | 64,371,441 |
| Stack Exchange 来自所有 StackExchange 的(标题,正文)对 | 25,316,456 |
| Stack Exchange 来自所有 StackExchange 的(标题,回答)对 | 21,396,559 |
| MS MARCO 来自必应搜索引擎的 50 万个查询的三元组(查询,回答,困难负例) | 17,579,773 |
| GOOAQ: Open Question Answering with Diverse Answer Types 300 万个 Google 查询和 Google 精选摘要的(查询,回答)对 | 3,012,496 |
| Amazon-QA 来自亚马逊产品页面的(问题,回答)对 | 2,448,839 |
| Yahoo Answers 来自 Yahoo Answers 的(标题,回答)对 | 1,198,260 |
| Yahoo Answers 来自 Yahoo Answers 的(问题,回答)对 | 681,164 |
| Yahoo Answers 来自 Yahoo Answers 的(标题,问题)对 | 659,896 |
| SearchQA 14 万个问题的(问题,回答)对,每个问题包含该问题的 Top5 Google 摘要 | 582,261 |
| ELI5 来自 Reddit ELI5(explainlikeimfive)的(问题,回答)对 | 325,475 |
| Stack Exchange 重复问题对(标题) | 304,525 |
| Quora Question Triplets Quora 问题对数据集的(问题,重复问题,困难负例)三元组 | 103,663 |
| Natural Questions (NQ) 10 万个真实 Google 查询及相关维基百科段落的(问题,段落)对 | 100,231 |
| SQuAD2.0 来自 SQuAD2.0 数据集的(问题,段落)对 | 87,599 |
| TriviaQA(问题,证据)对 | 73,346 |
| 总计 | 214,988,242 |
rawsh/multi-qa-MiniLM-distill-onnx-L6-cos-v1
作者 rawsh
创建时间: 2023-06-06 05:52:24+00:00
更新时间: 2023-06-06 10:13:26+00:00
在 Hugging Face 上查看