十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Qwen3-Coder 微调实操:从数据到合并的 4 个关键动作

Qwen3-Coder 微调实操:从数据到合并的 4 个关键动作 Qwen3-Coder 微调实操从数据到合并的 4 个关键动作【免费下载链接】Qwen3-CoderQwen3-Coder is the code version of Qwen3, the large language model series developed by Qwen team.项目地址: https://gitcode.com/GitHub_Trending/co/Qwen3-Coder微调前我把重构这个遗留函数丢给基座模型产出的是签名写错、参数类型漏标的代码同一份数据跑完 SFT 和 DPO再合并 LoRA 后同样提示词一次性输出能过单元测试的实现。这就是 Qwen3-Coder 微调要解决的问题把一个会写但写得不稳的模型变成直接可用的模型。先把数据喂对——格式、清洗与 Tokenize你手里有一堆原始对话第一步不是急着开训而是把它们整理成训练脚本认得的形状。SFT 数据用 ChatML每条样本的最小结构长这样{ messages: [ {role: system, content: You are a helpful assistant.}, {role: user, content: 写一个匹配任意字母的正则表达式}, {role: assistant, content: regex\n[a-zA-Z]\n} ], format: chatml }存储用 JSONL每行一个完整 JSON 对象。role 只允许 system、user、assistant 三种脚本遇到未知角色会直接抛错所以入库前先做一次角色字段校验。DPO 偏好数据是三元组三个字段各司其职prompt 是问题chosen 是好答案rejected 是坏答案。裁判逻辑全靠这个对比所以 rejected 不能是另一种同样正确的写法得是明显更差的版本否则模型学不到东西。Tokenize 这一步交给binarize_data.py输入是原始 JSONL 和 tokenizer 路径输出是带 input_ids 和 label 的编码数据其中用户轮和 system 轮的 label 会被置为 -100只在 assistant 轮上算损失bash ./scripts/binarize_data.sh /path/to/raw/sft.jsonl /path/to/processed/sft.jsonl /path/to/pretrained_models/Qwen2___5-Coder-1___5B/编码结果有三种落盘格式一句话选法数据类型文件名后缀适合场景一句话注意原始对话.jsonl调试、人工抽检、小批量先校验每行 JSON 合法再入库Tokenized 缓存.npy10 万条以内的常规训练加载时需要 allow_pickleTrue内存映射.mmap10 万条以上的大数据集会拆成 input_ids / labels / lengths 三个文件10 万条以上推荐直接上 MMAP内存吃紧也不怕10 万条以下用 NPY 更快更省事没必要纠结。SFT——让模型学会写代码的那一步数据编码完训练其实就是一条命令的事。脚本会自动探测 GPU 数量、算好梯度累积步数多机训练靠环境变量WORLD_SIZE、NODE_RANK扩出去你只需要填三个路径DATA_PATH/path/to/processed/sft.jsonl PRETRAINED_MODEL/path/to/pretrained_models/Qwen2___5-Coder-1___5B/ OUTPUT_DIR/path/to/checkpoints/sft_model bash ./scripts/sft_qwencoder.sh ${DATA_PATH} ${PRETRAINED_MODEL} ${OUTPUT_DIR}脚本里几个核心超参的取值逻辑参数推荐值为什么这么选learning_rate5e-5配合 cosine 衰减到 5e-6调太大容易把基座能力打坏BATCH_SIZE / MICRO_BATCH1024 / 4全局 1024 保稳定单卡 4 条差值自动走梯度累积MAX_LENGTH1280覆盖大部分代码样本再长显存代价大、收益小warmup_steps100开头让学习率缓升避免初期震荡num_train_epochs33 轮足够吸收数据分布更多轮开始过拟合精度bf16 tf32显存和速度双收益脚本里已默认打开断点续训不用手动干预find_latest_checkpoint会扫描输出目录里所有checkpoint-*子目录取编号最大的那个接着训。所以重跑时把--output_dir指向同一个目录就行训练会从最近一次存盘处恢复。两个性能开关的位置Flash Attention 对应train.py的--use_flash_attention参数打开后加载模型时会指定flash_attention_2实现DeepSpeed 走--deepspeed参数指向一个 JSON 配置SFT 脚本默认用的是configs/default_offload_opt_param.json。监控不用盯太多两条曲线就够loss 应该稳定下行偶尔的小回勾正常持续抬头再查数据tokens_per_second 反映吞吐掉得厉害多半是 IO 或通信瓶颈。DPO——给模型一个好坏裁判DPO 的直觉很直白不训练独立的奖励模型直接在好答案和坏答案的配对上比较让模型学会拉开好答案与坏答案的概率差。它的损失函数长这样$$L_{DPO} -\mathbb{E}_{(x, y_w, y_l)} \left[ \log \sigma \left( \beta \log \frac{\pi_\theta(y_w|x)}{\pi_{ref}(y_w|x)} - \beta \log \frac{\pi_\theta(y_l|x)}{\pi_{ref}(y_l|x)} \right) \right]$$其中 π_ref 就是 SFT 后的模型β 控制模型被往参考模型方向拉回的力度。β 推荐范围 0.1 到 0.5脚本默认 0.1属于轻拉适合偏好数据质量一般的情况。DPO 的学习率给到 3e-4比 SFT 的 5e-5 大 6 倍。原因不复杂SFT 阶段要塑造整句生成能力步子必须小DPO 阶段模型知识已经稳定只调偏好判断这一层步子可以迈得更大否则 1000 步训下来等于没动。显存方面DPO 要同时驻留策略模型和参考模型两份权重压力约为 SFT 的两倍。脚本因此挂的是configs/ds_z3_offload_config.jsonDeepSpeed Zero-3 把优化器状态和参数分片到所有卡上再 offload 到 CPU单卡显存不够也能跑。bash ./scripts/dpo_qwencoder.sh \ /path/to/preference_data.jsonl \ /path/to/sft_model \ /path/to/dpo_output 1 2048 3e-4 100 0.0 1280位置参数依次是数据路径、SFT 模型、输出目录、微批、全局批、学习率、warmup、权重衰减、最大长度。训练时盯两个 reward 指标rewards/chosen 应缓慢上升rewards/rejected 应缓慢下降两者差距margin持续拉宽就是健康的。旋钮往哪拧拧过头会怎样β输出漂移就升到 0.3拉太紧模型被钉回 SFT 行为偏好学不进去学习率reward 剧烈波动就降太高会让 margin 直接归零甚至转负全局批大小显存紧张优先降微批全局批太小偏好信号噪声大、收敛抖max_steps默认 1000 步封顶训过头rejected 的 reward 也跟着涨裁判失效LoRA 合并——把小补丁焊回大模型LoRA 可以理解为给模型打的补丁基座权重完全冻结只训练一对低秩矩阵前向传播从 Wx 变成 Wx BAx。补丁只有原参数量的 0.1% 到 1%训练省、存储省合并后即失即弃。configs/lora/adapter_config.json里真正要理解的只有三个参数参数默认值各管什么r8低秩矩阵的秩越大适配能力越强显存和参数量同步涨lora_alpha32缩放系数实际生效强度由 alpha/r 决定lora_dropout0.1训练期 dropout数据量小就调高一点防过拟合target_modules 为 null 时会自动选中全部投影层一般不用手动指定。合并时脚本先遍历适配器目录下每个checkpoint-*子目录逐个合并最后把外层目录整体再合并一遍等于单点合并和批量合并一次全做了bash finetuning/sft/scripts/merge_adapter.sh \ /path/to/base_model /path/to/trained_adapters /path/to/merged_model合并完必须做一次推理冒烟测试3 行代码即可确认输出不是乱码或复读model AutoModelForCausalLM.from_pretrained(/path/to/merged_model, torch_dtypebfloat16) out model.generate(**tokenizer(def fibonacci(n):, return_tensorspt), max_new_tokens64) print(tokenizer.decode(out[0], skip_special_tokensTrue))OOM 时的逃生通道就一条给合并进程加显存碎片治理再跑实在不够就把加载设备改成 CPU 内存里合并PYTORCH_CUDA_ALLOC_CONFexpandable_segments:True python merge_adapter.py -input_model_path /path/to/base -input_adapter_path /path/to/adapter -output_path /path/to/merged如果同时要 Python 代码和 SQL 两个方向的能力就在同一基座上训两个适配器推理时按任务动态挂载对应补丁即可基座不用动。踩坑速查FAQ合并时报 out of memory7B 模型合并时基座权重加临时缓冲同时驻留显存峰值很高。直接走 CPU 内存合并或者先加显存碎片治理再试。PYTORCH_CUDA_ALLOC_CONFexpandable_segments:True python merge_adapter.py -input_model_path /path/to/base -input_adapter_path /path/to/adapter -output_path /path/to/merged训练 loss 不降先怀疑 label 全被置成了 -100预处理把整条样本都 mask 掉时损失要么 nan 要么纹丝不动。用 JSONL 格式落盘几条出来人工检查确认 assistant 轮的 label 里有正常 token id。python binarize_data.py -input_path /path/to/raw/sft.jsonl -output_path /path/to/check.jsonl -save_format .jsonltokenizer 报 special token 未找到FIM 标记|fim_prefix| 系列和 ChatML 标记 系列必须显式注册自己写加载脚本时漏掉add_special_tokens就会报这个错。binarize_data.py里的setup_tokenizer已经做过了照抄即可。python -c from transformers import AutoTokenizer; tAutoTokenizer.from_pretrained(/path/to/model); print(t.convert_tokens_to_ids(|fim_prefix|))binarize 后数据量明显变少超过max_len的样本会被静默丢弃不报错。丢弃率高就先统计一下原始数据的长度分布再决定是调大max_len还是截断长尾样本别默认数据没问题。python binarize_data.py -input_path /path/to/raw/sft.jsonl -output_path /path/to/out.jsonl -max_len 8192 -save_format .jsonlDPO 的 margin 为正但输出没变好margin 只是微正说明模型刚能勉强分好坏继续加步数意义不大。优先检查偏好数据里 chosen/rejected 的差距是否足够明显数据噪声大时把学习率降到 1e-4 重跑一轮。bash ./scripts/dpo_qwencoder.sh /path/to/data /path/to/sft /path/to/out 1 2048 1e-4 100 0.0 1280一页纸总结阶段关键产物最容易卡住的点数据准备编码后的 .npy / .mmap角色字段写错、超长样本被静默丢弃SFT 训练SFT checkpoint显存规划不足、loss 不降DPO 对齐偏好对齐后的模型β 与学习率配比不当margin 拉不开LoRA 合并完整合并模型合并 OOM、跳过了推理验证冒烟测试可上线的模型没验证就直接部署产出乱码【免费下载链接】Qwen3-CoderQwen3-Coder is the code version of Qwen3, the large language model series developed by Qwen team.项目地址: https://gitcode.com/GitHub_Trending/co/Qwen3-Coder创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表