- Zero Padding策略
模型的输入是定长序列数据,每个文本的序列长度不一样,所以是变长的序列,一般的做法是使用pad token进行填充,通常会占训练token 50%或更多。Zero Padding策略提出在单条数据中拼接多个文本为长文本,使用attention_mask保证精度对齐。通常使用Zero Padding策略时会将batch size设为1,训练过程中没有pad token参与计算,有效提高模型训练效率。精调训练只需要添加一个zero_padding
为True
的配置,即可开启Zero Padding训练。
- PEFT结合低比特和分布式策略
PEFT(Parameter-Efficient Fine-Tuning)相比于全量参数大大降低了所需的显存资源,但对于百亿级别的模型对训练资源仍然要求很高。为了减少显存资源占用,PEFT中提供将16位浮点数的主干模型转化为4比特或8比特的量化模型,只有当权重参与计算时才将低比特的主干模型反量化为浮点数模型。PaddleNLP中提供量化为INT4、INT8、NF4、FP4等多种低比特数据类型。
对于千亿参数级别的模型,PEFT配合低比特策略并不能在单卡训练。PaddleNLP中支持上述所有PEFT策略包含低比特策略使用数据并行(data parallel)、张量并行(tensor parallel)、流水线并行(pipeline parallel)策略、分组参数切分并行 (Sharding)。PEFT、低比特策略、分布式能力三者组合,PaddleNLP在有限计算资源下,可以将模型微调拓展到单机(80G * 8)千亿参数级别。
- 统一对话模板
当前开源Chat 类型模型越来越多,PaddleNLP 已经集成了 LLaMA/LLaMA2、Baichuan/Baichuan2、ChatGLM、ChatGLM2/ChatGLM3、Qwen、Bloom、GPT-3等系列模型,也支持多轮对话 Prompt Template 推理,只需要调用apply_chat_template
函数即可构造将对话历史和用户最新 query 按照模型指定规则拼接到一起,实现不同模型的定制化 Prompt 规则推理。
此外多轮对话训练精调的应用场景也是越来越多,不同模型的多轮对话模板构造规则都不一致,为了在训练侧标准化前处理上的区别,设计了chat_template
来解决此问题。只需要添加一个chat_template
的配置即可为该模型添加相应的多轮对话精调训练支持,具体的配置可看多轮对话文档。
接下来我们将以Llama 2为例介绍如何使用统一脚本进行SFT、LoRA、Prefix Tuning。
- PaddlePaddle develop
- PaddleNLP develop
- PaddleSlim develop
git clone 代码到本地,即可开始。
git clone https://github.com/PaddlePaddle/PaddleNLP.git
# pip install ./PaddleNLP 使用develop版本
cd PaddleNLP/llm
# 到达运行目录
为了方便用户测试,我们也提供示例数据集广告生成数据集,用户也可以仿照数据集的格式制作自己的数据集进行精调。我们支持的数据格式是每行包含一个字典,每个字典包含以下字段:
src
:str, List(str)
, 模型的输入指令(instruction)、提示(prompt),模型应该执行的任务。tgt
:str, List(str)
, 模型的输出。
样例数据:
{"src": "类型#裙*颜色#蓝色*风格#清新*图案#蝴蝶结", "tgt": "裙身处采用立体蝴蝶结装饰辅以蓝色条带点缀,令衣身造型饱满富有层次的同时为其注入一丝甜美气息。将女孩清新娇俏的一面衬托而出。"}
...
SFT(Supervised Fine-Tuning)模型全参微调依托飞桨提出的4D混合分布式并行能力,支持使用Trainer API轻松切换数据并行(DP)、张量并行(TP, Tensor Parallelism)、流水线并行(PP, Pipeline Parallelism)(目前仅支持Llama)等多种分布式训练策略。
# 张量并行分布式训练(常用)
python -u -m paddle.distributed.launch --gpus "0,1,2,3" finetune_generation.py ./llama/sft_argument.json
# 目前ChatGLM2、OPT不支持张量并行,默认使用Sharding策略
python -u -m paddle.distributed.launch --gpus "0,1,2,3" finetune_generation.py ./chatglm2/sft_argument.json
# 张量并行&流水线并行分布式训练(目前仅支持Llama)
python -u -m paddle.distributed.launch --gpus "0,1,2,3" finetune_generation.py ./llama/sft_pp_argument.json
zero_padding
设为True有助于提高训练效率。建议将per_device_train_batch_size
设为1,使用gradient_accumulation_steps
控制batch size,适当调整max_length
取值。- 设置
use_flash_attention
为True使用FlashAttention。
# 单卡训练
python finetune_generation.py ./llama/lora_argument.json
# 张量并行分布式训练(ChatGLM2、OPT不支持张量并行)
# 将lora_argument.json中tensor_parallel_degree修改为2
python -u -m paddle.distributed.launch --gpus "0,1" finetune_generation.py ./llama/lora_argument.json
Note:
zero_padding
设为True有助于提高训练效率。建议将per_device_train_batch_size
设为1,使用gradient_accumulation_steps
控制batch size,适当调整max_length
取值。- LoRA策略默认应用在所有Linear层
- 可以通过设置
weight_quantize_algo
将主干模型量化低比特,例如'weight_only_int4','weight_only_int8','nf4'或'fp4'。具体参考精调参数介绍 - 设置
use_flash_attention
为True使用FlashAttention。 - LoRA API支持4D并行策略,可以通过控制
tensor_parallel_degree
、pipeline_parallel_degree
、sharding
、sharding_parallel_degree
调整并行训练策略,可拓展至单机LoRA微调千亿模型。 - LoRA策略默认应用在所有Linear层。
- 可以通过修改
lora_rank
改变LoRA算法中rank(秩)的值。
# 单卡训练
python finetune_generation.py ./llama/pt_argument.json
# 张量并行分布式训练(ChatGLM2、OPT不支持张量并行)
# 将pt_argument.json中tensor_parallel_degree修改为2
python -u -m paddle.distributed.launch --gpus "0,1" finetune_generation.py ./llama/pt_argument.json
Note:
zero_padding
设为True有助于提高训练效率。建议将per_device_train_batch_size
设为1,使用gradient_accumulation_steps
控制batch size,适当调整max_length
取值。- 可以通过设置
weight_quantize_algo
将主干模型量化低比特,例如'weight_only_int4','weight_only_int8','nf4'或'fp4'。具体参考精调参数介绍 - 设置
use_flash_attention
为True使用FlashAttention。 - Prefix Tuning API支持4D并行策略,可以通过控制
tensor_parallel_degree
、pipeline_parallel_degree
、sharding
、sharding_parallel_degree
调整并行训练策略,可拓展至单机LoRA微调千亿模型。 - 可以通过
num_prefix_tokens
控制Prefix Tuning策略中Prefix Token数量。
model_name_or_path
: 预训练模型名称或者本地的模型路径,用于热启模型和分词器,默认为None。每个模型支持模型权重详见各模型目录。use_flash_attention
: 模型是否使用FlashAttention,默认为False。lora
: 是否开启LoRA微调策略,默认为False。lora_path
: LoRA参数和配置路径,对LoRA参数进行初始化,默认为None。lora_rank
: LoRA算法中rank(秩)的值,默认为8。prefix_tuning
: 是否使用Prefix Tuning策略,默认为False。num_prefix_tokens
: Prefix Tuning策略中Prefix Token数量,默认为128。from_aistudio
: 模型权重是否从Aistudio下载,默认为False。save_to_aistudio
: 模型权重是否保存到Aistudio,默认为False。aistudio_repo_id
: 模型权重保存到Aistudio的repo id,默认为None。aistudio_repo_private
: 模型权重保存到Aistudio的repo是否为私有,默认为True。aistudio_repo_license
: 模型权重保存到Aistudio的repo license,默认为"Apache License 2.0"。aistudio_token
: 模型权重保存到Aistudio的token,默认为None。如果save_to_aistudio为True,且环境变量没有设置相应token,必须传入。neftune
: 是否使用NEFT,进行微调。默认为False。neftune_noise_alpha
: NEFT alpha参数,默认为5.0。
dataset_name_or_path
: 本地数据集目录或内置数据集名称,默认为None。脚本已适配单文件和多文件,会自己寻找dataset_name_or_path/train.json
或者dataset_name_or_path/train/*.json
作为训练集文件, 以及dataset_name_or_path/dev.json
或者dataset_name_or_path/dev/*.json
作为验证集文件。task_name
: 用于选择内置数据集中的具体任务,默认为None。eval_with_do_generation
: 在模型效果评估的时候是否调用model.generate,默认为False。设置为True时,指标为ppl, accuracy;设置为False时,指标为BLEU4/Rouge,建议将metric_for_best_model
设为bleu4。save_generation_output
: 当eval_with_do_generation
设为True,是否将生成结果保存在generated_output.json
文件中,默认为False。zero_padding
:是否使用Zero Padding数据流(减少Padding冗余计算,大幅提升有效Token计算效率),默认为False。当eval_with_do_generation
设为True,评估过程不支持Zero Padding数据流。。src_length
: 模型输入上下文最大token长度,默认为1024。max_length
:模型输入(上下文+生成内容)的最大token长度, 默认为2048。当zero_padding
设为True的时候,同时也为Zero Padding数据流模型训练输入最大长度,通常建议设为模型允许输入最大长度,同时per_device_train_batch_size
设为1,使用gradient_accumulation_steps
控制batch size。lazy
:设置为False则使用MapDataset
,设置为True则使用IterDataset
,默认为False。对于数据量较大的时候建议设为True,IterDataset
可以避免一次性将所有数据读入内存,注意需要设置max_steps
并且evaluation_strategy
和save_strategy
设为steps
注:以下参数仅在eval_with_do_generation
为True,调用model.generate()时生效。
top_k
: “采样”策略中为 top-k 过滤保留的最高概率标记的数量。默认为1,等价于贪心策略。top_p
:“采样”策略中 top-p 过滤的累积概率。默认为1.0,表示不起作用。
以下仅介绍TrainingArguments部分常用参数,详情请参见TrainingArguments文档。
output_dir
: 用于保存相关的文件目录,主要包括模型相关文件、训练过程中的checkpoint、分词器相关文件、评估的结果文件,默认为None。per_device_train_batch_size
: 训练集训练过程批处理大小,对应 micro batch size,默认为8。该参数需要根据具体的数据集来设定,该参数越大,占用显存越高,训练代价越大;反之,占用显存越小,训练速度越快。gradient_accumulation_steps
:梯度累积步数,顾名思义,就是将多次计算得到的梯度值进行累加,然后一次性进行参数更新,默认为1。等效于将原有训练batch size*gradient_accumulation_steps。per_device_eval_batch_size
: 验证集批处理大小,对应 micro batch size,默认为8。该参数越大,占用显存越高;该参数越小,占用显存越低。eval_accumulation_steps
:在将结果移动到CPU之前,累积输出张量的预测步骤数。如果如果未设置,则在移动到CPU之前,整个预测都会在GPU上累积(速度更快需要更多的显存),默认为None。num_train_epochs
:模型训练的轮次,默认为3。learning_rate
:优化器的初始学习率,默认为 5e-05。warmup_steps
: warmup的步数,默认为0。当warmup_steps>0时,会覆盖warmup_ratio的设置。logging_steps
: 日志打印的频率,仅当logging_strategy=="step"生效,默认为 500。如果希望看到较快的日志反馈或者即时的训练的速度,可以减小logging_steps。evaluation_strategy
: 评估策略,默认为no。"no":训练期间不进行评估;"steps":在每eval_steps结束进行;"epoch":在每个 epoch 结束时进行。save_strategy
: 保存策略,默认为no。"no":训练期间不进行评估;"steps":在每eval_steps结束进行;"epoch":在每个 epoch 结束时进行。fp16
: 是否需要开启FP16训练,开启FP16训练可以加速训练,默认为False。bf16
: 是否需要开启BF16训练,开启BF16训练可以加速训练,默认为False。fp16_opt_level
: 可设置O1或者O2,在 O1 级别下,在白名单中的算子将使用 float16/bfloat16 计算,在黑名单中的算子将使用 float32 计算。在 O2 级别下,模型的参数被转换为 float16/bfloat16, 如果算子的浮点型输入全是 float16/bfloat16,算子才会采用 float16/bfloat16 计算,若任意浮点型输入是 float32 类型,算子将采用 float32 计算。默认为O1。do_train
: 是否打开训练,默认为False。do_eval
: 是否打开评估,默认为False。disable_tqdm
: 是否关掉tqdm的进度条,默认为False。如果需要预估整体的训练时长,可以打开该配置,实时观察训练进度。load_best_model_at_end
: 训练结束后是否加载最优模型,通常与metric_for_best_model
配合使用,默认为False。metric_for_best_model
: 最优模型指标,如"accuarcy"等,用于比较模型好坏,默认为None。recompute
: 重计算,暂支持full策略。开启后可降低显存以达到增大batch size的目的,默认为False。save_total_limit
: 保留checkpoint的个数,老的checkpoint会被删除,默认为None。tensor_parallel_degree
: 此参数tensor_parallel_degree表示将一层transformer结构的份数,该方法对通信开销较大, 建议 tensor_parallel_degree<=8, 尽量使用机器内部通信。默认为-1,表示不启用张量并行。pipeline_parallel_degree
: 表示划分流水线的大小.(假设该参数为4, 模型12层, 则每一个pp stage 包含3层模型) 默认值-1, 表示不启用流水线并行。
我们使用张量并行(TP,Tensor Parallelism)和 流水线并行(PP,Pipeline Parallelism)训练过程中,为了节省TP参数合并时间通常在中间checkpoint将参数存储为多个TP和PP参数分片,可以使用提供的分片合并参数脚本进行参数合并。
python merge_tp_and_pp_params.py \
--model_name_or_path ./checkpoints/llama_sft_ckpts/checkpoint-100
为了后续的压缩和静态图推理方便,我们提供LoRA参数合并脚本,可以将LoRA参数合并到主干模型并保存相应的权重。
python merge_lora_params.py \
--model_name_or_path meta-llama/Llama-2-7b-chat \
--lora_path ./checkpoints/llama_lora_ckpts
model_name_or_path
: 必须,预训练模型名称或者本地的模型路径,用于热启模型和分词器,默认为None。lora_path
: LoRA参数和配置路径,对LoRA参数进行初始化,默认为None。merge_model_path
: 必须,合并参数后保存路径,默认为None。device
: 运行环境,默认为gpu。