预训练的大语言模型(LLM)可能无法完全满足特定用户需求,因此需要通过微调来提升其在特定任务中的表现。通过微调,模型能够更精准地适应用户的具体应用场景。本文为您介绍微调LLM时的策略选择(SFT/DPO)、微调技术(全参/LoRA/QLoRA)以及超参说明,旨在帮助实现模型性能的最佳优化。
微调方法简介
SFT/DPO
在Model Gallery模块中,您可以对模型进行监督微调(SFT)和直接偏好优化(DPO)训练。大语言模型(LLM)的训练流程通常包括以下三步:
1. 预训练(Pre-Training, PT)
预训练是LLM训练流程的第一步,模型在大规模语料库上进行学习,以掌握基本的语法规则、逻辑能力和常识知识。
目标:让模型具备语言理解能力、逻辑能力和常识知识。
示例模型:Model Gallery中提供了很多预训练后模型供您使用,如Qwen系列、Llama系列。
2. 监督微调(Supervised Fine-Tuning, SFT)
监督微调是对预训练模型的进一步调整,使其在特定领域的表现更优,适应对话和问答场景。
目标:使模型在输出形式和输出内容上表现更优。
示例问题:使模型能够专业回答用户特定领域(如中医)的问题。
解决方案:准备特定领域(如中医)相关的一问一答形式的数据对模型进行微调。
3. 偏好优化(Preference Optimization, PO)
监督微调后的模型可能会出现语法正确但不符合事实或人类价值观的回复。偏好优化(PO)用于进一步提升模型的对话能力并与人类价值观对齐。主要的方法包括基于强化学习的PPO(Proximal Policy Optimization)和直接优化语言模型的DPO(Direct Prefernece Optimization),DPO使用隐式的强化学习范式,无需显性奖励模型,不直接最大化 reward, 因此在训练上比PPO更加稳定。
3.1 直接偏好优化(Direct Preference Optimization, DPO)
DPO的模型由两个主要组件构成:一个是需要训练的大型语言模型(LLM);另一个是参考模型,用于防止模型偏离预期。参考模型也是经过微调的大型语言模型,但其参数是冻结的,不会更新。
训练数据格式:三元组(prompt,chosen(好的结果
),rejected(差的结果 )) 损失函数公式如下,从损失函数公式上来看,DPO算法的原理是让模型在好结果上生成的概率尽量大于reference model,同时在差结果上生成的概率尽量低于reference model。
σ是Sigmoid函数,用于将结果映射到(0, 1)范围。
β是一个超参数,通常在0.1到0.5之间,用于调整损失函数的敏感度。
PEFT: LoRA/QLoRA
参数高效微调技术(Parameter-Efficient Fine-Tuning, PEFT)广泛应用于微调大型预训练模型。其核心思想是在保持大部分模型参数不变的情况下,仅通过微调少量参数来实现具有竞争力甚至领先的性能。由于需要更新的参数量较小,所需的数据和计算资源也相应减少,从而提高了微调的效率。在Model Gallery模块中,支持全参微调以及LoRA、QLoRA两种高效微调技术:
LoRA(Low-Rank Adaptation)
LoRA技术通过在模型的参数矩阵(例如m*n维)旁边新增一条旁路来实现微调。这条旁路由两个低秩矩阵(m*r和r*n 维,其中r远小于m和n)相乘而成。在前向传播过程中,输入数据同时通过原始参数矩阵和LoRA旁路,得到的输出结果相加。训练过程中,原始参数被冻结,仅对LoRA部分进行训练。由于LoRA部分由两个低秩矩阵构成,其参数量远小于原始矩阵,因此能够显著减少训练的计算开销。
QLoRA(Quantized LoRA)
QLoRA结合了模型量化和LoRA技术。除了引入LoRA旁路,QLoRA在加载时将大模型量化为4bit或8bit。在实际计算时,这些量化的参数会被反量化为16bit进行处理。这样做不仅优化了非使用状态下模型参数的存储需求,还在与LoRA相比较时进一步降低了训练过程中的显存消耗。
训练方法选择与数据准备
在选择SFT和DPO时,请根据您的具体应用场景,参考之前的技术介绍进行决策。
选择全参数训练与LoRA、QLoRA
复杂任务:推荐使用全参数训练,因为它能够充分利用模型的所有参数,从而提升性能。
简单任务:建议使用LoRA或QLoRA,这两者训练速度较快且计算资源需求较低。
小数据量场景:当数据量较小(几百到小几千条),选择LoRA或QLoRA有助于防止模型过拟合。
计算资源有限:如果计算资源紧张,可以选择QLoRA以进一步降低显存消耗。不过需要注意的是,由于增加了量化和反量化的过程,QLoRA的训练时间可能会较LoRA更长。
训练数据准备
简单任务:不需要大量数据。
SFT数据需求:经验表明,对于SFT,数千条数据通常能够达到较好的效果。在这种情况下,数据质量的优化比单纯增加数据量更为重要。
超参介绍
learning_rate
学习率(learning rate)决定了模型在每次迭代中更新参数的幅度。较大的学习率可能加快训练速度,但也可能导致参数更新过度,无法收敛到损失函数的最小值。较小的学习率则提供了更稳定的收敛过程,但可能增加训练时间或陷入局部最优解。使用AdamW优化器能有效地防止长期不收敛的问题。
num_train_epochs
epoch是机器学习和深度学习中的重要概念,1个epoch代表对全部训练数据集进行一次完整的训练。例如设置epoch为10,则模型会遍历全部数据集10次来更新训练参数。
epoch过小可能导致欠拟合,epoch过大可能导致过拟合。推荐设置2~10个epoch。若样本量少,可增加epoch数以避免欠拟合;若样本量大,一般2个epoch即可。此外,较小的learning rate通常需要更多的epochs。可以通过观察验证集准确率的变化,当其不再提高时,即可终止训练。
per_device_train_batch_size
在实际训练中,我们不会遍历完所有训练数据再对模型参数进行更新,而是使用更小的数据集进行多次迭代,以提高训练效率。batch size代表每次迭代中使用的训练数据数量。例如设置batch size为32,则每次训练时模型使用32个训练数据。参数per_device_train_batch_size表示每个GPU卡上一次训练使用的数据量。
batch size参数主要用于调节训练速度,不应用于调节训练效果。较小的batch size会增加梯度估计的方差,需要更多的迭代才能收敛。增大batch size可以缩短训练时间。
理想的batch size通常是硬件能够支持的最大值。
保持相同的per_device_train_batch_size,增加GPU卡数,相当于增加总的batch size。
seq_length
对于LLM,训练数据经过分词器(tokenizer)处理后,会得到一个token序列,sequence length代表模型接受的单个训练样本的token序列长度。如果训练数据的token序列长度超过这个长度,数据会被截断;如果小于这个长度,数据会被填充。
在训练时,我们可以根据训练数据的token序列长度分布,选择合适的sequence length。给定文本序列,使用不同的分词器进行处理后,得到的token序列长度通常相似,因此我们可以统一使用OpenAI tokens 在线计算工具来估算文本的token序列长度。
对于SFT算法,请估算system prompt + instruction + output的序列长度;对于DPO算法,请估算system prompt + prompt + chosen 和 system prompt + prompt + rejected的序列长度,并取其中的较大值。
lora_dim
在Transformer中应用LoRA,主要是在多头注意力(multi-head attention)部分进行。有实验表明:
适配多头注意力中的多个权重矩阵比仅适配单一类型的权重矩阵效果更佳。
增加秩(rank)不一定能涵盖一个更有意义的子空间,一个低秩的适配矩阵可能已经足够。
在Model Gallery提供的llm_deepspeed_peft算法中,LoRA适配了多头注意力中的所有4种权重矩阵,并且我们提供的默认秩值为32。
lora_alpha
通常与lora_dim取相同的值。
dpo_beta
在DPO训练中使用,控制与参考模型的偏离程度,默认值为0.1。较高的beta值意味着与参考模型的偏离较小。该参数在SFT训练中会被忽略。
load_in_4bit/load_in_8bit
在QLoRA中使用,分别代表以4 bit和8 bit精度载入基模型。
gradient_accumulation_steps
较大的batch size需要更多的显存,这可能导致OOM(CUDA out of memory)错误。因此,我们通常设置较小的batch size。然而,较小的batch size会增加梯度估计的方差,影响收敛速度。为了在避免OOM的同时提高收敛速度,我们引入了梯度累积(gradient accumulation)。通过在积累多个batch 的梯度后再进行模型优化,我们可以实现更大的有效batch size,其值为设置的batch size* gradient_accumulation_steps。
apply_chat_template
当apply_chat_template设为true时,训练数据将自动加入模型默认的chat template。如果您希望使用自定义的聊天模板,请将apply_chat_template设置为false,并在训练数据中自行插入所需的特殊标记(special token)。即使apply_chat_template为true,您仍然可以手动定制系统提示(system prompt)。
system_prompt
在system prompt中,您可以提供说明、指导和背景信息,以帮助模型更好地回答用户的询问。例如,您可以使用以下system prompt:“你是一位热情、专业的客服,沟通友好且回答简练,喜欢通过例子来解决用户的问题。”