模型简介
模型特点
模型能力
使用案例
🚀 USER-base
USER-base(面向俄语的通用句子编码器,Universal Sentence Encoder for Russian)是一个基于 sentence-transformer 的模型,专门用于提取俄语句子的嵌入向量。它能将句子和段落映射到一个 768 维的密集向量空间,可用于聚类或语义搜索等任务。该模型基于 deepvk/deberta-v1-base
进行初始化,并针对俄语进行了专门训练,未对其在其他语言上的性能进行评估。
🚀 快速开始
使用该模型,你需要安装 sentence-transformers
:
pip install -U sentence-transformers
然后,你可以按以下方式使用该模型:
from sentence_transformers import SentenceTransformer
queries = [
"Когда был спущен на воду первый миноносец «Спокойный»?",
"Есть ли нефть в Удмуртии?"
]
passages = [
"Спокойный (эсминец)\nЗачислен в списки ВМФ СССР 19 августа 1952 года.",
"Нефтепоисковые работы в Удмуртии были начаты сразу после Второй мировой войны в 1945 году и продолжаются по сей день. Добыча нефти началась в 1967 году."
]
model = SentenceTransformer("deepvk/USER-base")
# Prompt should be specified according to the task (either 'query' or 'passage').
passage_embeddings = model.encode(passages, normalize_embeddings=True, prompt_name='passage')
# For tasks other than retrieval, you can simply use the `query` prompt, which is set by default.
query_embeddings = model.encode(queries, normalize_embeddings=True)
不过,你也可以直接使用 transformers
调用该模型:
import torch.nn.functional as F
from torch import Tensor, inference_mode
from transformers import AutoTokenizer, AutoModel
def average_pool(
last_hidden_states: Tensor,
attention_mask: Tensor
) -> Tensor:
last_hidden = last_hidden_states.masked_fill(
~attention_mask[..., None].bool(), 0.0
)
return last_hidden.sum(dim=1) / attention_mask.sum(dim=1)[..., None]
# You should manually add prompts when using the model directly. Each input text should start with "query: " or "passage: ".
# For tasks other than retrieval, you can simply use the "query: " prefix.
input_texts = [
"query: Когда был спущен на воду первый миноносец «Спокойный»?",
"query: Есть ли нефть в Удмуртии?",
"passage: Спокойный (эсминец)\nЗачислен в списки ВМФ СССР 19 августа 1952 года.",
"passage: Нефтепоисковые работы в Удмуртии были начаты сразу после Второй мировой войны в 1945 году и продолжаются по сей день. Добыча нефти началась в 1967 году."
]
tokenizer = AutoTokenizer.from_pretrained("deepvk/USER-base")
model = AutoModel.from_pretrained("deepvk/USER-base")
batch_dict = tokenizer(
input_texts, padding=True, truncation=True, return_tensors="pt"
)
with inference_mode():
outputs = model(**batch_dict)
embeddings = average_pool(
outputs.last_hidden_state, batch_dict["attention_mask"]
)
embeddings = F.normalize(embeddings, p=2, dim=1)
# Scores for query-passage
scores = (embeddings[:2] @ embeddings[2:].T) * 100
# [[55.86, 30.95],
# [22.82, 59.46]]
print(scores.round(decimals=2))
⚠️ 重要提示
每个输入文本都应以 "query: " 或 "passage: " 开头。对于检索以外的任务,你可以直接使用 "query: " 前缀。
✨ 主要特性
- 专门为俄语设计,能有效提取俄语句子的嵌入向量。
- 将句子和段落映射到 768 维的密集向量空间,适用于聚类和语义搜索等任务。
📦 安装指南
使用该模型,你需要安装 sentence-transformers
:
pip install -U sentence-transformers
💻 使用示例
基础用法
from sentence_transformers import SentenceTransformer
queries = [
"Когда был спущен на воду первый миноносец «Спокойный»?",
"Есть ли нефть в Удмуртии?"
]
passages = [
"Спокойный (эсминец)\nЗачислен в списки ВМФ СССР 19 августа 1952 года.",
"Нефтепоисковые работы в Удмуртии были начаты сразу после Второй мировой войны в 1945 году и продолжаются по сей день. Добыча нефти началась в 1967 году."
]
model = SentenceTransformer("deepvk/USER-base")
# Prompt should be specified according to the task (either 'query' or 'passage').
passage_embeddings = model.encode(passages, normalize_embeddings=True, prompt_name='passage')
# For tasks other than retrieval, you can simply use the `query` prompt, which is set by default.
query_embeddings = model.encode(queries, normalize_embeddings=True)
高级用法
import torch.nn.functional as F
from torch import Tensor, inference_mode
from transformers import AutoTokenizer, AutoModel
def average_pool(
last_hidden_states: Tensor,
attention_mask: Tensor
) -> Tensor:
last_hidden = last_hidden_states.masked_fill(
~attention_mask[..., None].bool(), 0.0
)
return last_hidden.sum(dim=1) / attention_mask.sum(dim=1)[..., None]
# You should manually add prompts when using the model directly. Each input text should start with "query: " or "passage: ".
# For tasks other than retrieval, you can simply use the "query: " prefix.
input_texts = [
"query: Когда был спущен на воду первый миноносец «Спокойный»?",
"query: Есть ли нефть в Удмуртии?",
"passage: Спокойный (эсминец)\nЗачислен в списки ВМФ СССР 19 августа 1952 года.",
"passage: Нефтепоисковые работы в Удмуртии были начаты сразу после Второй мировой войны в 1945 году и продолжаются по сей день. Добыча нефти началась в 1967 году."
]
tokenizer = AutoTokenizer.from_pretrained("deepvk/USER-base")
model = AutoModel.from_pretrained("deepvk/USER-base")
batch_dict = tokenizer(
input_texts, padding=True, truncation=True, return_tensors="pt"
)
with inference_mode():
outputs = model(**batch_dict)
embeddings = average_pool(
outputs.last_hidden_state, batch_dict["attention_mask"]
)
embeddings = F.normalize(embeddings, p=2, dim=1)
# Scores for query-passage
scores = (embeddings[:2] @ embeddings[2:].T) * 100
# [[55.86, 30.95],
# [22.82, 59.46]]
print(scores.round(decimals=2))
🔧 技术细节
训练详情
模型训练旨在遵循 bge-base-en
的训练算法,并在此基础上进行了改进:
- 初始化:基于
deepvk/deberta-v1-base
进行初始化。 - 第一阶段:在 mMarco 语料库 的俄语部分上进行弱监督对比预训练。
- 第二阶段:基于数据对称性对两个不同的模型进行有监督微调,然后通过
LM-Cocktail
进行合并:- 修改指令设计,简化多语言方法,以便更轻松地进行推理。对于对称数据
(S1, S2)
,使用指令"query: S1"
和"query: S2"
;对于非对称数据,使用"query: S1"
和"passage: S2"
。 - 由于对数据进行了分割,可以额外对对称模型应用 AnglE 损失,以提高对称任务的性能。
- 最后,将两个模型合并,使用
LM-Cocktail
调整合并权重,生成最终模型 USER。
- 修改指令设计,简化多语言方法,以便更轻松地进行推理。对于对称数据
数据集
在模型开发过程中,额外收集了两个数据集:deepvk/ru-HNP
和 deepvk/ru-WANLI
。
对称数据集 | 规模 | 非对称数据集 | 规模 |
---|---|---|---|
AllNLI | 282 644 | MIRACL | 10 000 |
MedNLI | 3 699 | MLDR | 1 864 |
RCB | 392 | Lenta | 185 972 |
Terra | 1 359 | Mlsum | 51 112 |
Tapaco | 91 240 | Mr-TyDi | 536 600 |
Opus100 | 1 000 000 | Panorama | 11 024 |
BiblePar | 62 195 | PravoIsrael | 26 364 |
RudetoxifierDataDetox | 31 407 | Xlsum | 124 486 |
RuParadetox | 11 090 | Fialka-v1 | 130 000 |
deepvk/ru-WANLI | 35 455 | RussianKeywords | 16 461 |
deepvk/ru-HNP | 500 000 | Gazeta | 121 928 |
Gsm8k-ru | 7 470 | ||
DSumRu | 27 191 | ||
SummDialogNews | 75 700 |
总正样本对:3,352,653
总负样本对:792,644(来自 AIINLI、MIRACL、deepvk/ru-WANLI、deepvk/ru-HNP 的负样本对)
对于所有有标签的数据集,仅使用其训练集进行微调。对于 Gazeta、Mlsum、Xlsum 数据集,将 (标题/文本) 和 (标题/摘要) 对组合起来,用作非对称数据。
AllNLI
是 SNLI、MNLI 和 ANLI 的俄语翻译组合。
实验
- 基准选择:选择
encodechka
排行榜上的当前顶级模型作为基线。此外,在MTEB
的俄语子集上对模型进行评估,该子集包含 10 个任务。由于计算资源过多,无法在某些 MTEB 任务(特别是聚类任务)上验证 bge-m3。除了这两个基准外,还在MIRACL
上对模型进行了评估。 - 实验环境:所有实验均使用 NVIDIA TESLA A100 40 GB GPU 进行。使用每个任务官方仓库中的验证脚本。
模型 | 大小(不含嵌入) | Encodechka (平均得分) | MTEB (俄语平均得分) | Miracl (Recall@100) |
---|---|---|---|---|
bge-m3 |
303 | 0.786 | 0.694 | 0.959 |
multilingual-e5-large |
303 | 0.78 | 0.665 | 0.927 |
USER (本模型) |
85 | 0.772 | 0.666 | 0.763 |
paraphrase-multilingual-mpnet-base-v2 |
85 | 0.76 | 0.625 | 0.149 |
multilingual-e5-base |
85 | 0.756 | 0.645 | 0.915 |
LaBSE-en-ru |
85 | 0.74 | 0.599 | 0.327 |
sn-xlm-roberta-base-snli-mnli-anli-xnli |
85 | 0.74 | 0.593 | 0.08 |
模型大小已列出,较大的模型在视觉上与其他模型有所区别。指标中的绝对领先者用粗体突出显示,同规模模型中的领先者用下划线标注。
本模型在 Encodechka 和 MTEB 上均优于所有其他同规模模型。鉴于该模型在检索任务上相对于现有解决方案略有不足,未来研究将致力于解决这一问题。
📚 详细文档
常见问题解答
是否需要在输入文本中添加 "query: " 和 "passage: " 前缀? 是的,模型是按此方式进行训练的,否则会出现性能下降。以下是一些经验法则:
- 对于非对称任务(如开放问答中的段落检索、临时信息检索),相应地使用
"query: "
和"passage: "
。 - 对于对称任务(如语义相似度、双语挖掘、释义检索),使用
"query: "
前缀。 - 如果你想将嵌入向量用作特征(如线性探测分类、聚类),使用
"query: "
前缀。
引用
@misc{deepvk2024user,
title={USER: Universal Sentence Encoder for Russian},
author={Malashenko, Boris and Zemerov, Anton and Spirin, Egor},
url={https://huggingface.co/datasets/deepvk/USER-base},
publisher={Hugging Face}
year={2024},
}
📄 许可证
本项目采用 Apache-2.0 许可证。







