提供LoRA微调和全量参数微调代码,训练数据为data/train_sft.csv
,验证数据为data/dev_sft.csv
,数据格式为"
。本文主要介绍Llama-2-7b模型LoRA微调以及4bit量化的实践过程。Human: "+问题+"nAssistant: "+答案
1.LoRA微调脚本
LoRA微调脚本train/sft/finetune_lora.sh
如下所示:
output_model=save_folder
#需要修改到自己的输入目录
if[!-d${output_model}];then
mkdir${output_model}
fi
cp./finetune.sh${output_model}
CUDA_VISIBLE_DEVICES=0,1deepspeed--num_gpus2finetune_clm_lora.py#用于训练的脚本
--model_name_or_pathmeta-llama/Llama-2-7b-chat-hf#预训练模型路径
--train_files../../data/train_sft.csv#训练数据
../../data/train_sft_sharegpt.csv#训练数据
--validation_files../../data/dev_sft.csv#验证数据
../../data/dev_sft_sharegpt.csv#验证数据
--per_device_train_batch_size1#每个设备的训练批次大小
--per_device_eval_batch_size1#每个设备的验证批次大小
--do_train#是否训练
--do_eval#是否验证
--use_fast_tokenizerfalse#是否使用快速分词器
--output_dir${output_model}#输出目录
--evaluation_strategysteps#评估策略
--max_eval_samples800#最大验证样本数
--learning_rate1e-4#学习率
--gradient_accumulation_steps8#梯度累积步数
--num_train_epochs10#训练轮数
--warmup_steps400#预热步数
--load_in_bits4#加载位数
--lora_r8#lora_r表示秩的大小
--lora_alpha32#lora_alpha表示控制模型对原始预训练参数的更新程度
--target_modulesq_proj,k_proj,v_proj,o_proj,down_proj,gate_proj,up_proj#目标模块
--logging_dir${output_model}/logs#日志目录
--logging_strategysteps#日志策略
--logging_steps10#日志步数
--save_strategysteps#保存策略
--preprocessing_num_workers10#预处理工作数
--save_steps20#保存步数
--eval_steps20#评估步数
--save_total_limit2000#保存总数限制
--seed42#种子
--disable_tqdmfalse#禁用tqdm
--ddp_find_unused_parametersfalse#ddp_find_unused_parameters
--block_size2048#块大小
--report_totensorboard#报告到tensorboard
--overwrite_output_dir#覆盖输出目录
--deepspeedds_config_zero2.json#deepspeed配置文件
--ignore_data_skiptrue#忽略数据跳过
--bf16#bf16
--gradient_checkpointing#梯度检查点
--bf16_full_eval#bf16_full_eval
--ddp_timeout18000000#ddp_timeout
|tee-a${output_model}/train.log#日志输出
#--resume_from_checkpoint${output_model}/checkpoint-20400#恢复检查点
2.LoRA微调代码
LoRA微调具体实现代码train/sft/finetune_clm_lora.py
参考文献[3]。这里要说明下HuggingFace开源的一个高效微调大模型的PEFT库,目前支持很多方法和模型,详见参考文献[4][5]。LoRA(Low-Rank Adaptation)的本质就是奇异值分解,使用包含矩阵能量的秩来近似和还原原始矩阵,这样就可以将平方复杂度转换为线性复杂度了。本人读研期间做了很长时间的概率矩阵分解,对此有所理解。核心代码如下所示:
#步骤1:导入peft库中Lora相关模块
frompeftimport(
LoraConfig,
PeftModel,
get_peft_model,
get_peft_model_state_dict,
prepare_model_for_int8_training,
prepare_model_for_kbit_training,
set_peft_model_state_dict,
)
#步骤2:lora配置
lora_config=LoraConfig(#lora配置
r=model_args.lora_r,#r表示秩
lora_alpha=model_args.lora_alpha,#alpha表示缩放因子
#target_modules=["query_key_value"],#目标模块
#target_modules=['q_proj','k_proj','v_proj','o_proj'],#目标模块
target_modules=model_args.target_modules,#目标模块
fan_in_fan_out=False,#是否使用fan_in_fan_out
lora_dropout=0.05,#lora_dropout
inference_mode=False,#是否使用推理模式
bias="none",#偏置
task_type="CAUSAL_LM",#任务类型
)
#步骤3:加载model
model=AutoModelForCausalLM.from_pretrained(#从预训练模型中加载模型
model_args.model_name_or_path,#模型名或路径
from_tf=bool(".ckpt"inmodel_args.model_name_or_path),#是否从tensorflow加载
config=config,#配置
cache_dir=model_args.cache_dir,#缓存目录
revision=model_args.model_revision,#模型版本
use_auth_token=Trueifmodel_args.use_auth_tokenelseNone,#是否使用token
torch_dtype=torch_dtype,#torch数据类型
device_map={"":int(os.environ.get("LOCAL_RANK")or0)}#设备映射
)
#步骤4:获取peft模型
model=get_peft_model(model,lora_config)
#步骤5:初始化Trainer
trainer=Trainer(#训练器
model=model,#模型
args=training_args,#训练参数
train_dataset=train_datasetiftraining_args.do_trainelseNone,#训练数据集
eval_dataset=eval_datasetiftraining_args.do_evalelseNone,#评估数据集
tokenizer=tokenizer,#tokenizer
#数据收集器将默认为DataCollatorWithPadding,因此我们将其更改
data_collator=transformers.DataCollatorForSeq2Seq(#数据收集器
tokenizer,pad_to_multiple_of=8,return_tensors="pt",padding=True#tokenizer,填充到8的倍数,返回张量,填充
),
compute_metrics=compute_metricsiftraining_args.do_evalandnotis_torch_tpu_available()elseNone,#计算指标
preprocess服务器托管网_logits_for_metrics=preprocess_logits_for_metricsiftraining_args.do_evalandnotis_torch_tpu_available()elseNone,#为指标预处理logits
callbacks=([SavePeftModelCallback]ifisinstance(model,PeftModel)elseNone),#回调
)
3.加载LoRA微调模型
加载LoRA微调模型需要通过PEFT加载预训练模型参数和微调模型参数,base_model_name_or_path为预训练模型参数保存路径,finetune_model_path为微调模型参数保存路径。核心代码如下所示:
importtorch
fromtransformersimportAutoTokenizer,AutoModelForCausalLM
frompeftimportPeftModel,PeftConfig
#例如:finetune_model_path='Llama2-Chinese-7b-LoRA'
finetune_model_path=''#微调模型参数保存路径
#例如:base_model_name_or_path='meta-llama/Llama-2-7b'
base_model_name_or_path=''#为预训练模型参数保存路径
tokenizer=AutoTokenizer.from_pretrained(base_model_name_or_path,use_fast=False)
tokenizer.pad_token=tokenizer.eos_token
model=AutoModelForCausalLM.from_pretrained(base_model_name_or_path,device_map='auto',torch_dtype=torch.float16,load_in_8bit=True)
model=PeftModel.from_pretrained(model,finetune_model_path,device_map={"":0})
model=model.eval()
input_ids=tokenizer(['Human:介绍一下北京nAssistant:'],return_tensors="pt",add_special_tokens=False).input_ids.to('cuda')
generate_input={
"input_ids":input_ids,
"max_new_tokens":512,
"do_sample":True,
"top_k":50,
"top_p":0.95,
"temperature":0.3,
"repetition_penalty":1.3,
"eos_token_id":tokenizer.eos_token_id,
"bos_token_id":tokenizer.bos_token_id,
"pad_token_id":tokenizer.pad_token_id
}
generate_ids=model.generate(**generate_input)
text=tokenizer.decode(generate_ids[0])
print(text)
4.模型量化和加载方式
模型量化和LoRA微调具体实现代码train/sft/finetune_clm_lora.py
参考文献[3]。修改ModelArguments
类中的load_in_bits: Optional[int] = field(default=4)
。本质上就是先对模型做量化,然后再LoRA微调。核心代码如下所示:
#步骤1:导入peft库中Lora相关模块
frompeftimport(
LoraConfig,
PeftModel,
get_peft_model,
get_peft_model_state_dict,
prepare_model_for_int8_training,
prepare_model_for_kbit_training,
set_peft_model_state_dict,
)
#步骤2:导入transformers库中量化相关模块
fromtransformersimport(
BitsAndBytesConfig,
)
#步骤3:lora服务器托管网配置
lora_config=LoraConfig(#lora配置
r=model_args.lora_r,#r表示秩
lora_alpha=model_args.lora_alpha,#alpha表示缩放因子
#target_modules=["query_key_value"],#目标模块
#target_modules=['q_proj','k_proj','v_proj','o_proj'],#目标模块
target_modules=model_args.target_modules,#目标模块
fan_in_fan_out=False,#是否使用fan_in_fan_out
lora_dropout=0.05,#lora_dropout
inference_mode=False,#是否使用推理模式
bias="none",#偏置
task_type="CAUSAL_LM",#任务类型
)
#步骤4:bnb配置
bnb_config=BitsAndBytesConfig(#bnb配置
load_in_4bit=True,#是否使用4bit
bnb_4bit_use_double_quant=True,#是否使用双量化
bnb_4bit_quant_type="nf4",#量化类型
bnb_4bit_compute_dtype=torch.bfloat16#计算类型
)
#步骤5:加载model
model=AutoModelForCausalLM.from_pretrained(#从预训练模型中加载模型
model_args.model_name_or_path,#模型名或路径
from_tf=bool(".ckpt"inmodel_args.model_name_or_path),#是否从tensorflow加载
config=config,#配置
cache_dir=model_args.cache_dir,#缓存目录
revision=model_args.model_revision,#模型版本
use_auth_token=Trueifmodel_args.use_auth_tokenelseNone,#是否使用token
torch_dtype=torch_dtype,#torch数据类型
load_in_8bit=Trueifmodel_args.load_in_bits==8elseFalse,#是否使用8bit
quantization_config=bnb_configifmodel_args.load_in_bits==4elseNone,#量化配置
device_map={"":int(os.environ.get("LOCAL_RANK")or0)}#设备映射
)
#步骤6:准备模型进行kbit训练
model=prepare_model_for_kbit_training(model)
#步骤7:获取peft模型
model=get_peft_model(model,lora_config)
#步骤8:初始化Trainer
trainer=Trainer(#训练器
model=model,#模型
args=training_args,#训练参数
train_dataset=train_datasetiftraining_args.do_trainelseNone,#训练数据集
eval_dataset=eval_datasetiftraining_args.do_evalelseNone,#评估数据集
tokenizer=tokenizer,#tokenizer
#数据收集器将默认为DataCollatorWithPadding,因此我们将其更改
data_collator=transformers.DataCollatorForSeq2Seq(#数据收集器
tokenizer,pad_to_multiple_of=8,return_tensors="pt",padding=True#tokenizer,填充到8的倍数,返回张量,填充
),
compute_metrics=compute_metricsiftraining_args.do_evalandnotis_torch_tpu_available()elseNone,#计算指标
preprocess_logits_for_metrics=preprocess_logits_for_metricsiftraining_args.do_evalandnotis_torch_tpu_available()elseNone,#为指标预处理logits
callbacks=([SavePeftModelCallback]ifisinstance(model,PeftModel)elseNone),#回调
)
虽然LoRA微调和模型量化代码走通了,但是里面涉及到很多细节知识点需要深挖,比如LoRA具体代码实现[4][5][6],peft库支持微调方法(LoRA|Prefix Tuning|P-Tuning v1|P-Tuning v2|Prompt Tuning|AdaLoRA|LLaMA-Adapter|IA3
)和模型(Causal Language Modeling|Conditional Generation|Sequence Classification|Token Classification|Text-to-Image Generation|Image Classification|Image to text (Multi-modal models)|Semantic Segmentation
)的具体代码实现[4][5],模型量化(混合精度训练、4bit、8bit、fp16、fp32、bf16、AutoGPTQ库和bitsandbytes库)等。不管怎样先实践起来,更高一层的实践才能够理解低一层的理论。
参考文献:
[1]llama2 hf:https://huggingface.co/blog/llama2
[2]全参数微调时,报没有target_modules变量:https://github.com/FlagAlpha/Llama2-Chinese/issues/169
[3]finetune_clm_lora.py:https://github.com/ai408/nlp-engineering/blob/main/20230916_Llama2-Chinese/train/sft/finetune_clm_lora.py
[4]peft github:https://github.com/huggingface/peft
[5]peft hf:https://huggingface.co/docs/peft
[6]LoRA论文:https://arxiv.org/pdf/2106.09685.pdf
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net
机房租用,北京机房租用,IDC机房托管, http://www.fwqtg.net
有多久,没有发过短信了? 一、背景简介 在常规的分布式架构下,「消息中心」的服务里通常会集成「短信」的渠道,作为信息触达的重要手段,其他常用的手段还包括:「某微」、「某钉」、「邮件」等方式; 对于《消息中心》的设计和实现来说,在前面已经详细的总结过,本文重点来…