【LLM】llama2(ラマ2)/ファインチューニング LORA編

2023/12/12に公開

↓ 環境構築に関しては下記を参照。
https://zenn.dev/timoneko/articles/57ff47dfcd8d26

llama-recipesのインストール

https://github.com/facebookresearch/llama-recipes/tree/main/examples

↓2023年12月時点のインストールコマンド

pip install --extra-index-url https://download.pytorch.org/whl/test/cu118 llama-recipes

HFモデルに変換

metaから取得したデータ(llama-2-7bの場合は下記の用にデータが入っている)をHugging face用に変換してあげる必要がある。

checklist.chk  consolidated.00.pth  params.json

(1) フォルダ名を7Bに変更しておく

cp -r llama-2-7b 7B

(2) transformersのgitをクローン

git clone https://github.com/huggingface/transformers.git

(3) convert_llama_weights_to_hf.py で変換処理を実施
⭐️手順2 1で作成した7Bがある同階層にllamaのtokenizer.modelを置いてあること

python src/transformers/models/llama/convert_llama_weights_to_hf.py \
   --input_dir <7Bフォルダとトークナイザーがあるディレクトリ> --model_size 7B --output_dir <outputのディレクトリ>

⭐️chatの場合はpip install protobufが必要か

変換後のフォルダの中身は下記のようになっているはず。

generation_config.json  pytorch_model-00002-of-00003.bin  tokenizer.json
pytorch_model-00003-of-00003.bin  tokenizer.model
pytorch_model.bin.index.json      tokenizer_config.json

デフォルトのデータセット(samsumデータセットを用いて学習する)

https://huggingface.co/datasets/samsum

カレントを
/mnt/pvc/llama/

HF用のモデルが下記のフォルダにあると仮定
/mnt/pvc/llama/output

出力先のフォルダ
output/peft

とする。

1GPUで実施
python -m llama_recipes.finetuning  --use_peft --peft_method lora --quantization --model_name /mnt/pvc/llama/output --output_dir output/peft

デフォルトでは、自動的に「samsum」で学習が開始する。(1GPUだと結構かかる)
実施すると出力先フォルダに下記のデータが作成される。

README.md  adapter_config.json  adapter_model.bin

通常のllamaのモデルの読み込みの場合はLlamaForCausalLMで良いが

tokenizer = LlamaTokenizer.from_pretrained("output")
model = LlamaForCausalLM.from_pretrained("output") 
model.to('cuda')

PEFT

peft_model_id = "output/peft" ## PEFT出力先フォルダのパス
model = LlamaForCausalLM.from_pretrained("output") 
lora_model = PeftModel.from_pretrained(model,peft_model_id)
lora_model.to('cuda')

のようにモデルを読み込む必要がある。
PEFT前のモデルとPEFT後のモデルで結果を検証してみよう。

from transformers import LlamaForCausalLM, LlamaTokenizer
from peft import PeftConfig,PeftModel
from transformers.trainer_utils import get_last_checkpoint
import torch

peft_model_id = "output/peft" # contains adapter_config.json and the associated .bin files

tokenizer = LlamaTokenizer.from_pretrained("output")
model = LlamaForCausalLM.from_pretrained("output") #instance
model.to('cuda')

prompt="Summarize this dialog:\nAmanda: I baked  cookies. Do you want some?\nJerry: Sure!\nAmanda: I'll bring you tomorrow :-)\n---"
print("prompt:" + prompt)
inputs = tokenizer(prompt, return_tensors="pt")

with torch.no_grad():
    pre_generate_ids = model.generate(do_sample=True,temperature=0.6,top_p=0.9 ,input_ids=inputs["input_ids"].to("cuda"),max_length= 100,pad_token_id=tokenizer.eos_token_id)
    pre_returned = tokenizer.batch_decode(pre_generate_ids, skip_special_tokens = True,clean_up_tokenization_spaces=False)[0]
    print("-----")
    print(pre_returned)

lora_model = PeftModel.from_pretrained(model,peft_model_id)
lora_model.to('cuda')

with torch.no_grad():
    
    lora_model = PeftModel.from_pretrained(model,peft_model_id)
    lora_model.to('cuda')

    generate_ids = lora_model.generate(do_sample=True,temperature=0.6,top_p=0.9,input_ids=inputs["input_ids"].to("cuda"),max_length= 100,pad_token_id=tokenizer.eos_token_id)
    returned = tokenizer.batch_decode(generate_ids, skip_special_tokens = True,clean_up_tokenization_spaces=False)[0]
    print("-----")
    print(returned)

カスタムデータを使用する場合

*公式のドキュメントを閲覧するのがおすすめだが、筆者は(ほぼ)力技で構築した。

/opt/miniconda/envs/llama/lib/python3.10/site-packages/llama_recipes/dataset
に'get_custom_dataset(dataset_config, tokenizer, split)' でデータセットを返す関数を作成。

def get_custom_dataset(dataset_config, tokenizer, split):
	....

if __name__=="__main__":
    tokenizer = LlamaTokenizer.from_pretrained("/mnt/pvc/llama/tokenizer.model")
    tokenizer.add_special_tokens(
         {
             "pad_token": "<PAD>",
         }
     )  

    print(tokenizer.special_tokens_map)
    print(get_custom_dataset({},tokenizer,"train"))

mainで実行して動作することを確認。

⭐️/opt/miniconda/envs/llama/lib/python3.10/site-packages/llama_recipes/configs/datasets.py
⭐️/opt/miniconda/envs/llama/lib/python3.10/site-packages/llama_recipes/utils/dataset_utils.py
🌟/opt/miniconda/envs/llama/lib/python3.10/site-packages/llama_recipes/datasets/init.py

を編集。

上記の設定を実施して、下記コマンドを実行。PEFTが行われる。

python -m llama_recipes.finetuning --dataset "custom_dataset"  --use_peft --peft_method lora --quantization --model_name /mnt/pvc/llama/output --output_dir output/peft2

Discussion