中文基于Qwen3-235B-2507蒸馏数据集的操作
flyfish
方式1
from datasets import load_dataset
from transformers import AutoTokenizer# -------------------------- 配置参数 --------------------------
TOKENIZER_PATH = "/media/models/models/Qwen/Qwen3-8B/"
# 数据集存放路径
DATASET_PATH = "/media/user/datasets/swift/Chinese-Qwen3-235B-2507-Distill-data-110k-SFT/qwen3_235b_2507_distill_110k.jsonl"# 最大序列长度(文本截断/填充的目标长度)
MAX_SEQ_LENGTH = 1024
# 训练集/验证集大小(按需调整)
TRAIN_SIZE = 128
VAL_SIZE = 32# -------------------------- 加载分词器 --------------------------
# 加载模型对应的分词器(负责文本→token转换)
tokenizer = AutoTokenizer.from_pretrained(TOKENIZER_PATH)
# 设置填充符号(Qwen等模型通常用eos_token作为pad_token)
tokenizer.pad_token = tokenizer.eos_token
# 设置填充方向为右侧(语言模型通常右侧填充更合理)
tokenizer.padding_side = "right"# -------------------------- 加载原始数据集 --------------------------
def load_raw_dataset(path):"""加载JSONL格式的原始数据集"""# 使用datasets库加载JSONL文件(split="train"表示加载全部数据为训练集)dataset = load_dataset("json", # 数据集格式为JSONdata_files=path, # 数据集文件路径split="train" # 加载为"train"拆分(后续可再划分))print(f"原始数据集加载完成,共 {len(dataset)} 条样本")return dataset# -------------------------- 验证数据格式 --------------------------
def check_data_format(dataset):"""验证数据集是否包含正确的对话格式(messages字段)"""# 查看第一条样本,确认结构是否正确sample = dataset[0]print("\n===== 样本格式示例 =====")print(sample)# 检查是否包含"messages"字段(对话数据核心)if "messages" not in sample:raise ValueError("数据集必须包含'messages'字段,格式应为[{role:..., content:...}, ...]")# 检查messages内部结构(需包含role和content)for msg in sample["messages"]:if not all(key in msg for key in ["role", "content"]):raise ValueError("messages中的每条消息必须包含'role'和'content'字段")# -------------------------- 数据预处理(核心) --------------------------
def preprocess_dataset(dataset):"""对原始数据集进行预处理:1. 将对话格式化为模型可接受的文本(应用聊天模板)2. 转换为token(input_ids)和标签(labels)3. 过滤无效样本"""def process_single_sample(example):"""处理单条样本:格式化→tokenize"""try:# 1. 提取对话消息(如[{"role": "user", "content": "你好"}, {"role": "assistant",...}])messages = example["messages"]# 2. 应用聊天模板(将对话转换为模型输入格式)# 不同模型的聊天模板不同(如Qwen的格式为"<|im_start|>user...<|im_end|>assistant...")formatted_text = tokenizer.apply_chat_template(messages,tokenize=False, # 先不tokenize,仅生成格式化文本add_generation_prompt=False # 不添加生成提示(SFT训练用))# 3. Tokenize:将文本转换为模型可处理的整数序列(input_ids)tokenized = tokenizer(formatted_text,padding="max_length", # 填充到MAX_SEQ_LENGTHtruncation=True, # 超过长度则截断max_length=MAX_SEQ_LENGTH,return_tensors="pt" # 返回PyTorch张量)# 4. 准备labels(与input_ids相同,自回归训练中用input_ids作为标签)return {"input_ids": tokenized["input_ids"].squeeze(), # 去除多余维度"labels": tokenized["input_ids"].squeeze().clone() # 复制作为标签}except Exception as e:# 跳过格式错误的样本print(f"跳过无效样本:{e}")return None# 批量处理所有样本(使用多进程加速)processed = dataset.map(process_single_sample,remove_columns=dataset.column_names, # 移除原始字段(只保留处理后的结果)num_proc=4 # 4个进程并行处理)# 过滤处理失败的样本(返回None的样本)processed = processed.filter(lambda x: x is not None)print(f"\n预处理完成,有效样本数:{len(processed)}")return processed# -------------------------- 划分训练集与验证集 --------------------------
def split_train_val(dataset, train_size, val_size):"""将预处理后的数据集划分为训练集和验证集"""# 计算划分比例(确保能截取到目标数量的样本)split_ratio = (val_size + 1) / (train_size + val_size + 2)# 随机划分(seed确保结果可复现)split_data = dataset.train_test_split(test_size=split_ratio,seed=42)# 截取目标大小的样本train_dataset = split_data["train"].select(range(train_size))val_dataset = split_data["test"].select(range(val_size))print(f"\n数据集划分完成:训练集 {len(train_dataset)} 条,验证集 {len(val_dataset)} 条")return train_dataset, val_dataset# -------------------------- 主流程 --------------------------
if __name__ == "__main__":# 1. 加载原始数据集raw_dataset = load_raw_dataset(DATASET_PATH)# 2. 验证数据格式是否正确check_data_format(raw_dataset)# 3. 预处理(格式化→tokenize)processed_dataset = preprocess_dataset(raw_dataset)# 4. 划分训练集和验证集train_data, val_data = split_train_val(processed_dataset,train_size=TRAIN_SIZE,val_size=VAL_SIZE)# 查看处理后的样本示例(input_ids的前10个token)print("\n===== 处理后样本示例 =====")print("input_ids(前10个):", train_data[0]["input_ids"][:10])print("labels(前10个): ", train_data[0]["labels"][:10])
输出
Generating train split: 110000 examples [00:01, 74385.42 examples/s]
原始数据集加载完成,共 110000 条样本
===== 样本格式示例 =====
{‘messages’: [{‘role’: ‘user’, ‘content’: ‘能给我讲一个寓意深刻的故事吗?’}, {‘role’: ‘assistant’, ‘content’: ‘当然可以。下面是一个寓意深刻的小故事,名为《石匠与神像》:\n\n很久以前,在一座深山里,有一位技艺精湛的石匠,名叫阿岩。他一生都在雕刻石头,作品精美绝伦,远近闻名。但他从不雕刻神像,别人问他为什么,他总是沉默不语。\n\n一天,村里要修建一座庙宇,村长请他雕刻一尊守护神像。阿岩犹豫了很久,终于答应了。他选了一块巨大的青石,开始日复一日地凿刻。每一锤、每一凿,他都极为专注,仿佛在与石头对话。\n\n三年过去了,神像终于完成。它面容庄严,目光深邃,仿佛能看透人心。村民们都惊叹不已,纷纷跪拜,称其为“活的神”。\n\n落成典礼那天,村长对阿岩说:“你创造了神,你就是神的化身。”\n\n阿岩却摇了摇头,轻声说:“不,我不是创造者,我只是唤醒了它。”\n\n众人不解。阿岩走到神像前,指着一处细微的裂痕说:“你们看,这块石头原本有一道裂纹,藏在深处。我本想避开它,可无论怎么雕,那裂痕总会出现在神像的眉心。最后我明白——它不是瑕疵,而是它本来的样子。”\n\n他顿了顿,望向群山:“这石头在山中沉睡了千年,经历了风雨雷电,才有了这道伤痕。我所做的,不是塑造完美,而是让伤痕也成为神圣的一部分。”\n\n众人沉默。\n\n阿岩又说:“人总想雕刻出完美的神,可真正的神,不是无瑕的偶像,而是包容伤痕、接纳残缺的存在。我们每个人心中都有一块石头,有裂痕,有沉重,有沉默。但正是这些,让我们真实,让我们值得被唤醒。”\n\n说完,他放下刻刀,走进山林,再也没有回来。\n\n——\n\n寓意: \n这个故事告诉我们,真正的美与力量,不在于完美无缺,而在于接纳自己的伤痕与不完美。每个人都有裂痕,但那不是缺陷,而是经历的印记,是灵魂的深度。我们不必成为别人眼中的“完美神像”,而是要勇敢地“唤醒”真实的自己——带着伤痕,依然庄严站立。’}]}
Map (num_proc=4): 100%|110000/110000 [01:01<00:00, 1775.05 examples/s]
Filter: 100%|
110000/110000 [01:17<00:00, 1416.82 examples/s]预处理完成,有效样本数:110000数据集划分完成:训练集 128 条,验证集 32 条===== 处理后样本示例 =====
input_ids(前10个): [151644, 872, 198, 100344, 107735, 77172, 41299, 110319, 33108, 112398]
labels(前10个): [151644, 872, 198, 100344, 107735, 77172, 41299, 110319, 33108, 112398]
方式2
from modelscope.msdatasets import MsDataset
dataset = MsDataset.load('swift/Chinese-Qwen3-235B-2507-Distill-data-110k-SFT')
print(f'dataset[0]: {dataset[0]}')
dataset[0]: {‘messages’: [{‘role’: ‘user’, ‘content’: ‘能给我讲一个寓意深刻的故事吗?’}, {‘role’: ‘assistant’, ‘content’: ‘当然可以。下面是一个寓意深刻的小故事,名为《石匠与神像》:\n\n很久以前,在一座深山里,有一位技艺精湛的石匠,名叫阿岩。他一生都在雕刻石头,作品精美绝伦,远近闻名。但他从不雕刻神像,别人问他为什么,他总是沉默不语。\n\n一天,村里要修建一座庙宇,村长请他雕刻一尊守护神像。阿岩犹豫了很久,终于答应了。他选了一块巨大的青石,开始日复一日地凿刻。每一锤、每一凿,他都极为专注,仿佛在与石头对话。\n\n三年过去了,神像终于完成。它面容庄严,目光深邃,仿佛能看透人心。村民们都惊叹不已,纷纷跪拜,称其为“活的神”。\n\n落成典礼那天,村长对阿岩说:“你创造了神,你就是神的化身。”\n\n阿岩却摇了摇头,轻声说:“不,我不是创造者,我只是唤醒了它。”\n\n众人不解。阿岩走到神像前,指着一处细微的裂痕说:“你们看,这块石头原本有一道裂纹,藏在深处。我本想避开它,可无论怎么雕,那裂痕总会出现在神像的眉心。最后我明白——它不是瑕疵,而是它本来的样子。”\n\n他顿了顿,望向群山:“这石头在山中沉睡了千年,经历了风雨雷电,才有了这道伤痕。我所做的,不是塑造完美,而是让伤痕也成为神圣的一部分。”\n\n众人沉默。\n\n阿岩又说:“人总想雕刻出完美的神,可真正的神,不是无瑕的偶像,而是包容伤痕、接纳残缺的存在。我们每个人心中都有一块石头,有裂痕,有沉重,有沉默。但正是这些,让我们真实,让我们值得被唤醒。”\n\n说完,他放下刻刀,走进山林,再也没有回来。\n\n——\n\n寓意: \n这个故事告诉我们,真正的美与力量,不在于完美无缺,而在于接纳自己的伤痕与不完美。每个人都有裂痕,但那不是缺陷,而是经历的印记,是灵魂的深度。我们不必成为别人眼中的“完美神像”,而是要勇敢地“唤醒”真实的自己——带着伤痕,依然庄严站立。’}]}
方式3
from swift.llm import load_datasetdataset, val_dataset = load_dataset('swift/Chinese-Qwen3-235B-2507-Distill-data-110k-SFT')
print(f'dataset: {dataset}')
print(f'dataset[0]: {dataset[0]}')
输出
dataset: Dataset({features: ['messages'],num_rows: 110000
})
dataset[0]: {‘messages’: [{‘role’: ‘user’, ‘content’: ‘能给我讲一个寓意深刻的故事吗?’}, {‘role’: ‘assistant’, ‘content’: ‘当然可以。下面是一个寓意深刻的小故事,名为《石匠与神像》:\n\n很久以前,在一座深山里,有一位技艺精湛的石匠,名叫阿岩。他一生都在雕刻石头,作品精美绝伦,远近闻名。但他从不雕刻神像,别人问他为什么,他总是沉默不语。\n\n一天,村里要修建一座庙宇,村长请他雕刻一尊守护神像。阿岩犹豫了很久,终于答应了。他选了一块巨大的青石,开始日复一日地凿刻。每一锤、每一凿,他都极为专注,仿佛在与石头对话。\n\n三年过去了,神像终于完成。它面容庄严,目光深邃,仿佛能看透人心。村民们都惊叹不已,纷纷跪拜,称其为“活的神”。\n\n落成典礼那天,村长对阿岩说:“你创造了神,你就是神的化身。”\n\n阿岩却摇了摇头,轻声说:“不,我不是创造者,我只是唤醒了它。”\n\n众人不解。阿岩走到神像前,指着一处细微的裂痕说:“你们看,这块石头原本有一道裂纹,藏在深处。我本想避开它,可无论怎么雕,那裂痕总会出现在神像的眉心。最后我明白——它不是瑕疵,而是它本来的样子。”\n\n他顿了顿,望向群山:“这石头在山中沉睡了千年,经历了风雨雷电,才有了这道伤痕。我所做的,不是塑造完美,而是让伤痕也成为神圣的一部分。”\n\n众人沉默。\n\n阿岩又说:“人总想雕刻出完美的神,可真正的神,不是无瑕的偶像,而是包容伤痕、接纳残缺的存在。我们每个人心中都有一块石头,有裂痕,有沉重,有沉默。但正是这些,让我们真实,让我们值得被唤醒。”\n\n说完,他放下刻刀,走进山林,再也没有回来。\n\n——\n\n寓意: \n这个故事告诉我们,真正的美与力量,不在于完美无缺,而在于接纳自己的伤痕与不完美。每个人都有裂痕,但那不是缺陷,而是经历的印记,是灵魂的深度。我们不必成为别人眼中的“完美神像”,而是要勇敢地“唤醒”真实的自己——带着伤痕,依然庄严站立。’}]}