---
base_model: llm-jp/llm-jp-3-13b
tags:
- text-generation-inference
- transformers
- unsloth
- llama
- trl
license: apache-2.0
language:
- en
---
# Uploaded model
- **Developed by:** IWAIYuma
- **License:** apache-2.0
- **Finetuned from model :** llm-jp/llm-jp-3-13b
This llama model was trained 2x faster with [Unsloth](https://github.com/unslothai/unsloth) and Huggingface's TRL library.
[
](https://github.com/unslothai/unsloth)
サンプルコードで作成したモデルを強化学習する。
使用するデータセットは、『cyberagent/chatbot-arena-ja-calm2-7b-chat-experimental』のオープンソースを使用
https://huggingface.co/datasets/cyberagent/chatbot-arena-ja-calm2-7b-chat-experimental)
このソースは『このデータセットを用いてcalm2-7b-chatに対してDirect Preference Optimization (DPO)を行い、calm2-7b-chat-dpoを作成しました。 Instruction Tuningの評価用タスクであるELYZA-tasks-100とJapanese MT-Benchを用いてGPT-4による自動評価を行ったところ、どちらのデータセットでもcalm2-7b-chat-dpoの方がcalm2-7b-chatよりも高いスコアが得られました。』とあるため期待
◯ 参考にしたコード『自作FT済みモデルからDPOするためのサンプルコード(Unsloth最新版 2024.12.2)』にある、藤越様のコードを参考にし、RLHFをしてみました。
https://matsuolab-geniac.notion.site/FT-DPO-Unsloth-2024-12-2-bac63c15586840b9ad118f5f5b27420a
'''python
# Google Colab の場合は上記の環境構築手順を行なわず、単にこのセルから実行していってください。
!pip uninstall unsloth -y
!pip install --upgrade --no-cache-dir "unsloth[colab-new] @ git+https://github.com/unslothai/unsloth.git"
# Google Colab のデフォルトで入っているパッケージをアップグレード(Moriyasu さんありがとうございます)
!pip install --upgrade torch
!pip install --upgrade xformers
# notebookでインタラクティブな表示を可能とする(ただし、うまく動かない場合あり)
!pip install ipywidgets --upgrade
# Install Flash Attention 2 for softcapping support
import torch
if torch.cuda.get_device_capability()[0] >= 8:
!pip install --no-deps packaging ninja einops "flash-attn>=2.6.3"
from google.colab import output
output.enable_custom_widget_manager()
# Hugging Face Token を指定
from huggingface_hub import login
from google.colab import userdata
hf_token = userdata.get('HF_TOKEN')
if hf_token:
login(token=hf_token)
print("Hugging Face token found and logged in.")
else:
print("Hugging Face token not found. Please set it using userdata.set('HF_TOKEN', '')")
print(dataset['train'][0])
# 学習時のプロンプトフォーマットの定義
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, # 並列処理数を指定
)
dataset
"""
training_arguments: 学習の設定
- output_dir:
-トレーニング後のモデルを保存するディレクトリ
- per_device_train_batch_size:
- デバイスごとのトレーニングバッチサイズ
- per_device_eval_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"など)
"""
from trl import SFTTrainer
from transformers import TrainingArguments
from unsloth import is_bfloat16_supported
trainer = SFTTrainer(
model = model,
tokenizer = tokenizer,
train_dataset=dataset["train"],
max_seq_length = max_seq_length,
dataset_text_field="formatted_text",
packing = False,
args = TrainingArguments(
per_device_train_batch_size = 2,
gradient_accumulation_steps = 4,
num_train_epochs = 1,
logging_steps = 10,
warmup_steps = 10,
save_steps=100,
save_total_limit=2,
max_steps=-1,
learning_rate = 2e-4,
fp16 = not is_bfloat16_supported(),
bf16 = is_bfloat16_supported(),
group_by_length=True,
seed = 3407,
output_dir = "outputs",
report_to = "none",
),
)
#@title 学習実行
trainer_stats = trainer.train()
edataset = load_dataset("elyza/ELYZA-tasks-100")
edataset = edataset.remove_columns('eval_aspect')
edataset = edataset.rename_columns({'input':'text'})
print(edataset['test'][0])
# 学習時のプロンプトフォーマットの定義
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
# # 各データにフォーマットを適用
edataset = edataset.map(
formatting_prompts_func,
num_proc= 4, # 並列処理数を指定
)
edataset
# データを確認
print(edataset["test"]["formatted_text"][3])
etrainer = SFTTrainer(
model = model,
tokenizer = tokenizer,
train_dataset=edataset["test"],
max_seq_length = max_seq_length,
dataset_text_field="formatted_text",
packing = False,
args = TrainingArguments(
per_device_train_batch_size = 2,
gradient_accumulation_steps = 4,
num_train_epochs = 1,
logging_steps = 10,
warmup_steps = 10,
save_steps=100,
save_total_limit=2,
max_steps=-1,
learning_rate = 2e-4,
fp16 = not is_bfloat16_supported(),
bf16 = is_bfloat16_supported(),
group_by_length=True,
seed = 3407,
output_dir = "outputs",
report_to = "none",
),
)
#@title 学習実行
trainer_stats = etrainer.train()
# 強化学習
%%capture
!pip install unsloth
# Also get the latest nightly Unsloth!
!pip uninstall unsloth -y && pip install --upgrade --no-cache-dir --no-deps git+https://github.com/unslothai/unsloth.git
from huggingface_hub import login
from google.colab import userdata
# hugging faseにlog in
hf_token = userdata.get('HF_TOKEN')
if hf_token:
login(token=hf_token)
print("Hugging Face token found. Logged in to Hugging Face.")
else:
print("Hugging Face token not found. Please set it using userdata.set('HF_TOKEN', '')")
from unsloth import PatchDPOTrainer
PatchDPOTrainer()
from unsloth import FastLanguageModel
import torch
max_seq_length = 2048 # Choose any! We auto support RoPE Scaling internally!
dtype = None # None for auto detection. Float16 for Tesla T4, V100, Bfloat16 for Ampere+
load_in_4bit = True # Use 4bit quantization to reduce memory usage. Can be False.
model, tokenizer = FastLanguageModel.from_pretrained(
model_name = "IWAIYuma/llm-jp-3-13b-it_v3", # 自分がUnslothを使ってFTして、loraだけアップロードしているモデル
max_seq_length = max_seq_length,
dtype = dtype,
load_in_4bit = load_in_4bit,
token = hf_token,
)
# cyberagent/chatbot-arena-ja-calm2-7b-chat-experimentalデータセットの読み込み
import json
import codecs
from pprint import pprint
from datasets import load_dataset
# データセットをロード
ds = load_dataset("cyberagent/chatbot-arena-ja-calm2-7b-chat-experimental")
# フィルタリング関数を定義
def filter_short_examples(example):
return (
len(example['prompt']) <= 2000 and
len(example['chosen']) <= 2000 and
len(example['rejected']) <= 2000
)
# トレーニングデータをフィルタリング
filtered_train = ds['train'].filter(filter_short_examples)
# データセットをトレーニング用と評価用に分割 (80%をトレーニング用、20%を評価用)
train_size = int(0.8 * len(filtered_train)) # トレーニングデータのサイズ
eval_size = len(filtered_train) - train_size # 評価データのサイズ
# インデックスを順序通りに生成 (ランダム性なし)
train_indices = list(range(train_size)) # トレーニング用インデックス
eval_indices = list(range(train_size, len(filtered_train))) # 評価用インデックス
# トレーニングデータと評価データを選択
train_dataset = filtered_train.select(train_indices)
eval_dataset = filtered_train.select(eval_indices)
# データセットのサイズを出力
print(f"トレーニングデータセットのサイズ: {len(train_dataset)}")
print(f"評価データセットのサイズ: {len(eval_dataset)}")
pprint(train_dataset[0])
print("\n")
pprint(eval_dataset[0])
# 一旦100までを学習
# 結果が良かったので修正
# use_dataset = train_dataset.select(range(100))
use_dataset = train_dataset
use_dataset
# One must patch the DPO Trainer first!
from unsloth import PatchDPOTrainer
PatchDPOTrainer()
from transformers import TrainingArguments
from trl import DPOTrainer, DPOConfig
from unsloth import is_bfloat16_supported
dpo_trainer = DPOTrainer(
model = model,
ref_model = None,
args = DPOConfig(
per_device_train_batch_size = 2,
gradient_accumulation_steps = 4,
warmup_ratio = 0.1,
num_train_epochs = 1,
learning_rate = 5e-6,
fp16 = not is_bfloat16_supported(),
bf16 = is_bfloat16_supported(),
logging_steps = 1,
optim = "adamw_8bit",
weight_decay = 0.0,
lr_scheduler_type = "linear",
seed = 42,
output_dir = "outputs",
report_to = "none", # Use this for WandB etc
),
beta = 0.1,
train_dataset = use_dataset, #raw_datasets["train"],
# eval_dataset = raw_datasets["test"],
tokenizer = tokenizer,
max_length = 2048,
max_prompt_length = 1024,
)
# 学習の開始
dpo_trainer.train()
# ELYZA-tasks-100-TV データセットの読み込み。
import json
datasets = []
with open("/content/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
# 推論するためにモデルのモードを変更
FastLanguageModel.for_inference(model)
results = []
for dt in tqdm(datasets):
input = dt["input"]
prompt = f"""### 指示\n{input} 簡潔に回答してください \n### 回答\n"""
inputs = tokenizer([prompt], return_tensors = "pt").to(model.device)
outputs = model.generate(**inputs, max_new_tokens = 2048, use_cache = True, do_sample=False, repetition_penalty=1.2)
prediction = tokenizer.decode(outputs[0], skip_special_tokens=True).split('\n### 回答')[-1]
results.append({"task_id": dt["task_id"], "input": input, "output": prediction})
# jsonlで保存
new_model_id = "llm-jp-3-13b-it"
with open(f"{new_model_id}_output.jsonl", 'w', encoding='utf-8') as f:
for result in results:
json.dump(result, f, ensure_ascii=False)
f.write('\n')
#書き込みにログイン
whf_token = userdata.get('WHF_TOKEN')
if whf_token:
login(token=whf_token)
print("Hugging Face token found and logged in.")
else:
print("Hugging Face token not found. Please set it using userdata.set('HF_TOKEN', '')")
# モデルとトークナイザーをHugging Faceにアップロード
new_model_id = "llm-jp-3-13b-it"
new_model_id = f"{new_model_id}_RLHFv3"
model.push_to_hub(new_model_id, token=whf_token, private=True)
tokenizer.push_to_hub(new_model_id, token=whf_token, private=True)
'''