智谱模型微调实战:ShareGPT数据集加载与处理完整教程
如果你正打算用ShareGPT格式的数据集来微调ChatGLM系列模型(比如ChatGLM3-6B),却遇到了数据加载失败或者训练中途报错的情况,别急,这多半是因为ShareGPT的数据结构和ChatGLM默认期待的instruction格式对不上号。下面,我们就来完整梳理一下,如何把ShareGPT数据顺畅地适配到ChatGLM的微调流程里。
一、确认ShareGPT数据结构并转换为ChatGLM兼容格式
首先得搞清楚两者的差异。ChatGLM最新的微调脚本(比如train_bash.py)默认接收的是instruction-input-output这样的三元组。而ShareGPT的数据呢,是conversations数组里嵌套着human、gpt这些角色字段。所以第一步,就是做个结构映射,确保每条数据都能被tokenizer正确处理,并且构造出正确的labels掩码。
具体操作起来,可以分几步走:打开你的ShareGPT原始JSON文件,找到每个样本里的conversations数组。然后,按顺序遍历数组里所有from: "human"和from: "gpt"的条目,把它们拼接成单轮或多轮的对话文本,注意保持原来的语义顺序。
接下来是关键:把第一条human的内容设为instruction字段,后面交替出现的human和gpt内容可以视为多轮上下文(具体处理方式取决于你的训练框架),而最后一个gpt的输出,就设为output。如果一条数据没有明确的gpt回复作为结尾,稳妥起见,建议直接舍弃这个样本。
最后,生成一个新的JSONL文件,每行都是一个标准的ChatGLM SFT样本,格式大致像这样:{"instruction": "用户第一句话", "input": "", "output": "模型最后一句回复"}。当然,根据实际情况,你可能需要把中间轮次的对话内容整合进input里。
二、使用LLaMA-Factory统一加载ShareGPT数据
如果你觉得手动转换太麻烦,或者数据里包含了复杂的function_call、observation字段,那么直接用LLaMA-Factory这个工具会更省心。它内置了解析器,能直接读取ShareGPT的conversations字段,自动处理系统提示和工具调用标记,避免了因JSON结构解析不当带来的问题。
怎么操作呢?首先,安装LLaMA-Factory:执行git clone https://github.com/hiyouga/LLaMA-Factory.git命令,然后进入项目目录。
接着,在项目的data子目录下,新建一个文件,比如叫sharegpt_zh_custom.json,直接把原始的ShareGPT数据原封不动地粘贴进去,完全不用修改字段名。
运行微调命令的时候,记得通过参数指定数据集:--dataset_dir ./data --dataset sharegpt_zh_custom --template sharegpt。这里--template sharegpt参数至关重要,它告诉LLaMA-Factory启用对应的模板文件(通常是sharegpt.py),来完成角色到instruction的映射,并确保tokenization的对齐。
三、修改ChatGLM-Efficient-Tuning源码以原生支持ShareGPT
对于一些更高级的需求,比如你需要精细控制对话轮次的截断逻辑,或者想要完整保留observation这类中间状态用于强化学习(PPO)阶段的建模,那么直接修改ChatGLM-Efficient-Tuning的源码可能是最彻底的办法。这样做绕过了格式转换可能带来的信息损耗,能最大程度保持原始数据的语义完整性。
动手修改前,先找到src/data.py文件里的get_dataset函数。在类似elif dataset_name == "alpaca_zh"这样的分支后面,新增一个elif dataset_name == "sharegpt_zh"的分支。
在这个新分支里,调用一个你自定义的解析函数,比如叫load_sharegpt_dataset。这个函数负责逐条读取conversations,并构建出模型需要的input_ids和labels张量。特别要注意,对于function_call和observation这类特殊字段,可能需要添加专门的token来标识。
改完数据加载部分,别忘了在src/train_bash.py的参数校验相关代码里,把"sharegpt_zh"加入到模型支持的数据集列表中。
完成这些修改后,启动训练时,你就能直接使用--dataset sharegpt_zh --stage sft这样的参数了,框架会自动加载并处理原始的ShareGPT结构。
四、验证数据加载是否成功
在正式开跑训练之前,有一个环节绝对不能跳过:验证数据是否真的被正确加载到了模型的输入管道里。这个步骤能帮你提前发现对齐错误、长度超限或者掩码设置不对等问题。
一个实用的方法是插入调试代码。你可以在src/train_bash.py中找到trainer.train()这行代码之前的位置,插入类似这样的语句:print('Sample input:', tokenizer.decode(train_dataset[0]["input_ids"][:50])),打印出一小段输入看看。
然后,运行训练脚本时,加上--do_train False --max_steps 1这样的参数,意思是“只加载一个batch的数据,然后退出,不进行实际训练”。
接下来,仔细检查日志输出的解码后文本:确认human的内容出现在开头,gpt的内容紧随其后,并且function_call这类字段被转换成了可识别的特殊token,而不是一堆乱码。
最后,也是最重要的一步:核对labels张量。在这个张量里,值-100应该覆盖所有非gpt输出的位置(即模型在训练时不应计算这些位置的损失),而只有gpt输出对应的位置,才是真实的token id。如果发现非-100的值出现在了human对话段,那就明确意味着掩码设置错了,必须回头检查数据处理的逻辑。
