ホームページ > 記事 > テクノロジー周辺機器 > わずか 250 ドルで、Hugging Face のテクニカル ディレクターが Llama 3 を段階的に微調整する方法を教えます
私たちは、Meta が立ち上げた Llama 3、Mistral AI が立ち上げた Mistral および Mixtral モデル、AI21 Lab が立ち上げた Jamba など、OpenAI の競合相手となったオープンソースの大規模言語モデルに精通しています。
ほとんどの場合、ユーザーはモデルの可能性を最大限に引き出すために、独自のデータに基づいてこれらのオープンソース モデルを微調整する必要があります。
単一の GPU で Q ラーニングを使用して、小規模な言語モデルと比較して、大規模な言語モデル (Mistral など) を微調整するのは難しくありませんが、Llama 370b や Mixtral のような大規模なモデルを効率的に微調整することは依然として困難です。今までの挑戦。
そこで、Hugging Face のテクニカル ディレクターである Philipp Schmid が、Hugging Face の TRL、Transformers、peft、およびデータセット ライブラリの助けを借りて、PyTorch FSDP と Q-Lora を使用して Llama 3 を微調整する方法を説明します。 FSDP に加えて、作者は PyTorch 2.2 アップデート後に Flash Attendant v2 も適応させました。
微調整の主な手順は次のとおりです:
ご注意ください: この記事は進行中です 実験は NVIDIA H100 および NVIDIA A10G GPU で作成および検証されました。プロファイルとコードは、それぞれ 24GB のメモリを搭載した 4xA10G GPU 用に最適化されています。ユーザーの計算能力が高い場合は、手順 3 で説明した構成ファイル (yaml ファイル) をそれに応じて変更する必要があります。
Answer.AI、Q-Lora 創設者 Tim Dettmers、Hugging Face が共同参加した共同プロジェクトに基づいて、著者は Q-Lora と PyTorch FSDP (完全共有データ) について理解しています。 Parallel) が提供できる技術サポートをまとめました。
FSDP と Q-Lora の組み合わせにより、ユーザーは 2 つのコンシューマーグレード GPU (24GB) で Llama 270b または Mixtral 8x7B を微調整できます。詳細については、以下の記事を参照してください。中でも、Hugging Face の PEFT ライブラリはこれに重要な役割を果たします。
記事のアドレス: https://www.answer.ai/posts/2024-03-06-fsdp-qlora.html
PyTorch FSDP は、GPU 間でモデルを分割し、メモリの必要性を削減できるデータ/モデル並列テクノロジです。より大きなモデルをより効率的にトレーニングできるようになります。 Q-LoRA は、量子化と低ランク アダプターを活用して、計算要件とメモリ フットプリントを効率的に削減する微調整方法です。
最初のステップは、trl、トランスフォーマー、データセットなどのライブラリを含む、Hugging Face ライブラリと Pyroch をインストールすることです。 trl は、トランスフォーマーとデータセットに基づいて構築された新しいライブラリであり、オープンソースの大規模言語モデルの微調整、RLHF、調整を容易にします。
# Install Pytorch for FSDP and FA/SDPA%pip install "torch==2.2.2" tensorboard# Install 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 モデルを入手します。
環境のセットアップが完了したら、データセットの作成と準備を開始できます。マイクロ呼び出しデータセットには、ユーザーが解決したいタスクのサンプルが含まれている必要があります。データセットの作成の詳細については、「2024 年に顔を抱きしめながら LLM を微調整する方法」を参照してください。
記事のアドレス: https://www.philschmid.de/fine-tune-llms-in-2024-with-trl#3-create-and-prepare-the-dataset
著者は HuggingFaceH4/no_robots データセットを使用しましたは、10,000 個の命令とサンプルを含む高品質のデータ セットであり、高品質のデータ アノテーションが施されています。このデータは、言語モデルが人間の指示によりよく従うようにするための教師あり微調整 (SFT) に使用できます。 no_robots データセットは、OpenAI によって発行された InstructGPT 論文で説明されている人間の命令データセットをモデルにしてモデル化されており、主に単一文の命令で構成されています。
{"messages": [{"role": "system", "content": "You are..."}, {"role": "user", "content": "..."}, {"role": "assistant", "content": "..."}]}{"messages": [{"role": "system", "content": "You are..."}, {"role": "user", "content": "..."}, {"role": "assistant", "content": "..."}]}{"messages": [{"role": "system", "content": "You are..."}, {"role": "user", "content": "..."}, {"role": "assistant", "content": "..."}]}
no_robots データセット内の 10,000 個のサンプルは、9,500 個のトレーニング サンプルと 500 個のテスト サンプルに分割されており、その一部にはシステム情報が含まれていません。作成者は、データセット ライブラリを使用してデータセットをロードし、不足しているシステム情報を追加して、それらを別の 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 sampleelse: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)
接下来使用 PyTorch FSDP、Q-Lora 和 SDPA 对大语言模型进行微调。作者是在分布式设备中运行模型,因此需要使用 torchrun 和 python 脚本启动训练。
作者编写了 run_fsdp_qlora.py 脚本,其作用是从磁盘加载数据集、初始化模型和分词器并开始模型训练。脚本使用 trl 库中的 SFTTrainer 来对模型进行微调。
SFTTrainer 能够让对开源大语言模型的有监督微调更加容易上手,具体来说有以下几点:
格式化的数据集,包括格式化的多轮会话和指令(已使用)只对完整的内容进行训练,忽略只有 prompts 的情况(未使用)打包数据集,提高训练效率(已使用)支持参数高效微调技术,包括 Q-LoRA(已使用)为会话级任务微调初始化模型和分词器(未使用,见下文)
注意:作者使用的是类似于 Anthropic/Vicuna 的聊天模板,设置了「用户」和「助手」角色。这样做是因为基础 Llama 3 中的特殊分词器(<|begin_of_text|> 及 <|reserved_special_token_XX|>)没有经过训练。
这意味着如果要在模板中使用这些分词器,还需要对它们进行训练,并更新嵌入层和 lm_head,对内存会产生额外的需求。如果使用者有更多的算力,可以修改 run_fsdp_qlora.py 脚本中的 LLAMA_3_CHAT_TEMPLATE 环境变量。
在配置参数方面,作者使用了新的 TrlParser 变量,它允许我们在 yaml 文件中提供超参数,或者通过明确地将参数传递给 CLI 来覆盖配置文件中的参数,例如 —num_epochs 10。以下是在 4x A10G GPU 或 4x24GB 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"
注意:训练结束时,GPU 内存使用量会略有增加(约 10%),这是因为模型保存所带来的开销。所以使用时,请确保 GPU 上有足够的内存来保存模型。
在启动模型训练阶段,作者使用 torchrun 来更加灵活地运用样本,并且易于被调整,就像 Amazon SageMaker 及 Google Cloud Vertex AI 一样。
对于 torchrun 和 FSDP,作者需要对环境变量 ACCELERATE_USE_FSDP 和 FSDP_CPU_RAM_EFFICIENT_LOADING 进行设置,来告诉 transformers/accelerate 使用 FSDP 并以节省内存的方式加载模型。
注意:如果想不使用 CPU offloading 功能,需要更改 fsdp 的设置。这种操作只适用于内存大于 40GB 的 GPU。
本文使用以下命令启动训练:
!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
预期内存使用情况:
在 g5.12xlarge 服务器上,基于包含 1 万个样本的数据集,作者使用 Flash Attention 对 Llama 3 70B 进行 3 个 epoch 的训练,总共需要 45 小时。每小时成本为 5.67 美元,总成本为 255.15 美元。这听起来很贵,但可以让你在较小的 GPU 资源上对 Llama 3 70B 进行微调。
如果我们将训练扩展到 4x H100 GPU,训练时间将缩短至大约 125 小时。如果假设 1 台 H100 的成本为 5-10 美元 / 小时,那么总成本将在 25-50 美元之间。
我们需要在易用性和性能之间做出权衡。如果能获得更多更好的计算资源,就能减少训练时间和成本,但即使只有少量资源,也能对 Llama 3 70B 进行微调。对于 4x A10G GPU 而言,需要将模型加载到 CPU 上,这就降低了总体 flops,因此成本和性能会有所不同。
注意:在作者进行的评估和测试过程中,他注意到大约 40 个最大步长(将 80 个样本堆叠为长度为三千的序列)就足以获得初步结果。40 个步长的训练时间约为 1 小时,成本约合 5 美元。
使用 QLoRA 时,作者只训练适配器而不对整个模型做出修改。这意味着在训练过程中保存模型时,只保存适配器权重,而不保存完整模型。
如果使用者想保存完整的模型,使其更容易与文本生成推理器一起使用,则可以使用 merge_and_unload 方法将适配器权重合并到模型权重中,然后使用 save_pretrained 方法保存模型。这将保存一个默认模型,可用于推理。
注意:CPU 内存需要大于 192GB。
#### COMMENT IN TO MERGE PEFT AND BASE MODEL ##### from peft import AutoPeftModelForCausalLM# # Load PEFT model on CPU# model = AutoPeftModelForCausalLM.from_pretrained(# args.output_dir,# torch_dtype=torch.float16,# low_cpu_mem_usage=True,# )# # Merge LoRA and base model and save# merged_model = model.merge_and_unload()# merged_model.save_pretrained(args.output_dir,safe_serialization=True, max_shard_size="2GB")
模型测试和推理
训练完成后,我们要对模型进行评估和测试。作者从原始数据集中加载不同的样本,并手动评估模型。评估生成式人工智能模型并非易事,因为一个输入可能有多个正确的输出。阅读《评估 LLMs 和 RAG,一个使用 Langchain 和 Hugging Face 的实用案例》可以了解到关于评估生成模型的相关内容。
文章地址:https://www.philschmid.de/evaluate-llm
import torchfrom peft import AutoPeftModelForCausalLMfrom transformers import AutoTokenizerpeft_model_id = "./llama-3-70b-hf-no-robot"# Load Model with PEFT adaptermodel = AutoPeftModelForCausalLM.from_pretrained(peft_model_id,torch_dtype=torch.float16,quantization_config= {"load_in_4bit": True},device_map="auto")tokenizer = AutoTokenizer.from_pretrained(peft_model_id)
接下来加载测试数据集,尝试生成指令。
from datasets import load_datasetfrom random import randint# Load our test dataseteval_dataset = load_dataset("json", data_files="test_dataset.json", split="train")rand_idx = randint(0, len(eval_dataset))messages = eval_dataset[rand_idx]["messages"][:2]# Test on sampleinput_ids = tokenizer.apply_chat_template(messages,add_generation_prompt=True,return_tensors="pt").to(model.device)outputs = model.generate(input_ids,max_new_tokens=512,eos_token_id= tokenizer.eos_token_id,do_sample=True,temperature=0.6,top_p=0.9,)response = outputs[0][input_ids.shape[-1]:]print(f"**Query:**\n{eval_dataset[rand_idx]['messages'][1]['content']}\n")print(f"**Original Answer:**\n{eval_dataset[rand_idx]['messages'][2]['content']}\n")print(f"**Generated Answer:**\n{tokenizer.decode(response,skip_special_tokens=True)}")# **Query:**# How long was the Revolutionary War?# **Original Answer:**# The American Revolutionary War lasted just over seven years. The war started on April 19, 1775, and ended on September 3, 1783.# **Generated Answer:**# The Revolutionary War, also known as the American Revolution, was an 18th-century war fought between the Kingdom of Great Britain and the Thirteen Colonies. The war lasted from 1775 to 1783.
至此,主要流程就介绍完了,心动不如行动,赶紧从第一步开始操作吧。
以上がわずか 250 ドルで、Hugging Face のテクニカル ディレクターが Llama 3 を段階的に微調整する方法を教えますの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。