Uploaded model

  • Developed by: Mori-kamiyama
  • License: apache-2.0
  • Finetuned from model : llm-jp/llm-jp-3-13b

This llama model was trained 2x faster with Unsloth and Huggingface's TRL library.

# Google Colab の場合は上記の環境構築手順を行なわず、単にこのセルから実行していってください。
!pip install --upgrade pip setuptools wheel build
!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でインタラクティブな表示を可能とする(ただし、うまく動かない場合あり)
# Google Colabでは実行不要
%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"

# llm-jp/llm-jp-3-13bを4bit量子化のqLoRA設定でロード。
from unsloth import FastLanguageModel
import torch

max_seq_length = 512  # コンテキスト長は任意に設定可能(unslothはRoPE対応)
dtype = None  # 自動でdtypeを選択
load_in_4bit = True  # 13Bモデルへの4bit量子化を有効化

model_id = "llm-jp/llm-jp-3-13b"
new_model_id = "llm-jp/llm-jp-3-13b-it" # Fine-Tuningしたモデル名

# trust_remote_codeはできればFalse推奨(安全性重視)
model, tokenizer = FastLanguageModel.from_pretrained(
    model_name = model_id,
    dtype = dtype,
    load_in_4bit = load_in_4bit,
    trust_remote_code = False,  # TrueからFalseに変更、安全を重視
)

# LoRA設定: lora_dropoutを0に変更して高速化
model = FastLanguageModel.get_peft_model(
    model,
    r = 32,
    target_modules = ["q_proj", "k_proj", "v_proj", "o_proj",
                      "gate_proj", "up_proj", "down_proj"],
    lora_alpha = 32,
    lora_dropout = 0.0,  # 0.05 → 0に変更して警告回避 & 高速化
    bias = "none",
    use_gradient_checkpointing = "unsloth",
    random_state = 3407,
    use_rslora = False,
    loftq_config = None,
    max_seq_length = max_seq_length,
)

# distutilsの警告対策(必要なら別途、setuptoolsアップデート)
# pip install --upgrade setuptools

print("Model and tokenizer loaded successfully with LoRA configuration.")

# 学習に用いるデータセットの指定
# 今回はLLM-jp の公開している Ichikara Instruction を使います。データにアクセスするためには申請が必要ですので、使いたい方のみ申請をしてください。
# Ichikara Instruciton を Hugging Face Hub にて公開することはお控えください。  
# また、CC-BY-NC-SAですのでモデルはライセンスを継承する前提でお使いください。  

# 下記のリンクから申請を終えた先に Google Drive があり、Distribution20241221_all というフォルダごとダウンロードしてください。
# 今回は「ichikara-instruction-003-001-1.json」を使います。必要であれば展開(!unzip など)し、データセットのパスを適切に指定してください。
# omnicampusの開発環境では取得したデータを左側にドラッグアンドドロップしてお使いください。
# Google Colab の場合も左のサイドバーよりドラッグ&ドロップでアップデートしてください。

# https://liat-aip.sakura.ne.jp/wp/llmのための日本語インストラクションデータ作成/llmのための日本語インストラクションデータ-公開/
# 関根聡, 安藤まや, 後藤美知子, 鈴木久美, 河原大輔, 井之上直也, 乾健太郎. ichikara-instruction: LLMのための日本語インストラクションデータの構築. 言語処理学会第30回年次大会(2024)

from datasets import load_dataset, concatenate_datasets  # concatenate_datasets をインポート

# ローカルデータセットの読み込み
dataset = load_dataset(
    "json",
    data_files=[
        "./ichikara-instruction-003-001-1.json",
        "./ichikara-instruction-003-001-2.1.json",
        "./ichikara-instruction-003-001-2.2.json",
        "./ichikara-instruction-003-001-5.1.json",
        "./ichikara-instruction-003-001-5.2.json"
    ]
)

# Hugging Face Hub 上のデータセットを読み込み
remote_dataset = load_dataset("llm-jp/magpie-sft-v1.0")

# データセットを結合し、10k件に制限
combined_dataset = concatenate_datasets([
    dataset['train'],  # 修正: ローカルデータセットの 'train' を参照
    remote_dataset['train'].select(range(min(len(remote_dataset['train']), 10000)))
])

# 結合後のデータセットを確認
print(combined_dataset)
# パスの指定にご注意ください。アップロードしたファイルを右クリックし、「パスをコピー」をクリック、上記の data_files と合致していることをご確認ください。Omnicampus のディレクトリ構造とは異なるかもしれません。

print(remote_dataset)  # データセットの情報を確認
print(remote_dataset['train'].num_rows)  # トレーニングデータのサンプル数
print(remote_dataset['train'][0])  # サンプルデータの一部を確認

# 学習時のプロンプトフォーマットの定義
prompt = """### 指示
{}
### 回答
{}"""

EOS_TOKEN = tokenizer.eos_token  # トークナイザーのEOSトークン(文末トークン)

# フォーマット関数
def formatting_prompts_func(examples):
    """
    datasetのサンプル(examples)からformatted_textを生成する関数。

    - `conversations` が存在し、かつ2つ以上の要素があれば、
      userとassistantのやりとりとしてフォーマット。
    - それ以外の場合は、ローカルdatasetの`text`と`output`を利用。
    - どちらもなければ空文字列を返す。
    """
    user_input = None
    assistant_output = None

    # conversationsが存在するかチェック
    conversations = examples.get("conversations", None)
    if conversations and len(conversations) >= 2:
        # remote_dataset形式: conversations[0]["content"]がユーザ発話、conversations[1]["content"]がアシスタント発話
        user_input = conversations[0]["content"]
        assistant_output = conversations[1]["content"]
    else:
        # local dataset形式: "text"と"output"フィールドが存在
        text_field = examples.get("text", None)
        output_field = examples.get("output", None)
        if text_field is not None and output_field is not None:
            user_input = text_field
            assistant_output = output_field

    if user_input is not None and assistant_output is not None:
        formatted = prompt.format(user_input, assistant_output) + EOS_TOKEN
    else:
        # conversations も text/output も有効でない場合は空文字
        formatted = ""

    return {"formatted_text": formatted}

# フォーマッティング
formatted_dataset = combined_dataset.map(
    formatting_prompts_func,
    num_proc=4
)

# 空文字のformatted_textをフィルタリング
def is_nonempty(example):
    return len(example["formatted_text"].strip()) > 0

formatted_dataset = formatted_dataset.filter(is_nonempty)

# データの確認
print(formatted_dataset)
print(formatted_dataset[0])

"""
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=formatted_dataset,
    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=5e-5,
        fp16=not is_bfloat16_supported(),
        bf16=is_bfloat16_supported(),
        group_by_length=True,
        seed=3407,
        output_dir="outputs",
        report_to="none",
    ),
)

#@title 現在のメモリ使用量を表示
gpu_stats = torch.cuda.get_device_properties(0)
start_gpu_memory = round(torch.cuda.max_memory_reserved() / 1024 / 1024 / 1024, 3)
max_memory = round(gpu_stats.total_memory / 1024 / 1024 / 1024, 3)
print(f"GPU = {gpu_stats.name}. Max memory = {max_memory} GB.")
print(f"{start_gpu_memory} GB of memory reserved.")

#@title 学習実行
trainer_stats = trainer.train()

# ELYZA-tasks-100-TVの読み込み。事前にファイルをアップロードしてください
# データセットの読み込み。
# omnicampusの開発環境では、左にタスクの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

# 推論するためにモデルのモードを変更
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 = 512, 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})

import os
import json

# ファイル名を指定
new_model_id = "llm-jp/llm-jp-3-13b-it"
file_path = f"{new_model_id}_output.jsonl"

# 必要なディレクトリを作成
os.makedirs(os.path.dirname(file_path), exist_ok=True)

# jsonlで保存
with open(file_path, 'w', encoding='utf-8') as f:
    for result in results:
        json.dump(result, f, ensure_ascii=False)
        f.write('\n')

!pip install --upgrade huggingface_hub


from huggingface_hub import HfApi
from requests.exceptions import HTTPError

new_model_id = "Mori-kamiyama/llm-jp-3-13b-it-241211"

# Hugging Face API を使用してリポジトリの存在確認
api = HfApi()
try:
    repo_info = api.repo_info(repo_id=new_model_id+"_lora", token=HF_TOKEN)
    print(f"Repository {new_model_id+'_lora'} already exists.")
except HTTPError as e:
    if e.response.status_code == 404:  # リポジトリが存在しない場合
        print(f"Repository {new_model_id+'_lora'} does not exist. Proceeding to create it.")

        # リポジトリを作成してアップロード
        model.push_to_hub_merged(
            new_model_id+"_lora",
            tokenizer=tokenizer,
            save_method="lora",
            token=HF_TOKEN,
            private=True
        )
    else:
        print(f"An unexpected HTTP error occurred: {e}")
        raise
Downloads last month

-

Downloads are not tracked for this model. How to track
Inference Providers NEW
This model is not currently available via any of the supported Inference Providers.
The model cannot be deployed to the HF Inference API: The model has no pipeline_tag.

Model tree for Mori-kamiyama/llm-jp-3-13b-it-241211_lora

Finetuned
(1122)
this model

Dataset used to train Mori-kamiyama/llm-jp-3-13b-it-241211_lora