文章目录
一、关于 Model2Vec
Model2Vec是一种将任何句子转换成非常小的静态模型的技术,将模型大小减少15倍,使模型速度提高500倍,性能略有下降。我们的最佳模型是世界上性能最好的静态嵌入模型。在这里查看我们的结果,或者深入了解它是如何工作的。
更新和公告
- 30/01/2024:我们发布了两个新模型:药水-基础-32M和potion-retrieval-32M。药水-基础-32M是我们迄今为止性能最好的模型,使用了更大的词汇量和更高的维度。potion-retrieval-32M是针对检索任务优化的药水-基础-32M的微调,是目前可用的性能最好的静态检索模型。
- 30/10/2024:我们发布了三个新模型:药水-基底-8M、药水-基底-4M和药水-基底-2M。这些模型使用Tokenlearn进行训练。在我们的博客文章中了解更多信息。注意:对于我们任何旧英语M2V模型的用户,我们建议切换到这些新模型,因为它们在所有任务上表现更好。
二、快速入门
安装
使用以下方式安装软件包:
pip install model2vec
这将安装基本推理包,它只依赖于numpy
和其他一些次要依赖项。如果您想提取自己的模型,您可以使用以下方式安装蒸馏附加组件:
pip install model2vec[distill]
简单调用
开始使用Model2Vec的最简单方法是从HuggingFace Hub 中加载我们的一个旗舰模型。这些模型经过预训练并可以使用。以下代码片段展示了如何加载模型并进行嵌入:
from model2vec import StaticModel
# Load a model from the HuggingFace hub (in this case the potion-base-8M model)
model = StaticModel.from_pretrained("minishlab/potion-base-8M")
# Make embeddings
embeddings = model.encode(["It's dangerous to go alone!", "It's a secret to everybody."])
# Make sequences of token embeddings
token_embeddings = model.encode_as_sequence(["It's dangerous to go alone!", "It's a secret to everybody."])
就是这样。您可以使用该模型对文本进行分类、聚类或构建RAG系统。
除了使用我们的模型之一,您还可以从 Sentence Transformer 模型中提取您自己的Model2Vec模型。以下代码片段展示了如何提取模型:
from model2vec.distill import distill
# Distill a Sentence Transformer model, in this case the BAAI/bge-base-en-v1.5 model
m2v_model = distill(model_name="BAAI/bge-base-en-v1.5", pca_dims=256)
# Save the model
m2v_model.save_pretrained("m2v_model")
蒸馏非常快,在中央处理器上只需要30秒。最重要的是,蒸馏不需要训练数据。
有关高级用法,例如在句子Transformers 库中使用Model2Vec,请参阅用法部分。
主要特点
- 最先进的性能:Model2Vec模型的性能大大优于任何其他静态嵌入(如GLoVe和BPEmb),如我们的结果所示。
- 小型:Model2Vec将 Sentence Transformer 模型的大小减少了15倍,从120M参数减少到7.5M(磁盘上30 MB,使其成为MTEB上最小的模型!)。
- 轻量级依赖项:基本包的唯一主要依赖项是
numpy
。 - 闪电般的推断:CPU速度比原始型号快500倍。去绿色或回家。
- 快速、无数据集的蒸馏:在CPU上在30秒内提取您自己的模型,无需数据集。您只需要一个模型和(可选)一个自定义词汇表。
- 集成在许多流行的库中:Model2Vec可以直接在流行的库中使用,如SentenceTransformers 、LangChain、txta和Chonkie。有关更多信息,请参阅集成部分。
- 与HuggingFace集线器紧密集成:使用熟悉的
from_pretrained
和push_to_hub
从HuggingFace集线器轻松共享和加载模型。我们自己的模型可以在这里找到。请随时分享您自己的。
什么是Model2Vec?
Model2vec创建了一个小型、快速、强大的模型,在我们能找到的所有任务上远远优于其他静态嵌入模型,同时创建速度比传统的静态嵌入模型(如GloVe)快得多。像BPEmb一样,它可以创建子词嵌入,但性能要好得多。蒸馏不需要任何数据,只需要一个词汇和一个模型。
基本模型2vec技术的工作原理是通过 Sentence Transformer 模型传递词汇,然后使用PCA降低生成嵌入的维数,最后使用zipf加权对嵌入进行加权。在推理过程中,我们只需取句子中出现的所有标记嵌入的平均值。
我们的药水模型使用Tokenlearn进行预训练,这是一种预训练Model2vec蒸馏模型的技术。
- 蒸馏:我们使用上述方法从 Sentence Transformer 模型中提取Model2Vec模型。
- Sentence Transformer 推断:我们使用 Sentence Transformer 模型为语料库中的大量文本创建均值嵌入。
- 训练:我们训练一个模型以最小化句子变换模型生成的平均嵌入与Model2Vec模型生成的平均嵌入之间的余弦距离。
- 训练后再正则化:我们通过首先执行PCA来重新正则化训练好的嵌入,然后使用以下公式使用
smooth inverse frequency (SIF)
加权嵌入:w = 1e-3 / (1e-3 + proba)
。在这里,proba
是我们用于训练的语料库中令牌的概率。
有关更广泛的深入了解,请参阅我们的Model2Vec博客文章和我们的Tokenlearn博客文章。
三、用法
推理
使用预训练模型推理
推理工作如下。该示例显示了我们自己的模型之一,但您也可以只加载本地模型,或者从集线器加载另一个。
from model2vec import StaticModel
# Load a model from the Hub. You can optionally pass a token when loading a private model
model = StaticModel.from_pretrained(model_name="minishlab/potion-base-8M", token=None)
# Make embeddings
embeddings = model.encode(["It's dangerous to go alone!", "It's a secret to everybody."])
# Make sequences of token embeddings
token_embeddings = model.encode_as_sequence(["It's dangerous to go alone!", "It's a secret to everybody."])
使用 Sentence Transformer 库进行推理
下面的代码片段展示了如何在 Sentence Transformer 库中使用Model2Vec模型。如果您想在 Sentence Transformer 管道中使用该模型,这很有用。
from sentence_transformers import SentenceTransformer
from sentence_transformers.models import StaticEmbedding
# Initialize a StaticEmbedding module
static_embedding = StaticEmbedding.from_model2vec("minishlab/potion-base-8M")
model = SentenceTransformer(modules=[static_embedding])
embeddings = model.encode(["It's dangerous to go alone!", "It's a secret to everybody."])
蒸馏
从 Sentence Transformer 蒸馏
以下代码可用于从 Sentence Transformer 中提取模型。如上所述,这会导致性能可能较差的非常小的模型。
from model2vec.distill import distill
# Distill a Sentence Transformer model
m2v_model = distill(model_name="BAAI/bge-base-en-v1.5", pca_dims=256)
# Save the model
m2v_model.save_pretrained("m2v_model")
从加载的模型中蒸馏
如果您已经加载了模型,或者需要以某种特殊方式加载模型,我们还提供了一个接口来提取内存中的模型。
from transformers import AutoModel, AutoTokenizer
from model2vec.distill import distill_from_model
# Assuming a loaded model and tokenizer
model_name = "baai/bge-base-en-v1.5"
model = AutoModel.from_pretrained(model_name)
tokenizer = AutoTokenizer.from_pretrained(model_name)
m2v_model = distill_from_model(model=model, tokenizer=tokenizer, pca_dims=256)
m2v_model.save_pretrained("m2v_model")
使用 Sentence Transformers 库蒸馏
下面的代码片段展示了如何使用 Sentence Transformer 库提取模型。如果您想在 Sentence Transformer 管道中使用模型,这很有用。
from sentence_transformers import SentenceTransformer
from sentence_transformers.models import StaticEmbedding
static_embedding = StaticEmbedding.from_distillation("BAAI/bge-base-en-v1.5", device="cpu", pca_dims=256)
model = SentenceTransformer(modules=[static_embedding])
embeddings = model.encode(["It's dangerous to go alone!", "It's a secret to everybody."])
用自定义词汇蒸馏
如果您传递一个词汇表,您将获得一组静态词嵌入,以及该词汇表的自定义标记器。这与您使用GLoVe或传统word2vec的方式相当,但实际上不需要语料库或数据。
from model2vec.distill import distill
# Load a vocabulary as a list of strings
vocabulary = ["word1", "word2", "word3"]
# Distill a Sentence Transformer model with the custom vocabulary
m2v_model = distill(model_name="BAAI/bge-base-en-v1.5", vocabulary=vocabulary)
# Save the model
m2v_model.save_pretrained("m2v_model")
# Or push it to the hub
m2v_model.push_to_hub("my_organization/my_model", token="<it's a secret to everybody>")
默认情况下,这将提取带有子单词标记器的模型,将模型(子单词)词汇与新词汇表相结合。如果您想获取单词级标记器(仅使用传递的词汇表),可以将use_subword
参数设置为False
,例如:
m2v_model = distill(model_name=model_name, vocabulary=vocabulary, use_subword=False)
**重要提示:**我们假设传递的词汇按等级频率排序。也就是说,我们不关心实际的单词频率,但是假设最频繁的单词是第一个,最不频繁的单词是最后一个。如果你不确定这是否是案例,将apply_zipf
设置为False
。这会禁用权重,但也会使性能稍微差一点。
四、评估
安装
我们的模型可以使用我们的评估包进行评估。
pip install git+https://github.com/MinishLab/evaluation.git@main
评估代码
以下代码片段显示了如何评估Model2Vec模型:
from model2vec import StaticModel
from evaluation import CustomMTEB, get_tasks, parse_mteb_results, make_leaderboard, summarize_results
from mteb import ModelMeta
# Get all available tasks
tasks = get_tasks()
# Define the CustomMTEB object with the specified tasks
evaluation = CustomMTEB(tasks=tasks)
# Load the model
model_name = "m2v_model"
model = StaticModel.from_pretrained(model_name)
# Optionally, add model metadata in MTEB format
model.mteb_model_meta = ModelMeta(
name=model_name, revision="no_revision_available", release_date=None, languages=None
)
# Run the evaluation
results = evaluation.run(model, eval_splits=["test"], output_folder=f"results")
# Parse the results and summarize them
parsed_results = parse_mteb_results(mteb_results=results, model_name=model_name)
task_scores = summarize_results(parsed_results)
# Print the results in a leaderboard format
print(make_leaderboard(task_scores))
五、集成
Sentence Transformers
Model2Vec可以使用StaticEmbedding
模块直接在 Sentence Transformer 中使用。
以下代码片段显示了如何将Model2Vec模型加载到 Sentence Transformer 模型中:
from sentence_transformers import SentenceTransformer
from sentence_transformers.models import StaticEmbedding
# Initialize a StaticEmbedding module
static_embedding = StaticEmbedding.from_model2vec("minishlab/potion-base-8M")
model = SentenceTransformer(modules=[static_embedding])
embeddings = model.encode(["It's dangerous to go alone!", "It's a secret to everybody."])
以下代码片段展示了如何将模型直接提取为 Sentence Transformer 模型:
from sentence_transformers import SentenceTransformer
from sentence_transformers.models import StaticEmbedding
static_embedding = StaticEmbedding.from_distillation("BAAI/bge-base-en-v1.5", device="cpu", pca_dims=256)
model = SentenceTransformer(modules=[static_embedding])
embeddings = model.encode(["It's dangerous to go alone!", "It's a secret to everybody."])
更多文档请参考句子Transformers 文档。
LangChain
Model2Vec可以在朗链中使用langchain-community
包。有关详细信息,请参阅朗链Model2Vec文档。以下代码片段显示了如何在使用pip install langchain-社区安装langchain-community
包后在pip install langchain-community
:
from langchain_community.embeddings import Model2vecEmbeddings
from langchain_community.vectorstores import FAISS
from langchain.schema import Document
# Initialize a Model2Vec embedder
embedder = Model2vecEmbeddings("minishlab/potion-base-8M")
# Create some example texts
texts = [
"Enduring Stew",
"Hearty Elixir",
"Mighty Mushroom Risotto",
"Spicy Meat Skewer",
"Fruit Salad",
]
# Embed the texts
embeddings = embedder.embed_documents(texts)
# Or, create a vector store and query it
documents = [Document(page_content=text) for text in texts]
vector_store = FAISS.from_documents(documents, embedder)
query = "Risotto"
query_vector = embedder.embed_query(query)
retrieved_docs = vector_store.similarity_search_by_vector(query_vector, k=1)
Txtai
Model2Vec可以在txtai中用于文本嵌入、最近邻搜索以及txta提供的任何其他功能。以下代码片段展示了如何在安装txtai
软件包(包括vectors
依赖项)后在pip install txtai[vectors]
中使用Model2Vec:
from txtai import Embeddings
# Load a model2vec model
embeddings = Embeddings(path="minishlab/potion-base-8M", method="model2vec", backend="numpy")
# Create some example texts
texts = ["Enduring Stew", "Hearty Elixir", "Mighty Mushroom Risotto", "Spicy Meat Skewer", "Chilly Fruit Salad"]
# Create embeddings for downstream tasks
vectors = embeddings.batchtransform(texts)
# Or create a nearest-neighbors index and search it
embeddings.index(texts)
result = embeddings.search("Risotto", 1)
Chonkie
Model2Vec是Chonkie中语义分块的默认模型。要在Chonkie中使用Model2Vec进行语义分块,只需使用pip install chonkie[semantic]
安装Chonkie,然后使用SemanticChunker
类中的potion
模型之一。以下代码片段展示了如何在Chonkie中使用Model2Vec:
from chonkie import SDPMChunker
# Create some example text to chunk
text = "It's dangerous to go alone! Take this."
# Initialize the SemanticChunker with a potion model
chunker = SDPMChunker(
embedding_model="minishlab/potion-base-8M",
similarity_threshold=0.3
)
# Chunk the text
chunks = chunker.chunk(text)
Transformers.js
要在transformers. js中使用Model2Vec模型,可以使用以下代码片段作为起点:
import { AutoModel, AutoTokenizer, Tensor } from '@huggingface/transformers';
const modelName = 'minishlab/potion-base-8M';
const modelConfig = {
config: { model_type: 'model2vec' },
dtype: 'fp32',
revision: 'refs/pr/1'
};
const tokenizerConfig = {
revision: 'refs/pr/2'
};
const model = await AutoModel.from_pretrained(modelName, modelConfig);
const tokenizer = await AutoTokenizer.from_pretrained(modelName, tokenizerConfig);
const texts = ['hello', 'hello world'];
const { input_ids } = await tokenizer(texts, { add_special_tokens: false, return_tensor: false });
const cumsum = arr => arr.reduce((acc, num, i) => [...acc, num + (acc[i - 1] || 0)], []);
const offsets = [0, ...cumsum(input_ids.slice(0, -1).map(x => x.length))];
const flattened_input_ids = input_ids.flat();
const modelInputs = {
input_ids: new Tensor('int64', flattened_input_ids, [flattened_input_ids.length]),
offsets: new Tensor('int64', offsets, [offsets.length])
};
const { embeddings } = await model(modelInputs);
console.log(embeddings.tolist()); // output matches python version
请注意,这要求Model2Vec有一个model.onnx
文件和几个必需的标记器文件。要为还没有它们的模型生成这些,可以使用以下代码片段:
python scripts/export_to_onnx.py --model_path <path-to-a-model2vec-model> --save_path "<path-to-save-the-onnx-model>"
六、模型列表
我们提供了许多可以开箱即用的模型,这些模型在HuggingFace集线器上提供,可以使用from_pretrained
方法加载,模型如下所列。
Model | Language | Vocab | Sentence Transformer | Tokenizer Type | Params | Tokenlearn |
---|---|---|---|---|---|---|
potion-base-32M | English | Output + Frequent C4 tokens | bge-base-en-v1.5 | Subword | 32.3M | ✅ |
potion-base-8M | English | Output | bge-base-en-v1.5 | Subword | 7.5M | ✅ |
potion-base-4M | English | Output | bge-base-en-v1.5 | Subword | 3.7M | ✅ |
potion-base-2M | English | Output | bge-base-en-v1.5 | Subword | 1.8M | ✅ |
potion-retrieval-32M | English | Output + Frequent C4 tokens | bge-base-en-v1.5 | Subword | 32.3M | ✅ |
M2V_multilingual_output | Multilingual | Output | LaBSE | Subword | 471M | ❌ |
七、结果
我们进行了广泛的实验来评估Model2Vec模型的性能。结果记录在结果文件夹中。结果在以下部分中呈现:
2025-02-03(一)