見出し画像

ファインチューニングのPEFTについて

今回は、PEFTについて紹介していきます。PEFTの略は、Parameter Efficient Fine Tuningとなります。大規模言語モデルを処理するときに、大規模リソースを持っているところは、大規模言語モデルを取り扱うことができます。しかし、それ以外の人や組織は、大規模リソースを用意するのが難しいのが現状です。

そんな人向けに、PEFTというアプローチで、事前トレーニング済みのLLMのほとんどのパラメータを凍結しながら、少数のモデルパラメータのみを微調整することで、計算コストとストレージを大幅に削減する方法となります。


PEFTに関する記事は以下です。


今回は、下記のコードを参考にしています。


まずは、必要なrequirementsをインストールします。

!pip install -q bitsandbytes datasets accelerate loralib
!pip install -q git+https://github.com/huggingface/transformers.git@main git+https://github.com/huggingface/peft.git

次に、opt-6.7bというモデルを読み込みます。

import os
os.environ["CUDA_VISIBLE_DEVICES"]="0"
import torch
import torch.nn as nn
import bitsandbytes as bnb
from transformers import AutoTokenizer, AutoConfig, AutoModelForCausalLM

model = AutoModelForCausalLM.from_pretrained(
    "facebook/opt-6.7b", 
    load_in_8bit=True, 
    device_map='auto',
)

tokenizer = AutoTokenizer.from_pretrained("facebook/opt-6.7b")


ダウンロードしたモデルにおける事前処理を行います。

for param in model.parameters():
  param.requires_grad = False  # freeze the model - train adapters later
  if param.ndim == 1:
    # cast the small parameters (e.g. layernorm) to fp32 for stability
    param.data = param.data.to(torch.float32)

model.gradient_checkpointing_enable()  # reduce number of stored activations
model.enable_input_require_grads()

class CastOutputToFloat(nn.Sequential):
  def forward(self, x): return super().forward(x).to(torch.float32)
model.lm_head = CastOutputToFloat(model.lm_head)


PEFTアプローチをLoRAに適用します。

def print_trainable_parameters(model):
    """
    Prints the number of trainable parameters in the model.
    """
    trainable_params = 0
    all_param = 0
    for _, param in model.named_parameters():
        all_param += param.numel()
        if param.requires_grad:
            trainable_params += param.numel()
    print(
        f"trainable params: {trainable_params} || all params: {all_param} || trainable%: {100 * trainable_params / all_param}"
    )
from peft import LoraConfig, get_peft_model 

config = LoraConfig(
    r=16,
    lora_alpha=32,
    target_modules=["q_proj", "v_proj"],
    lora_dropout=0.05,
    bias="none",
    task_type="CAUSAL_LM"
)

model = get_peft_model(model, config)
print_trainable_parameters(model)


次の結果が得られます。

trainable params: 8388608 || all params: 6666862592 || trainable%: 0.12582542214183376

全パラメータが約66億で、トレーニングパラメータが838万パラメータとなります。トレーニング率は0.12%ということが表示されています。ここのトレーニングパラメータと全パラメータの数が多くなると、大規模リソースと時間が必要になります。


次は、トレーニングです。warmup_stepsを25、max_stepsを50に変更しています。max_stepsが200だと1時間弱かかります。

import transformers
from datasets import load_dataset
data = load_dataset("Abirate/english_quotes")
data = data.map(lambda samples: tokenizer(samples['quote']), batched=True)

trainer = transformers.Trainer(
    model=model, 
    train_dataset=data['train'],
    args=transformers.TrainingArguments(
        per_device_train_batch_size=4, 
        gradient_accumulation_steps=4,
        warmup_steps=25, 
        max_steps=50, 
        learning_rate=2e-4, 
        fp16=True,
        logging_steps=1, 
        output_dir='outputs'
    ),
    data_collator=transformers.DataCollatorForLanguageModeling(tokenizer, mlm=False)
)
model.config.use_cache = False  # silence the warnings. Please re-enable for inference!
trainer.train()


そして、推論です。

batch = tokenizer("Two things are infinite: ", return_tensors='pt')

with torch.cuda.amp.autocast():
  output_tokens = model.generate(**batch, max_new_tokens=50)

print('\n\n', tokenizer.decode(output_tokens[0], skip_special_tokens=True))


結果を見ると、max_stepsやwarm_stepsを減らしても、同じように回答されていました。

Two things are infinite: the universe and human stupidity; and I'm not sure about the universe. -Albert Einstein I'm not sure about the universe either.

他にも推論してもらいます。

batch = tokenizer("We can do it. ", return_tensors='pt')

with torch.cuda.amp.autocast():
  output_tokens = model.generate(**batch, max_new_tokens=50)

print('\n\n', tokenizer.decode(output_tokens[0], skip_special_tokens=True))

結果は、途切れてしまっていますが、文章は出来ている感じがします。

We can do it. I'm not sure if I can do it, but I'm going to try. I'm going to try to be a better person. I'm going to try to be a better friend. I'm going to try to be

この記事が気に入ったらサポートをしてみませんか?