chore: import upstream snapshot with attribution
Lint test / lint (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 13:34:58 +08:00
commit a203934033
1368 changed files with 175001 additions and 0 deletions
+233
View File
@@ -0,0 +1,233 @@
# 架构介绍
ms-swift 4.0 采用模块化设计,各功能模块分布在一级目录下,便于开发者进行自定义扩展。本文档将详细介绍各模块的功能及自定义方法。
## Agent Template
agent模板的mapping文件可以参考[这里](https://github.com/modelscope/ms-swift/blob/main/swift/agent_template/mapping.py)。agent template设计目标是,基于统一的Agent数据集格式,可以灵活切换不同模型进行训练,无需修改数据。训练时使用`--agent_template`指定对应的agent模板。
所有的AgentTemplate需要继承自`BaseAgentTemplate`,并实现其中的几个方法: `_format_tools`, `_format_tool_calls`, `_format_tool_responses`, `get_toolcall`
- _format_tools: 将`tools``system`格式化,组成完整的system。
- _format_tool_calls: 将tool_call部分 `[{"role": "tool_call", "content": "..."}, {"role": "tool_call", "content": "..."}]`进行格式化,最后返回字符串。
- _format_tool_responses: 对tool(也称为tool_response)部分 `[{"role": "tool", "content": "..."}, {"role": "tool", "content": "..."}]`进行格式化。
- get_toolcall: 在部署的时候使用,用于解析模型输出内容中的工具名和参数,返回`List[Function]`
如何debug
```python
data = {"tools": "[{\"type\": \"function\", \"function\": {\"name\": \"realtime_aqi\", \"description\": \"天气预报。获取实时空气质量。当前空气质量,PM2.5,PM10信息\", \"parameters\": {\"type\": \"object\", \"properties\": {\"city\": {\"type\": \"string\", \"description\": \"城市名,例如:上海\"}}, \"required\": [\"city\"]}}}]", "messages": [{"role": "user", "content": "北京和上海今天的天气情况"}, {"role": "tool_call", "content": "{\"name\": \"realtime_aqi\", \"arguments\": {\"city\": \"北京\"}}"}, {"role": "tool_call", "content": "{\"name\": \"realtime_aqi\", \"arguments\": {\"city\": \"上海\"}}"}, {"role": "tool_response", "content": "{\"city\": \"北京\", \"aqi\": \"10\", \"unit\": \"celsius\"}"}, {"role": "tool_response", "content": "{\"city\": \"上海\", \"aqi\": \"72\", \"unit\": \"fahrenheit\"}"}, {"role": "assistant", "content": "根据天气预报工具,北京今天的空气质量指数为10,属于良好水平;上海今天的空气质量指数为72,属于轻度污染水平。"}]}
from swift import get_processor, get_template
tokenizer = get_processor('Qwen/Qwen3.5-2B')
template = get_template(tokenizer) # 使用默认agent模板
# template = get_template(tokenizer, agent_template='qwen3_5')
print(f'agent_template: {template._agent_template}')
template.set_mode('train')
encoded = template.encode(data)
print(f'[INPUT_IDS] {template.safe_decode(encoded["input_ids"])}\n')
print(f'[LABELS] {template.safe_decode(encoded["labels"])}')
```
如果你想要给我们提供PR,请参考[这里](https://github.com/modelscope/ms-swift/blob/main/tests/test_align/test_template/test_agent.py)书写你的测试案例。
## Callbacks
callbacks的mapping文件可以参考[这里](https://github.com/modelscope/ms-swift/blob/main/swift/callbacks/mapping.py)。callbacks可以对trainer中的关键节点的行为进行自定义。自定义后,你需要在mapping中进行注册,训练时使用`--callbacks`指定对应的回调类。例如,你可以自定义:
```python
class CustomCallback(TrainerCallback):
def on_train_begin(self, args: TrainingArguments, state: TrainerState, control: TrainerControl, **kwargs):
# Doing something when the training begins.
pass
def on_save(self, args: TrainingArguments, state: TrainerState, control: TrainerControl, **kwargs):
# Doing something when save checkpoint
pass
```
所有的回调类需继承自base.py中的`TrainerCallback`,并覆盖其方法。接口与transformers的`TrainerCallback`一致,请参考transformers的[callback文档](https://huggingface.co/docs/transformers/main_classes/callback)。
## Loss
Loss的mapping文件可以参考[这里](https://github.com/modelscope/ms-swift/blob/main/swift/loss/mapping.py)。
swift支持自定义loss(当前只支持sft/pretrain/reranker/embedding任务),注册后在训练时设置`--loss_type <loss-name>`使用你定制的loss方法。
自定义Loss需继承自`BaseLoss`,并实现`__call__`方法,返回标量Tensor。你可以参考[CustomCrossEntropyLoss](https://github.com/modelscope/ms-swift/blob/0d7c9f5bc0e7e7d67d914ce6edeb9ce24f60746f/swift/loss/causal_lm.py#L5)进行定制。例如:
```python
class CustomLoss(BaseLoss):
def __call__(self, outputs, labels, **kwargs) -> torch.Tensor:
pass
```
## Loss Scale
loss scale的mapping文件可以参考[这里](https://github.com/modelscope/ms-swift/blob/main/swift/loss_scale/mapping.py)。在pretrain和sft任务中,可训练token的loss是平均的,即每个token平等地对待。但在某些情况下,某些token需要被额外关注,并设置更高的权重或者对某些token不进行训练。loss_scale可以让开发者自由地定义自己的token权重。(预训练和SFT支持使用loss_scale控制token是否参与训练以及和其权重大小,RLHF中只支持控制token是否参与训练)
你可以通过继承LossScale基类,并实现`get_loss_scale`方法来自定义loss scale。
```python
class CustomLossScale(LossScale):
def get_loss_scale(self, context: str, **kwargs) -> Tuple[List[str], List[float]]:
...
```
`get_loss_scale`函数需要返回了一个Tuple,第一个返回是拆解后的字符串的列表,第二个参数是字符串对应的loss_scale的列表,float值代表了权重。例如下面的权重设置:
```text
["学习", "好", "数学", "是", "重要", "的"]
[1.0, 0.5, 2.0, 0.5, 2.0, 0.1]
```
例子中,我们更看重数学和重要两个词,因为其loss_scale为2.0。
当然我们也需要关注`__call__`方法的核心逻辑,即loss_scale基本策略(base_strategyall/default/last_round 对loss_scale的影响,具体参考[命令行参数文档](../Instruction/Command-line-parameters.md)的介绍。以及数据集中的'loss'字段对loss_scale的影响,参考[自定义数据集文档](../Customization/Custom-dataset.md)。
```python
if loss or loss is None and (self.base_strategy == 'all' or
(self.base_strategy == 'default' and is_assistant) or
(self.base_strategy == 'last_round' and is_assistant and is_last_round)):
new_context, loss_scale = self.get_loss_scale(context, query=query)
else:
new_context, loss_scale = [context], [0.]
```
此外你也可以使用[json配置文件](https://github.com/modelscope/ms-swift/tree/main/swift/loss_scale/config),继承内置的ConfigLossScale类,来自定义loss_scale。目前支持两种配置方式:字符串精确匹配和正则表达式匹配。你可以参考[Agent支持文档](../Instruction/Agent-support.md#loss_scale的使用)的内容进行理解。
- 字符串精确匹配,例如参考`react.json`, `qwen.json`。json中需要书写`Dict[str, List[float]]`的映射。字符串代表关键词,列表中需要有两个值。我们会根据关键词,将字符串切分成多段字符串。列表的第一个值代表关键词的权重,列表的第二个值代表该关键值后,下一关键词前的内容的权重。
- 正则表达式匹配,例如参考`ignore_empty_think.json`, `hermes.json`。json中需要书写`Dict[str, float]`的映射。字符串代表正则表达式pattern,浮点数代表匹配字符串的权重。
如何debug
```python
from swift import get_processor, get_template
data = {"messages": [
{"role": "user", "content": "今天的日期是多少?"},
{"role": "assistant", "content": (
"<think>\n我可以通过调用`get_date`函数来获取当前时间。\n</think>\n"
'<tool_call>\n{"name": "get_date", "arguments": {}}\n</tool_call>'
)}
]}
template = get_template(get_processor('Qwen/Qwen3-8B'), loss_scale='hermes')
template.set_mode('train')
inputs = template.encode(data)
print(template.safe_decode(inputs['labels']))
print(inputs['loss_scale'])
```
## Metrics
metrics的mapping文件可以参考[这里](https://github.com/modelscope/ms-swift/blob/main/swift/metrics/mapping.py)。该组件在ms-swift/Megatron-SWIFT中都有被使用。
- 如果是在ms-swift中被使用,你需要继承 base.py 中`EvalMetrics`基类,并实现`compute_metrics`函数,返回字典`Dict[str, float]`。你可以参考[NlgMetrics](https://github.com/modelscope/ms-swift/blob/0d7c9f5bc0e7e7d67d914ce6edeb9ce24f60746f/swift/metrics/nlg.py#L33)进行定制。
- 如果是在Megatron-SWIFT中被使用,你需要继承 utils.py 中`Metric`基类,并实现`update``compute`方法,compute方法需返回字典`Dict[str, float]`
你可以自定义metrics(当前只支持sft/pretrain/reranker/embedding任务),在训练时设置`--eval_metric <metric-name>`使用你定制的metrics。
## Optimizers
optimizer的mapping文件可以参考[这里](https://github.com/modelscope/ms-swift/blob/main/swift/optimizers/mapping.py)。如果你需要自定义优化器,你需要继承`OptimizerCallback`基类,并覆盖`create_optimizer`函数。训练时使用`--optimizer <optimizer-name>`指定自定义的优化器。
- 你可以参考[MultimodalOptimizerCallback](https://github.com/modelscope/ms-swift/blob/0d7c9f5bc0e7e7d67d914ce6edeb9ce24f60746f/swift/optimizers/multimodal.py#L43)进行实现,该类实现了vit_lr, aligner_lr的功能,即对vit, aligner和LLM分别使用不同的学习率。
## Tuner Plugin
Tuner插件的mapping文件可以参考[这里](https://github.com/modelscope/ms-swift/blob/main/swift/tuner_plugin/mapping.py)。如果你需要自定义tuner,你需要继承`Tuner`基类,并覆盖`prepare_model`, `save_pretrained`, `from_pretrained`函数。
- prepare_model: 该函数在训练前被调用,将原始模型进行处理与准备,使用tuner封装,并设置可训练参数。例如:你可以对某些层附加LoRA,对某些层进行冻结等。
- save_pretrained: 该函数在训练中被调用,对模型进行保存。
- from_pretrained: 该函数在推理/断点续训时被调用,准备模型并读取权重。
你可以参考[LoRALLMTuner](https://github.com/modelscope/ms-swift/blob/0d7c9f5bc0e7e7d67d914ce6edeb9ce24f60746f/swift/tuner_plugin/lora_llm.py#L24)进行实现,该类实现了对LLM进行LoRA训练,对ViT进行全参数训练的功能。
## ORM
example参考[这里](https://github.com/modelscope/ms-swift/blob/main/swift/rewards/orm.py)。
ORM是结果奖励模型。ORM一般使用正则表达式来进行,ORM决定了response是否是正确的。例如:
```python
class MathORM(ORM):
@staticmethod
def extract_boxed_result(text):
pattern = r'\\boxed{([^}]*)}'
match = re.search(pattern, text)
if match:
return match.group(1).strip()
else:
return None
def __call__(self, infer_requests: List[InferRequest], ground_truths: List[str],
**kwargs) -> List[float]:
rewards = []
predictions = [request.messages[-1]['content'] for request in infer_requests]
for prediction, ground_truth in zip(predictions, ground_truths):
res1 = MathORM.extract_boxed_result(prediction) or ''
res2 = MathORM.extract_boxed_result(ground_truth) or ''
rewards.append(float(res1.strip() == res2.strip()))
return rewards
orms = {
'math': MathORM,
}
```
在上面的代码中,我们定义了一个对数学response进行解析的过程,如果结果相同则返回score为1.0,否则为0.0。和PRM不同,这个类的infer中有一个额外参数`ground_truths`
该参数是对应的infer_requests的实际label(数据集中定义的标准response)。
## PRM
example参考[这里](https://github.com/modelscope/ms-swift/blob/main/swift/rewards/prm.py)。
PRM是过程奖励模型,PRM会在`swift sample`命令中使用。PRM需要支持的接口比较简单:
```python
class PRM:
def __init__(self):
# init here
pass
def __call__(self, infer_requests: List[InferRequest], **kwargs) -> List[Union[float, List[float]]]:
raise NotImplementedError
```
其中的InferRequest来自于`swift.infer_engine`,返回的`List[Union[float, List[float]]]`,列表中可能是reward也可能是若干reward。开发者可以在infer_requests中拿到queries和responses,并按照自己的方式进行切分,例如:
```text
Let's think step by step.
Step1: xxx
Step2: xxx
So, the answer is ...
```
开发者可以在这里对过程进行切分,并按batch传入PRM中进行推理并返回rewards。更通用来说,开发者可以在这里调用一个远端URL,例如一个闭源PRM大模型并返回rewards。
## 其他目录结构介绍
- arguments: 命令行参数定义,例如:`SftArguments`, `RLHFArguments`等。
- cli: swift命令行机制以及启动文件。例如`swift sft ...`等价于`python swift/cli/main.py sft ...`也等价于`python swift/cli/sft.py ...`
- config: deepspeed/fsdp2配置文件。
- dataloader: dataloader的实现,包括shard/dispatcher两种方式。
- dataset: 数据集相关模块实现,包括数据预处理、packing、流式数据等。内置数据集的注册在`dataset/dataset``dataset/data`文件夹内。具体参考[自定义数据集文档](Custom-dataset.md)。
- infer_engine: 推理引擎实现。包括transformers/vllm/sglang/lmdeploy为后端的推理引擎实现。
- megatron: Megatron-SWIFT 实现。
- model: 模型加载与注册。具体参考[自定义模型文档](Custom-model.md)[多模态模型注册最佳实践](../BestPractices/MLLM-Registration.md)。
- pipelines: `swift sft/rlhf/infer`等主函数pipeline实现,包括`sft_main/rlhf_main/infer_main`等。
- rlhf_trainers: GRPO/GKD/DPO/KTO/RM等算法的Trainer实现。
- rollout: RL算法中rollout过程的采样实现。
- rewards: RL算法中的奖励函数实现,支持自定义奖励计算逻辑。
- template: 对话模板的实现与注册,包含各个任务将messages转换成input_ids的逻辑,以及data_collator相关逻辑。具体参考[自定义模型文档](Custom-model.md)[多模态模型注册最佳实践](../BestPractices/MLLM-Registration.md)。
- trainers: 预训练/SFT/Embedding/Reranker/序列分类任务的Trainer实现。
- ui: `swift web-ui`界面训练与推理实现。
+427
View File
@@ -0,0 +1,427 @@
# 自定义数据集
自定义数据集的接入方法有三种,对预处理函数的控制能力逐渐加强,但接入难度逐步增加。例如,方案一最为方便,但对预处理函数的控制能力最弱,需要预先对数据集进行转换,传入特定格式的数据集:
1. 【推荐】直接使用命令行传参的方式接入,即`--dataset <dataset_path1> <dataset_path2>`。这将使用AutoPreprocessor将数据集转换为标准格式(支持4种数据集格式,具体查看下面对AutoPreprocessor的介绍)。你可以使用`--columns`进行列名转换。支持传入csv、json、jsonl、txt、文件夹(例如git clone开源数据集)。该方案不需要修改dataset_info.json,适合刚接触ms-swift的用户,下面两种方案适合对ms-swift进行拓展的开发者。
2. 添加数据集到`dataset_info.json`中,可以参考ms-swift内置的[dataset_info.json](https://github.com/modelscope/ms-swift/blob/main/swift/dataset/data/dataset_info.json)。该方案也将使用AutoPreprocessor将数据集转换为标准格式。dataset_info.json为数据集元信息的list,每一项元信息必填ms_dataset_id/hf_dataset_id/dataset_path中的一项,通过`columns`字段进行列名转换。添加到`dataset_info.json`或者注册的数据集在运行[run_dataset_info.py](https://github.com/modelscope/ms-swift/blob/main/scripts/utils/run_dataset_info.py)时将自动产生[支持的数据集文档](https://swift.readthedocs.io/zh-cn/latest/Instruction/Supported-models-and-datasets.html)。此外,你可以采用外接`dataset_info.json`的方式,使用`--custom_dataset_info xxx.json`解析json文件(方便pip install而非git clone的用户),然后指定`--dataset <dataset_id/dataset_dir/dataset_path>`
3. 手动注册数据集,具有最灵活的预处理函数定制能力,支持使用函数对数据集进行预处理,但难度较高。可以参考[内置数据集](https://github.com/modelscope/ms-swift/blob/main/swift/dataset/dataset/llm.py)或者[examples](https://github.com/modelscope/ms-swift/blob/main/examples/custom)中的样例。你可以通过指定`--external_plugins xxx.py`解析外置注册内容(方便pip install而非git clone的用户)。
- 方案一和二在实现中借助了方案三,只是注册的过程为自动发生。
以下将对`AutoPreprocessor`可以处理的数据集格式进行介绍:
ms-swift的标准数据集格式可接受的keys包括: 'messages'、'rejected_response'、'label'、'images'、'videos'、'audios'、'tools'和'objects'。其中'messages'是必需的key'rejected_response'用于DPO等RLHF训练,'label'用于KTO训练和分类模型训练,'images'、'videos'、'audios'用于存储多模态数据的路径或者url'tools'用于Agent任务,'objects'用于grounding任务。
ms-swift中存在三种核心预处理器:`MessagesPreprocessor``AlpacaPreprocessor``ResponsePreprocessor`。MessagesPreprocessor用于将类messages和sharegpt格式的数据集转换为标准格式,AlpacaPreprocessor则转换alpaca格式的数据集,ResponsePreprocessor则转换类query/response格式的数据集。`AutoPreprocessor`则自动选择合适的预处理进行处理。
以下四种格式在`AutoPreprocessor`处理下都会转换成ms-swift标准格式中的messages字段,即都可以直接使用`--dataset <dataset-path>`接入:
messages格式(标准格式):
```jsonl
{"messages": [{"role": "system", "content": "<system>"}, {"role": "user", "content": "<query1>"}, {"role": "assistant", "content": "<response1>"}, {"role": "user", "content": "<query2>"}, {"role": "assistant", "content": "<response2>"}]}
```
- 注意:system部分是可选的。数据集中的system优先级高于命令行传入的`--system`,最后是定义在template中的`default_system`
sharegpt格式:
```jsonl
{"system": "<system>", "conversation": [{"human": "<query1>", "assistant": "<response1>"}, {"human": "<query2>", "assistant": "<response2>"}]}
```
query-response格式:
```jsonl
{"system": "<system>", "query": "<query2>", "response": "<response2>", "history": [["<query1>", "<response1>"]]}
```
注意:以下字段会自动转成对应的system、query、response字段。(solution字段会保留)
- system: 'system', 'system_prompt'.
- query: 'query', 'prompt', 'input', 'instruction', 'question', 'problem'.
- response: 'response', 'answer', 'output', 'targets', 'target', 'answer_key', 'answers', 'solution', 'text', 'completion', 'content'.
alpaca格式:
```jsonl
{"system": "<system>", "instruction": "<query-inst>", "input": "<query-input>", "output": "<response>"}
```
- 注意:instruction和input字段将组合成query字段。若instruction和input不等于空字符串,`query = f'{instruction}\n{input}'`
## 标准数据集格式
以下给出ms-swift的标准数据集格式,其中system字段是可选的,默认使用template中定义的`default_system`。之前介绍的4种数据集格式也可以被AutoPreprocessor处理成标准数据集格式。
### 预训练
```jsonl
{"messages": [{"role": "assistant", "content": "I love music"}]}
{"messages": [{"role": "assistant", "content": "教练我要打篮球"}]}
{"messages": [{"role": "assistant", "content": "西红柿鸡蛋盖饭和地三鲜盖饭哪个更权威"}]}
```
### 监督微调
```jsonl
{"messages": [{"role": "system", "content": "你是个有用无害的助手"}, {"role": "user", "content": "告诉我明天的天气"}, {"role": "assistant", "content": "明天天气晴朗"}]}
{"messages": [{"role": "system", "content": "你是个有用无害的数学计算器"}, {"role": "user", "content": "1+1等于几"}, {"role": "assistant", "content": "等于2"}, {"role": "user", "content": "再加1呢"}, {"role": "assistant", "content": "等于3"}]}
```
- 可以通过增加"loss"字段,控制对应的模型回复部分("role"为"assistant")是否计算损失。默认该字段为None。若"loss"设置为true,则对应content进行损失计算(具体loss_scale依旧由`--loss_scale`决定);若"loss"设置为false,则对应content不进行损失计算。需要注意的是,该功能只对"role"为"assistant"的部分生效;该功能优先级高于命令行参数 `--loss_scale`的基本策略(即'default'、'last_round'、'all'部分),例如,loss_scale为`'default+ignore_empty_think'`时,"loss"字段优先级高于"default",但'ignore_empty_think'依旧发挥作用。
- 可以通过增加"loss_scale"字段,控制对应的模型回复部分("role"为"assistant")的loss_scale。(ms-swift>=4.2.0)默认为None。该功能优先级高于命令行参数 `--loss_scale`的其他策略部分,例如:'ignore_empty_think', 'hermes'等。当loss_scale中有`>1`的数字出现时,你需要额外设置`--is_binary_loss_scale false`参数。
```jsonl
{"messages": [{"role": "user", "content": "你好"}, {"role": "assistant", "content": "你好,有什么可以帮助你的吗?", "loss": false}, {"role": "user", "content": "1+1等于几?"}, {"role": "assistant", "content": "等于2", "loss": true}]}
{"messages": [{"role": "user", "content": "hello!"}, {"role": "assistant", "content": "<think>\n...\n</think>\n", "loss_scale": 1.0}, {"role": "assistant", "content": "hi!", "loss_scale": 2.0}, {"role": "user", "content": "1+1=?"}, {"role": "assistant", "content": "<think>\n...\n</think>\n1+1=3", "loss": false}]}
```
使用以下脚本进行测试:
```python
from swift import get_processor, get_template
data = {"messages": [
{"role": "user", "content": "hello!"},
{"role": "assistant", "content": "<think>\n...\n</think>\n", "loss_scale": 1.},
{"role": "assistant", "content": "hi!", "loss_scale": 2.},
{"role": "user", "content": "1+1=?"},
{"role": "assistant", "content": "<think>\n...\n</think>\n1+1=3", "loss": False},
]}
template = get_template(get_processor('Qwen/Qwen3-8B'), loss_scale='default+ignore_empty_think',
is_binary_loss_scale=False)
template.set_mode('train')
inputs = template.encode(data)
print(template.safe_decode(inputs['labels']))
print(inputs['loss_scale'])
```
注意:如果对messages中连续的"tool_call"设置"loss"/"loss_scale",则只生效最前面"tool_call"的配置。例如:
```jsonl
{"messages": [..., {"role": "tool_call", "content": "{\"name\": \"realtime_aqi\", \"arguments\": {\"city\": \"北京\"}}", "loss": false}, {"role": "tool_call", "content": "{\"name\": \"realtime_aqi\", \"arguments\": {\"city\": \"上海\"}}"}, ...]}
```
- "chat_template_kwargs"字段,(需ms-swift>=4.3.0),你可以通过在数据集中传入该字段**样本级别**控制template的min_pixels, max_pixels, fps等多模态参数,以及enable_thinking(推理时)等参数。以下为不同模型支持的参数:
- 其中"enable_thinking", "preserve_thinking", "response_prefix"支持所有模型(推理时生效);"max_pixels"参数支持所有多模态模型。
- Qwen系列多模态模型:min_pixels, max_pixels, fps等qwen_vl_utils/qwen_omni_utils支持的参数。
```jsonl
{"messages": [{"role": "user", "content": "<image>这是什么"}, {"role": "assistant", "content": "这是一只兔子", "loss": false}], "chat_template_kwargs": {"max_pixels": 1048576}}
{"messages": [{"role": "user", "content": "who are you?"}], "chat_template_kwargs": {"enable_thinking": false}}
```
#### channel loss
如果你要使用channel loss,你需要设置`--enable_channel_loss true`,并在数据集中增加"channel"字段。channel loss兼容packing/padding_free/loss_scale等技术。
```jsonl
{"messages": [{"role": "system", "content": "你是个有用无害的助手"}, {"role": "user", "content": "告诉我明天的天气"}, {"role": "assistant", "content": "明天天气晴朗"}], "channel": "general"}
{"messages": [{"role": "system", "content": "你是个有用无害的数学计算器"}, {"role": "user", "content": "1+1等于几"}, {"role": "assistant", "content": "等于2"}, {"role": "user", "content": "再加1呢"}, {"role": "assistant", "content": "等于3"}], "channel": "math"}
```
### RLHF
#### DPO/ORPO/CPO/SimPO/RM
```jsonl
{"messages": [{"role": "system", "content": "你是个有用无害的助手"}, {"role": "user", "content": "告诉我明天的天气"}, {"role": "assistant", "content": "明天天气晴朗"}], "rejected_response": "我不知道"}
{"messages": [{"role": "system", "content": "你是个有用无害的数学计算器"}, {"role": "user", "content": "1+1等于几"}, {"role": "assistant", "content": "等于2"}, {"role": "user", "content": "再加1呢"}, {"role": "assistant", "content": "等于3"}], "rejected_response": "我不知道"}
```
多模态数据的格式参考[多模态数据集](#多模态), 额外加入如`images`的列表示其他模态输入。当需要为偏好对数据关联不同的图片信息时,可通过`rejected_images`字段标注拒绝回答对应的图片信息。
对齐数据集中要求`rejected_images``rejected_response`至少提供一个。
> 注: RM 额外支持 margin 列,参考[RM文档](../Instruction/RLHF.md#rm)
当然,你也可以直接使用`rejected_messages`,而不是只提供`rejected_response`/`rejected_images`,这将提供更大的灵活度(例如多模态/agent场景)。若使用rejected_messages,在多模态场景下,你需要额外传入"rejected_images""rejected_audios""rejected_videos"等内容;在Agent场景下,你需要额外传入"rejected_tools"等内容。多模态数据格式例子如下:
- 若使用`rejected_response`'rejected_images/rejected_audios/rejected_videos/rejected_tools'的默认值为'images/audios/videos/tools';若使用`rejected_messages`,则需要额外传入。
```jsonl
{"messages": [{"role": "user", "content": "<image>这是什么"}, {"role": "assistant", "content": "这是一只小猫咪。"}], "images": ["cat.png"], "rejected_messages": [{"role": "user", "content": "<image>这是什么"}, {"role": "assistant", "content": "这是一只小狗。"}], "rejected_images": ["cat.png"]}
{"messages": [{"role": "user", "content": "<image>这是什么"}, {"role": "assistant", "content": "这是一只小猫咪。"}], "images": ["cat.png"], "rejected_messages": [{"role": "user", "content": "<image>这是什么"}, {"role": "assistant", "content": "这是一只小猫咪。"}], "rejected_images": ["dog.png"]}
```
以上格式等价于:
```jsonl
{"messages": [{"role": "user", "content": "<image>这是什么"}, {"role": "assistant", "content": "这是一只小猫咪。"}], "images": ["cat.png"], "rejected_response": "这是一只小狗。"}
{"messages": [{"role": "user", "content": "<image>这是什么"}, {"role": "assistant", "content": "这是一只小猫咪。"}], "images": ["cat.png"], "rejected_images": ["dog.png"]}
# 例子一也可写成:
{"messages": [{"role": "user", "content": "<image>这是什么"}, {"role": "assistant", "content": "这是一只小猫咪。"}], "images": ["cat.png"], "rejected_response": [{"role": "assistant", "content": "这是一只小狗。"}]}
```
你也可以将Agent数据集组织成以下形式:
```jsonl
# 会寻找`messages`最后一个user的位置,并替换之后的内容为`rejected_response`组成`rejected_messages`
{"tools": "[{\"type\": \"function\", \"function\": {\"name\": \"realtime_aqi\", \"description\": \"天气预报。获取实时空气质量。当前空气质量,PM2.5PM10信息\", \"parameters\": {\"type\": \"object\", \"properties\": {\"city\": {\"type\": \"string\", \"description\": \"城市名,例如:上海\"}}, \"required\": [\"city\"]}}}]", "messages": [{"role": "user", "content": "北京和上海今天的天气情况"}, {"role": "tool_call", "content": "{\"name\": \"realtime_aqi\", \"arguments\": {\"city\": \"北京\"}}"}, {"role": "tool_call", "content": "{\"name\": \"realtime_aqi\", \"arguments\": {\"city\": \"上海\"}}"}, {"role": "tool_response", "content": "{\"city\": \"北京\", \"aqi\": \"10\", \"unit\": \"celsius\"}"}, {"role": "tool_response", "content": "{\"city\": \"上海\", \"aqi\": \"72\", \"unit\": \"fahrenheit\"}"}, {"role": "assistant", "content": "根据天气预报工具,北京今天的空气质量指数为10,属于良好水平;上海今天的空气质量指数为72,属于轻度污染水平。"}], "rejected_response": [{"role": "assistant", "content": "我不知道。"}]}
```
如何debug:
```python
from swift import get_processor, get_template
data = {"tools": "[{\"type\": \"function\", \"function\": {\"name\": \"realtime_aqi\", \"description\": \"天气预报。获取实时空气质量。当前空气质量,PM2.5,PM10信息\", \"parameters\": {\"type\": \"object\", \"properties\": {\"city\": {\"type\": \"string\", \"description\": \"城市名,例如:上海\"}}, \"required\": [\"city\"]}}}]", "messages": [{"role": "user", "content": "北京和上海今天的天气情况"}, {"role": "tool_call", "content": "{\"name\": \"realtime_aqi\", \"arguments\": {\"city\": \"北京\"}}"}, {"role": "tool_call", "content": "{\"name\": \"realtime_aqi\", \"arguments\": {\"city\": \"上海\"}}"}, {"role": "tool_response", "content": "{\"city\": \"北京\", \"aqi\": \"10\", \"unit\": \"celsius\"}"}, {"role": "tool_response", "content": "{\"city\": \"上海\", \"aqi\": \"72\", \"unit\": \"fahrenheit\"}"}, {"role": "assistant", "content": "根据天气预报工具,北京今天的空气质量指数为10,属于良好水平;上海今天的空气质量指数为72,属于轻度污染水平。"}], "rejected_response": [{"role": "assistant", "content": "我不知道。"}]}
template = get_template(get_processor('Qwen/Qwen3.5-4B'), loss_scale='last_round')
template.set_mode('rlhf') # 具体查看命令行文档 `template_mode` 参数的介绍
inputs = template.encode(data)
print(template.safe_decode(inputs['chosen_labels']))
print(template.safe_decode(inputs['rejected_labels']))
```
#### KTO
```jsonl
{"messages": [{"role": "system", "content": "你是个有用无害的助手"}, {"role": "user", "content": "告诉我明天的天气"}, {"role": "assistant", "content": "我不知道"}], "label": false}
{"messages": [{"role": "system", "content": "你是个有用无害的数学计算器"}, {"role": "user", "content": "1+1等于几"}, {"role": "assistant", "content": "等于2"}, {"role": "user", "content": "再加1呢"}, {"role": "assistant", "content": "等于3"}], "label": true}
```
#### PPO/GRPO
```jsonl
{"messages": [{"role": "system", "content": "你是个有用无害的助手"}, {"role": "user", "content": "告诉我明天的天气"}]}
{"messages": [{"role": "system", "content": "你是个有用无害的数学计算器"}, {"role": "user", "content": "1+1等于几"}, {"role": "assistant", "content": "等于2"}, {"role": "user", "content": "再加1呢"}]}
{"messages": [{"role": "user", "content": "你的名字是什么"}]}
```
- 注意:GRPO会透传所有额外的字段内容给ORM,而不像其他训练方法,默认将额外的字段删除。例如: 你可以额外传入'solution'。自定义的ORM需要包含一个位置参数completions,其他为关键词参数,由数据集额外字段透传。
#### GKD
数据集格式如下
```jsonl
{"messages": [{"role": "system", "content": "你是个有用无害的助手"}, {"role": "user", "content": "告诉我明天的天气"}, {"role": "assistant", "content": "明天天气晴朗"}]}
{"messages": [{"role": "system", "content": "你是个有用无害的数学计算器"}, {"role": "user", "content": "1+1等于几"}, {"role": "assistant", "content": "等于2"}, {"role": "user", "content": "再加1呢"}, {"role": "assistant", "content": "等于3"}]}
```
若是在线生成训练(lmbda>0),不需要response部分(学生模型在线生成,数据集中的response部分会被删除)
```jsonl
{"messages": [{"role": "system", "content": "你是个有用无害的助手"}, {"role": "user", "content": "告诉我明天的天气"}]}
{"messages": [{"role": "system", "content": "你是个有用无害的数学计算器"}, {"role": "user", "content": "1+1等于几"}, {"role": "assistant", "content": "等于2"}, {"role": "user", "content": "再加1呢"}]}
```
### 序列分类
**单标签任务**
```jsonl
{"messages": [{"role": "user", "content": "今天天气真好呀"}], "label": 1}
{"messages": [{"role": "user", "content": "今天真倒霉"}], "label": 0}
{"messages": [{"role": "user", "content": "好开心"}], "label": 1}
```
**多标签任务**
```jsonl
{"messages": [{"role": "user", "content": "<sentence>"}], "label": []}
{"messages": [{"role": "user", "content": "<sentence>"}], "label": [0, 2]}
{"messages": [{"role": "user", "content": "<sentence>"}], "label": [1, 3, 5]}
```
**单回归任务**
```jsonl
{"messages": [{"role": "user", "content": "求两句话的相似度,范围为0-1。\nsentence1: <sentence1>\nsentence2: <sentence2>"}], "label": 0.8}
```
**多回归任务**
```jsonl
{"messages": [{"role": "user", "content": "<sentence>"}], "label": [1.2, -0.6, 0.8]}
```
### Embedding
请参考[embedding训练文档](../BestPractices/Embedding.md#数据集格式)
### Reranker
请参考[Reranker训练文档](../BestPractices/Reranker.md#数据集格式)
### 多模态
对于多模态数据集,和上述任务的格式相同。区别在于增加了`images`, `videos`, `audios`几个key,分别代表多模态资源的url或者path(推荐使用绝对路径),`<image>` `<video>` `<audio>`标签代表了插入图片/视频/音频的位置,ms-swift支持多图片/视频/音频的情况。这些特殊tokens将在预处理的时候进行替换,参考[这里](https://github.com/modelscope/ms-swift/blob/main/swift/template/templates/qwen.py#L198)。下面给出的四条示例分别展示了纯文本,以及包含图像、视频和音频数据的数据格式。
预训练:
```
{"messages": [{"role": "assistant", "content": "预训练的文本在这里"}]}
{"messages": [{"role": "assistant", "content": "<image>是一只小狗,<image>是一只小猫"}], "images": ["/xxx/x.jpg", "/xxx/x.png"]}
{"messages": [{"role": "assistant", "content": "<audio>描述了今天天气真不错"}], "audios": ["/xxx/x.wav"]}
{"messages": [{"role": "assistant", "content": "<image>是一个大象,<video>是一只狮子在跑步"}], "images": ["/xxx/x.jpg"], "videos": ["/xxx/x.mp4"]}
```
微调:
```jsonl
{"messages": [{"role": "user", "content": "浙江的省会在哪?"}, {"role": "assistant", "content": "浙江的省会在杭州。"}]}
{"messages": [{"role": "user", "content": "<image><image>两张图片有什么区别"}, {"role": "assistant", "content": "前一张是小猫,后一张是小狗"}], "images": ["/xxx/x.jpg", "/xxx/x.png"]}
{"messages": [{"role": "user", "content": "<audio>语音说了什么"}, {"role": "assistant", "content": "今天天气真好呀"}], "audios": ["/xxx/x.mp3"]}
{"messages": [{"role": "system", "content": "你是个有用无害的助手"}, {"role": "user", "content": "<image>图片中是什么,<video>视频中是什么"}, {"role": "assistant", "content": "图片中是一个大象,视频中是一只小狗在草地上奔跑"}], "images": ["/xxx/x.jpg"], "videos": ["/xxx/x.mp4"]}
```
- 注意:以下字段会自动转成对应的images, videos, audios字段。
- images: image, images.
- videos: video, videos.
- audios: audio, audios.
- 如果需要传入base64格式而不是文件路径,以下为样本例子:`"videos": ['data:video/mp4;base64,{base64_encoded}']`, `"images": ['data:image/jpg;base64,{base64_encoded}']`
- 若你希望直接传入视频帧,而不是视频,你可以使用以下格式:`"videos": [["/xxx/x.png", "/xxx/y.png"], ["/xxx/a.png", "/xxx/b.png", "/xxx/c.png"]]`。该格式只有部分模型支持,包括Qwen2/2.5/3-VL、Qwen2.5/3-Omni以及其衍生模型。
多模态模型的RLHF和序列分类的数据格式可以参考纯文本大模型的格式,并在此基础上增加`images`等字段。
#### grounding
如果是grounding(物体检测)任务,ms-swift支持两种方式:
1. 直接使用对应模型grounding任务的数据集格式,例如qwen2-vl的格式如下:
```jsonl
{"messages": [{"role": "system", "content": "You are a helpful assistant."}, {"role": "user", "content": "<image>描述图像"}, {"role": "assistant", "content": "<|object_ref_start|>一只狗<|object_ref_end|><|box_start|>(221,423),(569,886)<|box_end|>和<|object_ref_start|>一个女人<|object_ref_end|><|box_start|>(451,381),(733,793)<|box_end|>正在沙滩上玩耍"}], "images": ["/xxx/x.jpg"]}
{"messages": [{"role": "system", "content": "You are a helpful assistant."}, {"role": "user", "content": "<image>找到图像中的<|object_ref_start|>羊<|object_ref_end|>"}, {"role": "assistant", "content": "<|box_start|>(101,201),(150,266)<|box_end|><|box_start|>(401,601),(550,666)<|box_end|>"}], "images": ["/xxx/x.jpg"]}
{"messages": [{"role": "system", "content": "You are a helpful assistant."}, {"role": "user", "content": "<image>帮我打开谷歌浏览器"}, {"role": "assistant", "content": "Action: click(start_box='<|box_start|>(246,113)<|box_end|>')"}], "images": ["/xxx/x.jpg"]}
```
使用这种类型的数据需要注意:
- 不同模型grounding任务的特殊字符和数据集格式不同。
- 不同模型对bbox是否归一化的处理不同。例如:qwen2.5-vl使用绝对坐标,而qwen2/3-vl、internvl2.5需要对bbox的坐标进行千分位坐标归一化。
- 注意:Qwen2.5-VL采用绝对坐标,因此要小心每次的图像缩放,如果使用方案一的数据集格式,你需要预先对图像进行resize(H和W需要是28的系数),并根据该尺寸缩放坐标点。如果使用方案二的数据集格式,ms-swift会帮助你处理图像的缩放问题,你依旧可以使用`MAX_PIXELS`或者`--max_pixels`等进行图像缩放(仅训练,推理场景,你依旧需要自己处理图像的缩放问题)。
2. 使用ms-swift的grounding数据格式:
```jsonl
{"messages": [{"role": "system", "content": "You are a helpful assistant."}, {"role": "user", "content": "<image>描述图像"}, {"role": "assistant", "content": "<ref-object><bbox>和<ref-object><bbox>正在沙滩上玩耍"}], "images": ["/xxx/x.jpg"], "objects": {"ref": ["一只狗", "一个女人"], "bbox": [[331.5, 761.4, 853.5, 1594.8], [676.5, 685.8, 1099.5, 1427.4]]}}
{"messages": [{"role": "system", "content": "You are a helpful assistant."}, {"role": "user", "content": "<image>找到图像中的<ref-object>"}, {"role": "assistant", "content": "<bbox><bbox>"}], "images": ["/xxx/x.jpg"], "objects": {"ref": ["羊"], "bbox": [[90.9, 160.8, 135, 212.8], [360.9, 480.8, 495, 532.8]]}}
{"messages": [{"role": "system", "content": "You are a helpful assistant."}, {"role": "user", "content": "<image>帮我打开谷歌浏览器"}, {"role": "assistant", "content": "Action: click(start_box='<bbox>')"}], "images": ["/xxx/x.jpg"], "objects": {"ref": [], "bbox": [[615, 226]]}}
```
该格式将自动转换数据集格式为对应模型的grounding任务格式,且选择对应模型的bbox归一化方式。该格式比通用格式多了objects字段,该字段包含的字段有:
- ref: 用于替换messages中的`<ref-object>`。ref的长度需要与`<ref-object>`的数量一致。
- bbox: 用于替换messages中的`<bbox>`。若bbox中每个box长度为2,则代表x和y坐标,若box长度为4,则代表2个点的x和y坐标。bbox的长度需要与`<bbox>`的数量一致。
- 注意:`<ref-object>``<bbox>`并没有对应关系,ref和bbox各自替换各自的占位符。
- bbox_type: 可选项为'real''norm1'。默认为'real',即bbox为真实bbox值。若是'norm1',则bbox已经归一化为0~1。
- image_id: 通常用于多图grounding任务。该参数只有当bbox_type为'real'时生效,代表bbox对应的图片是第几张,用于缩放bbox。索引从0开始,默认全为第0张。image_id的数量需要和bbox的数量一致。例如:若bbox的长度为10,images的长度为2,那么image_id的长度需要是10,其值需要在`{0, 1}`集合内。
对于Qwen2.5-VL/Qwen3-VL,你可以使用环境`QWENVL_BBOX_FORMAT='new'`(默认为'legacy'),以兼容[官方cookbook](https://github.com/QwenLM/Qwen3-VL/blob/main/cookbooks/2d_grounding.ipynb)格式。并将数据集定义成以下格式:
```jsonl
{"messages": [{"role": "user", "content": "<image>找到图像中的<ref-object>"}, {"role": "assistant", "content": "[\n\t{\"bbox_2d\": <bbox>, \"label\": \"<ref-object>\"},\n\t{\"bbox_2d\": <bbox>, \"label\": \"<ref-object>\"}\n]"}], "images": ["cat.png"], "objects": {"ref": ["羊", "羊", "羊"], "bbox": [[90.9, 160.8, 135, 212.8], [360.9, 480.8, 495, 532.8]]}}
```
测试ms-swift格式的grounding数据格式的最终格式:
```python
import os
os.environ["MAX_PIXELS"] = "1003520"
from swift import get_processor, get_template
processor = get_processor('Qwen/Qwen2.5-VL-7B-Instruct')
template = get_template(processor)
data = {...}
template.set_mode('train')
encoded = template.encode(data, return_template_inputs=True)
print(f'[INPUT_IDS] {template.safe_decode(encoded["input_ids"])}\n')
print(f'[LABELS] {template.safe_decode(encoded["labels"])}')
print(f'images: {encoded["template_inputs"].images}')
```
### Agent格式
这里分别提供了纯文本Agent和多模态Agent的示例数据样本:
```jsonl
{"tools": "[{\"type\": \"function\", \"function\": {\"name\": \"realtime_aqi\", \"description\": \"天气预报。获取实时空气质量。当前空气质量,PM2.5PM10信息\", \"parameters\": {\"type\": \"object\", \"properties\": {\"city\": {\"type\": \"string\", \"description\": \"城市名,例如:上海\"}}, \"required\": [\"city\"]}}}]", "messages": [{"role": "user", "content": "北京和上海今天的天气情况"}, {"role": "tool_call", "content": "{\"name\": \"realtime_aqi\", \"arguments\": {\"city\": \"北京\"}}"}, {"role": "tool_call", "content": "{\"name\": \"realtime_aqi\", \"arguments\": {\"city\": \"上海\"}}"}, {"role": "tool_response", "content": "{\"city\": \"北京\", \"aqi\": \"10\", \"unit\": \"celsius\"}"}, {"role": "tool_response", "content": "{\"city\": \"上海\", \"aqi\": \"72\", \"unit\": \"fahrenheit\"}"}, {"role": "assistant", "content": "根据天气预报工具,北京今天的空气质量指数为10,属于良好水平;上海今天的空气质量指数为72,属于轻度污染水平。"}]}
{"tools": "[{\"type\": \"function\", \"function\": {\"name\": \"click\", \"description\": \"点击屏幕中的某个位置\", \"parameters\": {\"type\": \"object\", \"properties\": {\"x\": {\"type\": \"integer\", \"description\": \"横坐标,表示屏幕上的水平位置\"}, \"y\": {\"type\": \"integer\", \"description\": \"纵坐标,表示屏幕上的垂直位置\"}}, \"required\": [\"x\", \"y\"]}}}]", "messages": [{"role": "user", "content": "<image>现在几点了?"}, {"role": "assistant", "content": "<think>\n我可以通过打开日历App来获取当前时间。\n</think>\n"}, {"role": "tool_call", "content": "{\"name\": \"click\", \"arguments\": {\"x\": 105, \"y\": 132}}"}, {"role": "tool_response", "content": "{\"images\": \"<image>\", \"status\": \"success\"}"}, {"role": "assistant", "content": "成功打开日历App,现在的时间为中午11点"}], "images": ["desktop.png", "calendar.png"]}
```
- agent_template为"react_en", "hermes"等情况下,该格式适配所有模型Agent训练,可以轻松在不同模型间切换。
- 其中tools是一个包含tool列表的json字符串,messages中role为'tool_call'和'tool_response/tool'的content部分都需要是json字符串。
- tools字段将在训练/推理时和`{"role": "system", ...}"`部分组合,根据agent_template组成完整的system部分。
- `{"role": "tool_call", ...}`部分将根据agent_template自动转成对应格式的`{"role": "assistant", ...}`,多条连续的`{"role": "assistant", ...}`将拼接在一起组成完整的assistant_content。
- `{"role": "tool_response", ...}`也可以写成`{"role": "tool", ...}`,这两种写法是等价的。该部分也将根据`agent_template`自动转换格式。该部分在训练时将不进行损失的计算,角色类似于`{"role": "user", ...}`
- 该格式支持并行调用工具,例子参考第一条数据样本。多模态Agent数据样本中`<image>`标签数量应与"images"长度相同,其标签位置代表图像特征的插入位置。当然也支持其他模态,例如audios, videos。
- 注意:您也可以手动将数据处理为role为system/user/assistant的messages格式。agent_template的作用是将其中的tools字段以及role为tool_call和tool_response的messages部分,自动映射为标准的role为system/user/assistant的messages格式。
- 更多请参考[Agent文档](../Instruction/Agent-support.md)。
### 文生图格式
```jsonl
{"messages": [{"role": "system", "content": "你是个有用无害的助手"}, {"role": "user", "content": "给我画出一个苹果"}, {"role": "assistant", "content": "<image>"}], "images": ["/xxx/x.jpg"]}
```
## dataset_info.json
可以参考ms-swift内置的[dataset_info.json](https://github.com/modelscope/ms-swift/blob/main/swift/dataset/data/dataset_info.json)。该方案使用AutoPreprocessor预处理函数将数据集转换为标准格式。dataset_info.json文件中包含了数据集元信息的list,以下为一些例子:
```json
[
{
"ms_dataset_id": "xxx/xxx"
},
{
"dataset_path": "<dataset_dir/dataset_path>"
},
{
"ms_dataset_id": "<dataset_id>",
"subsets": ["v1"],
"split": ["train", "validation"],
"columns": {
"input": "query",
"output": "response"
}
},
{
"ms_dataset_id": "<dataset_id>",
"hf_dataset_id": "<hf_dataset_id>",
"subsets": [{
"subset": "subset1",
"columns": {
"problem": "query",
"content": "response"
}
},
{
"subset": "subset2",
"columns": {
"messages": "_",
"new_messages": "messages"
}
}]
}
]
```
支持以下参数:
- ms_dataset_id: 参考DatasetMeta参数。
- hf_dataset_id: 参考DatasetMeta参数。
- dataset_path: 参考DatasetMeta参数。
- dataset_name: 参考DatasetMeta参数。
- subsets: 参考DatasetMeta参数。
- split: 参考DatasetMeta参数。
- columns: 在数据集进行预处理前,对数据集进行列名转换。
## 数据集注册
register_dataset会在`DATASET_MAPPING`中注册数据集,调用函数`register_dataset(dataset_meta)`即可完成数据集注册,其中dataset_meta将存储模型的元信息。DatasetMeta的参数列表如下:
- ms_dataset_id: ModelScope的dataset_id,默认为None。
- hf_dataset_id: HuggingFace的dataset_id,默认为None。
- dataset_path: 数据集**文件/文件夹**的本地路径(推荐使用绝对路径)。默认为None。
- dataset_name: 数据集别名,可以通过`--dataset <dataset_name>`指定数据集,这在dataset_path很长时很方便。默认为None。
- subsets: 子数据集的名字列表或者`SubsetDataset`对象的列表,默认为`['default']`。(只有dataset_id或者dataset_dirgit clone开源数据集)有子数据集和split的概念)。
- split: 默认为`['train']`
- preprocess_func: 预处理函数或可调用对象,默认为`AutoPreprocessor()`。该预处理函数接口为传入`HfDataset`,并返回满足标准格式的`HfDataset`
- load_function: 默认为`DatasetLoader.load`。若需要自定义载入函数,则该载入函数需返回满足标准格式的`HfDataset`,这将抛弃ms-swift的数据集载入机制,提供给用户最大的自由度。通常该参数不需要进行修改。
以下介绍注册数据集的例子:
```python
from swift.dataset import (
ResponsePreprocessor, DatasetMeta, register_dataset, SubsetDataset, load_dataset
)
from typing import Dict, Any
class CustomPreprocessor(ResponsePreprocessor):
def preprocess(self, row: Dict[str, Any]) -> Dict[str, Any]:
query = f"""任务:判断下面两句话语意是否相似。
句子1: {row['text1']}
句子2: {row['text2']}
请输出类别[0/1]: 0代表含义不同, 1代表含义相似。
"""
response = str(row['label'])
row = {
'query': query,
'response': response
}
return super().preprocess(row)
register_dataset(
DatasetMeta(
ms_dataset_id='swift/financial_classification',
subsets=[SubsetDataset('train', split=['train']), SubsetDataset('test', split=['test'])],
preprocess_func=CustomPreprocessor(),
))
if __name__ == '__main__':
# load_dataset returns train_dataset and val_dataset based on `split_dataset_ratio`
# Here, since we didn't pass `split_dataset_ratio` (defaults to 0), we take the first one (index 0)
dataset = load_dataset('swift/financial_classification:train')[0]
test_dataset = load_dataset('swift/financial_classification:test')[0]
print(f'dataset[0]: {dataset[0]}')
print(f'test_dataset[0]: {test_dataset[0]}')
```
+38
View File
@@ -0,0 +1,38 @@
# 自定义模型
ms-swift内置的模型,你可以直接通过指定model_id或者model_path来使用:`--model <model_id_or_path>`。ms-swift会根据model_id/model_path的后缀和`config.json`文件来判断model_type。
每种model_type都有唯一的模型结构、template和加载方式。当然,你也可以手动传入`--model_type``--template`来进行覆盖。ms-swift已支持的model_type和template可以查看[支持的模型与数据集](../Instruction/Supported-models-and-datasets.md)。
以下介绍如何注册一个新模型和对应的template。最佳实践参考[注册多模态模型最佳实践](../BestPractices/MLLM-Registration.md)。
## 模型注册
自定义模型通常使用模型注册的方式进行,可以参考[内置模型](https://github.com/modelscope/ms-swift/blob/main/swift/model/models/qwen.py)、[内置对话模板](https://github.com/modelscope/ms-swift/blob/main/swift/template/templates/qwen.py)或者[examples](https://github.com/modelscope/ms-swift/blob/main/examples/custom)的示例代码。你可以通过指定`--external_plugins xxx.py`解析外置注册的内容(方便pip install而非git clone的用户)。
register_model会在`MODEL_MAPPING`中注册模型,调用函数`register_model(model_meta)`即可完成模型注册,其中model_meta将存储模型的元信息。ModelMeta的参数列表如下:
- model_type: 必填项。模型类型,也是唯一ID。
- model_groups: 必填项。罗列ModelScope/HuggingFace的模型id和模型本地路径。运行[run_model_info.py](https://github.com/modelscope/ms-swift/blob/main/scripts/utils/run_model_info.py)文件将自动产生[支持的模型文档](https://swift.readthedocs.io/zh-cn/latest/Instruction/Supported-models-and-datasets.html)以及自动根据`--model`后缀匹配model_type。
- loader: 模型和tokenizer/processor(多模态模型)的加载器。默认使用`swift.model.ModelLoader`
- template: 命令行不额外指定`--template`时的默认template类型。默认为None。
- model_arch: 模型架构。默认为None。多模态模型训练需要设置该参数来确定llm/vit/aligner的前缀。
- architectures: config.json中的architectures项,用于自动匹配模型对应的model_type。默认为`[]`
- additional_saved_files: 全参数训练和merge-lora时需要额外保存的文件。默认为`[]`
- torch_dtype: 模型加载时未传入`torch_dtype`时的默认dtype。默认为None,从config.json中读取。
- is_multimodal: 是否是多模态模型,默认为False。
- ignore_patterns: 从hub端下载文件需要忽略的文件patterns,默认为`[]`
register_template会在`TEMPLATE_MAPPING`中注册对话模板,调用函数`register_template(template_meta)`即可完成对话模板注册,其中template_meta将存储template的元信息。TemplateMeta的参数列表如下:
- template_type: 必填项。对话模板类型,也是唯一ID。
- prefix: 必填项。对话模板的前缀,通常包含system、bos_token等部分,独立于多轮对话而产生的对话模板循环。例如qwen的prefix为`[]`
- prompt: 必填项。表示对话模板中的`{{RESPONSE}}`之前的对话部分。我们使用`{{QUERY}}`代表user询问部分的填充符。例如qwen的prompt为`['<|im_start|>user\n{{QUERY}}<|im_end|>\n<|im_start|>assistant\n']`
- chat_sep: 必填项。多轮对话中每轮的分隔符。若设置为None,则该template不支持多轮对话。例如qwen的chat_sep为`['<|im_end|>\n']`
- suffix: 默认为`[['eos_token_id']]`。对话模板的后缀部分,独立于多轮对话而产生的对话模板循环,通常为eos_token。例如qwen的suffix为`['<|im_end|>']。`
- template_cls: 默认为`Template`。通常在定义多模态模型的template时需要进行自定义,自定义`_encode``_post_encode``_data_collator`函数。
- system_prefix: 默认为None。含system的对话模板前缀。我们使用`{{SYSTEM}}`作为system的填充符。例如qwen的system_prefix为`['<|im_start|>system\n{{SYSTEM}}<|im_end|>\n']`
- 注意:若system为空时,`prefix`可以被`system_prefix`替代,则可以将`prefix`写为含system的前缀,而无需设置`system_prefix`
- 若prefix不含`{{SYSTEM}}`且未设置system_prefix,则该template不支持system。
- default_system: 默认为None。不传入`--system`时使用的默认system。例如qwen的default_system为`'You are a helpful assistant.'`
- stop_words: 默认为`[]`。除了eos_token和`suffix[-1]`的额外停止符。例如qwen的stop_words为`['<|endoftext|>']`
- 注意:推理时,输出的response将会过滤eos_token和`suffix[-1]`,但是会保留额外的stop_words。