Trl SFT: llama2-7b-hf使用QLora 4bit量化后ds zero3加上flash atten v2单机多卡训练(笔记)

本文主要是介绍Trl SFT: llama2-7b-hf使用QLora 4bit量化后ds zero3加上flash atten v2单机多卡训练(笔记),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

一、环境

  1.1、环境安装

  1.2、安装flash atten

二、代码

  2.1、bash脚本 

  2.2、utils.py 注释与优化

  2.3、train.py 注释与优化

  2.4、模型/参数相关

    2.4.1、量化后的模型

      2.4.1.1 量化后模型结构

      2.4.1.2 量化后模型layers

    2.4.2、参数

     2.4.2.1 training args

     2.4.2.2 peft args

     2.4.2.3 model args

三、Trl 库

  3.1、SFTTrainer

  3.2、其他的代码

    3.2.1、datasets.map 使用 load_from_cache_file = False 方便调试​​​​​​​​​​​​​​

四、小结

  4.1、在SFTTrainer初始化peft模型时,为什么 开启了 QLoRA + FSDP / DS-Zero3 后不使用prepare_model_for_kbit_training 和 peft_module_casting_to_bf16 ,prepare_model_for_kbit_training 和 peft_module_casting_to_bf16 做了什么?QLoRA + FSDP / DS-Zero3 未开启offload​​​​​​​​​​​​​​模型加载后model为什么在cpu上?

  4.2、bfloat16和float16的区别

  4.3、绝对位置编码与相对位置编码的区别,为什么现在的大模型都使用RoPE

五、Trl 其他Trainer注释笔记

  5.1、DPOTrainer笔记​​​​​​​​​​​​​​

 5.2、... 


  • 项目地址

peft/examples/sft at main · huggingface/peft · GitHub🤗 PEFT: State-of-the-art Parameter-Efficient Fine-Tuning. - peft/examples/sft at main · huggingface/pefticon-default.png?t=N7T8https://github.com/huggingface/peft/tree/main/examples/sft

  • 文档

https://huggingface.co/docs/peft/accelerate/deepspeedicon-default.png?t=N7T8https://huggingface.co/docs/peft/accelerate/deepspeed

一、环境

系统:ubuntu 
cuda版本:12.1
torch版本:2.2.0
python版本:3.10conda 虚拟环境中 cuda版本
cuda:12.1  # 确保与"外界"cuda一致

  1.1、环境安装

pip install -r ...

    第一种

git+https://github.com/huggingface/transformers
git+https://github.com/huggingface/accelerate
git+https://github.com/huggingface/peft
git+https://github.com/huggingface/trl
git+https://github.com/huggingface/datatrove.git
unsloth[conda]@git+https://github.com/unslothai/unsloth.git
deepspeed
PyGithub
# flash-attn 单独安装
huggingface-hub
evaluate
datasets
bitsandbytes
einops
wandb
tensorboard
tiktoken
pandas
numpy
scipy
matplotlib
sentencepiece
nltk
xformers
hf_transfer

     第二种

absl-py==2.1.0
accelerate==0.30.0
aiohttp==3.9.4
aiosignal==1.3.1
annotated-types==0.6.0
appdirs==1.4.4
async-timeout==4.0.3
attrs==23.2.0
bitsandbytes==0.43.1
certifi==2024.2.2
cffi==1.16.0
charset-normalizer==3.3.2
click==8.1.7
contourpy==1.2.1
cryptography==42.0.5
cycler==0.12.1
datasets==2.18.0
datatrove==0.0.1
deepspeed==0.14.0
Deprecated==1.2.14
dill==0.3.8
docker-pycreds==0.4.0
docstring_parser==0.16
einops==0.7.0
evaluate==0.4.1
filelock==3.13.4
# flash-attn==2.5.7
# flash-attn 需要手动安装, 安装之前需要先保证:
# 第一 确保 linux "外界"的 cuda版本 与 conda 虚拟环境中cuda版本一致
# 第二 安装好 c++ g++ ninja
# 第三 参考官方命令: https://github.com/Dao-AILab/flash-attention
fonttools==4.51.0
frozenlist==1.4.1
fsspec==2024.2.0
gitdb==4.0.11
GitPython==3.1.43
grpcio==1.62.1
hf_transfer==0.1.6
hjson==3.1.0
huggingface-hub==0.22.2
humanize==4.9.0
idna==3.7
Jinja2==3.1.3
joblib==1.4.0
kiwisolver==1.4.5
loguru==0.7.2
Markdown==3.6
markdown-it-py==3.0.0
MarkupSafe==2.1.5
matplotlib==3.8.4
mdurl==0.1.2
mpmath==1.3.0
multidict==6.0.5
multiprocess==0.70.16
networkx==3.3
ninja==1.11.1.1
nltk==3.8.1
numpy==1.26.4
nvidia-cublas-cu12==12.1.3.1
nvidia-cuda-cupti-cu12==12.1.105
nvidia-cuda-nvrtc-cu12==12.1.105
nvidia-cuda-runtime-cu12==12.1.105
nvidia-cudnn-cu12==8.9.2.26
nvidia-cufft-cu12==11.0.2.54
nvidia-curand-cu12==10.3.2.106
nvidia-cusolver-cu12==11.4.5.107
nvidia-cusparse-cu12==12.1.0.106
nvidia-nccl-cu12==2.19.3
nvidia-nvjitlink-cu12==12.4.127
nvidia-nvtx-cu12==12.1.105
packaging==24.0
pandas==2.2.2
peft==0.10.1
pillow==10.3.0
pip==23.3.1
protobuf==3.20.3
psutil==5.9.8
py-cpuinfo==9.0.0
pyarrow==15.0.2
pyarrow-hotfix==0.6
pycparser==2.22
pydantic==2.7.0
pydantic_core==2.18.1
PyGithub==2.3.0
Pygments==2.17.2
PyJWT==2.8.0
PyNaCl==1.5.0
pynvml==11.5.0
pyparsing==3.1.2
python-dateutil==2.9.0.post0
pytz==2024.1
PyYAML==6.0.1
regex==2023.12.25
requests==2.31.0
responses==0.18.0
rich==13.7.1
safetensors==0.4.2
scipy==1.13.0
sentencepiece==0.2.0
sentry-sdk==1.45.0
setproctitle==1.3.3
setuptools==68.2.2
shtab==1.7.1
six==1.16.0
smmap==5.0.1
sympy==1.12
tensorboard==2.16.2
tensorboard-data-server==0.7.2
tiktoken==0.6.0
tokenizers==0.15.2
torch==2.2.2
tqdm==4.66.2
transformers==4.40.0
triton==2.2.0
trl==0.8.3
typing_extensions==4.11.0
tyro==0.8.3
tzdata==2024.1
unsloth==2024.4
urllib3==2.2.1
wandb==0.16.6
Werkzeug==3.0.2
wheel==0.43.0
wrapt==1.16.0
xformers==0.0.25.post1
xxhash==3.4.1
yarl==1.9.4

  1.2、安装flash atten

安装 flash atten 和 deepspeed 前,需要保证:

  • 第一 确保 linux "外界"的 cuda版本 与 conda 虚拟环境中cuda版本一致
  • 第二 安装好 c++ g++ ninja (c++ g++ Ninjia 安装版本过低后续安装可能会失败)
  • 第三 参考官方命令: GitHub - Dao-AILab/flash-attention: Fast and memory-efficient exact attentionFast and memory-efficient exact attention. Contribute to Dao-AILab/flash-attention development by creating an account on GitHub.icon-default.png?t=N7T8https://github.com/Dao-AILab/flash-attention
1. 安装 c++ g++
sudo apt-get update
sudo apt-get install build-essential2. 安装 Ninja
sudo apt-get install ninja-build3. 安装flash atten参考上面官方命令:pip install packagingpip install flash-attn --no-build-isolation          ----- flash atten 编译过程需要一定的时间,需要等待

二、代码

peft/examples/sft at main · huggingface/peft · GitHub🤗 PEFT: State-of-the-art Parameter-Efficient Fine-Tuning. - peft/examples/sft at main · huggingface/pefticon-default.png?t=N7T8https://github.com/huggingface/peft/tree/main/examples/sft

  2.1、bash脚本 

PYTHONPATH=$PWD
export PYTHONPATH
echo "当前bash执行目录: $PWD, 已经将PYTHONPATH设置为: $PYTHONPATH"# --resume_from_checkpoint dir   表示trainer从dir恢复ckpt
# 注释掉: 与wandb 不能共存
# 2>&1 | tee -a examples/sft/qlora_ds_zero3_log.out
accelerate launch --config_file "examples/sft/configs/deepspeed_config_z3_qlora.yaml"  examples/sft/train.py \--seed 100 \--model_name_or_path "/workspace/Llama-2-7b-chat-hf" \--dataset_name "smangrul/ultrachat-10k-chatml" \--chat_template_format "chatml" \--add_special_tokens False \--append_concat_token False \--splits "train,test" \--max_seq_len 2048 \--num_train_epochs 2 \--logging_steps 5 \--log_level "info" \--logging_strategy "steps" \--evaluation_strategy "epoch" \--save_strategy "steps" \--save_steps 100 \--save_total_limit 10 \--bf16 True \--packing True \--learning_rate 1e-4 \--lr_scheduler_type "cosine" \--weight_decay 1e-4 \--warmup_ratio 0.0 \--max_grad_norm 1.0 \--output_dir "/workspace/output/llama-sft-qlora-dsz3" \--per_device_train_batch_size 1 \--per_device_eval_batch_size 2 \--gradient_accumulation_steps 4 \--use_flash_attn True \--gradient_checkpointing True \--use_reentrant True \--dataset_text_field "content" \--use_peft_lora True \--lora_r 8 \--lora_alpha 16 \--lora_dropout 0.1 \--lora_target_modules "all-linear" \--use_4bit_quantization True \--use_nested_quant True \--bnb_4bit_compute_dtype "bfloat16" \--bnb_4bit_quant_storage_dtype "bfloat16" \--resume_from_checkpoint /workspace/output/llama-sft-qlora-dsz3/checkpoint-100 \2>&1 | tee -a examples/sft/qlora_ds_zero3_log.out# 上传至 hub 的参数# --push_to_hub \# --hub_private_repo True \# --hub_strategy "every_save" \

  2.2、utils.py 注释与优化

import os
from enum import Enumimport torch
from datasets import DatasetDict, load_dataset, load_from_disk
from datasets.builder import DatasetGenerationError
from transformers import (AutoModelForCausalLM,AutoTokenizer,BitsAndBytesConfig,
)from peft import LoraConfig# DEFAULT_CHATML_CHAT_TEMPLATE是一个用于格式化聊天消息的jinja2模板字符串
# jinja2是一种流行的Python模板引擎,它允许在模板中嵌入Python代码,使模板更加动态和可编程
# 在这个模板中,{% for message in messages %} 是一个jinja2的for循环语句,用于遍历messages列表中的每个消息
# {{'<|im_start|>' + message['role'] + '\n' + message['content'] + '<|im_end|>' + '\n'}}
# 这一部分定义了每条消息的格式化方式,包括:
#   1. <|im_start|>: 一个特殊标记,表示消息角色(如user、system或assistant)的开始
#   2. message['role']: 当前消息的角色,如user、system或assistant
#   3. \n: 换行符,用于在角色和消息内容之间添加新行
#   4. message['content']: 当前消息的实际内容
#   5. <|im_end|>: 一个特殊标记,表示消息内容的结束
#   6. \n: 换行符,用于在每条消息之后添加新行
# {% if loop.last and add_generation_prompt %}{{'<|im_start|>assistant\n' }}{% endif %}
# 这一部分是一个jinja2的条件语句,当循环遍历到最后一条消息时,如果add_generation_prompt为True,
# 则会在最后一条消息后添加'<|im_start|>assistant\n'作为提示,表示需要模型生成助手的回复
# 这种模板格式化方式的目的是将原始的聊天记录转换为适合语言模型输入的格式,以便进行对话生成任务
DEFAULT_CHATML_CHAT_TEMPLATE = "{% for message in messages %}\n{{'<|im_start|>' + message['role'] + '\n' + message['content'] + '<|im_end|>' + '\n'}}{% if loop.last and add_generation_prompt %}{{'<|im_start|>assistant\n' }}{% endif %}{% endfor %}"# DEFAULT_ZEPHYR_CHAT_TEMPLATE与DEFAULT_CHATML_CHAT_TEMPLATE类似,也是一个用于格式化聊天消息的jinja2模板
# 不同之处在于格式化方式和使用的特殊标记
# {% for message in messages %} 同样是一个用于遍历消息列表的for循环
# {% if message['role'] == 'user' %} 是一个条件语句,用于判断当前消息的角色是否为user
# 如果是user,则使用{{ '<|user|>\n' + message['content'] + eos_token }}将消息格式化为:
#   1. <|user|>: 用户角色的特殊标记
#   2. \n: 换行符
#   3. message['content']: 消息内容
#   4. eos_token: 句尾标记,如</s>
# {% elif message['role'] == 'system' %} 是另一个条件分支,用于判断当前消息的角色是否为system
# 如果是system,则使用{{ '<|system|>\n' + message['content'] + eos_token }}进行格式化
# {% elif message['role'] == 'assistant' %} 是第三个条件分支,用于判断当前消息的角色是否为assistant
# 如果是assistant,则使用{{ '<|assistant|>\n'  + message['content'] + eos_token }}进行格式化
# {% if loop.last and add_generation_prompt %}\n{{ '<|assistant|>' }}\n{% endif %}
# 这一部分与DEFAULT_CHATML_CHAT_TEMPLATE类似,当遍历到最后一条消息时,如果add_generation_prompt为True,
# 则会添加'<|assistant|>\n'作为提示,表示需要模型生成助手的回复
# 总的来说,这种格式化方式将原始聊天记录转换为适合语言模型输入的形式,但使用了不同的特殊标记
DEFAULT_ZEPHYR_CHAT_TEMPLATE = "{% for message in messages %}\n{% if message['role'] == 'user' %}\n{{ '<|user|>\n' + message['content'] + eos_token }}\n{% elif message['role'] == 'system' %}\n{{ '<|system|>\n' + message['content'] + eos_token }}\n{% elif message['role'] == 'assistant' %}\n{{ '<|assistant|>\n'  + message['content'] + eos_token }}\n{% endif %}\n{% if loop.last and add_generation_prompt %}\n{{ '<|assistant|>' }}\n{% endif %}\n{% endfor %}"# ZephyrSpecialTokens是一个继承自str和Enum的枚举类
# 它定义了Zephyr聊天格式中使用的各种特殊标记,如用户标记、助手标记、系统标记等
# 枚举类的好处是可以将一组相关的常量组织在一起,并提供更好的可读性和类型安全性
# 每个特殊标记都被定义为一个类属性,其值为对应的字符串形式
# 例如,user = "<|user|>"表示用户标记的字符串形式为"<|user|>"
class ZephyrSpecialTokens(str, Enum):user = "<|user|>"assistant = "<|assistant|>"system = "<|system|>"eos_token = "</s>"      # 句尾标记,表示一个句子或序列的结束bos_token = "<s>"       # 句首标记,表示一个句子或序列的开始pad_token = "<pad>"     # 填充标记,用于将序列填充至指定长度# list方法是一个类方法,它返回一个列表,包含了该枚举类中所有特殊标记的字符串形式# 这个方法常用于初始化分词器(tokenizer)时,将这些特殊标记添加到词表中@classmethoddef list(cls):return [c.value for c in cls]# ChatmlSpecialTokens与ZephyrSpecialTokens类似,也是一个定义了Chatml聊天格式中使用的特殊标记的枚举类
# 不同之处在于具体的特殊标记字符串形式
# 例如,user标记在Chatml格式中为"<|im_start|>user",而在Zephyr格式中为"<|user|>"
class ChatmlSpecialTokens(str, Enum):user = "<|im_start|>user"assistant = "<|im_start|>assistant"system = "<|im_start|>system"eos_token = "<|im_end|>"bos_token = "<s>"pad_token = "<pad>"@classmethoddef list(cls):return [c.value for c in cls]# create_datasets函数用于创建训练和测试数据集
# 参数包括:
#   tokenizer: 用于对文本进行分词(tokenization)和编码(encoding)的分词器对象
#   data_args: 包含数据相关配置的参数对象,如数据集名称、切分方式等
#   training_args: 包含训练相关配置的参数对象
#   apply_chat_template (bool): 是否应用聊天模板对数据进行预处理,默认为False
def create_datasets(tokenizer, data_args, training_args, apply_chat_template=False):# preprocess是一个内部函数,用于对数据样本进行预处理# 它接受一个字典样本作为输入,其中"messages"键对应一个列表,列表中的每个元素都是一个对话(conversation)def preprocess(samples):batch = []     # 初始化一个空列表,用于存储预处理后的对话# TODO 修改源码batch_tokens = []# 遍历样本中的每个对话for conversation in samples["messages"]:# 对每个对话应用tokenizer.apply_chat_template方法进行预处理# tokenize=False表示不执行分词操作,只进行格式化# https://huggingface.co/docs/transformers/main/zh/chat_templating# TODO 对源码进行修改chat_tmp = tokenizer.apply_chat_template(conversation, tokenize=False)batch.append(chat_tmp)chat_tmp_tokens = tokenizer.tokenize(chat_tmp)batch_tokens.append(chat_tmp_tokens)# 返回一个字典,其中"content"键对应预处理后的对话列表return {"content": batch, "content_tokens":batch_tokens}raw_datasets = DatasetDict()   # 初始化一个空的DatasetDict对象,用于存储数据集# 遍历data_args.splits指定的数据集切分(如train、test等)for split in data_args.splits.split(","):try:# Try first if dataset on a Hub repo, 首先尝试从Hugging Face Hub上加载指定的数据集dataset = load_dataset(data_args.dataset_name, split=split)except DatasetGenerationError:# If not, check local dataset, 如果从Hub上加载失败,则尝试从本地磁盘加载数据集dataset = load_from_disk(os.path.join(data_args.dataset_name, split))# 根据切分类型,将数据集存入raw_datasets的对应键值中if "train" in split:raw_datasets["train"] = datasetelif "test" in split:raw_datasets["test"] = datasetelse:raise ValueError(f"Split type {split} not recognized as one of test or train.")# 如果apply_chat_template为True,则对数据集应用preprocess函数进行预处理if apply_chat_template:raw_datasets = raw_datasets.map(preprocess,batched=True,         # 表示对样本进行批处理,提高效率remove_columns=raw_datasets["train"].column_names,# TODO 新增代码, 取消缓存, 用于调试load_from_cache_file = False)train_data = raw_datasets["train"]  # 获取训练数据集valid_data = raw_datasets["test"]   # 获取测试数据集# TODO 只有主进程打印if training_args.local_rank == 0 or training_args.local_rank == -1:print(f"Size of the train set: {len(train_data)}. Size of the validation set: {len(valid_data)}")  # 打印数据集大小print(f"A sample of train dataset: {train_data[0]}")  # 打印训练数据集的第一个样本return train_data, valid_data# create_and_prepare_model函数用于创建和准备模型
# 参数包括:
#   args: 包含模型相关配置的参数对象,如模型名称、是否使用量化等
#   data_args: 包含数据相关配置的参数对象,如最大序列长度等
#   training_args: 包含训练相关配置的参数对象,如是否使用梯度检查点等
def create_and_prepare_model(args, data_args, training_args):if args.use_unsloth:# 如果使用Unsloth库(一种用于加速语言模型的库),则导入FastLanguageModel类from unsloth import FastLanguageModelbnb_config = None    # 初始化BitsAndBytesConfig为None,用于量化配置quant_storage_dtype = None   # 初始化量化存储数据类型为None# 检查是否为分布式训练且使用Unsloth库,如果是则抛出NotImplementedError# 因为当前版本的Unsloth不支持分布式训练if (torch.distributed.is_available()and torch.distributed.is_initialized()and torch.distributed.get_world_size() > 1and args.use_unsloth):raise NotImplementedError("Unsloth is not supported in distributed training")# 如果使用4位量化,则设置计算数据类型和量化存储数据类型if args.use_4bit_quantization:# 获取指定的计算数据类型, getattr 会将字符串 bfloat16 ---> torch.bfloat16compute_dtype = getattr(torch, args.bnb_4bit_compute_dtype)# 获取指定的量化存储数据类型, getattr 会将字符串 bfloat16 ---> torch.bfloat16quant_storage_dtype = getattr(torch, args.bnb_4bit_quant_storage_dtype)# 创建BitsAndBytesConfig对象,用于配置量化相关参数# BitsAndBytesConfig是一个用于管理量化配置的类,可以指定量化类型、计算数据类型、存储数据类型等bnb_config = BitsAndBytesConfig(load_in_4bit=args.use_4bit_quantization,          # 是否使用4位量化bnb_4bit_quant_type=args.bnb_4bit_quant_type,     # 4位量化的类型, 如 nf4bnb_4bit_compute_dtype=compute_dtype,             # 计算数据类型bnb_4bit_use_double_quant=args.use_nested_quant,  # 是否使用双量化# TODO Qlora + zero3 修改的代码bnb_4bit_quant_storage=quant_storage_dtype,       # 量化存储数据类型)# 如果计算数据类型为float16且使用4位量化,则打印GPU是否支持bfloat16的提示if compute_dtype == torch.float16 and args.use_4bit_quantization:major, _ = torch.cuda.get_device_capability()if major >= 8:print("=" * 80)print("Your GPU supports bfloat16, you can accelerate training with the argument --bf16")print("=" * 80)# 如果使用8位量化,则创建相应的BitsAndBytesConfig对象elif args.use_8bit_quantization:bnb_config = BitsAndBytesConfig(load_in_8bit=args.use_8bit_quantization)# 如果使用Unsloth库if args.use_unsloth:# Load model, 使用FastLanguageModel.from_pretrained方法加载模型, 传入模型名称路径、最大序列长度、是否使用4位量化等参数model, _ = FastLanguageModel.from_pretrained(model_name=args.model_name_or_path,max_seq_length=data_args.max_seq_length,dtype=None,load_in_4bit=args.use_4bit_quantization,)else: # 如果不使用Unsloth库,则使用AutoModelForCausalLM.from_pretrained方法加载模型# TODO Qlora + zero3 修改的代码# 如果指定了quant_storage_dtype且是浮点数类型,则使用quant_storage_dtype, 否则使用默认的torch.float32torch_dtype = (quant_storage_dtype if quant_storage_dtype and quant_storage_dtype.is_floating_point else torch.float32)# 使用AutoModelForCausalLM.from_pretrained方法加载语言模型, 传入模型路径、量化配置、是否信任远程代码、注意力实现方式和数据类型等参数model = AutoModelForCausalLM.from_pretrained(args.model_name_or_path,quantization_config=bnb_config,trust_remote_code=True,# 注意力实现方式,flash_attention_2或eagerattn_implementation="flash_attention_2" if args.use_flash_attn else "eager",# TODO Qlora + zero3 修改的代码# 注意 torch_dtype 对于 AutoModelForCausalLM 与 bnb_4bit_quant_storage 数据类型相同。就是这样。其他所有事情都由 Trainer 和 TRL 处理。torch_dtype=torch_dtype,)peft_config = None      # 初始化PEFT配置为Nonechat_template = None    # 初始化聊天模板为None# 如果使用PEFT LoRA且不使用Unsloth库,则创建LoraConfig对象# PEFT (Parameter-Efficient Fine-Tuning)是一种模型微调技术,可以在保持大部分模型参数不变的情况下,只微调一小部分参数# LoRA (Low-Rank Adaptation)是PEFT的一种实现,通过添加低秩矩阵来适应新任务if args.use_peft_lora and not args.use_unsloth:peft_config = LoraConfig(lora_alpha=args.lora_alpha,         # LoRA的alpha参数,控制LoRA层的重要性lora_dropout=args.lora_dropout,r=args.lora_r,bias="none",                       # 是否对偏置项应用LoRAtask_type="CAUSAL_LM",             # 任务类型,这里是因果语言模型target_modules=args.lora_target_modules.split(",")if args.lora_target_modules != "all-linear"else args.lora_target_modules,)special_tokens = None   # 初始化特殊标记为Nonechat_template = None    # 初始化聊天模板为None# 根据args.chat_template_format参数,设置特殊标记和聊天模板if args.chat_template_format == "chatml":special_tokens = ChatmlSpecialTokens              # 使用Chatml格式的特殊标记chat_template = DEFAULT_CHATML_CHAT_TEMPLATE      # 使用Chatml聊天模板elif args.chat_template_format == "zephyr":special_tokens = ZephyrSpecialTokens            # 使用Zephyr格式的特殊标记chat_template = DEFAULT_ZEPHYR_CHAT_TEMPLATE    # 使用Zephyr聊天模板# 如果特殊标记不为Noneif special_tokens is not None:# 使用AutoTokenizer.from_pretrained方法加载分词器# 设置填充标记、句首标记、句尾标记和其他特殊标记tokenizer = AutoTokenizer.from_pretrained(args.model_name_or_path,pad_token=special_tokens.pad_token.value,     # 填充标记bos_token=special_tokens.bos_token.value,     # 句首标记eos_token=special_tokens.eos_token.value,     # 句尾标记additional_special_tokens=special_tokens.list(),  # 其他特殊标记trust_remote_code=True,)tokenizer.chat_template = chat_template           # 设置聊天模板# make embedding resizing configurable?# 调整tokenizer的嵌入大小,使其能够容纳新增的特殊标记# pad_to_multiple_of=8用于对齐,提高GPU计算效率model.resize_token_embeddings(len(tokenizer), pad_to_multiple_of=8)else:# 如果特殊标记为None,则直接加载分词器tokenizer = AutoTokenizer.from_pretrained(args.model_name_or_path, trust_remote_code=True)tokenizer.pad_token = tokenizer.eos_token     # 设置填充标记为句尾标记# 如果使用Unsloth库if args.use_unsloth:# Do model patching and add fast LoRA weights# 使用FastLanguageModel.get_peft_model方法对模型进行修补,并添加快速LoRA权重# 传入LoRA相关参数,如alpha、dropout、rank等,以及是否使用梯度检查点、随机种子和最大序列长度model = FastLanguageModel.get_peft_model(model,lora_alpha=args.lora_alpha,lora_dropout=args.lora_dropout,r=args.lora_r,target_modules=args.lora_target_modules.split(",")if args.lora_target_modules != "all-linear"else args.lora_target_modules,use_gradient_checkpointing=training_args.gradient_checkpointing,random_state=training_args.seed,max_seq_length=data_args.max_seq_length,)return model, peft_config, tokenizer       # 返回模型、PEFT配置和分词器

  2.3、train.py 注释与优化

import os
import sys
import torch
from dataclasses import dataclass, field
from typing import Optionalimport torch.distributed
from transformers import HfArgumentParser, TrainingArguments, set_seed, Seq2SeqTrainingArguments
from trl import SFTTrainer    # SFTTrainer用于序列到序列(Sequence-to-Sequence)的语言模型微调训练
from utils import create_and_prepare_model, create_datasets  # 自定义的实用函数,用于创建和准备模型、数据集# TODO 新增代码, wandb 与 bash 重定向 log.out 冲突, 关闭掉
os.environ["WANDB_DISABLED"] = "true" # 关闭 wandb# Define and parse arguments. 定义ModelArguments数据类,用于指定模型相关参数
@dataclass
class ModelArguments:"""Arguments pertaining to which model/config/tokenizer we are going to fine-tune from."""# 指定预训练语言模型的路径或在Hugging Face模型库中的标识符, 这允许您使用您选择的任何预训练模型,如GPT-2、GPT-3、BERT等model_name_or_path: str = field(metadata={"help": "Path to pretrained model or model identifier from huggingface.co/models"})# 指定聊天数据的格式,有以下选项:# 1) chatml: 使用Anthropic的chatml格式,例如: <human>: 你好 \n<assistant>: 你好,很高兴与你交谈。# 2) zephyr: 使用Pretrained.AI的zephyr格式,例如: Human: 你好 \nAssistant: 你好,很高兴与你交谈。 # 3) none: 如果数据集已经格式化为聊天模板,则设置为none# 这个参数可以帮助您灵活地处理不同格式的聊天数据chat_template_format: Optional[str] = field(default="none",metadata={"help": "chatml|zephyr|none. Pass `none` if the dataset is already formatted with the chat template."},)lora_alpha: Optional[int] = field(default=16)    # lora_alpha控制LoRA层的重要性,典型值为16或32lora_dropout: Optional[float] = field(default=0.1)  # lora_dropout设置LoRA层的dropout率,用于防止过拟合# lora_r指定LoRA低秩矩阵的秩(rank),较低的秩可以进一步减少参数量,但可能会影响性能, 秩越低,模型越压缩,但可能会导致性能下降lora_r: Optional[int] = field(default=64)# lora_target_modules指定应用LoRA的模块列表# 默认值包括注意力层的线性投影(q_proj, k_proj, v_proj, o_proj)和前馈神经网络层(down_proj, up_proj, gate_proj)# 也可以设置为"all-linear"以应用LoRA到所有线性层# 通过选择性地应用LoRA,可以在性能和参数量之间进行权衡lora_target_modules: Optional[str] = field(default="q_proj,k_proj,v_proj,o_proj,down_proj,up_proj,gate_proj",metadata={"help": "comma separated list of target modules to apply LoRA layers to"},)# use_nested_quant指定是否启用嵌套量化(nested quantization), 嵌套量化可以将4位量化模型进一步量化,从而进一步减小模型大小和内存占用,但可能会影响精度# 即 双量化use_nested_quant: Optional[bool] = field(default=False,metadata={"help": "Activate nested quantization for 4bit base models"},)# bnb_4bit_compute_dtype指定4位量化模型的计算数据类型,例如float16或bfloat16, 使用较低的计算精度可以提高计算速度,但可能会影响模型精度bnb_4bit_compute_dtype: Optional[str] = field(default="float16",metadata={"help": "Compute dtype for 4bit base models"},)# bnb_4bit_quant_storage_dtype指定4位量化模型的量化存储数据类型,如uint8或float16或bf16, 使用较低的存储精度可以减小模型大小,但可能会影响模型精度# 您需要权衡模型大小和精度的平衡bnb_4bit_quant_storage_dtype: Optional[str] = field(default="uint8",metadata={"help": "Quantization storage dtype for 4bit base models"},)# bnb_4bit_quant_type指定4位量化类型,包括fp4或nf4(normal float量化,一种新型的数据格式),信息论中表示nf4的效果可能会更好bnb_4bit_quant_type: Optional[str] = field(default="nf4",metadata={"help": "Quantization type fp4 or nf4"},)# use_flash_attn指定是否启用Flash注意力(Flash attention)# Flash注意力是一种高效的注意力实现,可以通过内存优化和并行计算提高训练速度use_flash_attn: Optional[bool] = field(default=False,metadata={"help": "Enables Flash attention for training."},)# use_peft_lora指定是否启用PEFT (Parameter-Efficient Fine-Tuning) LoRAuse_peft_lora: Optional[bool] = field(default=False,metadata={"help": "Enables PEFT LoRA for training."},)# use_8bit_quantization指定是否将模型加载为8位量化版本use_8bit_quantization: Optional[bool] = field(default=False,metadata={"help": "Enables loading model in 8bit."},)# use_4bit_quantization指定是否将模型加载为4位量化版本, 4位量化可以将模型大小减小到原始大小的1/4,从而进一步节省内存和加快计算,但可能会显著影响精度use_4bit_quantization: Optional[bool] = field(default=False,metadata={"help": "Enables loading model in 4bit."},)# use_reentrant是梯度检查点(Gradient Checkpointing)的一个参数, 梯度检查点可以通过重新计算激活值来节省内存,但会增加一些计算开销# use_reentrant指定是否使用可重入(reentrant)的梯度检查点实现,可能会进一步节省内存, 这个参数可以帮助在内存占用和计算开销之间进行权衡use_reentrant: Optional[bool] = field(default=False,metadata={"help": "Gradient Checkpointing param. Refer the related docs"},)# use_unsloth指定是否使用Unsloth库进行训练# Unsloth是一个优化库,可以通过内存优化和并行计算加速PEFT LoRA的训练过程# 这个参数可以帮助您进一步提高训练效率use_unsloth: Optional[bool] = field(default=False,metadata={"help": "Enables UnSloth for training."},)# 定义DataTrainingArguments数据类,用于指定数据集和数据处理相关参数
@dataclass
class DataTrainingArguments:# 指定要使用的数据集名称或路径,默认为OpenAssistant Guanaco数据集dataset_name: Optional[str] = field(default="timdettmers/openassistant-guanaco",metadata={"help": "The preference dataset to use."},)# packing指定是否使用数据集打包(packing)# 数据集打包可以将多个样本打包为一个更长的序列,从而提高训练效率, 这个参数可以帮助您在训练速度和内存占用之间进行权衡packing: Optional[bool] = field(default=False,metadata={"help": "Use packing dataset creating."},)# dataset_text_field指定数据集中作为input文本的字段名, 这个参数可以帮助您灵活地处理不同格式的数据集dataset_text_field: str = field(default="text", metadata={"help": "Dataset field to use as input text."})# max_seq_length指定输入序列的最大长度,超出部分将被截断, 这个参数可以帮助您在训练速度、内存占用和模型性能之间进行权衡max_seq_length: Optional[int] = field(default=512)# append_concat_token指定在打包数据集时,是否在每个样本的末尾追加一个连接标记(如<eos>),这个参数可以帮助您控制数据集的格式,从而影响模型的输出append_concat_token: Optional[bool] = field(default=False,metadata={"help": "If True, appends `eos_token_id` at the end of each sample being packed."},)# add_special_tokens指定在打包数据集时,是否由分词器(tokenizer)添加特殊标记(如<bos>和<eos>), 这个参数可以帮助您控制数据集的格式,从而影响模型的输出add_special_tokens: Optional[bool] = field(default=False,metadata={"help": "If True, tokenizers adds special tokens to each sample being packed."},)# splits指定要从数据集中使用的数据分割,如train、test或val,多个分割用逗号分隔, 这个参数可以帮助您灵活地使用数据集的不同部分进行训练和评估splits: Optional[str] = field(default="train,test",metadata={"help": "Comma separate list of the splits to use from the dataset."},)# TODO 新增代码, 打印模型的是否参与训练的参数名和数据类型
def print_model_allarguments_name_dtype(model):for n,v in model.named_parameters():if v.requires_grad:print(f"tr

这篇关于Trl SFT: llama2-7b-hf使用QLora 4bit量化后ds zero3加上flash atten v2单机多卡训练(笔记)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/912155

相关文章

C语言中联合体union的使用

本文编辑整理自: http://bbs.chinaunix.net/forum.php?mod=viewthread&tid=179471 一、前言 “联合体”(union)与“结构体”(struct)有一些相似之处。但两者有本质上的不同。在结构体中,各成员有各自的内存空间, 一个结构变量的总长度是各成员长度之和。而在“联合”中,各成员共享一段内存空间, 一个联合变量

Tolua使用笔记(上)

目录   1.准备工作 2.运行例子 01.HelloWorld:在C#中,创建和销毁Lua虚拟机 和 简单调用。 02.ScriptsFromFile:在C#中,对一个lua文件的执行调用 03.CallLuaFunction:在C#中,对lua函数的操作 04.AccessingLuaVariables:在C#中,对lua变量的操作 05.LuaCoroutine:在Lua中,

AssetBundle学习笔记

AssetBundle是unity自定义的资源格式,通过调用引擎的资源打包接口对资源进行打包成.assetbundle格式的资源包。本文介绍了AssetBundle的生成,使用,加载,卸载以及Unity资源更新的一个基本步骤。 目录 1.定义: 2.AssetBundle的生成: 1)设置AssetBundle包的属性——通过编辑器界面 补充:分组策略 2)调用引擎接口API

Vim使用基础篇

本文内容大部分来自 vimtutor,自带的教程的总结。在终端输入vimtutor 即可进入教程。 先总结一下,然后再分别介绍正常模式,插入模式,和可视模式三种模式下的命令。 目录 看完以后的汇总 1.正常模式(Normal模式) 1.移动光标 2.删除 3.【:】输入符 4.撤销 5.替换 6.重复命令【. ; ,】 7.复制粘贴 8.缩进 2.插入模式 INSERT

Lipowerline5.0 雷达电力应用软件下载使用

1.配网数据处理分析 针对配网线路点云数据,优化了分类算法,支持杆塔、导线、交跨线、建筑物、地面点和其他线路的自动分类;一键生成危险点报告和交跨报告;还能生成点云数据采集航线和自主巡检航线。 获取软件安装包联系邮箱:2895356150@qq.com,资源源于网络,本介绍用于学习使用,如有侵权请您联系删除! 2.新增快速版,简洁易上手 支持快速版和专业版切换使用,快速版界面简洁,保留主

如何免费的去使用connectedpapers?

免费使用connectedpapers 1. 打开谷歌浏览器2. 按住ctrl+shift+N,进入无痕模式3. 不需要登录(也就是访客模式)4. 两次用完,关闭无痕模式(继续重复步骤 2 - 4) 1. 打开谷歌浏览器 2. 按住ctrl+shift+N,进入无痕模式 输入网址:https://www.connectedpapers.com/ 3. 不需要登录(也就是

《offer来了》第二章学习笔记

1.集合 Java四种集合:List、Queue、Set和Map 1.1.List:可重复 有序的Collection ArrayList: 基于数组实现,增删慢,查询快,线程不安全 Vector: 基于数组实现,增删慢,查询快,线程安全 LinkedList: 基于双向链实现,增删快,查询慢,线程不安全 1.2.Queue:队列 ArrayBlockingQueue:

Toolbar+DrawerLayout使用详情结合网络各大神

最近也想搞下toolbar+drawerlayout的使用。结合网络上各大神的杰作,我把大部分的内容效果都完成了遍。现在记录下各个功能效果的实现以及一些细节注意点。 这图弹出两个菜单内容都是仿QQ界面的选项。左边一个是drawerlayout的弹窗。右边是toolbar的popup弹窗。 开始实现步骤详情: 1.创建toolbar布局跟drawerlayout布局 <?xml vers

操作系统实训复习笔记(1)

目录 Linux vi/vim编辑器(简单) (1)vi/vim基本用法。 (2)vi/vim基础操作。 进程基础操作(简单) (1)fork()函数。 写文件系统函数(中等) ​编辑 (1)C语言读取文件。 (2)C语言写入文件。 1、write()函数。  读文件系统函数(简单) (1)read()函数。 作者本人的操作系统实训复习笔记 Linux

C#中,decimal类型使用

在Microsoft SQL Server中numeric类型,在C#中使用的时候,需要用decimal类型与其对应,不能使用int等类型。 SQL:numeric C#:decimal