使用 Sentence Transformers 训练和微调多模态 Embedding 与 Reranker 模型

Hugging Face Blog 工具

摘要

本文提供了使用 Sentence Transformers 库训练和微调多模态 Embedding 与 Reranker 模型的技术指南,展示了在基于 Qwen3-VL 的视觉文档检索任务上的性能提升。

暂无内容
查看原文
查看缓存全文

缓存时间: 2026/05/08 09:06

使用 Sentence Transformers 训练和微调多模态 Embedding 与 Reranker 模型

来源:https://huggingface.co/blog/train-multimodal-sentence-transformers 返回文章列表 (https://huggingface.co/blog)

Tom Aarsen 的头像 (https://huggingface.co/tomaarsen)

  • 目录 (https://huggingface.co/blog/train-multimodal-sentence-transformers#table-of-contents)
  • 为什么要微调? (https://huggingface.co/blog/train-multimodal-sentence-transformers#why-finetune)
  • 训练组件 (https://huggingface.co/blog/train-multimodal-sentence-transformers#training-components)
  • 模型 (https://huggingface.co/blog/train-multimodal-sentence-transformers#model)
  • 数据集 (https://huggingface.co/blog/train-multimodal-sentence-transformers#dataset)- 视觉文档检索数据集 (https://huggingface.co/blog/train-multimodal-sentence-transformers#visual-document-retrieval-dataset) - 数据集格式 (https://huggingface.co/blog/train-multimodal-sentence-transformers#dataset-format)
  • 损失函数 (https://huggingface.co/blog/train-multimodal-sentence-transformers#loss-function)- CachedMultipleNegativesRankingLoss (https://huggingface.co/blog/train-multimodal-sentence-transformers#cachedmultiplenegativesrankingloss) - MatryoshkaLoss (https://huggingface.co/blog/train-multimodal-sentence-transformers#matryoshkaloss)
  • 训练参数 (https://huggingface.co/blog/train-multimodal-sentence-transformers#training-arguments)
  • 评估器 (https://huggingface.co/blog/train-multimodal-sentence-transformers#evaluator)
  • 训练器 (https://huggingface.co/blog/train-multimodal-sentence-transformers#trainer)
  • 结果 (https://huggingface.co/blog/train-multimodal-sentence-transformers#results)- 模型大小 vs NDCG@10 (https://huggingface.co/blog/train-multimodal-sentence-transformers#model-size-vs-ndcg10) - Matryoshka 维度 vs NDCG@10 (https://huggingface.co/blog/train-multimodal-sentence-transformers#matryoshka-dimensions-vs-ndcg10)
  • 训练多模态 Reranker 模型 (https://huggingface.co/blog/train-multimodal-sentence-transformers#training-multimodal-reranker-models)
  • 其他资源 (https://huggingface.co/blog/train-multimodal-sentence-transformers#additional-resources)- 训练示例 (https://huggingface.co/blog/train-multimodal-sentence-transformers#training-examples) - 文档 (https://huggingface.co/blog/train-multimodal-sentence-transformers#documentation) - 相关博客文章 (https://huggingface.co/blog/train-multimodal-sentence-transformers#companion-blogposts)

Sentence Transformers (https://sbert.net/) 是一个用于使用和训练 embedding 与 reranker 模型的 Python 库,适用于检索增强生成、语义搜索等应用。在我之前的博客文章 (https://huggingface.co/blog/multimodal-sentence-transformers) 中,我介绍了新的多模态功能,展示了如何使用能够处理文本、图像、音频和视频的 embedding 和 reranker 模型。在这篇文章中,我将向你展示如何训练或微调这些多模态模型,使用你自己的数据。

作为一个实际示例,我将演示如何微调 Qwen/Qwen3-VL-Embedding-2B (https://huggingface.co/Qwen/Qwen3-VL-Embedding-2B),用于视觉文档检索(Visual Document Retrieval, VDR)任务——即根据给定的文本查询,从大量文档中检索相关的文档页面(以图像形式保留图表、表格和版面布局)。最终得到的 tomaarsen/Qwen3-VL-Embedding-2B-vdr (https://huggingface.co/tomaarsen/Qwen3-VL-Embedding-2B-vdr) 展示了通过在特定领域数据上微调可以获得多大的性能提升。在我的评估数据上,微调后的模型 NDCG@10 达到 0.947,而基础模型仅为 0.888,并且超过了所有我测试过的现有 VDR 模型,包括那些体积是其 4 倍的模型。

VDR 模型的模型大小与 NDCG 对比 (https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/blog/multimodal-sentence-transformers/vdr_plot.png)

如果你刚接触 Sentence Transformers 中的多模态模型,建议先阅读《使用 Sentence Transformers 的多模态 Embedding 与 Reranker 模型》(https://huggingface.co/blog/multimodal-sentence-transformers)。对于仅文本的 embedding、reranker 或稀疏 embedding 模型的训练,请参阅文末的往期博客文章 (https://huggingface.co/blog/train-multimodal-sentence-transformers#prior-blogposts) 部分。

https://huggingface.co/blog/train-multimodal-sentence-transformers#table-of-contents 目录

  • 为什么要微调? (https://huggingface.co/blog/train-multimodal-sentence-transformers#why-finetune)
  • 训练组件 (https://huggingface.co/blog/train-multimodal-sentence-transformers#training-components)
  • 模型 (https://huggingface.co/blog/train-multimodal-sentence-transformers#model)
  • 数据集 (https://huggingface.co/blog/train-multimodal-sentence-transformers#dataset)- 视觉文档检索数据集 (https://huggingface.co/blog/train-multimodal-sentence-transformers#visual-document-retrieval-dataset) - 数据集格式 (https://huggingface.co/blog/train-multimodal-sentence-transformers#dataset-format)
  • 损失函数 (https://huggingface.co/blog/train-multimodal-sentence-transformers#loss-function)- CachedMultipleNegativesRankingLoss (https://huggingface.co/blog/train-multimodal-sentence-transformers#cachedmultiplenegativesrankingloss) - MatryoshkaLoss (https://huggingface.co/blog/train-multimodal-sentence-transformers#matryoshkaloss)
  • 训练参数 (https://huggingface.co/blog/train-multimodal-sentence-transformers#training-arguments)
  • 评估器 (https://huggingface.co/blog/train-multimodal-sentence-transformers#evaluator)
  • 训练器 (https://huggingface.co/blog/train-multimodal-sentence-transformers#trainer)
  • 结果 (https://huggingface.co/blog/train-multimodal-sentence-transformers#results)- 模型大小 vs NDCG@10 (https://huggingface.co/blog/train-multimodal-sentence-transformers#model-size-vs-ndcg10) - Matryoshka 维度 vs NDCG@10 (https://huggingface.co/blog/train-multimodal-sentence-transformers#matryoshka-dimensions-vs-ndcg10)
  • 训练多模态 Reranker 模型 (https://huggingface.co/blog/train-multimodal-sentence-transformers#training-multimodal-reranker-models)
  • 其他资源 (https://huggingface.co/blog/train-multimodal-sentence-transformers#additional-resources)- 往期博客文章 (https://huggingface.co/blog/train-multimodal-sentence-transformers#prior-blogposts) - 训练示例 (https://huggingface.co/blog/train-multimodal-sentence-transformers#training-examples) - 文档 (https://huggingface.co/blog/train-multimodal-sentence-transformers#documentation)

https://huggingface.co/blog/train-multimodal-sentence-transformers#why-finetune 为什么要微调?

Qwen/Qwen3-VL-Embedding-2B (https://huggingface.co/Qwen/Qwen3-VL-Embedding-2B) 这样的通用多模态 embedding 模型在多样化的数据上进行训练,以在广泛的语言和任务中表现良好:图像-文本匹配、视觉问答、文档理解等。但这种通用性意味着它很少是任何特定任务的最佳选择。

以视觉文档检索为例:给定一个文本查询如“公司第三季度的收入是多少?“,模型必须从成千上万的文档截图中找到最相关的页面。这需要理解文档布局、图表、表格和文本,这与匹配鞋子图片与产品描述等任务所需的技能截然不同。

通过在特定领域的数据上进行微调,模型可以学习这些专门的模式。在我的实验中,微调将 NDCG@10 从 0.888 提升到了 0.947,超过了我测试的每一个近期多模态模型,包括那些体积大 4 倍的模型。

https://huggingface.co/blog/train-multimodal-sentence-transformers#training-components 训练组件

训练多模态 Sentence Transformer 模型涉及与仅文本模型训练相同的组件:

  1. 模型 (https://huggingface.co/blog/train-multimodal-sentence-transformers#model):要训练或微调的多模态模型。
  2. 数据集 (https://huggingface.co/blog/train-multimodal-sentence-transformers#dataset):用于训练和评估的数据。
  3. 损失函数 (https://huggingface.co/blog/train-multimodal-sentence-transformers#loss-function):量化模型表现并指导优化过程的函数。
  4. 训练参数 (https://huggingface.co/blog/train-multimodal-sentence-transformers#training-arguments)(可选):影响训练性能和跟踪/调试的参数。
  5. 评估器 (https://huggingface.co/blog/train-multimodal-sentence-transformers#evaluator)(可选):在训练前、中、后评估模型的工具。
  6. 训练器 (https://huggingface.co/blog/train-multimodal-sentence-transformers#trainer):将模型、数据集、损失函数和其他组件整合起来进行训练。

多模态训练流程使用与仅文本训练相同的 SentenceTransformerTrainer (https://sbert.net/docs/package_reference/sentence_transformer/trainer.html#sentence_transformers.sentence_transformer.trainer.SentenceTransformerTrainer)。关键区别在于你的数据集包含图像(或其他模态)以及文本,并且模型的处理器会自动处理图像预处理。

让我们逐一介绍每个组件,以视觉文档检索(将文本查询与文档截图匹配)作为贯穿示例。

https://huggingface.co/blog/train-multimodal-sentence-transformers#model 模型

最常见的方法是微调现有的多模态 embedding 模型,或从视觉-语言模型(VLM)检查点开始。Transformer (https://sbert.net/docs/package_reference/base/modules.html#sentence_transformers.base.modules.Transformer) 模块会自动从模型的处理器中检测支持的模态。

要微调现有的多模态 embedding 模型(例如已经带有 modules.json 文件的模型),你可以传递 processor_kwargsmodel_kwargs 来分别控制预处理和模型加载。processor_kwargs 直接传递给 AutoProcessor.from_pretrained(...) (https://huggingface.co/docs/transformers/model_doc/auto#transformers.AutoProcessor.from_pretrained)(例如图像分辨率限制:max_pixels 越高意味着质量越高但内存消耗越大),而 model_kwargs 传递给相应的 AutoModel.from_pretrained(...) (https://huggingface.co/docs/transformers/model_doc/auto#transformers.AutoModel.from_pretrained) 调用(例如精度、注意力实现):

from sentence_transformers import SentenceTransformer

model = SentenceTransformer(
    "Qwen/Qwen3-VL-Embedding-2B",
    model_kwargs={"attn_implementation": "flash_attention_2", "torch_dtype": "bfloat16"},
    processor_kwargs={"min_pixels": 28 * 28, "max_pixels": 600 * 600},
)

你也可以从尚未用于 embedding 任务的全新 VLM 检查点开始。Sentence Transformers 会尝试识别架构,从处理器推断支持的模态,并设置适当的前向方法和池化。如果自动检测对某个特定模型不能完美工作,可以编辑保存的 sentence_bert_config.json 中的配置来调整模态设置、前向方法和输出处理:

from sentence_transformers import SentenceTransformer

model = SentenceTransformer("Qwen/Qwen3-VL-2B")

在这两种情况下,Transformer (https://sbert.net/docs/package_reference/base/modules.html#sentence_transformers.base.modules.Transformer) 模块会检查处理器以确定可用的模态,并在需要时自动添加 Pooling (https://sbert.net/docs/package_reference/sentence_transformer/modules.html#sentence_transformers.sentence_transformer.modules.Pooling)。你可以验证支持的模态:

print(model.modalities)
# ['text', 'image', 'video', 'message']

print(model.supports("image"))
# True

替代方案:使用 Router 构建多模态模型除了使用单个 VLM 骨干网络,你还可以使用 Router (https://sbert.net/docs/package_reference/base/modules.html#sentence_transformers.base.modules.Router) 模块为不同模态组合单独的编码器。这让你可以结合任何现有编码器,并根据检测到的模态将输入路由到适当的编码器:

from sentence_transformers import SentenceTransformer
from sentence_transformers.sentence_transformer.modules import Dense, Pooling, Router, Transformer

# 为不同模态创建单独的编码器
text_encoder = Transformer("sentence-transformers/all-MiniLM-L6-v2")
text_pooling = Pooling(text_encoder.get_embedding_dimension(), pooling_mode="mean")
text_projection = Dense(text_encoder.get_embedding_dimension(), 768)

# SigLIP 直接输出池化后的 embedding,因此不需要单独的 Pooling 模块
image_encoder = Transformer("google/siglip2-base-patch16-224")

# 根据模态路由输入
router = Router(
    sub_modules={
        "text": [text_encoder, text_pooling, text_projection],
        "image": [image_encoder],
    },
)

model = SentenceTransformer(modules=[router])

由于基于 Router 的多模态模型使用每个模态的单独编码器,它们的 embedding 空间最初是未对齐的。需要进行训练来对齐空间以实现有意义的跨模态相似度。上面展示的 Dense 投影层有助于将来自不同编码器的 embedding 映射到共享空间中。

当你想使用轻量级、专门的编码器而不是大型 VLM 时,这种方法很有用。你还可以将基于 Router 的多模态与基于任务的路由(例如查询与文档使用不同的编码器)结合使用,通过 route_mappings 实现。有关高级路由场景,请参阅 Router (https://sbert.net/docs/package_reference/base/modules.html#sentence_transformers.base.modules.Router) 文档。

https://huggingface.co/blog/train-multimodal-sentence-transformers#dataset 数据集

https://huggingface.co/blog/train-multimodal-sentence-transformers#visual-document-retrieval-dataset 视觉文档检索数据集

对于本示例,我使用 tomaarsen/llamaindex-vdr-en-train-preprocessed (https://huggingface.co/datasets/tomaarsen/llamaindex-vdr-en-train-preprocessed) 数据集,这是 llamaindex/vdr-multilingual-train (https://huggingface.co/datasets/llamaindex/vdr-multilingual-train) 的预处理英文子集。源数据集随 LlamaIndex 的《Visual Document Retrieval Goes Multilingual》(https://huggingface.co/blog/vdr-2b-multilingual) 博客文章一起发布,包含约 50 万条多语言查询-图像样本,收集自公共互联网 PDF,查询使用 VLM(gemini-1.5-pro 和 Qwen2-VL-72B)合成生成。我的预处理版本过滤出 53,512 条英文样本,并将每条样本中 16 个基于 ID 的难负例中的 4 个解析为实际的文档截图图像,因此可以直接用于训练而无需进一步预处理:

from datasets import load_dataset

train_dataset = load_dataset("tomaarsen/llamaindex-vdr-en-train-preprocessed", "train", split="train")
train_dataset = train_dataset.select_columns(["query", "image", "negative_0"])
eval_dataset = load_dataset("tomaarsen/llamaindex-vdr-en-train-preprocessed", "eval", split="train")

train 配置包含前 10,000 条样本,eval 配置包含接下来的 300 条样本(还有包含全部 53,512 条样本的 full 配置可用)。对于训练,我选择 queryimagenegative_0 来构成(锚点、正例、难负例)三元组。包含额外的难负例可能会改善训练信号,但每个额外的负例也会增加内存使用和训练时间,因此我只使用一个。对于评估,我保留每个查询的所有四个难负例,以构建更具挑战性的检索场景。

相似文章

Qwen-Image-2.0-RL 技术报告

Hugging Face Daily Papers

本技术报告介绍了 Qwen-Image-2.0-RL,这是一个基于强化学习与人类反馈及在策略蒸馏的后训练流程,旨在提升图像生成与编辑任务中的视觉质量和指令遵循能力。

利用自监督指南提升视觉指令调优

Hugging Face Daily Papers

本文提出通过将自监督任务表达为自然语言指令,增强多模态语言模型中的视觉指令调优,从而在不增加架构或标注的情况下提升以视觉为中心的推理能力。通过将经典的自监督预文本任务(如旋转预测、颜色匹配和跨视角对应)重构为图像-指令-响应对,该方法仅需在训练数据中注入3%-10%的视觉化指令,便能在多个基准测试中实现一致的性能提升。