# Uploaded model - **Developed by:** u9999Yoko - **License:** CC BY-NC-SA - **Finetuned from model :** llm-jp/llm-jp-3-13b ## Abstract 「llm-jp/llm-jp-3-13bモデルにichikara-instructionデータを用いてファインチューニングを行ったモデルです。 松尾研究室の講義のコンペ用としてモデルを作成しました。 https://weblab.t.u-tokyo.ac.jp/lecture/course-list/large-language-model/ https://llm-jp.nii.ac.jp/blog/2024/04/30/v2.0-release.html ## Dataset データセットは以下を使用しました。 - ichikara-instruction-003-001-1.json ## Attention ichikara-instructionデータは、CC BY-NC-SAライセンス(表示-非営利-継承)で公開されています。 このライセンスの下では、非営利目的での利用が許可されていますが、商用利用は認められていません。 詳しくは次のホームページをご覧ください。 https://llm-jp.nii.ac.jp/blog/2024/04/30/v2.0-release.html ## Usage Execute following code in Notebook ```python # 必要なライブラリをインストール conda install --yes --file requirements.txt from requests.exceptions import HTTPError from transformers import ( AutoModelForCausalLM, AutoTokenizer, TrainingArguments, ) from peft import ( LoraConfig, get_peft_model, ) import torch from datasets import load_dataset from trl import SFTTrainer from tqdm import tqdm # HuggingFaceにログイン from huggingface_hub import notebook_login # 取得したTokenを入力 notebook_login() # base model id base_model_id = "llm-jp/llm-jp-3-13b" new_model_id = "u9999Yoko//llm-jp-3-13b-finetune" model = AutoModelForCausalLM.from_pretrained( base_model_id, device_map="auto", torch_dtype=torch.bfloat16, # 半精度計算で効率化 ) tokenizer = AutoTokenizer.from_pretrained(base_model_id, trust_remote_code=True) """ peft_config: PEFTの構成設定 - r - LoRA のランク (4, 8, 16 ,32...) - 増やすほど学習が捗るが, 過学習のリスクも高まるので注意 - lora_alpha - LoRAのスケーリング係数 - lora_dropout - ドロップアウト率(過学習を防ぐための割合) - bias - バイアス項の扱い ("none"の場合、LoRAはバイアスを学習しない) - task_type - タスクタイプ - target_modules - LoRAを適用するターゲットモジュール (前のコードで特定した層) """ # LoRA設定 lora_config = LoraConfig( r=8, lora_alpha=16, target_modules=["q_proj", "v_proj"], # トレーニング対象の層 lora_dropout=0.1, task_type="CAUSAL_LM", ) model = get_peft_model(model, lora_config) dataset = load_dataset("json", data_files="./ichikara-instruction-003-001-1.json") # 学習時のプロンプトフォーマットの定義 prompt = """### 指示 {} ### 回答 {}""" """ formatting_prompts_func: 各データをプロンプトに合わせた形式に合わせる """ EOS_TOKEN = tokenizer.eos_token # トークナイザーのEOSトークン(文末トークン) def formatting_prompts_func(examples): input = examples["text"] # 入力データ output = examples["output"] # 出力データ text = prompt.format(input, output) + EOS_TOKEN # プロンプトの作成 return { "formatted_text" : text, } # 新しいフィールド "formatted_text" を返す pass # # 各データにフォーマットを適用 dataset = dataset.map( formatting_prompts_func, num_proc= 4, # 並列処理数を指定 ) # データを確認 print(dataset["train"]["formatted_text"][3]) # データをtrainデータとtestデータに分割 (test_sizeの比率に) dataset = dataset["train"].train_test_split(test_size=0.1) print(dataset) """ training_arguments: 学習の設定 output_dir:トレーニング後のモデルを保存するディレクトリ per_device_train_batch_size: デバイスごとのトレーニングバッチサイズ per_device__batch_size:デバイスごとの評価バッチサイズ gradient_accumulation_steps:勾配を更新する前にステップを積み重ねる回数 optim: オプティマイザの設定 num_train_epochs:エポック数 eval_strategy:評価の戦略 ("no"/"steps"/"epoch") eval_steps: eval_strategyが"steps"のとき、評価を行うstep間隔 logging_strategy: ログ記録の戦略 logging_steps: ログを出力するステップ間隔 warmup_steps: 学習率のウォームアップステップ数 save_steps: モデルを保存するステップ間隔 save_total_limit: 保存しておくcheckpointの数 max_steps:トレーニングの最大ステップ数 learning_rate: 学習率 fp16:16bit浮動小数点の使用設定(第8回演習を参考にすると良いです) bf16:BFloat16の使用設定 group_by_length:入力シーケンスの長さによりバッチをグループ化 (トレーニングの効率化) report_to:ログの送信先 ("wandb"/"tensorboard"など) """ training_arguments = TrainingArguments( output_dir=new_model_id, per_device_train_batch_size=1, gradient_accumulation_steps=8, # optim="paged_adamw_32bit", num_train_epochs=3, logging_strategy="steps", logging_steps=10, warmup_steps=10, save_steps=1000, save_total_limit = 2, max_steps = -1, learning_rate=5e-5, fp16=False, bf16=True, seed = 3407, group_by_length=True, report_to="none" ) """ SFTTrainer: Supervised Fine-Tuningに関する設定 model:読み込んだベースのモデル train_dataset:トレーニングに使用するデータセット eval_dataset:評価に使用するデータセット peft_config: PEFT(Parameter-Efficient Fine-Tuning)の設定(LoRAを利用する場合に指定) max_seq_length:モデルに入力されるシーケンスの最大トークン長 dataset_text_field:データセット内の学習に使うテキストを含むフィールド名 tokenizer:モデルに対応するトークナイザー args:トレーニングに使用するハイパーパラメータ(TrainingArgumentsの設定を指定) packing:入力シーケンスのパッキングを行うかどうかの設定 (False に設定することで、各入力を独立して扱う) """ trainer = SFTTrainer( model=model, train_dataset=dataset["train"], peft_config=lora_config, max_seq_length= 512, dataset_text_field="formatted_text", tokenizer=tokenizer, args=training_arguments, packing= False, ) model.config.use_cache = False # キャッシュ機能を無効化 trainer.train() # トレーニングを実行 # タスクとなるデータの読み込み。 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 = "" print(datasets) # モデルによるタスクの推論。 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=400, 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}) # 結果をjsonlで保存。 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') ```