当前位置:   article > 正文

大模型训练之微调篇_get_peft_model

get_peft_model

概览

  • 介绍了大模型训练的微调方法,包括prompt tuning、prefix tuning、LoRA、p-tuning和AdaLoRA等。

  • 介绍了使用deepspeed和LoRA进行大模型训练的相关代码。

  • 给出了petals的介绍,它可以将模型划分为多个块,每个用户的机器负责其中一块,分摊了计算压力。

理解篇

prompt tuning

20210302

固定预训练参数,为每一个任务额外添加一个或多个embedding,之后拼接query正常输入LLM,并只训练这些embedding。左图为单任务全参数微调,右图为prompt tuning。

  • 标准的T5模型(橙色线)多任务微调实现了强大的性能,但需要为每个任务存储单独的模型副本。

  • prompt tuning也会随着参数量增大而效果变好,同时使得单个冻结模型可重复使用于所有任务。

  • 显著优于使用GPT-3进行fewshot prompt设计。

  • 当参数达到100亿规模与全参数微调方式效果无异。

  • 代码样例:

    1. from peft import PromptTuningConfig, get_peft_model
    2. peft_config = PromptTuningConfig(task_type="SEQ_CLS", num_virtual_tokens=10)
    3. model = AutoModelForCausalLM.from_pretrained(model_name_or_path, return_dict=True)
    4. model = get_peft_model(model, peft_config)

    prefix tuning

    20210801

     

    prefix tuning依然是固定预训练参数,但除为每一个任务额外添加一个或多个embedding之外,利用多层感知编码prefix,注意多层感知机就是prefix的编码器,不再像prompt tuning继续输入LLM。

    1. embedding = torch.nn.Embedding(num_virtual_tokens, token_dim)
    2. transform = torch.nn.Sequential(
    3.     torch.nn.Linear(token_dim, encoder_hidden_size),
    4.     torch.nn.Tanh(),
    5.     torch.nn.Linear(encoder_hidden_size, num_layers * 2 * token_dim),
    6. )

    在三个数据集中prefix和全参数微调的表现对比:

     

    代码样例:

    1. peft_config = PrefixTuningConfig(task_type="CAUSAL_LM", num_virtual_tokens=20)
    2. model = AutoModelForCausalLM.from_pretrained(model_name_or_path, return_dict=True)
    3. model = get_peft_model(model, peft_config)

    LoRA

    20210816

     

    LoRA冻结了预训练模型的参数,并在每一层decoder中加入dropout+Linear+Conv1d额外的参数

    那么,LoRA是否能达到全参数微调的性能呢?

    根据实验可知,全参数微调要比LoRA方式好的多,但在低资源的情况下也不失为一种选择

    细致到每个任务中的差距如下图:

    代码样例:

    1. peft_config = LoraConfig(task_type="SEQ_CLS", inference_mode=False, r=8, lora_alpha=16, lora_dropout=0.1)
    2. model = AutoModelForCausalLM.from_pretrained(model_name_or_path, return_dict=True)
    3. model = get_peft_model(model, peft_config)

    p-tuning

    20211102

    手动尝试最优的提示无异于大海捞针,于是便有了自动离散提示搜索的方法(作图),但提示是离散的,神经网络是连续的,所以寻找的最优提示可能是次优的。p-tuning依然是固定LLM参数,利用多层感知机和LSTM对prompt进行编码,编码之后与其他向量进行拼接之后正常输入LLM。注意,训练之后只保留prompt编码之后的向量即可,无需保留编码器。

    1. self.lstm_head = torch.nn.LSTM(
    2.                     input_size=self.input_size,
    3.                     hidden_size=self.hidden_size,
    4.                     num_layers=num_layers,
    5.                     dropout=lstm_dropout,
    6.                     bidirectional=True,
    7.                     batch_first=True,
    8.   )
    9. self.mlp_head = torch.nn.Sequential(
    10.     torch.nn.Linear(self.hidden_size * 2self.hidden_size * 2),
    11.     torch.nn.ReLU(),
    12.     torch.nn.Linear(self.hidden_size * 2self.output_size),
    13. )
    14. self.mlp_head(self.lstm_head(input_embeds)[0])

    以上代码可清晰展示出prompt编码器的结构。

    如上图所示,GPT在P-tuning的加持下可达到甚至超过BERT在NLU领域的性能。下图是细致的对比:

    MP: Manual prompt

    FT: Fine-tuning

    MP+FT: Manual prompt augmented fine-tuning

    PT: P-tuning

    代码样例:

    1. peft_config = PromptEncoderConfig(task_type="CAUSAL_LM", num_virtual_tokens=20, encoder_hidden_size=128)
    2. model = AutoModelForCausalLM.from_pretrained(model_name_or_path, return_dict=True)
    3. model = get_peft_model(model, peft_config)

    p-tuning v2

    20220320

    p-tuning的问题是在小参数量模型上表现差(如上图所示),于是有了V2版本,类似于LoRA每层都嵌入了新的参数(称之为Deep FT),下图中开源看到p-tuning v2 集合了多种微调方法。p-tuning v2 在多种任务上下进行微调,之后对于不同的任务如token classification与sentence classification添加了随机初始化的任务头(AutoModelForTokenClassification、AutoModelForSequenceClassification),而非使用自然语言的方式,可以说V2是集大成者。

    KP: Knowledge Probe,知识探针,用于检测LLM的世界知识掌握能力:https://github.com/facebookresearch/LAMA

    SeqTag: Sequence Tagging,如抽取式问答、命名实体识别

    Re-param.:Reparameterization,对提示词做单独的编码器

    No verb.: No verbalizer,不直接使用LLM head而接一个随机初始化的linear head

    以下表格对比了[CLS] label linear head 和 verbalizer with LM head,[CLS] label linear head的方式药略好。

    v1到v2的可视化:蓝色部分为参数冻结,橙色部分为可训练部分

     

    下图中对比了FT、PT、PT-2三种方法,粗体为性能最好的,下划线为性能次好的。

    代码样例:

    1. peft_config = PrefixTuningConfig(task_type="SEQ_CLS", num_virtual_tokens=20)
    2. model = AutoModelForSequenceClassification.from_pretrained(model_name_or_path, return_dict=True)
    3. model = get_peft_model(model, peft_config)

    AdaLoRA

    20230318

    预训练语言模型中的不同权重参数对下游任务的贡献是不同的。因此需要更加智能地分配参数预算,以便在微调过程中更加高效地更新那些对模型性能贡献较大的参数。

    具体来说,通过奇异值分解将权重矩阵分解为增量矩阵,并根据新的重要性度量动态地调整每个增量矩阵中奇异值的大小。这样可以使得在微调过程中只更新那些对模型性能贡献较大或必要的参数,从而提高了模型性能和参数效率。

    详细的算法如下:

    对比不同方法的性能:

    代码样例:

    1. peft_config = AdaLoraConfig(peft_type="ADALORA", task_type="SEQ_2_SEQ_LM", r=8, lora_alpha=32, target_modules=["q""v"],lora_dropout=0.01)
    2. model = AutoModelForCausalLM.from_pretrained(model_name_or_path, return_dict=True)
    3. model = get_peft_model(model, peft_config)

    代码篇

    注:以下代码在pytorch 1.12.1版本下运行,其他包都是最新版本

    deepspeed

    官方的demo所需要的配置如下:

    GPU SKUsOPT-1.3BOPT-6.7BOPT-13.2BOPT-30BOPT-66BBloom-175B
    1x V100 32G1.8 days
    1x A6000 48G1.1 days5.6 days
    1x A100 40G15.4 hrs3.4 days
    1x A100 80G11.7 hrs1.7 days4.9 days
    8x A100 40G2 hrs5.7 hrs10.8 hrs1.85 days
    8x A100 80G1.4 hrs($45)4.1 hrs ($132)9 hrs ($290)18 hrs ($580)2.1 days ($1620)
    64x A100 80G31 minutes51 minutes1.25 hrs ($320)4 hrs ($1024)7.5 hrs ($1920)20 hrs ($5120)

    注意到官方给的样例单卡V100只能训练13亿规模的模型,如果换成67亿是否能跑起来呢?

    按照官方文档搭建环境:

    1. pip install deepspeed>=0.9.0
    2. git clone https://github.com/microsoft/DeepSpeedExamples.git
    3. cd DeepSpeedExamples/applications/DeepSpeed-Chat/
    4. pip install -r requirements.txt

    请注意如果你之前装了deepspeed,请更新至0.9.0

    试试全参数微调,这毫无疑问OOM

    1. deepspeed --num_gpus 1 main.py \
    2.       --data_path Dahoas/rm-static \
    3.       --data_split 2,4,4 \
    4.       --model_name_or_path facebook/opt-6.5b \
    5.        --gradient_accumulation_steps 2 \
    6.      --lora_dim 128 \
    7.      --zero_stage 0 \
    8.        --deepspeed \
    9.       --output_dir $OUTPUT \
    10.       &> $OUTPUT/training.log

    答案是:我们需要卸载,这次便能愉快的run起来了

    1. deepspeed main.py \
    2.    --data_path Dahoas/rm-static \
    3.    --data_split 2,4,4 \
    4.    --model_name_or_path facebook/opt-6.7b \
    5.    --per_device_train_batch_size 4 \
    6.    --per_device_eval_batch_size 4 \
    7.    --max_seq_len 512 \
    8.    --learning_rate 9.65e-6 \
    9.    --weight_decay 0.1 \
    10.    --num_train_epochs 2  \
    11.    --gradient_accumulation_steps 1 \
    12.    --lr_scheduler_type cosine \
    13.    --num_warmup_steps 0 \
    14.    --seed 1234 \
    15.    --lora_dim 128 \
    16.    --gradient_checkpointing \
    17.    --zero_stage 3 \
    18.    --deepspeed \
    19.    --output_dir $OUTPUT_PATH \
    20.    &> $OUTPUT_PATH/training.log

    可以加上LoRA

    1. deepspeed --num_gpus 1 main.py \
    2.    --data_path Dahoas/rm-static \
    3.    --data_split 2,4,4 \
    4.    --model_name_or_path facebook/opt-6.7b \
    5.    --per_device_train_batch_size 8 \
    6.    --per_device_eval_batch_size 8 \
    7.    --max_seq_len 512 \
    8.    --learning_rate 1e-3 \
    9.    --weight_decay 0.1 \
    10.    --num_train_epochs 2 \
    11.    --gradient_accumulation_steps 16 \
    12.    --lr_scheduler_type cosine \
    13.    --num_warmup_steps 0 \
    14.    --seed 1234 \
    15.    --gradient_checkpointing \
    16.    --zero_stage 0 \
    17.    --lora_dim 128 \
    18.    --lora_module_name decoder.layers. \
    19.    --deepspeed \
    20.    --output_dir $OUTPUT_PATH \
    21.    &> $OUTPUT_PATH/training.log

    peft

    以下代码省略了数据处理

    初始化

    1. from datasets import load_dataset,load_from_disk
    2. import transformers
    3. from transformers import AutoModelForCausalLM, AutoTokenizer,default_data_collator
    4. from peft import prepare_model_for_int8_training, LoraConfig, get_peft_model
    5. MICRO_BATCH_SIZE = 1  
    6. BATCH_SIZE = 1
    7. GRADIENT_ACCUMULATION_STEPS = BATCH_SIZE // MICRO_BATCH_SIZE
    8. EPOCHS = 3  
    9. LEARNING_RATE = 3e-6  
    10. CUTOFF_LEN = 256  
    11. LORA_R = 16
    12. LORA_ALPHA = 32
    13. LORA_DROPOUT = 0.05

    模型加载,并使用int8进行训练

    1. model_path = "facebook/opt-6.7b"
    2. output_dir = "model"
    3. model = AutoModelForCausalLM.from_pretrained(model_path)
    4. tokenizer = AutoTokenizer.from_pretrained(model_path, add_eos_token=True)
    5. model = prepare_model_for_int8_training(model)  
    6. config = LoraConfig(
    7.     r=LORA_R,
    8.     lora_alpha=LORA_ALPHA,
    9.     target_modules=None,
    10.     lora_dropout=LORA_DROPOUT,
    11.     bias="none",
    12.     task_type="CAUSAL_LM",
    13. )
    14. model = get_peft_model(model, config)
    15. tokenizer.pad_token_id = 0  
    16. data = load_from_disk("data")

    训练与保存

    1. trainer = transformers.Trainer(
    2.     model=model,
    3.     train_dataset=data["train"],
    4.     eval_dataset=data["validation"],
    5.     args=transformers.TrainingArguments(
    6.         per_device_train_batch_size=MICRO_BATCH_SIZE,
    7.         per_device_eval_batch_size=MICRO_BATCH_SIZE,
    8.         gradient_accumulation_steps=GRADIENT_ACCUMULATION_STEPS,
    9.         warmup_steps=1000,
    10.         num_train_epochs=EPOCHS,
    11.         learning_rate=LEARNING_RATE,
    12.         # bf16=True,  
    13.         fp16=True,  
    14.         logging_steps=1,
    15.         output_dir=output_dir,
    16.         save_total_limit=4,
    17.     ),
    18.     data_collator=default_data_collator,
    19. )
    20. model.config.use_cache = False
    21. trainer.train(resume_from_checkpoint=False)
    22. model.save_pretrained(output_dir)

    直接这么启动当然会OOM,依然需要卸载

    编写accelerate配置文件accelerate.yaml

    1. compute_environment: LOCAL_MACHINE
    2. deepspeed_config:
    3.   gradient_accumulation_steps: 1
    4.   gradient_clipping: 1.0
    5.   offload_optimizer_device: none
    6.   offload_param_device: none
    7.   zero3_init_flag: true
    8.   zero3_save_16bit_model: true
    9.   zero_stage: 3
    10. distributed_type: DEEPSPEED
    11. downcast_bf16'yes'
    12. dynamo_backend: 'yes'
    13. fsdp_config: {}
    14. machine_rank: 0
    15. main_training_function: main
    16. megatron_lm_config: {}
    17. mixed_precision: fp16
    18. num_machines: 1
    19. num_processes: 2
    20. rdzv_backend: static
    21. same_network: true
    22. use_cpu: true

    deepspeed配置文件:ds.json

    1. {
    2.     "fp16": {
    3.         "enabled"true,
    4.         "loss_scale"0,
    5.         "loss_scale_window"500,
    6.         "initial_scale_power"16,
    7.         "hysteresis"2,
    8.         "min_loss_scale"1
    9.     },
    10.     "optimizer": {
    11.         "type""AdamW",
    12.         "params": {
    13.             "lr""auto",
    14.             "betas""auto",
    15.             "eps"1e-8,
    16.             "weight_decay""auto"
    17.         }
    18.     },
    19.     "scheduler": {
    20.         "type""WarmupLR",
    21.         "params": {
    22.             "warmup_min_lr"0,
    23.             "warmup_max_lr"2e-05,
    24.             "warmup_num_steps"0
    25.         }
    26.     },
    27.     "zero_optimization": {
    28.         "stage"2,
    29.         "offload_optimizer": {
    30.             "device""cpu",
    31.             "pin_memory"false
    32.         },
    33.         "allgather_partitions"true,
    34.         "allgather_bucket_size"2e8,
    35.         "overlap_comm"true,
    36.         "reduce_scatter"true,
    37.         "reduce_bucket_size"2e8,
    38.         "contiguous_gradients"true
    39.     },
    40.     "gradient_accumulation_steps":2,
    41.     "gradient_clipping""auto",
    42.     "steps_per_print"2000,
    43.     "train_batch_size"4,
    44.     "train_micro_batch_size_per_gpu"1,
    45.     "wall_clock_breakdown"false
    46. }

    启动

    accelerate launch --dynamo_backend=nvfuser  --config_file accelearte.yaml finetune.py
    

    注:其他方法与Lora使用方法差距不大,不再赘述,在peft项目中均有代码样例。

    顺便提一嘴:petals

    petals将模型划分为多个块,每个用户的机器负责其中一块,分摊了计算压力,类似于某磁力链接下载工具,利用hivemind库进行去中心化的训练与推理。当然你也可以创建自己局域网的群组,对自己独有的模型进行分块等自定义操作。

     

     

     

     

     

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/479219
推荐阅读
相关标签
  

闽ICP备14008679号