当前 PaddleFormers 的预训练、后训练数据流支持 jsonl 、 json 等格式的数据,训练时需确保文件名后缀和文件内容格式保持一致。
如果您有格外的文件格式需要支持,可以在 paddleformers/datasets/reader/io.py 里面实现各种类型文件的读取函数,返回的数据格式为 List(Dict)
例如读取 json 文件:
def load_json(file_path):
try:
with open(file_path, "r", encoding="utf-8") as f:
return json.load(f)
except FileNotFoundError:
raise FileNotFoundError(f"file {file_path} not exists")
except json.JSONDecodeError:
pass # fallback to JSONL然后在 paddleformers/datasets/reader/file_reader.py 中 BaseReader 的 self.loader_map 中进行注册:
self.loader_map = {
".json": load_json,
".jsonl": load_json,
".txt": load_txt,
".csv": load_csv,
".parquet": load_parquet,
}PaddleFormers 支持业界常用的不同的数据集格式,通常情况下,我们推荐使用 messages 格式,该格式下数据的表示较为直观且功能齐全。
messages 格式(点击展开/收起)
使用
messages格式需要在train(/eval)_dataset_type处指定为messagesmessages 格式:每条数据都是一个字典,包含以下字段:
messages:List(Dict)样例数据:
{"messages": [{"role": "assistant", "content": "一个需要连续输入值的分类问题的示例是房屋价格预测。房屋的价格通常基于诸如平方英尺、位置、卧室和浴室数量以及像后院或车库等功能这样的因素定价。为了准确预测房屋价格,这些标准必须作为连续输入值输入到分类模型中。"}]} ...
erniekit 格式(点击展开/收起)
使用
erniekit格式需要在train(/eval)_dataset_type处指定为erniekiterniekit 格式:每条数据都是一个字典,包含以下字段:
text:str, List(str)样例数据:
{"text": ["一个需要连续输入值的分类问题的示例是房屋价格预测。房屋的价格通常基于诸如平方英尺、位置、卧室和浴室数量以及像后院或车库等功能这样的因素定价。为了准确预测房屋价格,这些标准必须作为连续输入值输入到分类模型中。"]} ...
为了方便测试,我们也提供了 demo 数据集可以直接使用:
# messages格式
wget https://paddleformers.bj.bcebos.com/datasets/release/v1.0/pt_online_data_messages.tar.gz
mkdir -p data/pt && tar -xf pt_online_data_messages.tar.gz -C data/pt/
# erniekit格式
wget https://paddleformers.bj.bcebos.com/datasets/release/v1.0/pt_online_data_erniekit.tar.gz
mkdir -p data/pt && tar -xf pt_online_data_erniekit.tar.gz -C data/pt/我们也可以选择使用离线的比特预训练数据流,更节省内存。
为了方便测试,我们也提供了 离线预训练 demo 数据集 可以直接使用:
wget https://paddleformers.bj.bcebos.com/datasets/pretrain_offline_data.tar.gz
mkdir -p data/pre-training && tar -xf pretrain_offline_data.tar.gz -C data/pre-training/您也可以制作自己的离线数据流,离线数据流制作方法如下:
下载一个文本数据集,例如 https://modelscope.cn/datasets/BazingaLyn/mini_pretrain_dataset
格式需为 jsonl,每行格式例如 BazingaLyn/mini_pretrain_dataset/pretrain_hq_v7.jsonl:
{"text": "番茄炒蛋\n材料:\n鸡蛋3个、番茄1个、油、盐、糖、水淀粉\n做法:..."}
{"text": "请描述一下如何正确规划个人理财。正确规划个人理财需要以下几个步骤..."}
{"text": "请输入一段描述有关海洋保护的情景对话。Person A: 哇,这个海滩真..."}
{"text": "鉴别两种不同类型的葡萄酒。鉴别葡萄酒的方法因其类型和品种而异,下..."}运行examples/tools/create_pretraining_data.py,生成数据将会保存在当前目录下的./pretrain_data.bin和./pretrain_data.idx
python -u examples/tools/create_pretraining_data.py \
--model_name_or_path "/path/to/your/Qwen3-0.6B-base" \
--data_format "JSON" \
--input_path "/path/to/your/BazingaLyn/mini_pretrain_dataset/pretrain_hq_v7.jsonl" \
--append_eos \
--output_prefix "./pretrain_data" \
--workers 1 \
--log_interval 10000 \
--data_impl "mmap"- 参数说明
| 参数名 | 类型 | 说明 |
|---|---|---|
--model_name_or_path |
string | 模型路径 |
--data_format |
string | 支持的文件格式,当前只支持 JSON |
--input_path |
string | 输入的 json 文件的路径 |
--append_eos |
store_true | 是否在每条数据的结尾添加 eos token |
--output_prefix |
str | 输出文件的前缀 |
--workers |
int | 运行的进程数 |
--log_interval |
int | 打印日志间隔 |
--data_impl |
str | 制作的数据集类型,默认为 mmap,也可以选择 lazy |
messages 格式(点击展开/收起)
使用
messages格式需要在train(/eval)_dataset_type处指定为messagesSFT 数据流中,每条数据都是一个字典,包含以下字段:
messages:List(Dict), 每个字典包含role、content、tool_calls(optional)三种 key。
role的值可以选择system,user,assistant,tool/tool_response/observation(optional)或tool_call/tool_call/function(optional)。content为具体的对话内容。tool_calls(optional)为申请工具调用。
tools(optional):List(Dict), 表示工具信息。
label(optional): Training flag (1=参与训练, 0=不参与训练)Notes:
- 每个训练样本均为 JSON 格式,多个样本以换行符分隔
样例数据:
[ { "messages": [ {"role": "system", "content": "You are a good coder."}, {"role": "user", "content": "Given an integer array nums and an integer target value target, find two integers in the array whose sum equals the target value target, and return their array indices. You may assume that each input will have exactly one solution, and you may not use the same element twice. You can return the answer in any order. Example 1: Input: nums = [2,7,11,15], target = 9\nOutput: [0,1]\nExplanation: Because nums[0] + nums[1] == 9, return [0, 1]."}, {"role": "assistant", "content": "<think>We are going to use a hash map (dictionary) to store the numbers we have seen so far along with their indices.\n For each number in the array, we calculate the complement (target - current number).\n If the complement exists in the hash map, that means we have found the two numbers that add up to the target.\n We then return the current index and the index of the complement from the hash map.\n Since we are guaranteed exactly one solution, we can return immediately when we find it.\n</think>\nTo solve this problem efficiently, we can use a hash map to store each number's index as we iterate through the array. For each number, we calculate its complement (target minus the current number). If the complement exists in the hash map, we immediately return the current index and the complement's index. This approach ensures we find the solution in linear time.\n\n### Approach\n1. **Initialization**: Create an empty dictionary to store numbers and their indices.\n2. **Iterate through the array**: For each number in the array:\n - Calculate the complement (target - current number).\n - Check if the complement exists in the dictionary.\n - If found, return the current index and the complement's index.\n - Otherwise, add the current number and its index to the dictionary.\n3. **Result**: Since the problem guarantees exactly one solution, we will always find it during iteration.\n\n### Solution Code\n```python\ndef twoSum(nums, target):\n num_map = {}\n for i, num in enumerate(nums):\n complement = target - num\n if complement in num_map:\n return [num_map[complement], i]\n num_map[num] = i\n```\n\n### Explanation\n- **Initialization**: The dictionary `num_map` will track each number encountered and its index.\n- **Iteration**: For each number `num` at index `i`:\n - Compute `complement = target - num`.\n - If `complement` is in `num_map`, return `[num_map[complement], i]` since these two numbers sum to the target.\n - Otherwise, store `num` with its index in `num_map` for future checks.\n- **Efficiency**: This approach runs in O(n) time, where n is the number of elements, as each dictionary operation (insertion and lookup) is O(1) on average. The space complexity is O(n) to store the dictionary.\n"} ] } ]用于 function call 训练的 demo 数据:
[ { "messages": [ {"role": "user", "content": "I'm feeling a bit down. Can you tell me a joke to cheer me up?"}, {"role": "assistant", "content": "<think>Okay, let me try to figure out how to approach this. The user is feeling down and asks for a joke to cheer up. I need to connect this request to the appropriate function call. Looking at the available tools, there's a function called get_random_joke which is designed exactly for this purpose. Since the user's main need is to feel better, providing a joke makes sense. The function doesn't require any parameters, so it's straightforward to call it without any additional arguments.\n</think>", "tool_calls": [{"type": "function", "function": {"name": "get_random_joke", "arguments": {}}}]}, {"role": "tool", "content": [{"joke": "Why don't scientists trust atoms? Because they make up everything!"}]}, {"role": "assistant", "content": "Sure, here's a joke for you: \"Why don't scientists trust atoms? Because they make up everything!\" I hope that brings a smile to your face."} ], "tools": [ {"type": "function", "function": {"name": "get_random_joke", "description": "Get a random joke", "parameters": {"type": "object", "properties": {}, "required": []}}}, {"type": "function", "function": {"name": "generate_random_number", "description": "Generate a random number within a specified range", "parameters": {"type": "object", "properties": {"min": {"type": "number", "description": "The minimum value of the range"}, "max": {"type": "number", "description": "The maximum value of the range"}}, "required": ["min", "max"]}}} ] } ]为了方便测试,我们也提供了
messages格式的function call数据集可以直接使用:wget https://paddleformers.bj.bcebos.com/datasets/release/v1.0/sft_function_call_data.tar.gz mkdir -p data/sft && tar -zxf sft_function_call_data.tar.gz -C data/sft/
erniekit 格式(点击展开/收起)
使用
erniekit格式需要在train(/eval)_dataset_type处指定为erniekitSFT 数据流中,每条数据都是一个字典,包含以下字段:
src:str, List(str), 模型的输入指令(instruction)、提示(prompt),模型应该执行的任务。tgt:str, List(str), 模型的输出。system(optional): 系统配置label(optional): Training flag (1=参与训练, 0=不参与训练)is_system(optional): 标志 src 的第一条数据是否是 systemNotes:
src和tgt为支持多轮对话的列表(List)对象- 每个训练样本均为 JSON 格式,多个样本以换行符分隔
样例数据:
{ "system": "你是一个生活小助理", "src": [ "我们如何在日常生活中减少用水?", "还有别的建议吗?" ], "tgt": [ "1. 使用节水装置,如节水淋浴喷头和水龙头。", "2. 使用水箱或水桶收集家庭废水,例如洗碗和洗浴。 \n3. 在社区中提高节水意识。 \n4. 检查水管和灌溉系统的漏水情况,并及时修复它们。 \n5. 洗澡时间缩短,使用低流量淋浴头节约用水。 \n6. 收集雨水,用于园艺或其他非饮用目的。 \n7. 刷牙或擦手时关掉水龙头。 \n8. 减少浇水草坪的时间。 \n9. 尽可能多地重复使用灰水(来自洗衣机、浴室水槽和淋浴的水)。 \n10. 只购买能源效率高的洗碗机和洗衣机。" ], "label": [0, 1], }
为了方便测试,我们也提供了 tatsu-lab/alpaca demo 数据集可以直接使用:
# messages格式
wget https://paddleformers.bj.bcebos.com/datasets/release/v1.0/sft_online_data_messages.tar.gz
mkdir -p data/sft && tar -xf sft_online_data_messages.tar.gz -C data/sft/
# erniekit格式
wget https://paddleformers.bj.bcebos.com/datasets/release/v1.0/sft_online_data_erniekit.tar.gz
mkdir -p data/sft && tar -xf sft_online_data_erniekit.tar.gz -C data/sft/离线数据流需要按下面脚本生成离线比特数据流:
paddleformers-cli train examples/config/sft/full.yaml make_offline_data=true- 制作离线数据集时,建议使用真实训练的 yaml 配置文件,另外需要注意以下参数:
| 参数名 | 类型 | 说明 |
|---|---|---|
dataset_output_dir |
string | 制作的离线数据集输出目录 |
estimation_output_file |
string | 训练步数估计结果输出文件路径 |
训练的时候需要指定dataset_type为offline,input_dir为数据集路径,例如:
# 流式数据流dataloader_shuffle不生效,非流式生效,如果要保持一致建议设置dataloader_shuffle=false
paddleformers-cli train examples/config/sft/full.yaml \
input_dir="dataset_output" \
dataset_type=offline \
dataloader_shuffle=falsemessages 格式(点击展开/收起)
使用
messages格式需要在train(/eval)_dataset_type处指定为messagesDPO 数据流中,每条数据都是一个字典,包含以下字段:
messages:List(dict), 对话历史列表, 包含role("user"或"assistant") 和content(str) 字段。chosen_response:List(dict), 偏好(chosen)的系统回复, 包含role("assistant") 和content(str) 等字段,根据是否调用工具可能包含工具调用信息 (tool_calls)。rejected_response:List(dict), 非偏好(rejected)的系统回复, 包含role("assistant") 和content(str) 等字段。tools:List(dict), 对话中可能用到的工具(函数)的定义列表。样例数据:
{ "messages": [ { "role": "system", "content": "You are a function calling AI model. You are provided with function signatures within <tools> </tools> XML tags. You may call one or more functions to assist with the user query. Don't make assumptions about what values to plug into functions.\n<tools>\n[{'type': 'function', 'function': {'name': 'play_music', 'description': 'Play music from a specified playlist or genre', 'parameters': {'type': 'object', 'properties': {'playlist': {'type': 'string', 'description': 'The playlist to play'}, 'genre': {'type': 'string', 'description': 'The genre of music to play'}}, 'required': []}}}, {'type': 'function', 'function': {'name': 'analyze_sentiment', 'description': 'Analyze the sentiment of a text', 'parameters': {'type': 'object', 'properties': {'text': {'type': 'string', 'description': 'The text to analyze'}, 'language': {'type': 'string', 'description': 'The language of the text (optional)'}}, 'required': ['text']}}}]\n</tools>\nFor each function call return a json object with function name and arguments within <tool_call> </tool_call> XML tags with the following schema:\n<tool_call>\n{'arguments': <args-dict>, 'name': <function-name>}\n</tool_call>\n" }, { "role": "user", "content": "I want to listen to some music. Can you play something for me?" } ], "chosen_response": [{ "role": "assistant", "content": "Of course! Do you have a specific playlist or genre in mind?" }], "rejected_response": [{ "role": "assistant", "content": "", "tool_calls": [ { "type": "function", "function": { "name": "play_music", "arguments": "{\n\t\"playlist\": \"Top hits\"\n}" } } ] }], "tools": [ { "type": "function", "function": { "name": "play_music", "description": "Play music from a specified playlist or genre", "parameters": { "type": "object", "properties": { "playlist": { "type": "string", "description": "The playlist to play" }, "genre": { "type": "string", "description": "The genre of music to play" } }, "required": [] } } }, ], }为了方便测试,我们也提供了 function call DPO 数据集可以直接使用:
# messages格式 wget https://paddleformers.bj.bcebos.com/datasets/release/v1.0/dpo_function_call_data.tar.gz mkdir -p data/dpo && tar -xf dpo_function_call_data.tar.gz -C data/dpo/
erniekit 格式(点击展开/收起)
使用
erniekit格式需要在train(/eval)_dataset_type处指定为erniekitDPO 数据流中,每条数据都是一个字典,包含以下字段:
system(optional): 系统配置src:str, List(str), 用户对话内容tgt:str, List(str), 系统回复内容(比 src 少一个)response:str, List(str), 包含 chosen 和 rejected 回复。sort:List(int), sort 值用于区分 response 中 chosen 和 rejected(sort 值小的是 rejected,sort 值大的是 chosen)。is_system(optional): 标志 src 的第一条数据是否是 systemNotes:
- 每个训练样本均为 JSON 格式,多个样本以换行符分隔
样例数据:
{ "system": "你是一个生活小助理", "src": [ "你好。", "哪一个富含蛋白质,床还是墙?" ], "tgt": ["你好呀,我是你的生活小助理。"], "response": [ [ "床和墙都不是蛋白质的来源,因为它们都是无生命的物体。蛋白质通常存在于肉类、奶制品、豆类和坚果等食物中。" ], [ "对不起,我无法回答那个问题。请提供更具体的信息,让我知道你需要什么帮助。" ] ], "sort": [ 1, 0 ] } ...
为了方便测试,我们也提供了偏好数据集可以直接使用:
# messages格式
wget https://paddleformers.bj.bcebos.com/datasets/release/v1.0/dpo_online_data_messages.tar.gz
mkdir -p data/dpo && tar -xf dpo_online_data_messages.tar.gz -C data/dpo/
# erniekit格式
wget https://paddleformers.bj.bcebos.com/datasets/release/v1.0/dpo_online_data_erniekit.tar.gz
mkdir -p data/dpo && tar -xf dpo_online_data_erniekit.tar.gz -C data/dpo/messages 格式(点击展开/收起)
使用
messages格式需要在train(/eval)_dataset_type处指定为messages多模态 messages 格式需要在纯文本 messages 格式的基础上加上
images、videos、audios几个 key,用于传入多模态资源的url或者path,同时在messages中插入<image>、<video>、<audio>标签来表述插入多模态数据的位置:纯文本:
{"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"]}
erniekit 格式(点击展开/收起)
使用
erniekit格式需要在train(/eval)_dataset_type处指定为erniekitSFT 数据流中,每条数据都是一个字典,包含以下字段:
text_info: 纯文本的列表,每个元素包含一个text和一个tag
text: 来自使用者的问题或系统回复的文字内容tag: 遮挡标签 (no_mask=包含在训练中,mask=排除)
image_info: 图像组成的列表,每个元素包含一个image_url和一个matched_text_index
image_url: 线上下载图像的网址或本地存取图像的路径matched_text_index:text_info中匹配文字的索引
- 预设值:
matched_text_index=0表示图像与第一个文字匹配,并将其放置在第一个文字之前
is_system(optional): 系统标志 (1=系统配置 0=无系统配置)
- 系统配置 = 如果
is_system=1,则为text_info[0]注意:
- 通过将
image_info替换为video_info来支持视频数据- 请确保
mask和no_mask在text_info中交替出现这是一个 SFT VL 数据集的多图像示例:
{ "image_info": [ {"matched_text_index": 0, "image_url": "./DoclingMatix/218/0.png"}, {"matched_text_index": 0, "image_url": "./DoclingMatix/218/1.png"} ], "text_info": [ {"text": "What is the purpose of the resolution discussed in the text?", "tag": "mask"}, {"text": "The purpose of the resolution is to approve the redevelopment contract of the Philadelphia Redevelopment Authority for the redevelopment and urban renewal of a portion of the Haddington Urban Renewal Area, Unit Nos. 2 and 3, and to authorize the Redevelopment Authority to execute the redevelopment contract with Danielle M. Carson-Varns.", "tag": "no_mask"}, {"text": "Who introduced Resolution No. 160204 to the City Council?", "tag": "mask"}, {"text": "Councilmember Blackwell introduced Resolution No. 160204 to the City Council.", "tag": "no_mask"}, ... ] }这是一个 SFT VL 数据集的单视频示例:
{ "video_info": [ {"matched_text_index": 0, "image_url": "./NExTVideo/1027/4789497818.mp4"} ], "text_info": [ {"text": "how does the man sit on the grass?\nA. kneel\nB. one leg in the air\nC. sitting on bicycle seat\nD. legs spread out\nE. squatting down\n Answer with the option's letter from the given choices directly.", "tag": "mask"}, {"text": "D", "tag": "no_mask"} ] }这是一个 SFT VL 数据集的系统配置示例:
{ "is_system": 1, "text_info": [ {"text": "Your role as ...", "tag": "mask"}, {"text": "好的", "tag": "no_mask"}, {"text": "What is written...", "tag": "mask"}, {"text": "<think>So I've got...", "tag": "no_mask"}, ... ] "image_info": [...] }
为了方便测试,我们也提供了用于快速训练的 demo 数据:
# messages格式
wget https://paddleformers.bj.bcebos.com/datasets/release/v1.0/sft_vl_data_messages.tar.gz
mkdir -p data/sft-vl && tar -xf sft_vl_data_messages.tar.gz -C data/sft-vl
# erniekit格式
wget https://paddleformers.bj.bcebos.com/datasets/release/v1.0/sft_vl_data_erniekit.tar.gz
mkdir -p data/sft-vl && tar -xf sft_vl_data_erniekit.tar.gz -C data/sft-vlmessages 格式(点击展开/收起)
使用
messages格式需要在train(/eval)_dataset_type处指定为messages多模态 DPO 数据流在纯文本 DPO 格式的基础上扩展支持多模态输入,内容中可以包含
<image>,<video>,<audio>标签来引用多模态资源。包含以下字段:
messages:List(dict), 对话历史列表, 包含role("user"或"assistant") 和content(str) 字段。chosen_response:List(dict), 偏好(chosen)的系统回复, 包含role("assistant") 和content(str) 等字段。rejected_response:List(dict), 非偏好(rejected)的系统回复, 包含role("assistant") 和content(str) 等字段。images:List(str), 图像资源的本地路径或在线 URL 列表videos:List(str), 视频资源的本地路径或在线 URL 列表audios:List(str), 音频资源的本地路径或在线 URL 列表样例数据(包含图像的多模态 DPO):
{ "messages": [ { "role": "system", "content": "你是一个多模态AI助手,可以理解和描述图像内容。" }, { "role": "user", "content": "请描述一下<image>中的场景" } ], "chosen_response": [{ "role": "assistant", "content": "这张图片展示了一个阳光明媚的公园场景,有绿树、草坪和散步的人们。" }], "rejected_response": [{ "role": "assistant", "content": "图片里有些东西,但我不太确定具体是什么。" }] "images": ["/path/to/image.jpg"], }样例数据(包含图像和视频的多模态 DPO):
{ "messages": [ { "role": "user", "content": "<image>中的动物和<video>中的动物有什么不同?" } ], "chosen_response": [{ "role": "assistant", "content": "图片中的是一只静态的猫,而视频展示的是一只正在奔跑的狗,它们在物种和行为上都有显著差异。" }], "rejected_response": [{ "role": "assistant", "content": "它们都是动物,没什么不同。" }] "images": ["/path/to/animal1.jpg"], "videos": ["/path/to/animal2.mp4"], }
为了方便测试,我们也提供了用于快速训练的 demo 数据:
# messages格式
wget https://paddleformers.bj.bcebos.com/datasets/release/v1.0/dpo_vl_data_messages.tar.gz
mkdir -p data/dpo-vl && tar -xf dpo_vl_data_messages.tar.gz -C data/dpo-vlPaddleFormers 支持多种不同的数据格式处理,我们通过将其他数据格式转换为 messages 格式来实现该功能
如果您有其他需要支持的数据格式,可以在 paddleformers/datasets/reader/convertor.py 里面实现对应格式的转换函数,统一转换成 messages 格式。
例如 erniekit 格式转 messages 格式:
def erniekit_convertor(item):
# erniekit dpo data
if "src" in item and "tgt" in item and "response" in item:
res = convert_dpo_txt_data(item)
# erniekit sft data
elif "src" in item and "tgt" in item:
res = convert_txt_data(item)
# erniekit pretraining data
elif "text" in item:
res = convert_pretraining_data(item)
# erniekit multi modal data
else:
res = convert_mm_data(item)
return res然后在 paddleformers/datasets/reader/file_reader.py 中 BaseReader 的 self.convertor_map 中进行注册:
self.convertor_map = {
"erniekit": erniekit_convertor,
"messages": messages_convertor,
}注册完成后在训练的时候指定 train/eval_dataset_type 为 erniekit / messages 即可使用