[NLP]LLM---FineTune 独自の Llama2 モデル

データセットの準備

ここで調整できるパラメータについて少し説明しましょう。まず、モデルをロードして (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 ブログ

おすすめ

転載: blog.csdn.net/zwqjoy/article/details/132765488