FastChat 微调实践指南:FSDP、QLoRA 与多硬件全参数训练 FastChat 微调实践指南FSDP、QLoRA 与多硬件全参数训练【免费下载链接】FastChatAn open platform for training, serving, and evaluating large language models. Release repo for Vicuna and Chatbot Arena.项目地址: https://gitcode.com/GitHub_Trending/fa/FastChatFastChat 仓库为 Vicuna 系模型与 FastChat-T5 提供了完整的监督微调SFT工具链docs/training.md 是这套工具链的官方操作手册涵盖基于 FSDP 的 T5 全参数微调、基于 DeepSpeed ZeRO 的 LoRA/QLoRA 低秩微调以及面向本地 NPU 集群的 Vicuna-7B 全参数训练。读完本文你将掌握这四种训练路径的完整命令、参数含义与适用场景并能结合 fastchat/train 下的源码理解数据预处理、loss 掩码与检查点保存的底层机制。训练数据格式所有脚本共用的对话 JSON四条训练路径共享同一种数据格式。仓库自带示例数据 data/dummy_conversation.json每条样本是一个对象conversations字段交替存放human与gpt两个角色的消息[ { id: identity_0, conversations: [ { from: human, value: Who are you? }, { from: gpt, value: I am Vicuna, a language model trained by researchers from LMSYS. } ] } ]所有训练脚本通过--data_path指向该 JSON 文件。从源码结构看fastchat/train/train.py 中make_supervised_data_module直接json.load该文件并取example[conversations]作为训练输入因此自定义数据集时只需保持这一结构即可。全参数微调数据预处理与 loss 掩码机制在讲解具体命令之前先看全参数训练脚本 fastchat/train/train.py 的预处理逻辑它解释了为什么微调只对模型回复计算损失preprocess函数使用 Vicuna 对话模板get_conversation_template(vicuna)把human/gpt消息渲染成带USER:/ASSISTANT:标记的完整 prompt再按tokenizer.model_max_length填充截断见 train.py#L92-L177。随后将input_ids克隆为targets用分隔符conv.sep conv.roles[1] : 逐轮切分把用户指令片段和 padding 位置的标签全部替换为IGNORE_TOKEN_ID即LabelSmoother.ignore_index最终只对 ASSISTANT 回复的 token 计算交叉熵损失。数据集有两种加载方式SupervisedDataset在构造时一次性完成全部 tokenizationLazySupervisedDataset则按索引惰性预处理并做单样本缓存。训练脚本中的--lazy_preprocess True就是切换二者的开关见 train.py#L235-L253适合数据量大、不想预先把全部序列驻留显存的场景。另外train()入口处有一个值得注意的细节当model_max_length超过模型配置的max_position_embeddings时会自动设置rope_scaling {type: linear, factor: ceil(model_max_length / orig_ctx_len)}见 train.py#L265-L275。这意味着如果你想把 Vicuna-7B 的微调长度扩展到 16k直接把--model_max_length设为 16384 即可RoPE 缩放因子会按整倍数自动推导。保存环节同样针对 FSDP 做了适配trainer_save_model_safe使用FullStateDictConfig(offload_to_cpuTrue, rank0_onlyTrue)把分片参数聚合到 CPU 后由 rank 0 统一落盘见 train.py#L81-L89避免多卡保存时的显存峰值。使用 FSDP 微调 FastChat-T54 x A100 40GBdocs/training.md 给出的 T5 全参数微调命令如下官方标注为 4 x A10040GB配置torchrun --nproc_per_node4 --master_port9778 fastchat/train/train_flant5.py \ --model_name_or_path google/flan-t5-xl \ --data_path ./data/dummy_conversation.json \ --bf16 True \ --output_dir ./checkpoints_flant5_3b \ --num_train_epochs 3 \ --per_device_train_batch_size 1 \ --per_device_eval_batch_size 1 \ --gradient_accumulation_steps 4 \ --evaluation_strategy no \ --save_strategy steps \ --save_steps 300 \ --save_total_limit 1 \ --learning_rate 2e-5 \ --weight_decay 0. \ --warmup_ratio 0.03 \ --lr_scheduler_type cosine \ --logging_steps 1 \ --fsdp full_shard auto_wrap \ --fsdp_transformer_layer_cls_to_wrap T5Block \ --tf32 True \ --model_max_length 2048 \ --preprocessed_path ./preprocessed_data/processed.json \ --gradient_checkpointing True关键参数说明--fsdp full_shard auto_wrap启用 FSDP 全分片并自动包装配合--fsdp_transformer_layer_cls_to_wrap T5Block指定以T5Block为分片粒度使编码器/解码器的每层块成为独立 FSDP unit--preprocessed_pathT5 训练脚本特有参数指定预处理缓存路径见 train_flant5.py#L57-L60与--data_path配合使用可跳过重复预处理--model_max_length 2048train_flant5.py中该参数默认即为 2048train_flant5.py#L67-L72其余为 HF Trainer 标准超参3 个 epoch、每卡 batch size 1、梯度累积 4等效全局 batch 16、余弦学习率调度、3% 步数 warmup、按步保存并只保留最近 1 个 checkpoint。T5 脚本还有两个与因果 LM 训练不同的实现细节必须使用非 fast 的 T5Tokenizer。源码注释明确指出fast tokenizer 会在特殊 token 前错误地补空格见 train_flant5.py#L405-L413。词表扩展。smart_tokenizer_and_embedding_resize会向 T5 词表追加[PAD]及、{、\n等 T5 特殊字符 token并把新增 embedding 初始化为旧 embedding 的均值见 train_flant5.py#L84-L112。数据侧则以### user:\n/### assistant:\n信号切分多轮对话只把回答部分外加 EOS构造为 labels问题部分被 mask见 train_flant5.py#L142-L176。训练后必须做权重修复。原文档特别提醒用 HF FSDP 训练 Flan-T5 保存的 checkpoint 中共享嵌入shared embeddings权重会损坏训练完成后要调用仓库自带工具函数修复才能正常加载。该函数就是 fastchat/utils.py 中的clean_flant5_ckpt它读取 checkpoint 目录下的pytorch_model.bin.index.json取出shared.weight再将其回写到decoder.embed_tokens.weight与encoder.embed_tokens.weight两个分片中。使用方式from fastchat.utils import clean_flant5_ckpt clean_flant5_ckpt(./checkpoints_flant5_3b)使用 (Q)LoRA 微调 Vicuna-7BDeepSpeed ZeRO2原文档给出的 Vicuna-7B QLoRA 命令基于 ZeRO2并明确说明两个前提约束QLoRA 与 ZeRO3 当前不兼容LoRA 支持 ZeRO3参考配置见 playground/deepspeed_config_s3.json以及依赖版本要求bitsandbytes0.39.0、transformers4.30.0。deepspeed fastchat/train/train_lora.py \ --model_name_or_path ~/model_weights/llama-7b \ --lora_r 8 \ --lora_alpha 16 \ --lora_dropout 0.05 \ --data_path ./data/dummy_conversation.json \ --bf16 True \ --output_dir ./checkpoints \ --num_train_epochs 3 \ --per_device_train_batch_size 1 \ --per_device_eval_batch_size 1 \ --gradient_accumulation_steps 1 \ --evaluation_strategy no \ --save_strategy steps \ --save_steps 1200 \ --save_total_limit 100 \ --learning_rate 2e-5 \ --weight_decay 0. \ --warmup_ratio 0.03 \ --lr_scheduler_type cosine \ --logging_steps 1 \ --tf32 True \ --model_max_length 2048 \ --q_lora True \ --deepspeed playground/deepspeed_config_s2.jsonLoRA 相关参数在 fastchat/train/train_lora.py 的LoraArguments中有完整定义train_lora.py#L55-L65除命令中显式给出的三项外还有两个可调项参数默认值说明--lora_r8低秩分解的秩 r--lora_alpha16缩放系数 alpha实际缩放为 alpha/r--lora_dropout0.05LoRA 层 dropout--lora_target_modules[q_proj, v_proj]注入 LoRA 的线性层默认只改 attention 的 Q/V 投影--lora_biasnone支持none/all/lora_only控制是否保存偏置项--q_loraFalse置 True 启用 4bit 量化底模QLoRA--deepspeed指向的 playground/deepspeed_config_s2.json 是仓库自带的 ZeRO2 配置zero_optimization.stage2优化器状态 offload 到 CPUoffload_optimizer.devicecpu并开启contiguous_gradients与overlap_commbatch size、梯度累积步数、fp16 均设为auto由命令行参数接管。若改用 LoRA ZeRO3则切换到 playground/deepspeed_config_s3.json该配置在 ZeRO3 基础上同时 offload 优化器与参数到 CPU并开启stage3_gather_16bit_weights_on_model_save保证存盘时聚合出完整 16bit 权重。从源码可以印证文档中的兼容性警告train_lora.py在检测到q_loraTrue且启用了 FSDP 或 ZeRO3 时会打印 FSDP and ZeRO3 are both currently incompatible with QLoRAtrain_lora.py#L121-L126。QLoRA 路径下底模通过BitsAndBytesConfig(load_in_4bitTrue, bnb_4bit_use_double_quantTrue, bnb_4bit_quant_typenf4, ...)以 NF4 双重量化加载train_lora.py#L128-L146计算 dtype 跟随--bf16/--fp16选择。训练结束后 rank 0 只保存 LoRA 适配器权重model.save_pretrained保存 PEFT state dict而非完整模型train_lora.py#L211-L218因此 checkpoint 目录很小后续需要与底模合并或加载适配器推理。仓库还提供了一个可直接套用的 LoRA 训练脚本 scripts/train_lora.sh以lmsys/vicuna-7b-v1.5为底模--q_lora False纯 LoRA、--fp16 True、--num_train_epochs 150并新增了--gradient_checkpointing True与--flash_attn False两个选项——flash_attn为 True 时会调用 fastchat/train/llama_flash_attn_monkey_patch.py 中的replace_llama_attn_with_flash_attn把 Llama 的 attention 替换为 FlashAttention 实现。T5-XL / XXL 的 QLoRA 微调对 encoder-decoder 架构的 Flan-T5使用独立的 fastchat/train/train_lora_t5.pydeepspeed fastchat/train/train_lora_t5.py \ --model_name_or_path google/flan-t5-xl \ --data_path ./data/dummy_conversation.json \ --bf16 True \ --output_dir ./checkpoints_flant5_3b \ --num_train_epochs 3 \ --per_device_train_batch_size 1 \ --per_device_eval_batch_size 1 \ --gradient_accumulation_steps 4 \ --evaluation_strategy no \ --save_strategy steps \ --save_steps 300 \ --save_total_limit 1 \ --learning_rate 2e-5 \ --weight_decay 0. \ --warmup_ratio 0.03 \ --lr_scheduler_type cosine \ --logging_steps 1 \ --model_max_length 2048 \ --preprocessed_path ./preprocessed_data/processed.json \ --gradient_checkpointing True \ --q_lora True \ --deepspeed playground/deepspeed_config_s2.json该脚本复用train_flant5.py的数据模块与词表扩展逻辑smart_tokenizer_and_embedding_resize、make_supervised_data_module但 LoRA 的task_type设为SEQ_2_SEQ_LM且由于 QLoRA 同样不兼容 ZeRO3这里依然使用deepspeed_config_s2.json。在本地 NPU 上全参数微调 Vicuna-7B原文档最后给出了面向昇腾等本地 NPU 集群的 Vicuna-7B 全参数训练命令以 8 x NPU 为例通过--nproc_per_node指定 NPU 数量torchrun --nproc_per_node8 --master_port20001 fastchat/train/train.py \ --model_name_or_path ~/vicuna-7b-v1.5-16k \ --data_path data/dummy_conversation.json \ --fp16 True \ --output_dir output_vicuna \ --num_train_epochs 3 \ --per_device_train_batch_size 8 \ --per_device_eval_batch_size 1 \ --gradient_accumulation_steps 1 \ --evaluation_strategy no \ --save_strategy steps \ --save_steps 1200 \ --save_total_limit 10 \ --learning_rate 2e-5 \ --weight_decay 0. \ --warmup_ratio 0.03 \ --lr_scheduler_type cosine \ --logging_steps 1 \ --fsdp full_shard auto_wrap \ --fsdp_transformer_layer_cls_to_wrap LlamaDecoderLayer \ --model_max_length 2048 \ --gradient_checkpointing True \ --lazy_preprocess True与 T5 版本对比该命令有三个针对性调整FSDP 包装单元改为LlamaDecoderLayer与 Llama 的层结构对应T5 版本是T5Block底模选择vicuna-7b-v1.5-16k即 16k 上下文的 Vicuna--model_max_length 2048低于 16384不会触发 RoPE 重缩放若需要按 16k 长度训练可按前述机制把该参数调大显式开启--lazy_preprocess True利用LazySupervisedDataset惰性 tokenization 控制 CPU 内存。该命令走的是 fastchat/train/train.py 的完整流程加载数据 → 构造掩码后的input_ids/labels/attention_mask→ HF Trainer 训练 → 检测output_dir下是否已有checkpoint-*有则自动resume_from_checkpoint续训否则从零开始train.py#L303-L314。训练参数速查四个脚本共享的 HF Trainer 核心参数在原文档中的取值基本一致可作为默认起点参数取值说明--learning_rate2e-5三条路径统一--lr_scheduler_typecosine余弦退火--warmup_ratio0.033% 步数线性预热--weight_decay0.文档命令未启用权重衰减--num_train_epochs3配合--save_steps300/1200 与--save_total_limit控制磁盘占用--model_max_length2048T5 脚本的默认值Llama 脚本默认为 512命令中显式覆盖精度--bf16 True或--fp16 TrueNPU 场景用 fp16GPU 场景用 bf16小结docs/training.md 给出的四条命令覆盖了 FastChat 微调的典型场景T5 系列全参数微调FSDP训练后需用clean_flant5_ckpt修复共享嵌入、Vicuna-7B 的 QLoRAZeRO2 NF4 量化底模注意与 ZeRO3 的不兼容、T5 系列 QLoRA以及 NPU 集群上的 Vicuna 全参数训练。实现层面的三个关键点值得记住loss 只计算在 assistant 回复 token 上LoRA checkpoint 只保存适配器权重FSDP 保存走 CPU 聚合 rank0 落盘。更深入的模型加载与适配细节可继续参考 fastchat/model/model_adapter.py数据准备与清洗工具位于 fastchat/data 目录。【免费下载链接】FastChatAn open platform for training, serving, and evaluating large language models. Release repo for Vicuna and Chatbot Arena.项目地址: https://gitcode.com/GitHub_Trending/fa/FastChat创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考