Llama2-Chinese项目:3.2-LoRA微调和模型量化
提供LoRA微调和全量参数微调代码,训练数据为data/train_sft.csv,验证数据为data/dev_sft.csv,数据格式为"<s>Human: "+问题+"\n</s><s>Assistant: "+答案。本文主要介绍Llama-2-7b模型LoRA微调以及4bit量化的实践过程。
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,1 deepspeed --num_gpus 2 finetune_clm_lora.py \ # 用于训练的脚本
--model_name_or_path meta-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_size 1 \ # 每个设备的训练批次大小
--per_device_eval_batch_size 1 \ # 每个设备的验证批次大小
--do_train \ # 是否训练
--do_eval \ # 是否验证
--use_fast_tokenizer false \ # 是否使用快速分词器
--output_dir ${output_model} \ # 输出目录
--evaluation_strategy steps \ # 评估策略
--max_eval_samples 800 \ # 最大验证样本数
--learning_rate 1e-4 \ # 学习率
--gradient_accumulation_steps 8 \ # 梯度累积步数
--num_train_epochs 10 \ # 训练轮数
--warmup_steps 400 \ # 预热步数
--load_in_bits 4 \ # 加载位数
--lora_r 8 \ # lora_r表示秩的大小
--lora_alpha 32 \ # lora_alpha表示控制模型对原始预训练参数的更新程度
--target_modules q_proj,k_proj,v_proj,o_proj,down_proj,gate_proj,up_proj \ # 目标模块
--logging_dir ${output_model}/logs \ # 日志目录
--logging_strategy steps \ # 日志策略
--logging_steps 10 \ # 日志步数
--save_strategy steps \ # 保存策略
--preprocessing_num_workers 10 \ # 预处理工作数
--save_steps 20 \ # 保存步数
--eval_steps 20 \ # 评估步数
--save_total_limit 2000 \ # 保存总数限制
--seed 42 \ # 种子
--disable_tqdm false \ # 禁用tqdm
--ddp_find_unused_parameters false \ # ddp_find_unused_parameters
--block_size 2048 \ # 块大小
--report_to tensorboard \ # 报告到tensorboard
--overwrite_output_dir \ # 覆盖输出目录
--deepspeed ds_config_zero2.json \ # deepspeed配置文件
--ignore_data_skip true \ # 忽略数据跳过
--bf16 \ # bf16
--gradient_checkpointing \ # 梯度检查点
--bf16_full_eval \ # bf16_full_eval
--ddp_timeout 18000000 \ # 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相关模块
from peft import (
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" in model_args.model_name_or_path), # 是否从tensorflow加载
config = config, # 配置
cache_dir = model_args.cache_dir, # 缓存目录
revision = model_args.model_revision, # 模型版本
use_auth_token = True if model_args.use_auth_token else None, # 是否使用token
torch_dtype = torch_dtype, # torch数据类型
device_map = {"": int(os.environ.get("LOCAL_RANK") or 0)} # 设备映射
)
# 步骤4:获取peft模型
model = get_peft_model(model, lora_config)
# 步骤5:初始化Trainer
trainer = Trainer( # 训练器
model = model, # 模型
args = training_args, # 训练参数
train_dataset = train_dataset if training_args.do_train else None, # 训练数据集
eval_dataset = eval_dataset if training_args.do_eval else None, # 评估数据集
tokenizer = tokenizer, # tokenizer
# 数据收集器将默认为DataCollatorWithPadding,因此我们将其更改
data_collator = transformers.DataCollatorForSeq2Seq( # 数据收集器
tokenizer, pad_to_multiple_of=8, return_tensors="pt", padding=True # tokenizer,填充到8的倍数,返回张量,填充
),
compute_metrics=compute_metrics if training_args.do_eval and not is_torch_tpu_available() else None, # 计算指标
preprocess_logits_for_metrics=preprocess_logits_for_metrics if training_args.do_eval and not is_torch_tpu_available() else None, # 为指标预处理logits
callbacks=([SavePeftModelCallback] if isinstance(model, PeftModel) else None), # 回调
)
3.加载LoRA微调模型
加载LoRA微调模型需要通过PEFT加载预训练模型参数和微调模型参数,base_model_name_or_path为预训练模型参数保存路径,finetune_model_path为微调模型参数保存路径。核心代码如下所示:
import torch
from transformers import AutoTokenizer, AutoModelForCausalLM
from peft import PeftModel,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(['<s>Human: 介绍一下北京\n</s><s>Assistant: '], 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相关模块
from peft import (
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库中量化相关模块
from transformers import (
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" in model_args.model_name_or_path), # 是否从tensorflow加载
config = config, # 配置
cache_dir = model_args.cache_dir, # 缓存目录
revision = model_args.model_revision, # 模型版本
use_auth_token = True if model_args.use_auth_token else None, # 是否使用token
torch_dtype = torch_dtype, # torch数据类型
load_in_8bit = True if model_args.load_in_bits == 8 else False, # 是否使用8bit
quantization_config = bnb_config if model_args.load_in_bits == 4 else None, # 量化配置
device_map = {"": int(os.environ.get("LOCAL_RANK") or 0)} # 设备映射
)
# 步骤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_dataset if training_args.do_train else None, # 训练数据集
eval_dataset = eval_dataset if training_args.do_eval else None, # 评估数据集
tokenizer = tokenizer, # tokenizer
# 数据收集器将默认为DataCollatorWithPadding,因此我们将其更改
data_collator = transformers.DataCollatorForSeq2Seq( # 数据收集器
tokenizer, pad_to_multiple_of=8, return_tensors="pt", padding=True # tokenizer,填充到8的倍数,返回张量,填充
),
compute_metrics=compute_metrics if training_args.do_eval and not is_torch_tpu_available() else None, # 计算指标
preprocess_logits_for_metrics=preprocess_logits_for_metrics if training_args.do_eval and not is_torch_tpu_available() else None, # 为指标预处理logits
callbacks=([SavePeftModelCallback] if isinstance(model, PeftModel) else None), # 回调
)
虽然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
Llama2-Chinese项目:3.2-LoRA微调和模型量化的更多相关文章
- osg项目经验1<MFC+OSG中模型点选效果>
点选主要是重载osg的GUIEventHandler, class CPickHandler : public osgGA::GUIEventHandler{ //自定义回调函数名:CPickHand ...
- [iOS微博项目 - 4.1] - cell的frame模型
github: https://github.com/hellovoidworld/HVWWeibo A.cell的frame模型设计 1.需求 每个cell都有一个frame实例引用 frame模型 ...
- 使用 LoRA 进行 Stable Diffusion 的高效参数微调
LoRA: Low-Rank Adaptation of Large Language Models 是微软研究员引入的一项新技术,主要用于处理大模型微调的问题.目前超过数十亿以上参数的具有强能力的大 ...
- 解密Prompt系列6. lora指令微调扣细节-请冷静,1个小时真不够~
上一章介绍了如何基于APE+SELF自动化构建指令微调样本.这一章咱就把微调跑起来,主要介绍以Lora为首的低参数微调原理,环境配置,微调代码,以及大模型训练中显存和耗时优化的相关技术细节 标题这样写 ...
- 使用BERT预训练模型+微调进行文本分类
本文记录使用BERT预训练模型,修改最顶层softmax层,微调几个epoch,进行文本分类任务. BERT源码 首先BERT源码来自谷歌官方tensorflow版:https://github.co ...
- 花 1 小时,开源设计 LoRa 继电器开关
提示1:锐米所有 LoRa 产品严格遵循国标标准的 LoRaWAN 协议. 提示2:您可以免费复制,修改和商用本项目,请注明锐米原创. 提示3:如果您有其他 LoRa 需求或建议,欢迎联系锐米 sup ...
- 3.Scikit-Learn实现完整的机器学习项目
1 完整的机器学习项目 完成项目的步骤: (1) 项目概述 (2) 获取数据 (3) 发现并可视化数据,发现规律. (4) 为机器学习算法准备数据. (5) ...
- 一个完整的机器学习项目在Python中演练(四)
大家往往会选择一本数据科学相关书籍或者完成一门在线课程来学习和掌握机器学习.但是,实际情况往往d是,学完之后反而并不清楚这些技术怎样才能被用在实际的项目流程中.就像你的脑海中已经有了一块块" ...
- 一个完整的机器学习项目在Python中演练(三)
大家往往会选择一本数据科学相关书籍或者完成一门在线课程来学习和掌握机器学习.但是,实际情况往往是,学完之后反而并不清楚这些技术怎样才能被用在实际的项目流程中.就像你的脑海中已经有了一块块"拼 ...
- 一个完整的机器学习项目在Python中的演练(二)
大家往往会选择一本数据科学相关书籍或者完成一门在线课程来学习和掌握机器学习.但是,实际情况往往是,学完之后反而并不清楚这些技术怎样才能被用在实际的项目流程中.就像你的脑海中已经有了一块块"拼 ...
随机推荐
- Spring配置动态数据库
前言 本文主要介绍使用spring boot 配置多个数据库,即动态数据库 开始搭建 首先创建一个SpringWeb项目--dynamicdb(spring-boot2.5.7) 然后引入相关依赖lo ...
- DosBox环境配置
DosBox环境配置 DOSBox 是一个基于 x86 架构的 PC 的模拟器,它允许用户在现代操作系统上运行 DOS 程序.DOSBox 是自由软件,可以在 Windows.Linux ,macOS ...
- 曲线艺术编程 coding curves 第八章 贝赛尔曲线(Bézier Curves)
贝赛尔曲线(Bézier Curves) 原作:Keith Peters https://www.bit-101.com/blog/2022/11/coding-curves/ 译者:池中物王二狗(s ...
- undefined reference to错误的解决方法
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明.本文链接:https://blog.csdn.net/cserchen/article/deta ...
- 探秘高逼格艺术二维码的制作过程-AI绘画图生图
在之前的文章<AI制作艺术二维码-文生图>中,我介绍了一种直接通过提示词生成高逼格二维码的方法,但是通过提示词我们无法很好的控制生成图片的样式,特别是有些同学想要将自己的Logo或者头像附 ...
- Button按钮:得到鼠标焦点后自动放大,失去鼠标焦点后自动缩小_
作用 程序设计过程中,我们经常需要增加一些动态效果,以此改善用户的使用体验.本文将介绍一种方法,动态显示按钮状态,使其得到鼠标焦点后自动放大,失去鼠标焦点后自动缩小. 效果图 先放一张原图(鼠标还未移 ...
- 数据分析之jupyter notebook工具
一.jupyter notebook介绍 1.简介 Jupyter Notebook是基于网页的用于交互计算的应用程序.其可被应用于全过程计算:开发.文档编写.运行代码和展示结果.--Jupyter ...
- PTA 21级数据结构与算法实验7—查找表
目录 7-1 电话聊天狂人 7-2 两个有序序列的中位数 7-3 词频统计 7-4 集合相似度 7-5 悄悄关注 7-6 单身狗 7-7 词典 7-8 这是二叉搜索树吗? 7-9 二叉搜索树 7-1 ...
- 2023-07-22:一共有n个项目,每个项目都有两个信息, projects[i] = {a, b}, 表示i号项目做完要a天,但是当你投入b个资源,它就会缩短1天的时间, 你一共有k个资源,你的目
2023-07-22:一共有n个项目,每个项目都有两个信息, projects[i] = {a, b}, 表示i号项目做完要a天,但是当你投入b个资源,它就会缩短1天的时间, 你一共有k个资源,你的目 ...
- Pandas:删除最后一行
解决方案 代码 效果展示 完整代码 import pandas as pd import numpy as np df = pd.DataFrame(np.arange(12).reshape(3,4 ...