首页
/ 深入理解 Transformers 中的 JinaEmbeddingsV3:基于 XLM-RoBERTa 的多语言多任务文本嵌入模型

深入理解 Transformers 中的 JinaEmbeddingsV3:基于 XLM-RoBERTa 的多语言多任务文本嵌入模型

2026-09-07 21:29:56作者:房伟宁

Jina-Embeddings-v3 是一个面向检索、分类、聚类、文本相似度等多种 NLP 场景的多语言文本嵌入模型。它在 🤗 Transformers 仓库中由 JinaEmbeddingsV3 系列类实现(模型发布论文日期为 2024-09-16,贡献进 Transformers 的时间为 2026-03-19),其架构以 XLM-RoBERTa 为基础,用旋转位置编码(RoPE)替换绝对位置编码以支持最长 8192 token 的输入,并内置 5 个任务专用 LoRA Adapter。读完本文,你将掌握通过 PipelineAutoModel 提取嵌入的两种标准做法,理解 5 类任务 Adapter 的适用场景与加载切换方法,并能结合源码弄清其注意力实现、位置编码细节与各 Head 类的职责。

模型核心特性一览

从官方模型文档可知,JinaEmbeddingsV3 的核心技术特点集中在三点:

  1. 多语言、多任务:单个模型同时服务检索、分类、聚类、相似度计算等多种下游任务,用于推断与训练均适用;
  2. 基于 XLM-RoBERTa 架构:词表与骨干网络继承自 XLM-RoBERTa;
  3. RoPE + 长序列:以旋转位置编码(Rotary Position Embeddings)替代绝对位置嵌入,从而把输入长度扩展至 8192 tokens
  4. 5 个内置 Task-Specific LoRA Adapter:在不显著增加推理延迟的前提下,按任务切换得到专用的文本嵌入。

这些能力都可以在 JinaEmbeddingsV3 模型文档 中找到依据;模型权重归档在 jinaai 组织下,Transformers 官方推荐使用的 Hub 检查点为 jinaai/jina-embeddings-v3-hf

架构设计:从源码理解它是“如何长成这样”的

JinaEmbeddingsV3 的实现位于 src/transformers/models/jina_embeddings_v3/ 目录,其中包含了配置、模型定义与“模块化源文件”(modular):

从 modular 源码的 import 语句可以看出它的“血统”——它复用了多个现有模型的构件:

构件 来源 在本模型中的角色
XLMRobertaConfig / XLMRobertaPreTrainedModel XLM-RoBERTa 骨干与各类任务 Head 的基座
XLMRobertaEmbeddings XLM-RoBERTa 词嵌入 + token_type 嵌入 + LayerNorm + Dropout
LlamaRotaryEmbeddingLlamaAttentionapply_rotary_pos_emb Llama 旋转位置编码与多头注意力
GPTNeoXLayer GPT-NeoX 残差块层结构
CLIPMLP CLIP 前馈网络(MLP)

为什么可以支持 8192 token?——RoPE 对绝对位置编码的替换

在标准 XLM-RoBERTa 的 embedding 里,位置信息来自可学习的 position_embeddings 表。而 modular_jina_embeddings_v3.pyJinaEmbeddingsV3Embeddings.__init__ 明确执行了两件事:

del self.padding_idx
del self.position_embeddings

即删除了 padding 索引与绝对位置嵌入,同时把 create_position_ids_from_input_idscreate_position_ids_from_inputs_embeds 两个方法置为 AttributeError("Not needed for JinaEmbeddingsV3")。位置信息改由 JinaEmbeddingsV3RotaryEmbedding(继承自 LlamaRotaryEmbedding)在注意力计算前实时生成。

旋转位置编码在 modeling_jina_embeddings_v3.py 中的 compute_default_rope_parameters 中计算逆频率:

base = config.rope_parameters["rope_theta"]
dim = getattr(config, "head_dim", None) or config.hidden_size // config.num_attention_heads
inv_freq = 1.0 / (base ** (torch.arange(0, dim, 2, dtype=torch.float) / dim))

对应的 RoPE 超参 default_theta = 20000.0 记录在 configuration_jina_embeddings_v3.py 中。由于 RoPE 是“按位置实时外推”的旋转插值,不需要学习一个固定长度的位置嵌入表,模型因而能自然支持更长的输入序列。

双向注意力与层结构

JinaEmbeddingsV3 是一个双向(encoder)嵌入模型,不是 decoder 式的因果模型:

  • JinaEmbeddingsV3Attentionself.is_causal = False
  • 在模型前向中,attention mask 由 create_bidirectional_mask 生成,保证每个 token 都能看到上下文两侧;
  • 注意力投影(q/k/v/o)全部带 bias,head 维度为 hidden_size // num_attention_heads(默认 1024/16 = 64),缩放因子 scaling = head_dim ** -0.5

注意力实现通过 ALL_ATTENTION_FUNCTIONS.get_interface(self.config._attn_implementation, eager_attention_forward) 动态分发。结合 JinaEmbeddingsV3PreTrainedModel 中声明的能力标志 _supports_flash_attn = True_supports_sdpa = True_supports_flex_attn = True_supports_attention_backend = True,可以确认该模型原生支持 Flash Attention、SDPA、Flex Attention 等多种加速注意力后端(文档页顶部的 PyTorch / FlashAttention / SDPA 徽标也印证了这一点),并支持梯度检查点(supports_gradient_checkpointing = True)。

每个 JinaEmbeddingsV3Layer 的前向路径是:残差 + 注意力输出 → post_attention_dropoutpost_attention_layernorm → 残差 + MLP → post_mlp_dropoutpost_mlp_layernorm,即 LayerNorm 位于每个残差加法之后,而非经典 Transformer 的 pre-norm 位置;同时设置了 post_attention_dropout / post_mlp_dropout 两处 Dropout。这一点可在 modeling_jina_embeddings_v3.pyJinaEmbeddingsV3Layer.forward 中直接核对。

嵌入输出形态

JinaEmbeddingsV3Model.forward 返回 BaseModelOutputWithPooling

  • last_hidden_state:形状为 (batch_size, sequence_length, hidden_size) 的全部 token 隐状态;
  • pooler_output:取序列首 token(<s>)过一层 dense + tanh 的池化结果(对应 JinaEmbeddingsV3Pooler)。

值得注意的是:官方文档明确要求生成句级/段级高质量嵌入时,不要直接用首 token 池化,而要自行做 mean pooling(详见下文),这正是 LoRA 任务嵌入的标准后处理。

快速上手:三种方式提取嵌入特征

模型文档给出了通过 PipelineAutoModel 提取嵌入的示例,两者都使用 jinaai/jina-embeddings-v3-hf 检查点。仓库集成测试 test_modeling_jina_embeddings_v3.py 也以同一 model_id 和提示句 "Jina Embeddings V3 is great for semantic search." 断言了输出形状为 (1, 17, 1024),说明该检查点单条输入会产出与模型 hidden_size = 1024 一致的特征维度。

方式一:Pipeline(feature-extraction)

from transformers import pipeline


pipeline = pipeline(
    task="feature-extraction",
    model="jinaai/jina-embeddings-v3-hf",
)
# Returns a list of lists containing the embeddings for each token
embeddings = pipeline("Jina Embeddings V3 is great for semantic search.")

feature-extraction 任务是 Transformers 通用嵌入管线的标准入口。PipelineTesterMixin 在测试文件中将 feature-extraction 映射到 JinaEmbeddingsV3Model,同时也映射了 fill-maskJinaEmbeddingsV3ForMaskedLM)、text-classification / zero-shotJinaEmbeddingsV3ForSequenceClassification)、token-classificationJinaEmbeddingsV3ForTokenClassification),说明该模型可无缝接入这些现成管线。

方式二:AutoModel + AutoTokenizer

import torch

from transformers import AutoModel, AutoTokenizer


tokenizer = AutoTokenizer.from_pretrained("jinaai/jina-embeddings-v3-hf")
model = AutoModel.from_pretrained("jinaai/jina-embeddings-v3-hf", device_map="auto")

prompt = "Jina Embeddings V3 is great for semantic search."
inputs = tokenizer(prompt, return_tensors="pt").to(model.device)

with torch.no_grad():
    outputs = model(**inputs)
    # The base AutoModel returns the raw hidden states for all tokens
    last_hidden_states = outputs.last_hidden_state

print(f"Features shape: {last_hidden_states.shape}")

device_map="auto" 交给 Transformers/accelerate 自动安排设备;outputs.last_hidden_state 是逐 token 的原始隐状态(默认上下文长度下形状如 (1, seq_len, 1024))。

方式三:命令行

模型文档在说明中同样提到可以“从命令行”完成特征提取。除上述 Python API 外,你可以在终端中复用仓库示例目录下的脚本逻辑,例如以 examples/pytorch/ 中相关示例脚本为基础封装批处理任务;更直接的做法是把上面两段代码保存为脚本后以 python your_script.py 运行(具体 CLI 入口取决于你安装的 Transformers 版本与配套命令行工具)。

Task-Specific LoRA Adapters:一个模型,五种任务语义

JinaEmbeddingsV3 的招牌特性是任务专用 LoRA Adapter:不必为每个任务加载一整份不同的模型权重,而是共享同一骨干、仅切换轻量的 LoRA 适配层,即可让嵌入空间针对特定任务“定向塑造”。

5 类任务 Adapter 及用途

官方文档列出了以下任务语义(注意文档中的“点分/连字符”命名是语义名称,实际加载时对应 Hub 上的子目录名,见下文示例):

  • retrieval.query(子目录 retrieval_query:用于非对称检索中的“查询”侧嵌入(如搜索引擎的 query);
  • retrieval.passage(子目录 retrieval_passage:用于非对称检索中的“段落/文档”侧嵌入(如被检索的语料);
  • separation:用于聚类与重排(re-ranking)应用的嵌入;
  • classification:用于分类任务的嵌入;
  • text-matching(子目录 text_matching:用于衡量两段文本相似度的任务,例如语义文本相似度(STS)或对称检索。

句嵌入必须配合 Mean Pooling

要产出高质量的句子/段落级嵌入,需要对模型输出的 token 嵌入做 mean pooling:把所有 token 的嵌入取平均,并且通过 attention mask 把 padding token 屏蔽在求和之外。

完整示例:为检索查询任务生成句嵌入

以下代码完整取自官方文档,展示如何在 AutoModel API 中加载 retrieval_query Adapter、执行 mean pooling 并做 L2 归一化:

import torch
import torch.nn.functional as F

from transformers import AutoModel, AutoTokenizer


def mean_pooling(model_output, attention_mask):
    # First element of model_output contains all token embeddings
    token_embeddings = model_output[0]
    input_mask_expanded = attention_mask.unsqueeze(-1).expand(token_embeddings.size()).float()

    # Sum the embeddings and divide by the number of non-padding tokens
    sum_embeddings = torch.sum(token_embeddings * input_mask_expanded, 1)
    sum_mask = torch.clamp(input_mask_expanded.sum(1), min=1e-9)
    return sum_embeddings / sum_mask


sentences = [
    "How is the weather today?",
    "What is the current weather like today?"
]

tokenizer = AutoTokenizer.from_pretrained("jinaai/jina-embeddings-v3-hf")
model = AutoModel.from_pretrained("jinaai/jina-embeddings-v3-hf", device_map="auto")

encoded_input = tokenizer(sentences, padding=True, truncation=True, return_tensors="pt").to(model.device)

# Set up the adapter mask for your specific task
task = 'retrieval_query'  # Can be any of (retrieval_passage, separation, classification, text_matching) depending on the use-case.

model.load_adapter("jinaai/jina-embeddings-v3-hf", adapter_name=task, adapter_kwargs={"subfolder": task})

model.set_adapter(task)

with torch.no_grad():
    model_output = model(**encoded_input)

embeddings = mean_pooling(model_output, encoded_input["attention_mask"])
embeddings = F.normalize(embeddings, p=2, dim=1)

print(embeddings.shape)
# Output: torch.Size([2, 1024])

几个容易踩坑的细节,均可以对照代码验证:

  1. 任务名即 Hub 子目录名load_adapter(..., adapter_kwargs={"subfolder": task}) 表示 Adapter 权重存放在同一模型仓库下名为 retrieval_query(或 retrieval_passageseparationclassificationtext_matching)的子目录中;
  2. load_adapterset_adapter 缺一不可:前者把 Adapter 权重挂载进模型,后者激活它;集成测试 test_inference_retrieval_query_adaptertest_inference_retrieval_passage_adaptertest_inference_separation_adaptertest_inference_classification_adaptertest_inference_text_matching_adapter(见 test_modeling_jina_embeddings_v3.py)逐一验证了这 5 个任务的加载路径与输出数值,可用作回归基准;
  3. padding/truncation 必须开启mean_pooling 依赖 attention_mask 屏蔽 padding,因此 tokenizer 需要 padding=True, truncation=True
  4. 归一化是可选的惯例F.normalize(embeddings, p=2, dim=1) 对嵌入做 L2 归一化,使余弦相似度计算与内积/点积检索在数值上等价,是向量检索实践的常见步骤;
  5. 无任务时直接取逐 token 隐状态:基础 AutoModel 前向(不做任何 Adapter)返回的就是逐 token 原始隐状态,未经过任务定向;一旦需要可复现且可对比的“检索查询 vs 文档”嵌入空间,就应各自加载对应 Adapter。

JinaEmbeddingsV3Config 默认超参数速查

configuration_jina_embeddings_v3.py 定义了 JinaEmbeddingsV3Configmodel_type = "jina_embeddings_v3"),其类级默认值如下,可与 jinaai/jina-embeddings-v3-hf 检查点的 config.json 对照:

参数 默认值 含义
vocab_size 250002 词表大小(含特殊 token)
hidden_size 1024 隐层维度(也即嵌入维度)
num_hidden_layers 24 Transformer 层数
num_attention_heads 16 注意力头数(单头 64 维)
intermediate_size 4096 MLP 中间层维度
hidden_act "gelu" 激活函数
hidden_dropout_prob 0.1 隐层 Dropout
attention_probs_dropout_prob 0.1 注意力 Dropout
max_position_embeddings 8194 RoPE 支持的最大序列位置(对应 8192 token + 首尾特殊位置)
type_vocab_size 1 segment 类型数(文档注明该参数≥2 时才能传入 token_type_ids)
initializer_range 0.02 权重初始化范围
layer_norm_eps 1e-5 LayerNorm 的 eps
pad_token_id / bos_token_id / eos_token_id 1 / 0 / 2 特殊 token id
use_cache True 是否启用 KV cache
tie_word_embeddings True MLM Head 与词嵌入是否共享权重
default_theta 20000.0 RoPE 基础频率 rope_theta
rope_parameters None(默认按 default) 高级 RoPE 参数(rope_type/rope_theta 等),实现于 JinaEmbeddingsV3RotaryEmbedding

注意配置类同时把 add_cross_attentionis_decoder 声明为 AttributeError(),这是架构层面的强约束:JinaEmbeddingsV3 是纯双向编码器,不能当作带交叉注意力的 decoder 使用。从测试看,JinaEmbeddingsV3ModelTest.test_model_rope_scaling_from_config 针对 linear/dynamic/yarn 缩放被 @unittest.skip("Model doesn't support scaling - due to non-RoPE related reasons") 跳过,说明从源码层面该模型暂不支持对 RoPE 的额外 length scaling 配置。

模型 API 家族:五个公开类

官方文档以 autodoc 形式收录了以下类(全部位于 modeling_jina_embeddings_v3.py):

  • JinaEmbeddingsV3Config:模型配置类,见上文默认值表;
  • JinaEmbeddingsV3Model:裸骨干模型,输出逐 token 隐状态与(可选)首 token 池化结果,是最常用于“提取嵌入”的入口;
  • JinaEmbeddingsV3ForMaskedLM:在骨干上叠 JinaEmbeddingsV3LMHead(dense → GELU → LayerNorm → decoder 线性层)用于掩码语言建模。测试断言其 logits 形状为 (batch_size, seq_length, vocab_size);它同时设置了 _tied_weights_keys,把 lm_head.decoderroberta.embeddings.word_embeddings 的权重做 tied(与 tie_word_embeddings=True 呼应);
  • JinaEmbeddingsV3ForSequenceClassification:分类 Head(取首 token 特征后接多层/输出层),输出 (batch_size, num_labels)
  • JinaEmbeddingsV3ForTokenClassification:序列标注 Head,输出 (batch_size, seq_length, num_labels)
  • JinaEmbeddingsV3ForQuestionAnswering:抽取式问答 Head,输出 start_logits / end_logits,形状均为 (batch_size, seq_length)

modular_jina_embeddings_v3.py 的类定义可以确认,这四个“For 任务”类分别继承自 XLMRobertaForMaskedLMXLMRobertaForSequenceClassificationXLMRobertaForTokenClassificationXLMRobertaForQuestionAnswering,因此其输入输出约定与 XLM-RoBERTa 家族保持一致,使用门槛很低。

各任务 Head 的 forward 参数约定

  • JinaEmbeddingsV3Model.forward(input_ids, attention_mask, token_type_ids, position_ids, inputs_embeds)input_idsinputs_embeds 必须二选一且只能选一(否则抛 ValueError);
  • JinaEmbeddingsV3ForMaskedLM 额外支持 labels(形状同 input_ids,取值 [-100, 0, …, config.vocab_size]-100 表示忽略该位置);
  • JinaEmbeddingsV3ForSequenceClassification 额外支持 labels(整型标签);
  • JinaEmbeddingsV3ForTokenClassification 额外支持逐 token 的 labels
  • JinaEmbeddingsV3ForQuestionAnswering 额外支持 start_positions / end_positions

在仓库中验证:测试与模型结构佐证

如果你希望在本仓库中亲手复现与验证本文结论,最直接的两个入口是:

  1. 结构阅读modular_jina_embeddings_v3.py 是模型的“人类可读”源,逐类阅读其 import 与 del/raise AttributeError 行为,就能快速定位它与 XLM-RoBERTa、Llama、GPT-NeoX、CLIP 的差异点;生成的 modeling_jina_embeddings_v3.py 则为实际运行使用的实现;
  2. 运行测试test_modeling_jina_embeddings_v3.py 中的 JinaEmbeddingsV3ModelIntegrationTest 提供了 6 个 @slow 集成用例:一个“无 Adapter”基线 + 5 个 Adapter(retrieval_query/retrieval_passage/separation/classification/text_matching)用例,它们不仅验证输出形状 (1, 17, 1024),还通过 torch.testing.assert_close 对若干位置的浮点值做 rtol=1e-4 级别的数值对齐。若你在本地修改了推理逻辑,这些用例可作为“数值是否发生变化”的判据。

普通(非 slow)的单元测试则由 JinaEmbeddingsV3ModelTester 生成小型随机配置(如 hidden_size=16num_hidden_layers=2seq_length=7),覆盖模型、MLM、QA、序列分类、Token 分类五个前向的形状正确性,并复用 ModelTesterMixin / PipelineTesterMixin 的统一校验逻辑。

小结

围绕 JinaEmbeddingsV3,本文梳理了从“官方模型文档一句话”到“可落地代码”的完整链路:它是一个 XLM-RoBERTa 血统的多语言嵌入模型,通过 RoPE 换取最长 8192 token 的输入能力;通过内置 5 个任务 LoRA Adapter 让“单模型 + 轻量切换”即可覆盖查询/文档检索、聚类重排、分类与语义匹配等场景;在 Transformers 中它有完整的配置类、骨干模型与 4 类任务 Head,同时支持 FlashAttention/SDPA/Flex Attention 等加速后端。实践中最关键的三步是:用 AutoModel 加载并切到对应任务 Adapter → 对逐 token 隐状态做带 mask 的 mean pooling → 视场景做 L2 归一化。后续在多语言 RAG、语义搜索或文本聚类项目中,你可以直接复用文档中的示例代码,并结合本仓库源码按需深入排查细节。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.14 K
2.75 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
857
1.35 K
docsdocs
暂无描述
Markdown
897
5.8 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
531
594
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
916
1.83 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.58 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.36 K
1.46 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.01 K
516
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
547
388