Embedding训练
SWIFT已经支持Embedding模型的训练,包括纯文本和多模态两个类型。目前已经支持的模型有:
- modernbert embedding模型
- gte embedding模型
- 1.5B: ModelScope Hugging Face
- 7B: ModelScope Hugging Face
- gme embedding模型
- 2B: ModelScope Hugging Face
- 7B: ModelScope Hugging Face
- qwen3-embedding模型
- 0.6B: ModelScope Hugging Face
- 4B: ModelScope Hugging Face
- 8B: ModelScope Hugging Face
- qwen3-vl-embedding模型
- 2B: ModelScope Hugging Face
- 8B: ModelScope Hugging Face
开发者可以自行集成自己的模型,模型forward输出值需要满足:
{"last_hidden_state": some-embedding-tensor}
返回值是一个json,具有last_hidden_state key,value是embedding tensor即可,输入部分可以使用我们已经支持的template。用户也可以通过指定
--task_type embedding
参数来将任意一个其他模型转换为embedding模型进行训练。
需要注意的是,SWIFT目前支持的embedding模型均为符合纯文本或多模态LLM,目前并不支持CLIP类型的模型训练。
此外,SWIFT支持的所有embedding模型在模型forward最后都增加了normalize,如自行增加新模型请注意增加normalize层。
loss
目前SWIFT支持的Embedding模型可以使用的loss有:
- cosine_similarity: cosine相似度loss,计算两个embedding的相似度,并根据label的值拟合,实际为MSE loss
- contrastive: 可调margin的对比学习loss,label仅支持0和1两个值
- online_contrastive: 考虑hard negative和hard positive部分的contrastive loss,label仅支持0和1两个值
- infonce: 在同一个batch中不同row两两计算cosine相似度,并使row内部相似度最大,不同row相似度最小,不需要label
loss的源代码可以在这里找到。
数据集格式
注:
<image>标签可以出现在messages/positive_messages/negative_messages的任意位置;它们各自拥有独立的images/positive_images/negative_images字段用于提供图片路径或URL。- 不再需要跨字段的“对应顺序”。对齐规则为:
images的长度等于messages中<image>标签的数量;positive_images与negative_images均为“list of list”,其外层长度分别等于positive_messages与negative_messages的长度;并且外层每一项的内层列表长度等于该条消息序列中<image>标签的数量。messages代表anchor样本(anchor sample);positive_messages/negative_messages为“list of messages”(因此多一层[]);相应地,positive_images/negative_images也多一层[]并与之逐项对齐。- 也支持
<video>,<audio>标签;可按相同规则分别通过videos/positive_videos/negative_videos与audios/positive_audios/negative_audios提供对应模态数据。- 当前约束:
positive_messages的外层长度必须为1(即仅提供一个positive样本);对应地,positive_images的外层长度也必须为1。
cosine_similarity loss对应的格式
# LLM
{"messages": [{"role": "user", "content": "sentence1"}], "positive_messages": [[{"role": "user", "content": "sentence2"}]], "label": 0.8}
# MLLM
{"messages": [{"role": "user", "content": "<image>"}], "images": ["/some/images1.jpg"],"positive_messages": [[{"role": "user", "content": "<image>sentence"}]], "positive_images": [["/some/images2.jpg"]], "label": 0.7}
{"messages": [{"role": "user", "content": "sentence1"}], "positive_messages": [[{"role": "user", "content": "<image>sentence2"}]], "positive_images": [["/some/images.jpg"]], "label": 0.7}
contrastive/online_contrastive loss对应的格式
# LLM
{"messages": [{"role": "user", "content": "sentence1"}], "positive_messages": [[{"role": "user", "content": "sentence2"}]], "label": 1}
# MLLM
{"messages": [{"role": "user", "content": "<image>"}], "images": ["/some/images1.jpg"], "positive_messages": [[{"role": "user", "content": "<image>sentence"}]], "positive_images": [["/some/images2.jpg"]], "label": 1}
{"messages": [{"role": "user", "content": "sentence1"}], "positive_messages": [[{"role": "user", "content": "<image>sentence2"}]], "positive_images": [["/some/images.jpg"]], "label": 0}
评测的指标分别是两个embedding的欧式距离、点积等的pearson系数以及spearman系数,共八个指标。
infonce 格式
# LLM
{"messages": [{"role": "user", "content": "sentence1"}], "positive_messages": [[{"role": "user", "content": "sentence2"}]]}
# MLLM
{"messages": [{"role": "user", "content": "<image>"}], "images": ["/some/images.jpg"], "positive_messages": [[{"role": "user", "content": "sentence"}]]}
{"messages": [{"role": "user", "content": "<image>sentence1"}], "images": ["/some/images.jpg"], "positive_messages": [[{"role": "user", "content": "<image>sentence2"}]], "positive_images": [["/some/positive_images.jpg"]], "negative_messages": [[{"role": "user", "content": "<image><image>sentence3"}], [{"role": "user", "content": "<image>sentence4"}]], "negative_images": [["/some/negative_images1.jpg", "/some/negative_images2.jpg"], ["/some/negative_images3.jpg"]]}
infonce loss支持几个环境变量:
INFONCE_TEMPERATURE: temperature参数,不设置的话默认值是0.1INFONCE_USE_BATCH: 使用sample内部的negative_messages(hard negative样例)还是使用一个batch内其他样本作为in-batch negatives;默认为True,表示使用batch内部的样本作为负例INFONCE_HARD_NEGATIVES: hard negatives的数量;如果不设置会使用数据中提供的所有negative_messages。由于长度未必一致,因此会采用for循环计算loss(计算会慢)。若设置为某个数值,则不足会随机采样补齐,超长会选用前INFONCE_HARD_NEGATIVES个INFONCE_MASK_FAKE_NEGATIVE: mask掉假negative。默认为False,开启时会判断positive_similarity + INFONCE_FAKE_NEG_MARGIN,比该阈值大的样本相似度会被设置为-inf,以防止正样本泄露问题INFONCE_FAKE_NEG_MARGIN:假负样本屏蔽的边际,默认0.1。INFONCE_INCLUDE_QQ:是否在分母中加入 q–q 分量(query 间相似度)作为负例,默认False。INFONCE_INCLUDE_DD:是否在分母中加入 d–d 分量(正样本文档与 batch 内所有文档的相似度)作为负例,默认False。
也可以在数据集中将hard negatives数量设置为数量相等,这样即使不设置也不会使用for循环方式,加快计算速度
negative_messages也可以不提供。在这种情况下,保持INFONCE_USE_BATCH=True,会使用一个batch内部的其他样本作为负例
infonce loss的评测会有下面几个指标:
- mean_neg 所有hard_negative的平均值
- mean_pos 所有positive的平均值
- margin positive-max_hard_negative的平均值
训练
SWIFT提供的脚手架训练脚本:
推理
SWIFT已经支持GME、GTE、Qwen3-Embedding模型的部署,请查看这里。
- 推理脚本参考这里。
也可以使用原模型的代码进行推理:
https://www.modelscope.cn/models/iic/gte_Qwen2-7B-instruct
https://www.modelscope.cn/models/iic/gme-Qwen2-VL-7B-Instruct
如果使用了其他模型从0训练embedding(例如,原版qwen2-vl模型+--task_type embedding),也可以使用gme的推理代码,但请注意:
这里的模板请修改为模型自身的template,以免最后的embedding对不上。需要额外注意的是,gme模型的template和qwen2-vl或qwen2.5-vl系列的chatml template并不相同,其推理代码最后的结束字符是<|endoftext|>而非<|im_end|>.
高级功能
- Qwen3-Embedding 自定义 Instruction:
- 默认无 Instruction,输入模板为:
{Query}<|endoftext|>。 - 通过在 system message 中添加 Instruction,可将输入改为:
{Instruction} {Query}<|endoftext|>。 - 示例:
- 默认无 Instruction,输入模板为:
{"messages": [
{"role": "system", "content": "请用中文回答,并输出简洁要点"},
{"role": "user", "content": "介绍一下Qwen3-Embedding"}
]}
说明:Qwen3-Embedding 模板会将 system 内容前置拼接到首条 user 消息中,并使用
<|endoftext|>作为结束标记。
转换前后示例
不加 Instruction:
输入数据(messages):
{"messages": [ {"role": "user", "content": "北京明天天气如何?"} ]}模板转换后(送入模型的实际文本):
北京明天天气如何?<|endoftext|>加 Instruction:
输入数据(messages,包含system):
{"messages": [ {"role": "system", "content": "请使用中文、精炼输出要点"}, {"role": "user", "content": "北京明天天气如何?"} ]}模板转换后(送入模型的实际文本):
请使用中文、精炼输出要点 北京明天天气如何?<|endoftext|>positive/negative 同理:
若在某个 positive/negative 的消息序列中提供 system,则会将该 system 内容前置到该序列首条 user 内容之前;未提供 system 则不前置。
输入数据(包含一个 positive 带 system,和一个 negative 无 system):
{ "messages": [ {"role": "user", "content": "Anchor"} ], "positive_messages": [[ {"role": "system", "content": "指令"}, {"role": "user", "content": "Positive"} ]], "negative_messages": [[ {"role": "user", "content": "Negative"} ]] }模板转换后(送入模型的实际文本):
Anchor<|endoftext|> 指令 Positive<|endoftext|> Negative<|endoftext|>