QLoRA:16GBのGPUで大規模な言語モデルの訓練を行う
QLoRA:16GB GPUで大規模な言語モデルのトレーニングを行う
量子化の仕組みを探求し、Google ColabのT4 16GB GPUで7兆パラメータのBloomモデルをファインチューニングする例を提供しましょう。
この記事は、Large Language Modelsの無料コースの一部です。GitHubで利用できます。
量子化などのモデルの重量削減技術と、LoRAなどのパラメータ効率の良いファインチューニング技術を組み合わせる予定です。この組み合わせの結果、非常に効率的なリソース利用で大規模モデルをファインチューニングできるQLoRAが実現します。
以前の記事では、LoRAを使用して大型言語モデルのファインチューニング方法を探求しました。
- 大規模なMLライフサイクルの統治、パート1:Amazon SageMakerを使用してMLワークロードを設計するためのフレームワーク
- 「自己改善のための生成AIと強化学習の統合」
- ニューラルネットワークの簡単な歴史
LoRAによる効率的なファインチューニング。大規模言語モデルの最適なトレーニング。
LoRAは、大規模言語モデルに適用可能な最も効率的で効果的なファインチューニング技術の一つです。記事では…
levelup.gitconnected.com
今回はQuantizationを追加し、より大規模かつパワフルなモデルのファインチューニングを行うことができます。
QLoRAでは、Lllama-2 7BやBloom 7Bなどの7兆パラメータモデルを、わずか16 GBのメモリを持つGPU上でファインチューニングすることが可能です。これにより、実際に使用できるファインチューニングモデルの中で最も効率的なメソッドの一つとなります。
そして、Hugging Faceの素晴らしいプロフェッショナルたちを活用し、わずか数行のコードでこれらの利点を享受することができます。
量子化の仕組みはどのように機能しますか?
基本的なアイデアは簡単です。通常は32ビットを占有する浮動小数点数の精度を、8ビットまたはさらに4ビットの整数に縮小します。
この縮小は、モデルのパラメータ、ニューラルレイヤーの重み、およびモデルのレイヤーを通過する活性化値において行われます。
つまり、モデルのストレージサイズとメモリ消費量の改善だけでなく、計算の素早さも向上させることができます。
もちろん精度の損失がありますが、特に8ビットの量子化の場合は、この損失は最小限です。
小さな例を見てみましょう。
量子化と非量子化のための関数を作成します。
実際に見たいのは、32ビットの数値から量子化された8/4ビットの数値に移行し、元の32ビットの値に戻った場合の精度の損失です。
#必要なライブラリをインポートimport numpy as npimport mathimport matplotlib.pyplot as plt#量子化および非量子化の関数def quantize(value, bits=4): quantized_value = np.round(value * (2**(bits - 1) - 1)) return int(quantized_value)def unquantize(quantized_value, bits=4): value = quantized_value / (2**(bits - 1) - 1) return float(value)quant_4 = quantize(0.622, 4)print (quant_4)quant_8 = quantize(0.622, 8)print(quant_8)
0.622を量子化すると、以下の結果が得られます:
- 4ビット: 4。
- 8ビット: 79
これらの値を元の精度に戻してみて、得られた結果を確認しましょう。
unquant_4 = unquantize(quant_4, 4)print(unquant_4)unquant_8 = unquantize(quant_8, 8)print(unquant_8)
- 4ビットの非量子化: 0.57142
- 8ビットの非量子化: 0.62204
元の数値が0.622だったと考えると、8ビットの量子化はほとんど精度を失いません、そして4ビットの量子化による損失は管理可能です。
量子化モデルの意図された使用法を常に考慮することが重要です。テキスト生成やソースコード生成などのタスクでは、精度の損失は重要ではありませんが、疾患診断に使用される画像認識モデルでは、大きな精度の損失が望ましくない場合があります。
コサインの非量子化値を持つ曲線をプロットしてみましょう。
x = np.linspace(-1, 1, 50)y = [math.cos(val) for val in x]y_quant_8bit = np.array([quantize(val, bits=8) for val in y])y_unquant_8bit = np.array([unquantize(val, bits=8) for val in y_quant_8bit])y_quant_4bit = np.array([quantize(val, bits=4) for val in y])y_unquant_4bit = np.array([unquantize(val, bits=4) for val in y_quant_4bit])
plt.figure(figsize=(10, 12))plt.subplot(4, 1, 1)plt.plot(x, y, label="元の値")plt.plot(x, y_unquant_8bit, label="非量子化_8ビット")plt.plot(x, y_unquant_4bit, label="非量子化_4ビット")plt.legend()plt.title("グラフの比較")plt.grid(True)
グラフから分かるように、8ビットの値を非量子化した線は元の値をほぼ完全に重ね合わせた形となっています。これに対して、4ビットの値を非量子化した線ではいくつかの目立つジャンプが見られます。8ビットの量子化と4ビットの量子化の精度の違いは非常に顕著です。モデルを量子化する際に考慮すべき重要な要素です。
とはいえ、テキスト生成の場合はほとんど差を感じないため、16GBの単一のGPUにモデルを読み込む必要があるため、4ビットの量子化を使用することにします。
QLoRA: LoRAを使用した4ビットの量子化モデルの微調整。
この記事と一緒にノートブックをフォローするために、Githubで入手できます:
Large-Language-Model-Notebooks-Course/5-Fine Tuning/QLoRA_Tuning_PEFT.ipynb at main ·…
Large Language Modelsについての実践的なコース。 .peremartra / Large-Language-Model-Notebooks-Courseに寄稿
github.com
使用するモデルはBloom 7Bです。これはHugging Faceで確立されたモデルの1つであり、非常に強力で、LLAMAのレベルで実行されます。このモデルは量子化しないと16GBのGPUに読み込むことができません。
前の記事では、同じ系列のモデルを使ってトレーニングしましたが、はるかに小さなモデルですので、二つのノートブックの違いを学ぶことができます。
必要なライブラリを読み込むことから始めましょう。
!pip -q install accelerate!pip -q install datasets!pip -q install trl
trlおよびaccelerateライブラリは、HuggingFaceエコシステムの一部であり、モデルの微調整を実行するために使用されます。
datasetsライブラリには、多くの前処理済みデータセットが含まれており、今回の例で使用するものも含まれています。
おそらく、2つの主要なライブラリが欠けていることに気付いたかもしれません:transformersとpeftです。最初のライブラリは、Hugging Faceモデルへの主要なインターフェースとして機能し、2番目のライブラリはさまざまな微調整技術の実装を含んでいます。PEFTはParameter Efficient Fine Tuningの略です。
これらのライブラリを特別な方法でインストールしましょう。
#最新バージョンのpeftとtransformersライブラリをインストールします(もし最新モデルを使用する場合は推奨)!pip install -q git+https://github.com/huggingface/peft.git!pip install -q git+https://github.com/huggingface/transformers.git
この方法で、プロジェクトのGitHubから直接これらのライブラリの最新バージョンをインストールしています。これには、MistralやLLAMA-2などの最新モデルの実装が含まれています。今回の場合、利用可能なバージョンのこれらのライブラリにBloomモデルファミリーが既に一定期間サポートされているため、厳密に必要ではないかもしれません。
さあ、必要なさまざまなクラスをインポートしましょう。
from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfigfrom trl import SFTTrainerimport torch
モデルをロードする。
#任意のモデルを使用します。高速なテストを行いたい場合は、最も小さいモデルを使用してください。#model_name = "bigscience/bloomz-560m"#model_name="bigscience/bloom-1b1"model_name = "bigscience/bloom-7b1"target_modules = ["query_key_value"]
選択したモデルはBloom 7Bですが、テストを行っている場合は、トレーニング時間とリソース使用量を最小限に抑えるために、より小さいモデルのいずれかを使用することをお勧めします。結果に満足したら、7Bモデルを試して結果を確認できます。
モデルをロードするには、クォンタイズの実行方法を指定する設定クラスが必要です。これは、TransformersライブラリのBitesAndBytesConfigを使用して実現します。
bnb_config = BitsAndBytesConfig( load_in_4bit=True, bnb_4bit_use_double_quant=True, bnb_4bit_quant_type="nf4", bnb_4bit_compute_dtype=torch.bfloat16)
ここでは4ビットのクォンタイズの使用と、精度損失を減らすためのダブルクォンタイズの有効化を指定しています。
bnb_4bit_quant_typeパラメータには、論文「QLoRA: Efficient Finetuning of Quantized LLMs.」で推奨される値を使用しました。
では、モデルの読み込みを行いましょう。
device_map = {"": 0}foundation_model = AutoModelForCausalLM.from_pretrained(model_name, quantization_config=bnb_config, device_map=device_map, use_cache = False)
これにより、モデルのクォンタイズバージョンがメモリに読み込まれます。もしもquantizationパラメータを削除してモデルを読み込もうとすると、メモリ制約のため読み込むことができない可能性が非常に高いです。
次に、トークナイザを読み込んで、モデルのテストの準備が整います。
tokenizer = AutoTokenizer.from_pretrained(model_name)tokenizer.pad_token = tokenizer.eos_token
ファインチューニングなしでモデルをテストする。
モデルのファインチューニングがどのような効果をもたらすかを判断するためには、修正を加える前に最近読み込まれたモデルでテストを実施するのが最適です。
この目的を達成するために、モデル、ユーザーの入力、および最大応答長を引数とする関数を作成します。
#この関数は、入力として受け取ったモデルからの出力を返します。def get_outputs(model, inputs, max_new_tokens=100): outputs = model.generate( input_ids=inputs["input_ids"], attention_mask=inputs["attention_mask"], max_new_tokens=max_new_tokens, repetition_penalty=1.5, #重複を避ける。 early_stopping=False, #モデルはmax_lengthに到達する前に停止できる eos_token_id=tokenizer.eos_token_id, ) return outputs
モデルにリクエストを渡して、そのレスポンスを確認することができます。それによって、ファインチューニング後のレスポンスと比較することができます。
# インファレンス元のモデルinput_sentences = tokenizer("私はあなたにモチベーションコーチとして行動してもらいたいです。", return_tensors="pt").to('cuda')foundational_outputs_sentence = get_outputs(foundation_model, input_sentences, max_new_tokens=50)print(tokenizer.batch_decode(foundational_outputs_sentence, skip_special_tokens=True))
[“私はあなたにモチベーションコーチとして行動してもらいたいです。私は、人々に何をすべきかを伝えるという意味ではなく、むしろ彼らを励まし、自分の行動を助けることができます。\n次のような質問をして始めることができます:\n\nあなたの目標は何ですか?\nこれによってそれを達成することができますか?\n\nそれから”]
レスポンスはかなり良いです。Bloomは、さまざまな状況で正確なレスポンスを提供できるよく訓練されたモデルです。560MのBloomでも同じテストを行いましたが、レスポンスは本当に違いました: [“私はあなたにモチベーションコーチとして行動してもらいたいです。挑戦されることを恐れないでください。”]。
データセットの準備
使用するデータセットは、datasetsライブラリで利用できるデータセットの1つです:fka/awesome-chatgpt-prompts。
データセットに含まれるいくつかのプロンプトを見てみましょう:
- I want you to act as a javascript console. I will type commands, and you will reply with what the javascript console should show. I want you to only reply with the terminal output inside one unique code block and nothing else. do not write explanations. do not type commands unless I instruct you to do so. when i need to tell you something in english, i will do so by putting text inside curly brackets {like this}. my first command is console.log(“Hello World”);
- I want you to act as a travel guide. I will write you my location and you will suggest a place to visit near my location. In some cases, I will also give you the type of places I will visit. You will also suggest me places of similar type that are close to my first location. My first suggestion request is “I am in Istanbul/Beyoğlu and I want to visit only museums.”
- I want you to act as a screenwriter. You will develop an engaging and creative script for either a feature length film, or a Web Series that can captivate its viewers. Start with coming up with interesting characters, the setting of the story, dialogues between the characters etc. Once your character development is complete — create an exciting storyline filled with twists and turns that keeps the viewers in suspense until the end. My first request is “I need to write a romantic drama movie set in Paris.”
ファインチューンされたモデルから期待する応答スタイルを明確に把握しました。それが達成できるか見てみましょう。
from datasets import load_datasetdataset = "fka/awesome-chatgpt-prompts"# プロンプトを作成するためのデータセットを作成data = load_dataset(dataset)data = data.map(lambda samples: tokenizer(samples["prompt"]), batched=True)train_sample = data["train"].select(range(50))del datatrain_sample = train_sample.remove_columns('act')display(train_sample)
Dataset({ features: [‘prompt’, ‘input_ids’, ‘attention_mask’], num_rows: 50 })
データセットには2つのカラムが含まれています。私はプロンプトを含むカラムのみを保持することを選びましたが、他のカラムは有用な情報を提供しないと考えています。
ただし、これは私が行った設計上の決定であり、actカラムを削除する行にコメントを記入して、ファインチューニングされたモデルがより良い結果を出すかどうかを検証してください。
QLoRAによるファインチューニング
モデル、トークナイザー、およびダウンロードしたデータセットがすべて揃いました。
QLoRAを使用して、データセットに含まれるプロンプトのようなプロンプトを生成できる新しいモデルを作成するためのファインチューニングプロセスを開始することができます。
最初のステップは、ファインチューニングプロセスの特性を指定する変数を設定するLoRA構成オブジェクトを作成することです。
# TARGET_MODULES# https://github.com/huggingface/peft/blob/39ef2546d5d9b8f5f8a7016ec10657887a867041/src/peft/utils/other.py#L220import peftfrom peft import LoraConfig, get_peft_modellora_config = LoraConfig( r=16, # Rが大きいほどトレーニングするパラメータが多くなります。 lora_alpha=16, # 重み行列の大きさを調整するスケーリングファクター。これが高ければ高いほど、新しいトレーニングに重みが加えられます。 target_modules=target_modules, lora_dropout=0.05, # 過学習を防ぐのに役立ちます。 bias="none", # バイアスパラメータをトレーニングするかどうかを指定します。 task_type="CAUSAL_LM")
以下に設定した値を検証しましょう:
- r:これは再パラメータ化のサイズを示します。値が小さいほど、トレーニングされるパラメータが少なくなります。より多くのパラメータをトレーニングすると、入力と出力の関係を学習する可能性が高くなりますが、計算コストも高くなります。16の値は妥当な妥協点であり、パラメータを制御しながら正しい結果を得ることができます。
- lora_alpha:この係数は重み行列の大きさを調整します。小さなモデルでは通常重要な影響を与えませんが、大きなモデルでは調整されない重みに比べて微調整により重みを与えるのに役立ちます。
- target_modules:トレーニングしたいモジュールを示します。モデル内の内部モジュール名を知る必要があるため、少し難しい決定に見えるかもしれません。幸いなことに、利用可能なモデルファミリーごとのモジュールが指定されているHugging Faceによって提供されたドキュメントを参照することができます。
- lora_dropout:以前にディープラーニングモデルをトレーニングしたことがある場合、おそらくドロップアウトについて知っているでしょう。オーバーフィッティングを防ぐために使用されます。この場合、短いトレーニング期間と限られたデータを考慮すると、ドロップアウト値を0で試してみることができます。
- bias:3つのオプションがあります – none、all、およびlora_only。テキスト分類にはnoneが一般的に使用されます。より複雑なタスクでは、allとlora_onlyの間から選ぶことができます。
さて、TrainingArgumentsクラスを引数として指定する必要がある新しく微調整されたモデルを含むディレクトリを作成しましょう。
#Modelを含むディレクトリを作成しますimport osworking_dir = './'output_directory = os.path.join(working_dir, "peft_lab_outputs")
#TrainingArgsを作成しますimport transformersfrom transformers import TrainingArguments # , Trainertraining_args = TrainingArguments( output_dir=output_directory, auto_find_batch_size=True, # データのサイズに合った正しいバッチサイズを見つけます。 learning_rate= 2e-4, # フルファインチューニングより高い学習率。 num_train_epochs=5)
TrainingArgumentsクラスは、トレーニングエポックの数や学習率など、私たち全員が馴染みがあるパラメータを受け取ります。
これで、モデルをトレーニングするために必要なものがすべて揃いました。
- モデル。
- TrainingArgs。
- データセット。
- LoRAの設定。
tokenizer.pad_token = tokenizer.eos_tokentrainer = SFTTrainer( model=foundation_model, args=training_args, train_dataset=train_sample, peft_config = lora_config, dataset_text_field="prompt", tokenizer=tokenizer, data_collator=transformers.DataCollatorForLanguageModeling(tokenizer, mlm=False))trainer.train()
TrainOutput(global_step=65, training_loss=2.7377777099609375, metrics={‘train_runtime’: 404.0462, ‘train_samples_per_second’: 0.619, ‘train_steps_per_second’: 0.161, ‘total_flos’: 966262938697728.0, ‘train_loss’: 2.7377777099609375, ‘epoch’: 5.0})
このモデルは正常に動作するはずなので、保存しましょう。
#モデルを保存します.peft_model_path = os.path.join(output_directory, f"lora_model")trainer.model.save_pretrained(peft_model_path)
ファインチューニングされたモデルのテスト。
#import peftfrom peft import AutoPeftModelForCausalLM, PeftConfig#import osdevice_map = {"": 0}working_dir = './'output_directory = os.path.join(working_dir, "peft_lab_outputs")peft_model_path = os.path.join(output_directory, f"lora_model")#モデルをロードします.loaded_model = AutoPeftModelForCausalLM.from_pretrained( peft_model_path, torch_dtype=torch.bfloat16, is_trainable=False, load_in_4bit=True, device_map = 'auto')
#微調整されたモデルへのリクエスト.input_sentences = tokenizer("私はあなたにモチベーションコーチとして行動してほしいです。", return_tensors="pt").to('cuda')foundational_outputs_sentence = get_outputs(loaded_model, input_sentences, max_new_tokens=50)print(tokenizer.batch_decode(foundational_outputs_sentence, skip_special_tokens=True))
[「私はあなたにモチベーションコーチとして行動して欲しいです。あなたはキャリアで苦戦して成功を収めることができていません。その人は以前に経験があるかもしれませんが、新しい機会を見つけてより多くの成果を上げるために探しています。
クライアントの現在の状況」]
私はこの回答が好きです!
結論。
回答を比較しましょう:
- 事前学習モデル:私はあなたにモチベーションコーチとして行動して欲しいです。私は人々に何をすべきかを伝える意味ではなく、彼らを励まし、自分自身の行動を促すことを意味します。
以下のような質問から始めることができます:目標は何ですか?
どのようにそれがそれを達成するのに役立ちますか?次に。
- ファインチューニングモデル:私はあなたにモチベーションコーチとして行動して欲しいです。自信を高めるために助けが必要な個人についての詳細を提供します。「自信を高めるためのアイデア」があなたの目標です。最初の提案は「彼らが最も必要とする時に励ましを提供する」です。私の返信
ファインチューニングプロセスは回答の構造に良い影響を与えていることが明確です。ファインチューニングされたモデルは、私たちが期待していたプロンプトにかなり近い回答を生成しました。 この実験を成功と考えています。
より長いトレーニングを行えば、より良い結果を得ることが可能です。
トレーニング変数を変更し、独自の結論を引き出すためにテストを実施することができます。大きな挑戦を目指す場合は、Mistral 7Bモデルのファインチューニングを繰り返してみてください!
リソース。
「Large Language Models」に関する完全なコースは、GitHubで利用できます。 新しい記事の最新情報を知りたい場合は、このリポジトリをフォローするか、スターをつけることをご検討ください。これにより、新しいコンテンツが追加されるたびに通知を受け取ることができます。
GitHub – peremartra/Large-Language-Model-Notebooks-Course: Practical course about Large Language…
Practical course about Large Language Models. . Contribute to peremartra/Large-Language-Model-Notebooks-Course…
github.com
QLoRAの動作に関する詳細情報をご希望の場合は: https://arxiv.org/abs/2305.14314
この記事はLarge Language Modelsの実践的な応用を探るシリーズの一部です。他の記事は、以下のリストで見つけることができます:
Large Language Models実践的なコース
リストを表示する10 ストーリー
私は定期的に深層学習とAIについて書いています。 VoAGIで私に従っていただき、新しい記事の更新情報を入手してください。そして、もちろん、LinkedInやTwitterで私とつながっていただくことも歓迎します。
We will continue to update VoAGI; if you have any questions or suggestions, please contact us!
Was this article helpful?
93 out of 132 found this helpful
Related articles