
Qwen3-Coder 仓库 SFT 监督微调全流程实战数据二值化、全参/LoRA 训练与 Adapter 合并【免费下载链接】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本文基于 Qwen3-Coder 仓库内置的监督微调SFT套件完整梳理从环境搭建、ChatML 训练数据准备、数据二值化Binarize、分布式全参/LoRA 训练到 Adapter 权重合并的端到端流程。读完本文你将掌握该套件四个 Shell 脚本与三个 Python 入口的调用方式、每个训练超参数的作用与默认值并能结合源码理解 ChatML 掩码Masking、DeepSpeed ZeRO-3 卸载和 LoRA 合并的底层原理可直接复制命令在自有数据与算力上跑通代码模型的指令微调。1. SFT 流水线一览从原始 JSONL 到合并后的模型权重该套件位于仓库的 finetuning/sft 目录围绕 README.md 定义的四步流水线组织步骤作用入口脚本/程序产出1. 环境准备创建 Conda 环境并安装依赖requirements.txt可运行训练的环境2. 数据二值化将 ChatML 格式 JSONL 按 tokenizer 切分并生成掩码标签binarize_data.sh → binarize_data.py.npy/.jsonl/.mmap预训练格式数据3. 模型训练全参或 LoRA 方式的监督微调sft_qwencoder.sh / sft_qwencoder_with_lora.sh → train.pycheckpoint-{step}权重目录4. 合并 Adapter将 LoRA 适配器与基座模型合并merge_adapter.sh → merge_adapter.py可直接部署的完整模型权重目录中还提供了 LoRA 配置 adapter_config.json、DeepSpeed 配置 default_offload_opt_param.json 以及数据/评测工具链 utils。2. 环境准备Conda 环境与依赖安装2.1 创建并激活虚拟环境README 使用 Python 3.9 创建独立环境避免与已有项目互相污染conda create -n sft_env python3.9 conda activate sft_env2.2 安装依赖pip install -r requirements.txtrequirements.txt 中锁定了完整的深度学习训练栈关键组件及版本如下依赖版本作用torch2.4.0深度学习框架transformers4.51.0模型、tokenizer 与 Trainer 框架deepspeed0.14.5ZeRO-3 分布式优化与参数/优化器 CPU 卸载peft0.14.0LoRA 适配器训练与合并trl0.9.6Transformer RL/对齐训练工具链datasets3.2.0数据集加载flash_attn2.7.3Flash Attention 加速train.py 中通过--use_flash_attention开启sentencepiece / tokenizers0.2.0 / 0.21.0Qwen 系列词表加载tensorboardX2.6.2.2训练指标上报--report_to tensorboard注意requirements 为固定版本如与其他项目共用环境建议按 README 建议新建独立 Conda 环境避免版本冲突。3. 训练数据格式ChatML 多轮 JSONL3.1 单样本结构SFT 套件要求原始数据为 JSONL每行一个 JSON 对象每个样本遵循 ChatML 格式{ messages:[ {role: system, content: You are Qwen, created by Alibaba Cloud. You are a helpful assistant.}, {role: user, content: Write a regex expression to match any letter of the alphabet}, {role: assistant, content: The regex expression to match any letter of the alphabet (either in uppercase or lowercase) is: \n\nregex\n[a-zA-Z]\n}, {role: user, content: How about if I only want to match uppercase letters? Can you modify the regex expression for that?}, {role: assistant, content: Sure, the regex expression to match any uppercase letter of the alphabet is:\n\nregex\n[A-Z]\n} ], format: chatml }字段说明messages对话轮次列表role支持system/user/assistant三种角色可包含一轮 system 提示词与任意轮 user/assistant 交替content对应角色的文本内容format固定为chatml由 binarize_data.py 的chatml_format_preprocess处理可选字段only_last_turn_loss布尔值控制是否只对最后一轮 assistant 回复计算损失见 4.3 节。3.2 数据集形态SFT 数据集的原始 JSONL 文件整体形态为多行样本{messages: [sample1...], format: chatml} {messages: [sample2...], format: chatml} {messages: [sample3...], format: chatml}每一行即一条独立样本全部来自代码指令与人工/模型生成的对应回答可用于代码生成、代码问答、多轮对话等场景的指令微调。4. 数据二值化将原始 JSONL 转为模型可读的 token 序列4.1 调用方式INPUT_PATH/path/to/raw/sft.jsonl OUTPUT_PATH/path/to/processed/sft.jsonl TOKENIZER_PATH/path/to/pretrained_models/Qwen/Qwen2___5-Coder-1___5B/ bash ./scripts/binarize_data.sh ${INPUT_PATH} ${OUTPUT_PATH} ${TOKENIZER_PATH}binarize_data.sh 内部将三个位置参数透传给 Python 入口未传时使用脚本内置默认值INPUT_PATH${1} OUTPUT_PATH${2} TOKENIZER_PATH${3} INPUT_PATH${INPUT_PATH:-./raw/sft.jsonl} OUTPUT_PATH${OUTPUT_PATH:-./processed/sft.jsonl} TOKENIZER_PATH${TOKENIZER_PATH:-./pretrained_models/Qwen/Qwen2___5-Coder-1___5B/} python binarize_data.py -input_path ${INPUT_PATH} -output_path ${OUTPUT_PATH} -workers 64 -tokenizer_path ${TOKENIZER_PATH}binarize_data.py 支持的完整命令行参数参数默认值说明-input_path./raw/sft.jsonl.sampled原始 ChatML JSONL 输入路径-output_path./raw/sft.jsonl.sampled.processed处理后输出路径后缀决定保存格式-workers1并行处理 worker 数脚本固定传 64-chunk_size0.1 * 2**30约 107MB每个 worker 负责的文件字节块大小-max_len8192单样本 token 数上限超长样本会被丢弃-tokenizer_path./pretrained_models/qwen/Qwen2.5-Coder-7B/基座模型 tokenizer 路径-save_format.npy输出格式.npy/.jsonl/.mmap示例中的Qwen2___5-Coder-1___5B是 HuggingFace 缓存目录中把.转写为___的路径写法实际使用时请替换为本地真实模型目录。4.2 底层原理ChatML 模板化与特殊 token入口加载 tokenizer 时显式设置了对齐参数并注册代码模型所需的所有特殊 tokenbinarize_data.pytokenizer transformers.AutoTokenizer.from_pretrained( args.tokenizer_path, add_eos_tokenFalse, add_bos_tokenFalse, pad_token|endoftext|, eos_token|im_end|, model_max_length8192 * 5, truncationTrue, padding_sideright, trust_remote_codeTrue ) tokenizer setup_tokenizer(tokenizer) # 注册 FIM / ChatML 特殊 tokensetup_tokenizerbinarize_data.py一次性注册 7 个特殊 token|fim_prefix|、|fim_middle|、|fim_suffix|、|repo_name|、|file_sep|、|im_start|、|im_end|。其中|im_start|/|im_end|是 ChatML 对话边界标记二值化后的每条样本会被展开为如下 token 结构|im_start|system\n [system_prompt] |im_end| |im_start|user\n [user_prompt] |im_end| |im_start|assistant\n response |im_end|4.3 掩码Masking规则只学 assistant 回复chatml_format_preprocessbinarize_data.py在生成input_ids的同时生成等长的label并用IGNORE_INDEX -100标记不需要回传梯度的位置。其掩码策略为system 提示除边界 token 外全部置为-100不参与损失计算user 提问全部置为-100模型不学习复述问题assistant 回答仅将\n|im_start|assistant角色前缀部分置为-100回答正文完整保留为训练目标only_last_turn_lossTrue默认多轮对话中除最后一轮外的中间轮次也被整体掩码即只让模型学习最终回复这一行为。该开关通过每条样本的only_last_turn_loss字段读取binarize_data.py。二值化期间长度超过-max_len的样本会直接返回None被过滤binarize_data.py因此-max_len同时充当超长样本的硬性筛除条件。4.4 三种输出格式.npy / .jsonl / .mmaptokenize_filebinarize_data.py根据输出路径后缀选择落盘格式.jsonl将{input_ids, label, length}逐条写回 JSONL适合小数据量调试.npy默认格式。input_ids/test_input_ids转为uint32label转为int32后以allow_pickleTrue整体保存为.npy.mmap内存映射格式。将input_ids、labels、lengths分别写入*.input_ids.mmap、*.labels.mmap、*.lengths.mmap并额外生成*.shape.json记录样本数与最大长度供训练时零拷贝按行读取适合海量数据。save_mmap(output_objs, keyinput_ids, output_pathf{output_path}.input_ids.mmap, padding_valuetokenizer.pad_token_id) save_mmap(output_objs, keylabel, output_pathf{output_path}.labels.mmap, padding_valueIGNORE_INDEX) save_mmap(output_objs, keylength, output_pathf{output_path}.lengths.mmap, padding_valueIGNORE_INDEX)5. 启动训练全参 SFTsft_qwencoder.sh5.1 调用方式DATA_PATH/path/to/processed/sft.jsonl PRETRAINED_MODEL/path/to/pretrained_models/Qwen/Qwen2___5-Coder-1___5B/ OUTPUT_DIR/path/to/checkpoints/sft_model/ bash ./scripts/sft_qwencoder.sh ${DATA_PATH} ${PRETRAINED_MODEL} ${OUTPUT_DIR}三个位置参数依次为二值化后的数据路径、预训练基座模型路径、checkpoint 输出目录。脚本通过torchrun拉起分布式训练sft_qwencoder.shtorchrun ${DISTRIBUTED_ARGS} train.py \ --model_name_or_path ${PRETRAINED_MODEL} \ --data_path $DATA_PATH \ --model_max_length ${MAX_LENGTH} \ --output_dir ${OUTPUT_DIR} \ --num_train_epochs 3 \ --per_device_train_batch_size ${MICRO_BATCH_SIZE} \ --gradient_accumulation_steps ${GRAD_ACCU} \ --per_device_eval_batch_size 4 \ --evaluation_strategy no \ --save_strategy steps \ --save_steps 100 \ --save_total_limit 100 \ --learning_rate ${LR} \ --weight_decay ${WEIGHT_DECAY} \ --warmup_steps ${WARMUP_STEPS} \ --lr_scheduler_type cosine \ --logging_strategy steps \ --logging_steps 1 \ --deepspeed ${DEEPSPEED_CONFIG} \ --report_to tensorboard \ --bf16 True \ --tf32 True \ --truncate_source False5.2 训练超参数解析脚本内置的默认超参数sft_qwencoder.sh参数默认值说明BATCH_SIZE1024全局 batch size所有 GPU 累计MICRO_BATCH_SIZE4单卡单步 batch sizeGRAD_ACCU自动计算BATCH_SIZE / WORLD_SIZE / MICRO_BATCH_SIZE即梯度累积步数LR5e-5峰值学习率MIN_LR5e-6学习率下限配合 cosine 调度WARMUP_STEPS100warmup 步数WEIGHT_DECAY0.0权重衰减本套件默认关闭MAX_LENGTH1280最大序列长度NUM_TRAIN_EPOCHS3训练轮数调度器cosine余弦退火从 5e-5 衰减到 5e-6保存策略steps / 100 / 上限 100每 100 步存一个 checkpoint最多保留 100 个以 8 卡单机为例WORLD_SIZE 8GRAD_ACCU 1024 / 8 / 4 32即每 32 个微步做一次参数更新等效全局 batch 为 1024 条样本。5.3 分布式参数torchrun 与多机扩展脚本自动推导分布式环境sft_qwencoder.shGPUS_PER_NODE$(python -c import torch; print(torch.cuda.device_count());) MASTER_ADDR${MASTER_ADDR:-localhost} NNODES${WORLD_SIZE:-1} NODE_RANK${RANK:-0} WORLD_SIZE$(($GPUS_PER_NODE*$NNODES)) MASTER_PORT${MASTER_PORT:-6105}单机多卡无需设置任何环境变量脚本自动按torch.cuda.device_count()识别卡数多机训练设置WORLD_SIZE节点数、RANK当前节点序号、MASTER_ADDR主节点 IP、MASTER_PORT默认 6105脚本头部保留了 InfiniBand / RoCE 相关的 NCCL 调优环境变量NCCL_IB_TC、NCCL_IB_SL、NCCL_IB_GID_INDEX、NCCL_SOCKET_IFNAME、NCCL_IB_HCA等的注释样例多机高带宽场景可按需放开。5.4 DeepSpeed ZeRO-3 CPU 卸载配置default_offload_opt_param.json 采用 ZeRO-3 并将优化器与模型参数同时卸载到 CPU{ zero_optimization: { stage: 3, offload_optimizer: { device: cpu, pin_memory: true }, offload_param: { device: cpu, pin_memory: true }, overlap_comm: true, contiguous_gradients: true, sub_group_size: 1e9, stage3_gather_16bit_weights_on_model_save: true }, optimizer: { type: AdamW, params: { lr: auto, betas: auto, eps: auto, weight_decay: auto } }, gradient_accumulation_steps: auto, train_batch_size: auto, train_micro_batch_size_per_gpu: auto }要点stage: 3将模型参数、梯度、优化器状态按层切分到各卡配合offload_optimizer/offload_param的 CPU 卸载大幅降低显存占用适合在显存受限环境下训练 7B 级别模型优化器与lr、weight_decay等均设为auto从train.py的 TrainingArguments 自动接管stage3_gather_16bit_weights_on_model_save: true保证保存 checkpoint 时聚合出完整的 16bit 权重训练端同时开启--bf16 True --tf32 Truesft_qwencoder.sh需 Ampere 及以上架构 GPU如 A100/H100以获得最佳吞吐。5.5 truncate_source 的语义--truncate_source False控制超长样本的处理方式其实现位于 training_datasets.pyFalse默认加载数据时直接丢弃长度超过model_max_length的样本len(example[input_ids]) args.model_max_length才保留True将样本截断到model_max_length并追加eos_token后参与训练。因此二值化与训练两侧的长度约束共同决定了有效样本集二值化按-max_len过滤一次训练再按model_max_length过滤/截断一次。从 train.py 的LoggingCallback可以看到训练日志会打印tokens_per_second、grad_norm、loss、learning_rate、epoch、step、world_size等指标便于监控吞吐与收敛。6. LoRA 微调sft_qwencoder_with_lora.sh当显存或数据量有限时可改用 LoRA 冻结基座参数、只训练低秩适配器。调用方式与全参脚本一致DATA_PATH/path/to/processed/sft.jsonl PRETRAINED_MODEL/path/to/pretrained_models/Qwen/Qwen2___5-Coder-1___5B/ OUTPUT_DIR/path/to/checkpoints/lora_model/ bash ./scripts/sft_qwencoder_with_lora.sh ${DATA_PATH} ${PRETRAINED_MODEL} ${OUTPUT_DIR}与全参脚本相比仅多出两个参数sft_qwencoder_with_lora.sh--use_peft True \ --peft_config_path ${PEFT_CONFIG_FOLDER}其中PEFT_CONFIG_FOLDER./configs/lora。训练入口据此加载 PEFT 配置并冻结非 LoRA 参数train.pyif training_args.use_peft: peft_config PeftConfig.from_pretrained(training_args.peft_config_path) model.enable_input_require_grads() model get_peft_model(model, peft_config) model.print_trainable_parameters()adapter_config.json 中的 LoRA 超参字段值说明r8低秩矩阵维度秩越高可学习容量越大lora_alpha32缩放系数实际缩放为 alpha/r 4lora_dropout0.1适配器 dropout 比例缓解过拟合biasnone不训练偏置项task_typeCAUSAL_LM因果语言建模任务peft_typeLORAPEFT 方法类型init_lora_weightstrue采用默认高斯初始化use_rslora/use_dorafalse未启用 Rank-Stabilized / DoRA 变体由于 requirements.txt 锁定了peft0.14.0LoRA 训练产物为标准的adapter_config.json adapter_model.safetensors可直接被第 7 节的合并脚本消费。7. 合并 Adapter将 LoRA 权重还原为完整模型LoRA 训练产出的 checkpoint 目录中只有适配器权重不能直接用于推理需要将其合并回基座模型BASE_MODEL_PATH${1} TRAIN_ADAPTERS_PATH${2} OUTPUT_PATH${3} bash ./scripts/merge_adapter.sh ${BASE_MODEL_PATH} ${TRAIN_ADAPTERS_PATH} ${OUTPUT_PATH}三个参数依次为基座模型路径、训练得到的 adapter 目录、合并后模型的输出目录脚本内默认值见 merge_adapter.sh。merge_adapter.py 的合并逻辑包含两层逐 checkpoint 合并merge_all_checkpoint_with_adapter遍历 adapter 目录下所有checkpoint-*子目录将每个 checkpoint 与基座模型合并为独立的output_path/checkpoint-{step}/最终合并对 adapter 根目录再做一次完整合并得到可直接部署的最终模型。单次合并核心流程merge_adapter.pypeft_config PeftConfig.from_pretrained(adapter_dir) peft_config.base_model_name_or_path base_model_path peft_model AutoPeftModelForCausalLM.from_pretrained(adapter_dir, configpeft_config) merged_model peft_model.merge_and_unload(progressbarTrue) merged_model.save_pretrained(output_path) tokenizer AutoTokenizer.from_pretrained(base_model_path) tokenizer.save_pretrained(output_path)合并时通过PeftConfig.from_pretrained读取每个 checkpoint 自带的 adapter 配置并用base_model_name_or_path指回基座模型merge_and_unload完成低秩矩阵展开后卸载 PEFT 包装最终连同基座 tokenizer 一起保存输出即为与基座同结构、可直接加载推理的完整权重。8. 运行要点与调参提示路径占位符必须替换README 与脚本中的/path/to/...、ROOT_PATH/path/to/sft/脚本开头的cd行均为占位符运行前需逐一替换为实际路径示例中的Qwen2___5-Coder-1___5B是 HuggingFace 缓存转写形式本地目录请按实际命名填写。执行目录约定binarize_data.sh与merge_adapter.sh内部使用cd ./Qwen2.5-Coder-evaluation/sft/这类相对路径进入工作目录建议在 finetuning/sft 目录下按 README 方式bash ./scripts/xxx.sh ...调用。数据长度双过滤二值化阶段按-max_len丢弃超长样本训练阶段按--model_max_length默认 1280再次过滤或截断两处配置需保持一致避免样本意外缺失。显存与分布式全参训练默认开启 DeepSpeed ZeRO-3 CPU 卸载与bf16/tf32适用于显存受限环境若显存充足且追求吞吐可关闭 offload 或减少GRAD_ACCU调小BATCH_SIZE换取更快的收敛步进。LoRA 与全参的选择数据量小、资源有限时优先 LoRAr8, alpha32训练产物体积小且可随时合并追求效果上限且算力充足时使用全参脚本。两类脚本的训练配置完全对齐便于横向对比实验。训练监控--logging_steps 1每步打印一次日志--report_to tensorboard将指标写入 TensorBoard配合 train.py 中的吞吐统计tokens_per_second可实时观察 GPU 利用率与收敛曲线。【免费下载链接】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),仅供参考