データセットの準備
ここで調整できるパラメータについて少し説明しましょう。まず、モデルをロードして (1,000 サンプル)llama-2-7b-hf
でトレーニングし mlabonne/guanaco-llama2-1k
、微調整されたモデルを生成します llama-2-7b-miniguanaco
。このデータセットがどのように作成されたかに興味がある場合は、このノートブックを確認してください 。自由に変更してください。Hugging Face Hubには、 databricks/databricks-dolly-15kなどの優れたデータセットが多数あります 。
次のコードを使用してオフライン データ セットを準備します (GPU マシンはインターネットに接続できません)
import os
from datasets import load_from_disk, load_dataset
print("loading dataset...")
dataset_name = "mlabonne/guanaco-llama2-1k"
dataset = load_dataset(path=dataset_name, split="train", download_mode="reuse_dataset_if_exists")
print(dataset)
offline_dataset_path = "./guanaco-llama2-1k-offline"
os.makedirs(offline_dataset_path, exist_ok=True)
print("save to disk...")
dataset.save_to_disk('./guanaco-llama2-1k-offline')
print("load from disk")
dataset = load_from_disk("./guanaco-llama2-1k-offline")
print(dataset)
<s>[INST] 32 ビット アプリケーションのメモリが不足している場合はどうすればよいですか[/INST] 1. 不要なデータとアプリケーションを削除します。Intelligent Manager (メモリ マネージャ) - 記憶域スペース/メモリ。\n2. 不要なアプリケーションを終了します: 画面の左下隅にある最近のタスク キーをクリックします - 閉じたいアプリケーションの右上隅にある「X」をクリックします/下の「すべて閉じる」をクリックします。\n3. 携帯電話がメモリ カードをサポートしている場合は、マルチメディア ファイルを拡張カードに移動するか、撮影ストレージ パスを拡張カードに設定します。メモリ カードがない場合は、マルチメディア ファイルを定期的にコンピュータに移動することをお勧めします。\n4. 使用頻度の低いソフトウェアまたはファイルをアンインストールします。</s>
['<s>[INST] 失恋したとき、どうやって自分を慰めればいいですか? [/INST] 失恋はつらい経験ですが、その過程で自分を慰める方法を学び、立ち直る必要があります。ここでは自分を慰めるためのヒントをいくつか紹介します:\n\n1. 痛みを自分に感じさせてください: 失恋は正常な感情的反応であり、自分の感情を隠したり抑えたりする必要はありません。ゆっくりとこの事実と向き合い、自分の感情を受け入れてください。\n\n2. サポートを見つける: 打ち明けられる友人、家族、カウンセラーを見つけて、感情を解決し、悩みを聞いてもらうのを手伝ってもらいましょう。この問題に一人で直面しないでください。\n\n3. 気分が良くなる何かをする: 運動、読書、音楽を聴く、旅行など、気分が良くなる何かを見つけます。これらの活動は気を紛らわせるのに役立ち、痛みを軽減することができます。\n\n4. 自分自身の成長に注意を払う: 恋人との別れは成長の機会であり、自分自身をより深く理解し、感情や対人関係に対処する方法を学ぶことができます。自分の成長に集中し、その過程にも意味があることを忘れないでください。\n\n5. 時間をかける: 壊れた関係が修復するには時間がかかります。すぐに回復しようと無理にしないでください。十分な時間をかけてプロセスを処理し、ゆっくりと心の状態を取り戻してください。\n\n失恋は辛い経験ですが、学び成長する機会でもあります。この困難を乗り越えれば、未来はさらに良くなると信じてください。</s><s>[INST] 失恋した私を慰めてくれませんか?[/INST] そういえば、がっかりするかもしれません。テキストを処理する AI 言語モデルとして、表現内容に基づいてテキストで回答を与えることはできますが、実際の出来事を理解する本当の能力はありません。現実の人々に共感する能力。でも、もしあなたが自分の気持ちや考えを分かち合って、どんな助けやサポートが必要なのか教えていただければ、喜んで慰めとサポートをさせていただきます。この悲しい時期を乗り越えるために全力を尽くします。期間。</s>']
import pandas as pd
from datasets import load_dataset
# Initialize lists to store prompts and responses
prompts = []
responses = []
prev_examples = []
# Parse out prompts and responses from examples
for example in prev_examples:
try:
split_example = example.split('-----------')
prompts.append(split_example[1].strip())
responses.append(split_example[3].strip())
except:
pass
# Create a DataFrame
df = pd.DataFrame({
'prompt': prompts,
'response': responses
})
# Remove duplicates
df = df.drop_duplicates()
print('There are ' + str(len(df)) + ' successfully-generated examples. Here are the first few:')
df.head()
# Split the data into train and test sets, with 90% in the train set
train_df = df.sample(frac=0.9, random_state=42)
test_df = df.drop(train_df.index)
# Save the dataframes to .jsonl files
train_df.to_json('train.jsonl', orient='records', lines=True)
test_df.to_json('test.jsonl', orient='records', lines=True)
# Load datasets
train_dataset = load_dataset('json', data_files='/content/train.jsonl', split="train")
valid_dataset = load_dataset('json', data_files='/content/test.jsonl', split="train")
# Preprocess datasets
train_dataset_mapped = train_dataset.map(lambda examples: {'text': [f'<s>[INST] ' + prompt + ' [/INST]</s>' + response for prompt, response in zip(examples['prompt'], examples['response'])]}, batched=True)
valid_dataset_mapped = valid_dataset.map(lambda examples: {'text': [f'<s>[INST] ' + prompt + ' [/INST]</s>' + response for prompt, response in zip(examples['prompt'], examples['response'])]}, batched=True)
# trainer = SFTTrainer(
# model=model,
# train_dataset=train_dataset_mapped,
# eval_dataset=valid_dataset_mapped, # Pass validation dataset here
# peft_config=peft_config,
# dataset_text_field="text",
# max_seq_length=max_seq_length,
# tokenizer=tokenizer,
# args=training_arguments,
# packing=packing,
# )
独自のデータ セットの場合、トレーニング データにはプロンプトとレスポンスという 2 つの列が含まれているため、最初にトレーニング データを処理する必要があります。2 つの列のテキストを結合し、文字の書式設定によってそれらを区別する必要があります。次のフォーマット関数:
{'テキスト': ['[INST] + プロンプト + ' [/INST] ' + 応答)
2、Llama2 の微調整を開始する
このセクションでは、高 RAM を備えた A800 GPU (90G) 上で 70 億のパラメーターを備えた Llama 2 モデルを微調整します。LoRA や QLoRAのようなパラメータ効率の良い微調整 (PEFT) テクニックが必要です 。
QLoRA は、スケーリング パラメーター 16 でランク 64 を使用します ( LoRA パラメーターの詳細については、この記事を参照してください)。NF4 タイプを使用して、Llama 2 モデルを 4 ビット精度で直接ロードし、1 エポックの間トレーニングします。他のパラメーターの詳細については、 TrainingArguments、 PeftModel、および SFTTrainer の ドキュメントを確認してください。
import os
import torch
from transformers import (
AutoModelForCausalLM,
AutoTokenizer,
BitsAndBytesConfig,
HfArgumentParser,
TrainingArguments,
pipeline,
logging,
)
from peft import LoraConfig, PeftModel
from trl import SFTTrainer
# Load dataset (you can process it here)
# from datasets import load_dataset
#
# print("loading dataset")
# dataset_name = "mlabonne/guanaco-llama2-1k"
# dataset = load_dataset(dataset_name, split="train")
# dataset.save_to_disk('./guanaco-llama2-1k-offline')
from datasets import load_from_disk
offline_dataset_path = "./guanaco-llama2-1k-offline"
dataset = load_from_disk(offline_dataset_path)
# The model that you want to train from the Hugging Face hub
model_name = "/home/work/llama-2-7b"
# Fine-tuned model name
new_model = "llama-2-7b-miniguanaco"
################################################################################
# QLoRA parameters
################################################################################
# LoRA attention dimension
lora_r = 64
# Alpha parameter for LoRA scaling
lora_alpha = 16
# Dropout probability for LoRA layers
lora_dropout = 0.1
################################################################################
# bitsandbytes parameters
################################################################################
# Activate 4-bit precision base model loading
use_4bit = True
# Compute dtype for 4-bit base models
bnb_4bit_compute_dtype = "float16"
# Quantization type (fp4 or nf4)
bnb_4bit_quant_type = "nf4"
# Activate nested quantization for 4-bit base models (double quantization)
use_nested_quant = False
################################################################################
# TrainingArguments parameters
################################################################################
# Output directory where the model predictions and checkpoints will be stored
output_dir = "./results"
# Number of training epochs
num_train_epochs = 1
# Enable fp16/bf16 training (set bf16 to True with an A100)
fp16 = False
bf16 = False
# Batch size per GPU for training
per_device_train_batch_size = 16
# Batch size per GPU for evaluation
per_device_eval_batch_size = 16
# Number of update steps to accumulate the gradients for
gradient_accumulation_steps = 1
# Enable gradient checkpointing
gradient_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 weights
weight_decay = 0.001
# Optimizer to use
optim = "paged_adamw_32bit"
# Learning rate schedule
lr_scheduler_type = "cosine"
# Number of training steps (overrides num_train_epochs)
max_steps = -1
# 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 considerably
group_by_length = True
# Save checkpoint every X updates steps
save_steps = 0
# Log every X updates steps
logging_steps = 25
################################################################################
# SFT parameters
################################################################################
# Maximum sequence length to use
max_seq_length = None
# Pack multiple short examples in the same input sequence to increase efficiency
packing = False
# Load the entire model on the GPU 0
device_map = {"": 0}
# Load tokenizer and model with QLoRA configuration
compute_dtype = getattr(torch, bnb_4bit_compute_dtype)
bnb_config = BitsAndBytesConfig(
load_in_4bit=use_4bit,
bnb_4bit_quant_type=bnb_4bit_quant_type,
bnb_4bit_compute_dtype=compute_dtype,
bnb_4bit_use_double_quant=use_nested_quant,
)
# Check GPU compatibility with bfloat16
if compute_dtype == torch.float16 and use_4bit:
major, _ = torch.cuda.get_device_capability()
if major >= 8:
print("=" * 80)
print("Your GPU supports bfloat16: accelerate training with bf16=True")
print("=" * 80)
# Load base model
model = AutoModelForCausalLM.from_pretrained(
model_name,
quantization_config=bnb_config,
device_map=device_map
)
model.config.use_cache = False
model.config.pretraining_tp = 1
# Load LLaMA tokenizer
tokenizer = AutoTokenizer.from_pretrained(model_name, trust_remote_code=True)
tokenizer.pad_token = tokenizer.eos_token
tokenizer.padding_side = "right" # Fix weird overflow issue with fp16 training
# Load LoRA configuration
peft_config = LoraConfig(
lora_alpha=lora_alpha,
lora_dropout=lora_dropout,
r=lora_r,
bias="none",
task_type="CAUSAL_LM",
)
# Set training parameters
training_arguments = TrainingArguments(
output_dir=output_dir,
num_train_epochs=num_train_epochs,
per_device_train_batch_size=per_device_train_batch_size,
gradient_accumulation_steps=gradient_accumulation_steps,
optim=optim,
save_steps=save_steps,
logging_steps=logging_steps,
learning_rate=learning_rate,
weight_decay=weight_decay,
fp16=fp16,
bf16=bf16,
max_grad_norm=max_grad_norm,
max_steps=max_steps,
warmup_ratio=warmup_ratio,
group_by_length=group_by_length,
lr_scheduler_type=lr_scheduler_type
)
# Set supervised fine-tuning parameters
trainer = SFTTrainer(
model=model,
train_dataset=dataset,
peft_config=peft_config,
dataset_text_field="text",
max_seq_length=max_seq_length,
tokenizer=tokenizer,
args=training_arguments,
packing=packing,
)
# Train model
trainer.train()
# Save trained model
trainer.model.save_pretrained(new_model)
これで、すべてをロードして微調整プロセスを開始できます。複数のラッパーに依存しているので、ご了承ください。
- まず最初に、 定義したデータセットをロードします 。ここで、データセットはすでに前処理されていますが、通常はここでプロンプトの再フォーマット、不正なテキストの除外、複数のデータセットの結合などが行われます。
bitsandbytes
次に、 4 ビット量子化用に設定します 。- 次に、対応するトークナイザーを使用して、Llama 2 モデルを GPU に 4 ビット精度でロードします。
- 最後に、QLoRA の設定、通常のトレーニング パラメーターをロードし、すべてを に渡します
SFTTrainer
。いよいよ研修がスタートできます!
3 つの lora ウェイトをマージし、完全なモデルを保存します
import os
import torch
from transformers import (
AutoModelForCausalLM,
AutoTokenizer
)
from peft import PeftModel
# Save trained model
model_name = "/home/work/llama-2-7b"
# Load the entire model on the GPU 0
device_map = {"": 0}
new_model = "llama-2-7b-miniguanaco"
# Reload model in FP16 and merge it with LoRA weights
base_model = AutoModelForCausalLM.from_pretrained(
model_name,
low_cpu_mem_usage=True,
return_dict=True,
torch_dtype=torch.float16,
device_map=device_map,
)
model = PeftModel.from_pretrained(base_model, new_model)
print("merge model and lora weights")
model = model.merge_and_unload()
output_merged_dir = "final_merged_checkpoint2"
os.makedirs(output_merged_dir, exist_ok=True)
print("save model")
model.save_pretrained(output_merged_dir, safe_serialization=True)
# Reload tokenizer to save it
tokenizer = AutoTokenizer.from_pretrained(model_name, trust_remote_code=True)
tokenizer.pad_token = tokenizer.eos_token
tokenizer.padding_side = "right"
print("save tokenizer")
tokenizer.save_pretrained(output_merged_dir)
対話用に微調整されたモデルをロードする
2000 個のアルパカ中国語単語を使用して 1 エポックでトレーニングした後の答えは次のようになります。質問が [INST] [/INST] で始まる場合、答えは正確になります。
import torch fromTransformers import ( AutoModelForCausalLM, AutoTokenizer, ) # ハギング フェイス ハブからトレーニングするモデル model_name = "./final_merged_alpaca" device_map = {"": 0} # FP16 でモデルをリロード model = AutoModelForCausalLM.from_pretrained ( model_name, low_cpu_mem_usage=True, return_dict=True, torch_dtype=torch.float16, device_map=device_map, ) # トークナイザーをリロードして保存します tokenizer = AutoTokenizer.from_pretrained(model_name, trust_remote_code=True) トランスフォーマーのインポート パイプラインから # プロンプト = f" [INST] 中国の首都はどこですか? [/INST]" # ここのコマンドをタスクに関連するコマンドに置き換えます # num_new_tokens = 100 #生成したい新しいトークンの数に変更します。 # # プロンプト内のトークンの数を数えます。 # num_prompt_tokens = len(tokenizer(prompt)['input_ids']) # # 世代の最大長を計算します # max_length = num_prompt_tokens + num_new_tokens gen = Pipeline('text-generation', model=model, tokenizer=tokenizer, max_length= 256) print("############################################# ###############") prompt1 = "[INST] 中国の首都はどこですか?[/INST]" # ここのコマンドをタスクに関連するコマンドに置き換えます result1 = gen (prompt1) print(prompt1) print(result1[0]['generated_text']) print("############################ #################################") プロンプト 2 = "中国の首都はどこですか?" # コマンドを置き換えますここでは、タスクに関連するものを使用します。 result2 = gen(prompt2) print(result2[0]['generated_text'])
微調整する前に:
4つのまとめ
この記事では、Llama-2-7b モデルを微調整する方法について説明しました。LLM のトレーニングと微調整について必要な背景と、命令データセットに関連する重要な考慮事項をいくつか紹介しました。 ネイティブ プロンプト テンプレートとカスタム パラメーターを使用して、Llama 2 モデルを微調整することに成功しました。
これらの微調整されたモデルは、OpenAI API の有利な代替手段として LangChain やその他のアーキテクチャに統合できます。この新しいパラダイムでは、命令データセットが新たな金であり、モデルの品質は微調整されたデータに大きく依存することを忘れないでください。それでは、高品質のデータセットの構築を頑張ってください。
ML ブログ - Colab ノートブックで独自の Llama 2 モデルを微調整する (mlabonne.github.io)
拡張ガイド: 命令チューン Llama 2 (philschmid.de)
SFT、LORA を使用して LLaMA 2 を微調整する方法 (accubits.com)単一の GPU、QLoRA、AI ノートブックを使用した LLaMA 2 モデルの微調整 - OVHcloud ブログ
GPT-LLM-Trainer: 独自のデータを使用して LLM を簡単かつ迅速に微調整してトレーニングする方法_Technology Frenzy AI のブログ - CSDN ブログ