Pythonコード生成のためのLlama-2 7Bモデルのファインチューニング

Pythonコード生成のためのLlama-2 7Bモデルのファインチューニング

PEFT、QLoRa、およびHuggingfaceユーティリティを使用して新しいLlama-2を微調整するデモ

Leonardo.aiで作成された著者の画像

約2週間前、生成AIの世界はMeta社の新しいLlama-2 AIモデルのリリースによって衝撃を受けました。その前身であるLlama-1は、新しいファインチューニングの技術とともにその重みが公開されたことで、オープンソースのLLMモデルの大量作成が引き起こされ、Vicuna、Koalaなどの高性能モデルの出現につながりました。

この記事では、このモデルの関連するポイントについて簡単に説明し、この世界で標準的なライブラリやツールを使用してモデルを特定のタスクに迅速にトレーニングする方法を示すことに重点を置きます。新しいモデルの徹底的な分析は行いません。すでに数多くの記事が公開されています。

新しいLlama-2モデル

Metaは7B、13B、70Bのサイズを持つチャットバージョンのベースモデルとともに、オープンソースおよび商用の特性を備えた事前学習およびファインチューニング済みのモデルの新しいファミリーであるLlama-2をリリースしました。モデルとともに、それらの特性と学習プロセスの関連するポイントについて記載した論文も公開されており、非常に興味深い情報が提供されています。

Llama 1のアップデート版で、公開されているデータの新しいミックスでトレーニングされています。事前トレーニングのコーパスサイズは40%増加し、モデルのコンテキスト長が2倍になり、グループ化クエリアテンションが採用されました。 7B、13B、70Bのパラメータバリアントがリリースされていますが、論文にはリリースされていない34Bのバリアントも報告されています。[1]

事前トレーニングでは、トークン数が40%増加し、2Tに達し、コンテキスト長が2倍になり、70Bモデルの推論を高速化するためにグループ化クエリアテンション(GQA)技術が適用されました。標準のトランスフォーマーアーキテクチャでは、RMSNorm正規化、SwiGLUアクティベーション、回転位置埋め込みが使用され、コンテキスト長は4096トークンに達し、Adam最適化プログラムが適用され、余弦学習率スケジュール、重み減衰率0.1、勾配クリッピングが行われます。

教師ありファインチューニング(SFT)ステージは、高品質のデータの使用が最終的なモデルのパフォーマンス向上につながるという多くの報告から、量よりも品質の優先順位を付けたものです。最後に、ユーザーの好みにモデルを合わせるための人間のフィードバックによる強化学習(RLHF)ステップが適用されます。アノテーターがバイナリ比較で好ましいモデルの出力を選択する複数の例が収集されます。このデータを使用して報酬モデルをトレーニングし、ヘルプフルさと安全性に焦点を当てます。

要約すると:

・2Tトークンでトレーニング

・商用利用許可

・対話の使用例に対応したチャットモデル

・デフォルトのコンテキストウィンドウは4096(増やすことも可能)

・7B、13B、70Bのパラメータバージョン

・70Bモデルにはグループ化クエリアテンション(GQA)が採用されています

・チャットモデルにはツールとプラグインを使用できます

・LLaMA 2-CHATはOpenAI ChatGPTと同等の性能

微調整用データセット

微調整のために、与えられたタスクを解決するPythonコードを構築するようモデルに求められる約18,000の例を含むデータセットを使用します。これは、元のデータセット[2]の抽出であり、Python言語の例のみが選択されています。各行には、解決すべきタスクの説明、該当する場合のタスクへのデータ入力の例、およびタスクを解決する生成されたコードフラグメントが提供されます[3]。

# データセットをハブからロード
dataset = load_dataset(dataset_name, split=dataset_split)
# データセットのサイズを表示
print(f"データセットのサイズ:{len(dataset)}")
# 例を表示
print(dataset[randrange(len(dataset))])

プロンプトの作成

指示の微調整を行うためには、各データの例を指示として変換し、以下のように主なセクションをアウトラインする必要があります:

def format_instruction(sample): return f"""### 指示:以下のタスクと与えられた入力を使用して、以下のタスクを解決するプログラムコードであるレスポンスを書いてください:### タスク:{sample['instruction']}### 入力:{sample['input']}### レスポンス:{sample['output']}"""

出力:

### 指示:以下のタスクと与えられた入力を使用して、以下のタスクを解決するプログラムコードであるレスポンスを書いてください:### タスク:Pythonプログラムを開発し、実行時に「Hello, World!」と表示します。### 入力:### レスポンス:#Pythonプログラムで「Hello, World!」を表示するprint("Hello, World!")
Image by Irvan Smith from Unsplash

モデルの微調整

このステージを実行するために、Google Colab環境を使用し、トレーニングをインタラクティブに実行するためのノートブックと、トレーニングを無人で実行するためのPythonスクリプトを開発しました。最初のテストランでは、高いRAM容量を持つT4インスタンスが十分ですが、データセット全体とエポックを実行する場合は、実行時間を短縮し合理的な実行時間を確保するためにA100インスタンスを使用することにしました。

モデルを共有できるようにするために、適切なトークンを使用してHuggingfaceハブにログインします。このプロセス全体の最後に、モデルファイルをアップロードして他のユーザーと共有することができるようにします。

from huggingface_hub import loginfrom dotenv import load_dotenvimport os# 環境変数をロードするload_dotenv()# Hugging Face Hubにログインするlogin(token=os.getenv("HF_HUB_TOKEN"))

微調整技術:PEFT、Lora、およびQLora

最近、いくつかの論文が登場し、PEFT技術を使用して大規模な言語モデルを訓練することで、RAM要件を劇的に削減し、したがってリーズナブルなサイズの単一のGPUでこれらのモデルを微調整できるようになったことを示しています。LLMのトレーニングの通常の手順は、まず、数十億または数兆のトークンでの集中的な事前トレーニングを行い、基礎モデルを取得し、その後、このモデルで微調整を行い、ダウンストリームタスクに特化させます。この微調整フェーズでPEFT技術が目的を持ちます。

パラメータ効率的な微調整(PEFT)により、追加のパラメータをごくわずかに微調整することで、RAMおよびストレージ要件を大幅に削減することができます。ほぼすべてのモデルパラメータは凍結されたままであり、PEFTは比較的低容量のデータセットで良好な汎化を実現します。さらに、モデルの再利用性と移植性が向上し、小さなチェックポイントを基本モデルに簡単に追加でき、基本モデルにPEFTパラメータを追加することで複数のシナリオで簡単に微調整して再利用することができます。最後に、基本モデルが調整されないため、事前トレーニングフェーズで獲得したすべての知識が保持され、カタストロフィックな忘却を回避します。

最も広く使用されているPEFT技術は、事前トレーニングされた基本モデルをそのままにして新しいレイヤーまたはパラメータを追加することを目指しています。これらのレイヤーは「アダプター」と呼ばれ、その調整手法は「アダプターの微調整」と呼ばれています。これらの新しいレイヤーのパラメータのみをトレーニングします。しかし、このアプローチの深刻な問題は、これらのレイヤーが推論フェーズでのレイテンシーを増加させることであり、多くのシナリオではプロセスが非効率になります。 LoRaテクニックでは、大規模な言語モデルの低ランク適応を行うため、新しいレイヤーを追加するのではなく、パラメータに値を追加する方法で推論フェーズのレイテンシーの問題を回避します。LoRaは、追加の重みの変更をトレーニングおよび保存し、事前トレーニングされたモデルのすべての重みを凍結します。したがって、事前トレーニングされたモデル行列の変更を新しい重み行列でトレーニングし、この新しい行列を2つの低ランク行列に分解します。詳細はこちらで説明されています:

LLMのすべてのパラメータを行列W0に、行列∆Wの追加の重み変化を、最終的な重みはW0 + ∆Wとします。LoRA [1]の著者は、重み変化行列∆Wは2つの低ランク行列AとBに分解できると提案しました。LoRAは∆Wのパラメータを直接トレーニングせず、AとBのパラメータをトレーニングします。そのため、トレーニング可能なパラメータの数ははるかに少なくなります。仮にAの次元が100 * 1であり、Bの次元が1 * 100であると仮定すると、∆Wのパラメータの数は100 * 100 = 10000になります。AとBのトレーニングは100 + 100 = 200だけで済みますが、∆Wのトレーニングには10000が必要です

[4]. Fine-tuning a GPT — LoRAにおけるDr. Datamanによる説明

これらの低ランク行列のサイズはrパラメータによって定義されます。この値が小さいほど、トレーニングするパラメータが少なくなり、したがって労力と時間が節約できますが、逆に情報とパフォーマンスの損失の可能性もあります。より詳細な説明が必要な場合は、元の論文を参照するか、詳細に説明している記事がたくさんあります([4]など)。

最後に、QLoRa [6]は、LoRaメソッドに4ビットの通常の量子化であるnf4を適用することで構成され、メモリの使用量を削減するためのダブル量子化およびNVIDIA統合メモリの最適化が行われます。これらはメモリ使用量を最適化するための技術であり、より「軽量」で費用のかからないトレーニングを実現します。

Leonardo.aiからの画像

私たちの実験でQLoRaを実装するには、BitsAndBytesの設定を指定し、4ビットの量子化で事前学習されたモデルをダウンロードし、LoraConfigを定義する必要があります。最後に、トークナイザを取得する必要があります。

# タイプを取得compute_dtype = getattr(torch, bnb_4bit_compute_dtype)# BitsAndBytesConfigの設定bnb_config = BitsAndBytesConfig(    load_in_4bit=use_4bit,    bnb_4bit_use_double_quant=use_double_nested_quant,    bnb_4bit_quant_type=bnb_4bit_quant_type,    bnb_4bit_compute_dtype=compute_dtype)# モデルとトークナイザをロードmodel = AutoModelForCausalLM.from_pretrained(model_id,   quantization_config=bnb_config, use_cache = False, device_map=device_map)model.config.pretraining_tp = 1# トークナイザをロードtokenizer = AutoTokenizer.from_pretrained(model_id, trust_remote_code=True)tokenizer.pad_token = tokenizer.eos_tokentokenizer.padding_side = "right"

パラメータの定義,

# 4ビット精度ベースモデルをアクティベートuse_4bit = True# 4ビットベースモデルの計算dtypebnb_4bit_compute_dtype = "float16"# 量子化タイプ(fp4またはnf4)bnb_4bit_quant_type = "nf4"# 4ビットベースモデルのためのネストされた量子化をアクティベートするかどうか(ダブル量子化)use_double_nested_quant = False# LoRAの注意次元lora_r = 64# LoRAスケーリングのためのアルファパラメータlora_alpha = 16# LoRAレイヤのドロップアウト確率lora_dropout = 0.1

次のステップは、すべてのHugging Faceユーザーにとってよく知られているものです。トレーニング引数を設定し、トレーナーを作成します。私たちは指示のファインチューニングを実行しているため、PEFTモデルの定義や他のステップをカプセル化したSFTTrainerメソッドを呼び出します。

# トレーニング引数を定義args = TrainingArguments(    output_dir=output_dir,    num_train_epochs=num_train_epochs,    per_device_train_batch_size=per_device_train_batch_size, # use_flash_attentionで6、それ以外は4    gradient_accumulation_steps=gradient_accumulation_steps,    gradient_checkpointing=gradient_checkpointing,    optim=optim,    logging_steps=logging_steps,    save_strategy="epoch",    learning_rate=learning_rate,    weight_decay=weight_decay,    fp16=fp16,    bf16=bf16,    max_grad_norm=max_grad_norm,    warmup_ratio=warmup_ratio,    group_by_length=group_by_length,    lr_scheduler_type=lr_scheduler_type,    disable_tqdm=disable_tqdm,    report_to="tensorboard",    seed=42)# トレーナーを作成trainer = SFTTrainer(    model=model,    train_dataset=dataset,    peft_config=peft_config,    max_seq_length=max_seq_length,    tokenizer=tokenizer,    packing=packing,    formatting_func=format_instruction,    args=args,)# モデルをトレーニングtrainer.train() # tqdmが無効になっているので進捗バーは表示されません# モデルを保存trainer.save_model()

パラメータはGitHubリポジトリで見つけることができます。ほとんどはLLMのファインチューニングスクリプトでよく使用されるもので、以下のものです。

# Number of training epochsnum_train_epochs = 1# Enable fp16/bf16 training (set bf16 to True with an A100)fp16 = Falsebf16 = True# Batch size per GPU for trainingper_device_train_batch_size = 4# Number of update steps to accumulate the gradients forgradient_accumulation_steps = 1# Enable gradient checkpointinggradient_checkpointing = True# Maximum gradient normal (gradient clipping)max_grad_norm = 0.3# Initial learning rate (AdamW optimizer)learning_rate = 2e-4# Weight decay to apply to all layers except bias/LayerNorm weightsweight_decay = 0.001# Optimizer to useoptim = "paged_adamw_32bit"# Learning rate schedulelr_scheduler_type = "cosine" #"constant"# Ratio of steps for a linear warmup (from 0 to learning rate)warmup_ratio = 0.03# Group sequences into batches with same length# Saves memory and speeds up training considerablygroup_by_length = False# Save checkpoint every X updates stepssave_steps = 0# Log every X updates stepslogging_steps = 25# Disable tqdmdisable_tqdm= True

ベースモデルとアダプタの重みをマージする

前述のように、ベースモデルに対して「変更の重み」をトレーニングし、最終モデルでは事前学習モデルとアダプタを1つのモデルにマージする必要があります。

from peft import AutoPeftModelForCausalLMmodel = AutoPeftModelForCausalLM.from_pretrained(    args.output_dir,    low_cpu_mem_usage=True,    return_dict=True,    torch_dtype=torch.float16,    device_map=device_map,    )# Merge LoRA and base modelmerged_model = model.merge_and_unload()# Save the merged modelmerged_model.save_pretrained("merged_model",safe_serialization=True)tokenizer.save_pretrained("merged_model")# push merged model to the hubmerged_model.push_to_hub(hf_model_repo)tokenizer.push_to_hub(hf_model_repo)

モデルは、Hugging Faceアカウントedumunozsala/llama-2-7b-int4-python-code-20kで見つけてダウンロードすることができます。 試してみてください!

Pythonコードの推論または生成

最後に、Hugging Face Hubからモデルをダウンロードし、モデルを呼び出して正確な結果を生成する方法を示します。

import torchfrom transformers import AutoModelForCausalLM, AutoTokenizer# トークナイザを取得するtokenizer = AutoTokenizer.from_pretrained(hf_model_repo)# モデルをロードするmodel = AutoModelForCausalLM.from_pretrained(hf_model_repo, load_in_4bit=True,                                              torch_dtype=torch.float16,                                             device_map=device_map)# インストラクションを作成するinstruction="Pythonで書かれたコードスニペットを最適化します。コードスニペットは、0から10までの数値のうち、2で割り切れる数値のリストを作成する必要があります。"input=""prompt = f"""### インストラクション:以下のタスクと与えられたインプットを使用して、タスクを解決するプログラミングコードであるレスポンスを作成してください。### タスク:{instruction}### インプット:{input}### レスポンス:"""# インプットをトークン化するinput_ids = tokenizer(prompt, return_tensors="pt", truncation=True).input_ids.cuda()# モデルを実行して出力を生成するoutputs = model.generate(input_ids=input_ids, max_new_tokens=100, do_sample=True, top_p=0.9,temperature=0.5)# 結果を表示するprint(f"Prompt:\n{prompt}\n")print(f"Generated instruction:\n{tokenizer.batch_decode(outputs.detach().cpu().numpy(), skip_special_tokens=True)[0][len(prompt):]}")

Prompt:### インストラクション:以下のタスクと与えられたインプットを使用して、タスクを解決するプログラミングコードであるレスポンスを作成してください。### タスク:Pythonで書かれたコードスニペットを最適化します。コードスニペットは、0から10までの数値のうち、2で割り切れる数値のリストを作成する必要があります。### インプット:arr = []for i in range(10): if i % 2 == 0: arr.append(i)### レスポンス:Generated instruction:arr = [i for i in range(10) if i % 2 == 0]Ground truth:arr = [i for i in range(11) if i % 2 == 0]

優れた記事[9]のためにMaxime Labonneさん、またインスピレーションを提供してくれたコード[8]のためにPhilipp Schmidさんに感謝します。Llama 2とモデルのファインチューニングに興味のある方は、彼らの記事を必読としてください。

それが私が言及するすべてであり、この記事が役立つことを願っています。拍手は歓迎です!私の記事をフォローしたり、購読したり、Linkedinで私に連絡したりすることもできます。コードは私のGithubリポジトリで利用できます。

参考文献

[1] Llama-2の論文

[2] Huggingfaceハブでの元のデータセットへのリンク

[3] Huggingfaceハブで使用されるデータセットへのリンク

[4] Chris Kuo/Dr. DatamanによるGPTのファインチューニング – LoRA

[5] Edward J. Hu、Yelong Shen、Phillip Wallis、Zeyuan Allen-Zhu、Yuanzhi Li、Shean Wang、Lu Wang、およびWeizhu Chen(2021)。LoRA:大規模言語モデルの低ランク適応。arXiv:2106.09685

[6]. QLoRa:量子化されたLLMの効率的なファインチューニング

[7] Few-Shot Parameter-Efficient Fine-Tuningは、コンテキスト内学習よりも良く、安価です

[8] 拡張ガイド:Llama 2の命令チューニング – Philipp Schmid

[9] Colabノートブックで独自のLlama 2モデルをファインチューニングする – Maxime Labonne

[10]. 私のGithubリポジトリ

We will continue to update VoAGI; if you have any questions or suggestions, please contact us!

Share:

Was this article helpful?

93 out of 132 found this helpful

Discover more