文章目录
- GitHub地址
- 参数说明
- 训练命令
Firefly: 大模型训练工具,支持训练Qwen2.5、Qwen2、Yi1.5、Phi-3、Llama3、Gemma、MiniCPM、Yi、Deepseek、Orion、Xverse、Mixtral-8x7B、Zephyr、Mistral、Baichuan2、Llma2、Llama、Qwen、Baichuan、ChatGLM2、InternLM、Ziya2、Vicuna、Bloom等大模型
GitHub地址
https://github.com/yangjianxin1/Firefly
-
Firefly 不仅支持全量参数训练,还提供了 LoRA 和 QLoRA 高效训练的功能,同时支持预训练、SFT和DPO等多种训练方式。
-
特别值得一提的是,如果你的训练资源有限,Firefly团队极力推荐使用QLoRA进行指令微调。
-
训练加速;支持Unsloth,训练Llama3-8B仅需7.75GB显存,可减少==42.58%显存占用,减少30.72%==训练时间。 训练增益评测。
参数说明
📝 train_args目录下存储了不同模型使用不同训练方式的配置文件,主要参数说明如下:
output_dir:训练输出目录,存储checkpoint、tokenizer、tensorboard等
model_name_or_path:预训练模型的本地目录,或者在huggingface上的模型名称。
train_file:训练数据集路径。sft时,需要设置为文件,可以使用data/dummy_data.jsonl进行debug。pretrain时,需要设置为目录。脚本会自动扫描目录下的所有jsonl文件。
template_name:指令微调时,使用的模板名称。具体有哪些template_name,可参考component/template.py文件
num_train_epochs:训练的轮次。如果数据量足够大,一般建议只训一个epoch。
tokenize_num_workers:预训练时,tokenize的线程数,默认为10。
deepspeed:deepspeed的训练配置文件。全量参数训练时,将采用deepspeed,关于deepspeed的参数配置说明,请参考deepspeed文档
train_mode:训练模式,full、lora或qlora,默认为qlora。
task_type:任务类型,pretrain、sft或dpo,默认为sft。
per_device_train_batch_size:每张显卡的batch size。
gradient_accumulation_steps:梯度累计步数。global batch=num_gpus * per_device_train_batch_size * gradient_accumulation_steps。
gradient_checkpointing:如果显存捉襟见肘,可以开启。以时间换空间,模型不缓存激活状态,会进行两次forward计算,以节省显存。
learning_rate:学习率。全量参数微调的时候,建议小一些,1e-5或5e-6。
max_seq_length:训练时的最大长度。按照自己的设备进行设置,越长需要占用越多显存。
max_prompt_length:进行dpo时,prompt的最大长度。
logging_steps:每隔多少步统计一次train loss。
save_steps:每隔多少步保存一个模型。
save_total_limit:output_dir目录中最多保存多少个checkpoint,超出则会将最旧的删除。
lr_scheduler_type:学习率变化策略。
warmup_steps:warm up步数。学习率经过多少步,增长到指定的数值。
optim:优化器。如果是全量参数微调,建议使用adamw_hf。
seed:随机种子,用于复现实验结果。
fp16:使用使用fp16混合精度。V100建议开启。
bf16:使用使用bf16混合精度。A100建议开启。
use_unsloth:是否使用unsloth,目前unsloth仅支持部分模型,例如Llama3、Mistral、Gemma、TinyLlama等,详情见Unsloth。
以下几个参数,当使用QLoRA训练的时候,需要设置:
lora_rank:qlora矩阵的秩。一般设置为8、16、32、64等,在qlora论文中作者设为64。越大则参与训练的参数量越大,一般来说效果会更好,但需要更多显存,。
lora_alpha: qlora中的缩放参数。一般设为16、32即可。
lora_dropout: lora权重的dropout rate。
关于deepspeed的参数配置,可按需自行修改。
训练命令
User1、Assistant1、User2、Assistant2、User3 的文本都视为模型的输入部分,将 Assistant3 的文本视为模型的预测部分,只有 Assistant3 部分的 loss 参与权重更新。
这种方法的弊端在于,没有充分利用多轮对话的训练数据,Assistant1 和 Assistant2 的内容没有参与模型训练,这部分数据在训练时被浪费了。并且对于很多多轮对话数据而言,中间的 Assitant 回复部分的信息量更丰富详细,最后一个 Assitant 回复部分往往是”谢谢“、”不客气“等诸如此类的较为简短的文本。如果只使用这部分文本训练模型,会严重影响模型的训练效果。
将一条多轮对话数据,拆分成多条数据。例如将以上示例拆分成如下三条数据。
Firefly 项目训练多轮对话模型时,采取了一种更加充分高效的方法。如下图所示,我们将一条多轮对话数据拼接之后,输入模型,并行计算每个位置的 loss,只有 Assistant 部分的 loss 参与权重更新。
为什么这种做法是可行的?答案在于因果语言模型的 attention mask。以 GPT为代表的 Causal Language Model (因果语言模型),这种模型的 attention mask 是一个对角掩码矩阵,每个 token 在编码的时候,只能看到它之前的 token,看不到它之后的 token。
所以 User1 部分的编码输出,只能感知到 User1 的内容,无法感知到它之后的文本,可以用来预测 Assistant1 的内容。而 User2 部分的编码输出,只能看到 User1、Assistant1、User2 的内容,可以用来预测 Assistant2 的内容,依此类推。对于整个序列,只需要输入模型一次,便可并行获得每个位置的 logits,从而用来计算 loss。
值得注意的是,GLM 和 UniLM 不属于严格意义上的 Causal Language Model (因果语言模型),因为它们存在 prefix attention mask 的设计。对于 prefix 而言,它的 attention 是双向的,而预测部分的 attention 是单向的