YAML Metadata Warning:empty or missing yaml metadata in repo card
Check out the documentation for more information.
以下に本モデルの推論手順を記載する
実行手順
・Hugging Face上のモデル(llm-jp/llm-jp-3-13b)を使用 ・入力データ(elyza-tasks-100-TV_0.jsonl)を推論 ・その結果を{new_model_id}-outputs.jsonlというファイルに出力
前提条件
・Python環境があること(例: Google Colab) ・Hugging Faceのアクセストークン (HF_TOKEN) が取得済みであること
Pythonのソフトウェアパッケージをインストール(以下はpython 3.10.12の例)
!pip install -U pip !pip install -U transformers !pip install -U bitsandbytes !pip install -U accelerate !pip install -U datasets !pip install -U peft !pip install -U trl !pip install -U wandb !pip install ipywidgets --upgrade
特定のモジュールやライブラリをプログラムに取り込むためにインポート
from transformers import ( AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig, TrainingArguments, logging, ) from peft import ( LoraConfig, PeftModel, get_peft_model, ) import os, torch, gc from datasets import load_dataset import bitsandbytes as bnb from trl import SFTTrainer
Hugging Faceのアクセストークン (HF_TOKEN)
HF_TOKEN = "write権限のあるトークン"
読み込むモデルと出力するモデル
base_model_id = "models/models--llm-jp--llm-jp-3-13b/snapshots/cd3823f4c1fcbb0ad2e2af46036ab1b0ca13192a" new_model_id = "llm-jp-3-13b-finetune"
量子化の設定
bnb_config = BitsAndBytesConfig( load_in_4bit=True, bnb_4bit_quant_type="nf4", # nf4は通常のINT4より精度が高く、ニューラルネットワークの分布に最適です bnb_4bit_compute_dtype=torch.bfloat16, )
事前学習済みの言語モデルとトークナイザーを指定されたモデルIDから読み込み、量子化設定を適用し、デバイスマップを自動設定
model = AutoModelForCausalLM.from_pretrained( base_model_id, quantization_config=bnb_config, device_map="auto" )
tokenizer = AutoTokenizer.from_pretrained(base_model_id, trust_remote_code=True)
指定されたモデル内の全ての4bit量子化線形層を探索し、そのモジュール名を収集してリストとして返す
def find_all_linear_names(model): cls = bnb.nn.Linear4bit # 4bit量子化線形層クラスを指定 lora_module_names = set() # ここに取得した線形層を保持します。
# モデル内の全てのモジュールを探索します
for name, module in model.named_modules():
if isinstance(module, cls): # モジュールが4bit量子化線形層の場合
names = name.split('.') # モジュールの名前を分割 (ネストされてる際などに対処)
lora_module_names.add(names[0] if len(names) == 1 else names[-1]) # 最下層の名前をlora_module_namesに追加
# 'lm_head' は16ビット演算の際に除外する必要があるため、lora_module_namesから削除
if 'lm_head' in lora_module_names:
lora_module_names.remove('lm_head')
return list(lora_module_names) # lora_module_namesをリストに変換して返します。
modules = find_all_linear_names(model)
PEFTの構成設定
peft_config = LoraConfig( r=16, lora_alpha=32, lora_dropout=0.05, bias="none", task_type="CAUSAL_LM", target_modules=modules, )
model = get_peft_model(model, peft_config)
学習に用いるデータセットの指定
dataset = load_dataset("json", data_files="./ichikara-instruction-003-001-1.json") dataset
学習時のプロンプトフォーマットの定義と適用
prompt = """--- 指示 {} --- 回答 {}"""
EOS_TOKEN = tokenizer.eos_token def formatting_prompts_func(examples): input = examples["text"] output = examples["output"] text = prompt.format(input, output) + EOS_TOKEN return { "formatted_text" : text, } pass
dataset = dataset.map( formatting_prompts_func, num_proc= 4, )
dataset
データの確認
print(dataset["train"]["formatted_text"][3])
データをtrainとtestに分割 (test_sizeの比率に) ※option
dataset = dataset["train"].train_test_split(test_size=0.1) dataset
学習の設定
training_arguments = TrainingArguments( output_dir=new_model_id, per_device_train_batch_size=1, gradient_accumulation_steps=2, optim="paged_adamw_32bit", num_train_epochs=1, logging_strategy="steps", logging_steps=10, warmup_steps=10, save_steps=100, save_total_limit = 2, max_steps = -1, learning_rate=5e-5, fp16=False, bf16=False, seed = 3407, group_by_length=True, report_to="none" )
Supervised Fine-Tuningに関する設定
trainer = SFTTrainer( model=model, train_dataset=dataset["train"], peft_config=peft_config, max_seq_length= 512, dataset_text_field="formatted_text", tokenizer=tokenizer, args=training_arguments, packing= False, )
model.config.use_cache = False trainer.train()
タスクとなる入力データ(elyza-tasks-100-TV_0.jsonl)の読み込み
import json datasets = [] with open("./elyza-tasks-100-TV_0.jsonl", "r") as f: item = "" for line in f: line = line.strip() item += line if item.endswith("}"): datasets.append(json.loads(item)) item = ""
タスクの推論
from tqdm import tqdm
results = [] for data in tqdm(datasets):
input = data["input"]
prompt = f"""--- 指示 {input} --- 回答 """
tokenized_input = tokenizer.encode(prompt, add_special_tokens=False, return_tensors="pt").to(model.device) attention_mask = torch.ones_like(tokenized_input)
with torch.no_grad(): outputs = model.generate( tokenized_input, attention_mask=attention_mask, max_new_tokens=100, do_sample=False, repetition_penalty=1.2, pad_token_id=tokenizer.eos_token_id )[0] output = tokenizer.decode(outputs[tokenized_input.size(1):], skip_special_tokens=True)
results.append({"task_id": data["task_id"], "input": input, "output": output})
推論結果の保存
import re jsonl_id = re.sub(".*/", "", new_model_id) with open(f"./{jsonl_id}-outputs.jsonl", 'w', encoding='utf-8') as f: for result in results: json.dump(result, f, ensure_ascii=False) # ensure_ascii=False for handling non-ASCII characters f.write('\n')
以上