File size: 11,797 Bytes
7134ce7 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 | # Embedding训练
SWIFT已经支持Embedding模型的训练,包括纯文本和多模态两个类型。目前已经支持的模型有:
1. modernbert embedding模型
- [ModelScope](https://modelscope.cn/models/iic/gte-modernbert-base) [Hugging Face](https://huggingface.co/Alibaba-NLP/gte-modernbert-base)
2. gte embedding模型
- 1.5B: [ModelScope](https://www.modelscope.cn/models/iic/gte_Qwen2-1.5B-instruct) [Hugging Face](https://huggingface.co/Alibaba-NLP/gte-Qwen2-1.5B-instruct)
- 7B: [ModelScope](https://www.modelscope.cn/models/iic/gte_Qwen2-7B-instruct) [Hugging Face](https://huggingface.co/Alibaba-NLP/gte-Qwen2-7B-instruct)
3. gme embedding模型
- 2B: [ModelScope](https://www.modelscope.cn/models/iic/gme-Qwen2-VL-2B-Instruct) [Hugging Face](https://huggingface.co/Alibaba-NLP/gme-Qwen2-VL-2B-Instruct)
- 7B: [ModelScope](https://www.modelscope.cn/models/iic/gme-Qwen2-VL-7B-Instruct) [Hugging Face](https://huggingface.co/Alibaba-NLP/gme-Qwen2-VL-7B-Instruct)
4. qwen3-embedding模型
- 0.6B: [ModelScope](https://www.modelscope.cn/models/Qwen/Qwen3-Embedding-0.6B) [Hugging Face](https://huggingface.co/Qwen/Qwen3-Embedding-0.6B)
- 4B: [ModelScope](https://www.modelscope.cn/models/Qwen/Qwen3-Embedding-4B) [Hugging Face](https://huggingface.co/Qwen/Qwen3-Embedding-4B)
- 8B: [ModelScope](https://www.modelscope.cn/models/Qwen/Qwen3-Embedding-8B) [Hugging Face](https://huggingface.co/Qwen/Qwen3-Embedding-8B)
5. qwen3-vl-embedding模型
- 2B: [ModelScope](https://www.modelscope.cn/models/Qwen/Qwen3-VL-Embedding-2B) [Hugging Face](https://huggingface.co/Qwen/Qwen3-VL-Embedding-2B)
- 8B: [ModelScope](https://www.modelscope.cn/models/Qwen/Qwen3-VL-Embedding-8B) [Hugging Face](https://huggingface.co/Qwen/Qwen3-VL-Embedding-8B)
开发者可以自行集成自己的模型,模型forward输出值需要满足:
```text
{"last_hidden_state": some-embedding-tensor}
```
返回值是一个json,具有`last_hidden_state` key,value是embedding tensor即可,输入部分可以使用我们已经支持的template。用户也可以通过指定
```shell
--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的源代码可以在[这里](https://github.com/modelscope/ms-swift/blob/main/swift/loss/mapping.py)找到。
## 数据集格式
> 注:
> 1. `<image>`标签可以出现在`messages`/`positive_messages`/`negative_messages`的任意位置;它们各自拥有独立的`images`/`positive_images`/`negative_images`字段用于提供图片路径或URL。
> 2. 不再需要跨字段的“对应顺序”。对齐规则为:`images`的长度等于`messages`中`<image>`标签的数量;`positive_images`与`negative_images`均为“list of list”,其外层长度分别等于`positive_messages`与`negative_messages`的长度;并且外层每一项的内层列表长度等于该条消息序列中`<image>`标签的数量。
> 3. `messages`代表anchor样本(anchor sample);`positive_messages`/`negative_messages`为“list of messages”(因此多一层`[]`);相应地,`positive_images`/`negative_images`也多一层`[]`并与之逐项对齐。
> 4. 也支持`<video>`, `<audio>`标签;可按相同规则分别通过`videos`/`positive_videos`/`negative_videos`与`audios`/`positive_audios`/`negative_audios`提供对应模态数据。
> 5. 当前约束:`positive_messages`的外层长度必须为1(即仅提供一个positive样本);对应地,`positive_images`的外层长度也必须为1。
### cosine_similarity loss对应的格式
```json lines
# 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对应的格式
```json lines
# 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 格式
```json lines
# 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支持几个环境变量:
1. `INFONCE_TEMPERATURE`: temperature参数,不设置的话默认值是0.1
2. `INFONCE_USE_BATCH`: 使用sample内部的`negative_messages`(hard negative样例)还是使用一个batch内其他样本作为in-batch negatives;默认为True,表示使用batch内部的样本作为负例
3. `INFONCE_HARD_NEGATIVES`: hard negatives的数量;如果不设置会使用数据中提供的所有`negative_messages`。由于长度未必一致,因此会采用for循环计算loss(计算会慢)。若设置为某个数值,则不足会随机采样补齐,超长会选用前`INFONCE_HARD_NEGATIVES`个
4. `INFONCE_MASK_FAKE_NEGATIVE`: mask掉假negative。默认为False,开启时会判断 `positive_similarity + INFONCE_FAKE_NEG_MARGIN`,比该阈值大的样本相似度会被设置为 `-inf`,以防止正样本泄露问题
5. `INFONCE_FAKE_NEG_MARGIN`:假负样本屏蔽的边际,默认 `0.1`。
6. `INFONCE_INCLUDE_QQ`:是否在分母中加入 q–q 分量(query 间相似度)作为负例,默认 `False`。
7. `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提供的脚手架训练脚本:
- [Qwen3-Embedding/Qwen3-VL-Embedding模型](https://github.com/modelscope/ms-swift/blob/main/examples/train/embedding/qwen3)
- [GME模型](https://github.com/modelscope/ms-swift/blob/main/examples/train/embedding/train_gme.sh)
## 推理
SWIFT已经支持GME、GTE、Qwen3-Embedding模型的部署,请查看[这里](https://github.com/modelscope/ms-swift/blob/main/examples/deploy/embedding/client.py)。
- 推理脚本参考[这里](https://github.com/modelscope/ms-swift/blob/main/examples/infer/demo_embedding.py)。
也可以使用原模型的代码进行推理:
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的推理代码,但请注意:
https://www.modelscope.cn/models/iic/gme-Qwen2-VL-7B-Instruct/file/view/master/gme_inference.py?status=1#L111
这里的模板请修改为模型自身的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|>`。
- 示例:
```json lines
{"messages": [
{"role": "system", "content": "请用中文回答,并输出简洁要点"},
{"role": "user", "content": "介绍一下Qwen3-Embedding"}
]}
```
> 说明:Qwen3-Embedding 模板会将 system 内容前置拼接到首条 user 消息中,并使用 `<|endoftext|>` 作为结束标记。
### 转换前后示例
- 不加 Instruction:
输入数据(messages):
```json lines
{"messages": [
{"role": "user", "content": "北京明天天气如何?"}
]}
```
模板转换后(送入模型的实际文本):
```text
北京明天天气如何?<|endoftext|>
```
- 加 Instruction:
输入数据(messages,包含system):
```json lines
{"messages": [
{"role": "system", "content": "请使用中文、精炼输出要点"},
{"role": "user", "content": "北京明天天气如何?"}
]}
```
模板转换后(送入模型的实际文本):
```text
请使用中文、精炼输出要点 北京明天天气如何?<|endoftext|>
```
- positive/negative 同理:
若在某个 positive/negative 的消息序列中提供 system,则会将该 system 内容前置到该序列首条 user 内容之前;未提供 system 则不前置。
输入数据(包含一个 positive 带 system,和一个 negative 无 system):
```json lines
{
"messages": [
{"role": "user", "content": "Anchor"}
],
"positive_messages": [[
{"role": "system", "content": "指令"},
{"role": "user", "content": "Positive"}
]],
"negative_messages": [[
{"role": "user", "content": "Negative"}
]]
}
```
模板转换后(送入模型的实际文本):
```text
Anchor<|endoftext|>
指令 Positive<|endoftext|>
Negative<|endoftext|>
```
|