![見出し画像](https://assets.st-note.com/production/uploads/images/101480615/rectangle_large_type_2_b91a3be0f9d136854c75626e655c2c8c.png?width=1200)
ファインチューニングの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
この記事が気に入ったらサポートをしてみませんか?