LoRaを使用してMistral-7Bをファインチューニングする
紹介
この記事では、7億パラメータを持つ大規模言語モデルMistral 7Bを紹介します。このモデルは、性能と効率性で知られており、評価されたすべてのベンチマークで、主要な13Bモデル(Llama 2)を上回る性能を発揮し、推論、数学、コード生成においては、最高の34Bモデル(Llama 1)をも上回っています。Mistral 7Bは、高い性能を発揮しながらも、効率的な推論を維持することを主張しています。
このモデルは、推論速度を向上させるためにグループクエリーアテンション(GQA)を採用し、任意の長さのシーケンスを効率的に処理するためにスライディングウィンドウアテンション(SWA)を取り入れており、推論コストを最小限に抑えています。
このチュートリアルでは、A6000 GPUの強力な能力を利用して、モデルをファインチューニングします。このプロセスは、時間あたり2ドル未満で済みます。A6000の力を活用して、高速かつ予算に優しいファインチューニングプロセスを実現しましょう。
前提条件
ハードウェア要件:
- 十分なVRAM(推奨は16GB以上)を備えた互換性のあるGPU(例:H100、A100)。
- 適切なシステムメモリ(最低32GBのRAM)。
ソフトウェア要件:
- Python(バージョン3.7以上).
データ準備:
- 目的のファインチューニングタスクに関連する構造化されたデータセット。
親しみ:
- 深層学習の概念とモデルのファインチューニングの理解。
環境設定:
- 必要な依存関係が整った環境を設定します。これには、仮想環境(例:condaやvenv)を使用することが含まれる場合があります。
ファインチューニングミストラル-7B
私たちの焦点は、MosaicML instructデータセットを使用してLoRaで4ビットのダブル量子化を用いてモデルを訓練することにあります。さらに、私たちはデータセットの「dolly_hhrlhf」サブセットに絞り込みます。これは、クリーンな応答-入力ペアです。データセットのサイズにかかわらず、プロセスは同じままです。このプロセスは、実際のデータをプロンプトに変換することを含みます。
コンセプト
概念はこうです:私たちはモデルにデータセットからの応答を提供し、その応答に至る元の指示を生成するよう挑戦します。これは全過程を逆にしたようなものです。
必要なパッケージをインポートすることから始めましょう:
!pip install transformers trl accelerate torch bitsandbytes peft datasets -qU
モデルを微調整するために必要なデータセットをダウンロードしてください。
from datasets import load_dataset
instruct_tune_dataset = load_dataset("mosaicml/instruct-v3")
instruct_tune_dataset
type(instruct_tune_dataset)
訓練データは56,200行のペアであり、テストデータは6,800行であり、'datasets.dataset_dict.DatasetDict'型のデータセットです。
さらに、‘dolly_hhrlhf’でフィルタリングすることによってデータセットを絞り込み、データのサブセットを取得します。
instruct_tune_dataset = instruct_tune_dataset.filter(lambda x: x["source"] == "dolly_hhrlhf")
私たちはデータの小さなサブセットでトレーニングとテストを行います。これにより、トレーニングにかかる時間を減らすことができます!
instruct_tune_dataset["train"] = instruct_tune_dataset["train"].select(range(3000))
instruct_tune_dataset["test"] = instruct_tune_dataset["test"].select(range(200))
次に、サンプル入力を受け取り、シーケンスを生成する関数を作成します。このシーケンスは、本質的にメッセージと、その応答を得るためのプロンプトです。
def create_prompt(sample):
bos_token = "<s>"
original_system_message = "Below is an instruction that describes a task. Write a response that appropriately completes the request."
system_message = "Use the provided input to create an instruction that could have been used to generate the response with an LLM."
response = sample["prompt"].replace(original_system_message, "").replace("\n\n### Instruction\n", "").replace("\n### Response\n", "").strip()
input = sample["response"]
eos_token = "</s>"
full_prompt = ""
full_prompt += bos_token
full_prompt += "### Instruction:"
full_prompt += "\n" + system_message
full_prompt += "\n\n### Input:"
full_prompt += "\n" + input
full_prompt += "\n\n### Response:"
full_prompt += "\n" + response
full_prompt += eos_token
return full_prompt
例えば:-
instruct_tune_dataset["train"][0]
キャンプ中に食べ物を料理する最良の方法は火の上で料理することです。まず、火を起こし、点火する必要があります。その後、火の上に鍋を置いて食べ物を加熱します。
create_prompt(instruct_tune_dataset["train"][0])
キャンプ中に食べ物をどのように調理できますか?
モデルをロードして訓練する
これは重要なステップです。モデルには十分なGPUスペースが必要です。32ビットから4ビットへの量子化されたバージョンのモデルで進めます。
私たちは、計算データ型に16ビットまたは半精度の量子化であるBFloat16を実装することを決定しました。一方、ストレージデータ型は4ビットになります。これは、すべての重みを4ビットで保存しますが、トレーニング中は一時的に16ビットにアップキャストすることを意味します。このアプローチにより、4ビットの量子化によるスペースの節約の恩恵を受けながら、効率的にトレーニングを行うことができます。
nf4_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_quant_type="nf4",
bnb_4bit_use_double_quant=True,
bnb_4bit_compute_dtype=torch.bfloat16
)
次に、モデルとトークナイザーをロードします。
model = AutoModelForCausalLM.from_pretrained(
"mistralai/Mistral-7B-Instruct-v0.1",
device_map='auto',
quantization_config=nf4_config,
use_cache=False
)
tokenizer = AutoTokenizer.from_pretrained("mistralai/Mistral-7B-v0.1")
tokenizer.pad_token = tokenizer.eos_token
tokenizer.padding_side = "right"
それでは、微調整の部分に移りましょう!
私たちはモデルの量子化されたバージョンを使用しているので、LoRaと呼ばれるものを使用する必要があります。チュートリアルをよりよく理解するために、LoRaについてより深い知識を得ることを強くお勧めします。
しかし今はLoRaを簡単に理解しましょう。
LoRa
このファインチューニングプロセスでは、パラメータ効率的ファインチューニング(PEFT)であるLoRa(低ランク適応)手法を使用しています。つまり、モデルを訓練する際に、大きな情報のセットを行列と呼びます。これらの行列はたくさんあります。LoRaは、大きな行列を表すずっと小さな行列を使うのに役立つ技術です。それは、大きな行列に多数の繰り返しの項目があるという事実を利用して機能します。特に私たちがやろうとしていることに関連するものです。
だから、全体のマトリックスは、学習できるすべてのタスクの大きなリストのように考えてください。ただし、私たちの特定のタスクはそのリストの小さな部分だけを必要とします。LoRaを用いて、私たちはその小さな部分に焦点を合わせる方法を見つけます。こうすることで、特定の仕事のためにモデルを訓練するたびに、毎回全体のリストを扱う必要がなくなります。これがLoRaの基本的なアイデアです!
このアプローチは、モデルが不要な情報を処理して保存する必要がないため、必要なGPUスペースの量をさらに減らします。本質的に、LoRaはGPUリソースの使用を最適化し、トレーニングプロセスをより効率的にし、貴重なコンピューティングリソースを節約します。
peft_config = LoraConfig(
lora_alpha=16,
lora_dropout=0.1,
r=64,
bias="none",
task_type="CAUSAL_LM"
)
kビットトレーニングのためにモデルを準備する
model = prepare_model_for_kbit_training(model)
model = get_peft_model(model, peft_config)
次に、ハイパーパラメータを設定します。これはモデルがトレーニングデータに過剰適合しないようにするためです。
args = TrainingArguments(
output_dir = "mistral_instruct_generation",
#num_train_epochs=5,
max_steps = 100,
per_device_train_batch_size = 4,
warmup_steps = 0.03,
logging_steps=10,
save_strategy="epoch",
#evaluation_strategy="epoch",
evaluation_strategy="steps",
eval_steps=20,
learning_rate=2e-4,
bf16=True,
lr_scheduler_type='constant',
)
教師ありファインチューニング(SFT)の過程では、事前学習された言語モデル(LLM)が、ラベル付きデータを使用して教師あり学習手法を通じて調整されます。このモデルの重みは、LLMによって行われた予測と実際のグラウンドトゥルースラベルとの間の差で測定されるタスク特有の損失から得られた勾配に従って修正されます。
max_seq_length = 2048
trainer = SFTTrainer(
model=model,
peft_config=peft_config,
max_seq_length=max_seq_length,
tokenizer=tokenizer,
packing=True,
formatting_func=create_prompt,
args=args,
train_dataset=instruct_tune_dataset["train"],
eval_dataset=instruct_tune_dataset["test"]
)
次に、トレイン関数を呼び出します。ここでは、モデルを100ステップで訓練します。エポック数を使用して訓練するようにコードを修正してください。
import time
start = time.time()
trainer.train()
print(time.time()- start)
損失がステップごとに徐々に減少していることがわかります。また、モデルのトレーニングには約16分かかることに注意してください。トレーニングの前にワンドの資格情報を追加する必要があることにも注意してください。
私たちはこのトレーニングされたモデルをローカルに保存します。
trainer.save_model("mistral_instruct_generation")
モデルをHugging Faceハブにプッシュすることができます。モデルをプッシュするためにHugging Faceの認可を確認してください。
この場合、アダプターをプッシュしますが、ここではフルモデルをプッシュしているわけではありません。LoRaを使用してトレーニングを行うと、アダプターとして知られるコンポーネントが得られます。このアダプターは、ベースモデルに適用できる拡張機能として機能し、ファインチューニング中に獲得した特定の能力を与えます。
trainer.push_to_hub("shaoni/mistral-instruct-generation")
wandb.aiで最近の実行をチェックして、システムメトリクスとモデルのパフォーマンスを確認してください。
モデルは小さなサンプルデータセットでファインチューニングされているため、パフォーマンスが依然として不十分になる可能性があることに注意してください。
generate_response("### Instruction:\nUse the provided input to create an instruction that could have been used to generate the response with an LLM.### Input:\nThere are more than 12,000 species of grass. The most common is Kentucky Bluegrass, because it grows quickly, easily, and is soft to the touch. Rygrass is shiny and bright green colored. Fescues are dark green and shiny. Bermuda grass is harder but can grow in drier soil.\n\n### Response:", model)
1万2000種以上の草の種類が存在します。最も一般的なのはケンタッキー・ブルーグラスで、成長が早く、育てやすく、触り心地が柔らかいため人気です。ライグラスは光沢のある鮮やかな緑色をしています。フェスクは濃い緑色で光沢があります。バermuda草は硬いですが、乾燥した土壌でも育つことができます。
この応答ははるかに良く、モデルはただ草についてのランダムな単語を追加しているわけではありません。
そして、これでPEFT LoRaを使用したMistral-7Bのファインチューニングが終了しました。
参考セクションをチェックして、もっと詳しい情報を見つけることをお勧めします。この記事を楽しんでいただけたら嬉しいです!
読んでくれてありがとう!
結論
この記事では、LoRaを使用してMistral-7Bをうまくファインチューニングできたことを報告します。このファインチューニングは、より性能の低いGPUを使用しても行うことができますが、結果を得るまでに時間がかかる場合があります。
GPUにアクセスできない場合は、クラウドサービスを利用することを検討してください。多くのプロバイダーがGPUオプションを提供しています。DigitalOceanのGPU Dropletsは現在、早期利用可能です。詳細を確認し、興味を示すにはこちらをご覧ください。
参照
- コード参照
- Hugging Face データセット
- オリジナル研究論文




