大数跨境
0
0

在 NVIDIA L20 上使用 FSDP 和 QLora 微调 Llama 3 70B 模型

在 NVIDIA L20 上使用 FSDP 和 QLora 微调 Llama 3 70B 模型 紫光数码企业解决方案
2024-04-25
0
导读:测试报告分享

Meta 最近发布了 Llama 3 模型,展现了强大的性能, Llama 3 的亮点包括:


  1. 首次出现 8B 模型,且 8B 模型与 70B 模型全系列使用 GQA (Group Query Attention)。

  2. 最大模型达到 400B 规模大小,未来几个月内发布!

  3. 分词器由 SentencePiece 换为了 Tiktoken,与 GPT4 保持一致。

  4. 相比于 Llama2 的 32000 词表大小,Llama3 的词表大小来到了惊人的 128256。

  5. 数据方面上,Llama3 使用了约 15T token 用于模型的训练。

  6. 开源模型大小为 8B 和 70B 两种,每种规模均有开源基座模型和 instruct 模型。

  7. Llama3 8B Instruct 模型在数学与代码能力方面数倍于 Llama2 7B chat 模型。


然而大多数时候,我们需要根据数据微调这些模型,以释放模型的全部潜力。因此我们使用 FSDP 和 QLora 技术来微调 Llama 3 70B 模型:


FSDP:将训练扩展到多个 GPU

一个 70B 参数的模型需要 140GB 的显存,通过 FSDP,我们将 Llama 3 70B 模型分布在 4 张 L20 组成的 192 GB 显存上,满足了高效训练的要求。


QLoRA:在单个 GPU 上训练更大的模型

QLoRA 是现代神经网络中两个至关重要的进步的简单而出色的组合:量化和 LoRA,QLoRA 的开发团队在 48GB 的 GPU 卡上成功的训练了 65B 参数的模型(未量化需要 130GB 显存)。


本次测试,我们使用了NVIDIA在国内可以合规获得的L20服务器,服务器配置如下,如果您对L20感兴趣,请与我们联系。






01

搭建开发环境


我们的第一步是安装 Hugging Face 库和 PyTorch,包括 trl、transformers 和 datasets。如果你还没有听说过 trl,不用担心。它是建立在 transformers 和 datasets 之上的一个新库,可以更方便地进行微调、 rlhf 、对齐开放的大型语言模型(LLMs)。


# 使用conda先构建一个Python-3.10的虚拟环境%conda create --name llama3 python=3.10 -y%conda activate llama3
# 安装Pytorch for FSDP和FA/SDPA%pip install "torch==2.2.2" tensorboard
# 安装Hugging Face libraries%pip install --upgrade "transformers==4.40.0" "datasets==2.18.0" "accelerate==0.29.3" "evaluate==0.4.1" "bitsandbytes==0.43.1" "huggingface_hub==0.22.2" "trl==0.8.6" "peft==0.10.0"


接下来我们需要登录 Hugging Face 来访问 Llama 3 70b 模型。如果您还没。有帐户并接受条款,您可以此处在创建一个。


# Log in using a token from huggingface.co/settings/tokens%huggingface-cli login --token "your own token"


接下来我们安装 trl 和 Peft 。


# 从github上安装trl & peft%pip install -i https://pypi.tuna.tsinghua.edu.cn/simple  git+https://github.com/huggingface/trl.git%pip install -i https://pypi.tuna.tsinghua.edu.cn/simple  git+https://github.com/huggingface/peft.git


如果您使用的是 Ampere 架构或更新的 GPU,则可以使用 Flash Attention 。Flash Attention 是一种对注意力计算进行重新排序的方法,它利用经典技术(平铺、重新计算)显著加快计算速度,并将内存使用量从序列长度的二次方降低到线性。简而言之,就是将训练速度提高 3 倍。


import torch
# 检查GPU是否支持Flash Attentionassert torch.cuda.get_device_capability()[0] >= 8, 'Hardware not supported for Flash Attention'
# 安装flash-attn所需的依赖项print("Installing dependencies...")%pip install -i https://pypi.tuna.tsinghua.edu.cn/simple ninja packaging
# 安装flash-attn,使用4个并行作业并禁用构建隔离print("Installing flash-attn...")%MAX_JOBS=4 pip install -i https://pypi.tuna.tsinghua.edu.cn/simple flash-attn --no-build-isolation





02

创建和准备数据集


开发环境设置好后,我们可以开始创建和准备数据集,我们就需要创建一个数据集来微调我们的模型。这个数据集应该是你想要解决的任务的各种演示,有多种方法可以创建这样的数据集:


  1. 使用现有的开放源码数据集,如 Spider

  2. 使用 LLMs 创建合成数据集,如 Alpaca

  3. 利用人类创建数据集,如 Dolly

  4. 综合使用上述方法,如 Orca


每种方法都有自己的优缺点,并取决于预算、时间和质量要求。例如,使用现有的数据集是最简单的,但可能不适合您的具体使用情况;而使用人类可能是最准确的,但可能耗时且昂贵。也可以将几种方法结合起来创建一个指令数据集。


我们将使用 HuggingFaceH4/noo_robots 数据集,这是一个由熟练的人类注释者创建的高质量数据集,包含 10,000 个指令和演示。该数据可用于监督微调(SFT),使语言模型更好地遵循指令。No Robots 以 OpenAI 的 InstructGPT 论文中描述的指令数据集为模型,主要由单转指令组成。


no_robots 数据集有 10,000 个示例,分为 9,500 个训练示例和 500 个测试示例。有些示例不包含 system 消息。我们将使用 datasets 库加载数据集,添加缺失的 system 消息,并将它们保存到单独的 json 文件中。


from datasets import load_dataset
# Convert dataset to OAI messagessystem_message = """You are Llama, an AI assistant created by Philipp to be helpful and honest. Your knowledge spans a wide range of topics, allowing you to engage in substantive conversations and provide analysis on complex subjects."""
def create_conversation(sample):    if sample["messages"][0]["role"] == "system":        return sample    else:      sample["messages"] = [{"role": "system", "content": system_message}] + sample["messages"]      return sample
# Load dataset from the hubdataset = load_dataset("HuggingFaceH4/no_robots")
# Add system message to each conversationcolumns_to_remove = list(dataset["train"].features)columns_to_remove.remove("messages")dataset = dataset.map(create_conversation, remove_columns=columns_to_remove,batched=False)
# Filter out conversations which are corrupted with wrong turns, keep which have even number of turns after adding system messagedataset["train"] = dataset["train"].filter(lambda x: len(x["messages"][1:]) % 2 == 0)dataset["test"] = dataset["test"].filter(lambda x: len(x["messages"][1:]) % 2 == 0)
# save datasets to diskdataset["train"].to_json("train_dataset.json", orient="records", force_ascii=False)dataset["test"].to_json("test_dataset.json", orient="records", force_ascii=False)





03

使用 PyTorch FSDP、QLora 和 SDPA 对 LLM 进行微调

现在,我们准备使用 PyTorch FSDP、QLora 和 SDPA 对模型进行微调。由于我们采用的是分布式设置,因此需要使用 torchrun 和 python 脚本来启动训练。


我们编写了 run_fsdp_qlora.py 脚本,它将从磁盘加载数据集、准备模型、标记符并开始训练。它使用 trl 中的 SFTTrainer 来微调我们的模型。SFTTrainer 可以直接监督微调打开 LLMs 支持:


  • 数据集格式,包括会话和指令格式(✅已使用)

  • 只对完成情况进行培训,忽略提示(❌ 未使用)

  • 打包数据集,提高训练效率(✅已使用)

  • 支持 PEFT(参数效率微调),包括 QLoRA(✅ 已使用)

  • 为会话微调准备模型和标记符(❌ 未使用,见下文)


在配置方面,我们使用了新的 TrlParser ,它允许我们在 yaml 文件中提供超参数,或者通过明确地将参数传递给 CLI 来覆盖配置文件中的参数,例如 --num_epochs 10。以下是在 4xL20 GPU 上微调 Llama 3 70B 的配置文件。


%%writefile llama_3_70b_fsdp_qlora.yaml# script parametersmodel_id: "meta-llama/Meta-Llama-3-70b" # Hugging Face model iddataset_path: "."                      # path to datasetmax_seq_len:  3072 # 2048              # max sequence length for model and packing of the dataset# training parametersoutput_dir: "./llama-3-70b-hf-no-robot" # Temporary output directory for model checkpointsreport_to: "tensorboard"               # report metrics to tensorboardlearning_rate: 0.0002                  # learning rate 2e-4lr_scheduler_type: "constant"          # learning rate schedulernum_train_epochs: 3                    # number of training epochsper_device_train_batch_size: 1         # batch size per device during trainingper_device_eval_batch_size: 1          # batch size for evaluationgradient_accumulation_steps: 2         # number of steps before performing a backward/update passoptim: adamw_torch                     # use torch adamw optimizerlogging_steps: 10                      # log every 10 stepssave_strategy: epoch                   # save checkpoint every epochevaluation_strategy: epoch             # evaluate every epochmax_grad_norm: 0.3                     # max gradient normwarmup_ratio: 0.03                     # warmup ratiobf16: true                             # use bfloat16 precisiontf32: true                             # use tf32 precisiongradient_checkpointing: true           # use gradient checkpointing to save memory# FSDP parameters: https://huggingface.co/docs/transformers/main/en/fsdpfsdp: "full_shard auto_wrap offload" # remove offload if enough GPU memoryfsdp_config:  backward_prefetch: "backward_pre"  forward_prefetch: "false"  use_orig_params: "false"


未启动训练之前,当前L20 GPU卡的状态如下图:



对于 torchrun 和 FSDP ,我们需要设置环境变量 ACCELERATE_USE_FSDP 和 FSDP_CPU_RAM_EFFICIENT_LOADING 以告诉 transformers/accelerate 使用 FSDP ,并以节省内存的方式加载模型。现在,让我们用以下命令启动训练:


%ACCELERATE_USE_FSDP=1 FSDP_CPU_RAM_EFFICIENT_LOADING=1 torchrun --nproc_per_node=4 ./scripts/run_fsdp_qlora.py --config llama_3_70b_fsdp_qlora.yaml


训练开始后,GPU利用率开始上升,显示如下:



随着微调过程的深入,4 张 L20GPU 的利用率逐渐上升到 80% 左右,但功耗仍然保持在 85W 左右的较低水平



从 23:18 分开始微调,23:46 分结束微调工作,我们在 NVIDIA L20 上使用 FSDP 和 QLora 微调 Llama 3 70B 模型用时 28 分钟,L20 在整个微调过程中展现了良好的性能和较低的功耗。


感谢开源社区和 NVIDIA 公司的努力、贡献和支持,也特别感谢 Philschmid 的技术分享。


欢迎扫码关注,

获取更多精彩资讯!

【声明】内容源于网络
0
0
紫光数码企业解决方案
第一时间获取紫光数码企业级解决方案、成功案例介绍,报名市场活动。
内容 283
粉丝 0
紫光数码企业解决方案 第一时间获取紫光数码企业级解决方案、成功案例介绍,报名市场活动。
总阅读6
粉丝0
内容283