report-review

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | Submodules | README | LICENSE

train.py (4600B)


      1 import torch
      2 from datasets import load_dataset
      3 from peft import LoraConfig, get_peft_model, prepare_model_for_kbit_training
      4 from transformers import (
      5     AutoModelForCausalLM,
      6     AutoTokenizer,
      7     BitsAndBytesConfig,
      8     Trainer,
      9     TrainingArguments,
     10 )
     11 
     12 # --- 設定 ---
     13 MODEL_NAME = "mistralai/Mistral-7B-Instruct-v0.2"  # 高性能なベースモデル
     14 DATASET_PATH = "typst_feedback_dataset.jsonl"  # 統合した学習データセット
     15 OUTPUT_DIR = "./mistral_typst_adapter"  # 学習結果(LoRAアダプター)の保存先
     16 LORA_R = 16  # LoRAのランク(精度とメモリのトレードオフ)
     17 LORA_ALPHA = 32
     18 LORA_DROPOUT = 0.05
     19 BATCH_SIZE = 1
     20 
     21 # --- 1. データセットの準備 ---
     22 # JSON Linesファイルをロード
     23 dataset = load_dataset("json", data_files=DATASET_PATH, split="train")
     24 
     25 
     26 def format_prompt(example):
     27     """
     28     Typstコードを入力(Instruction)として、JSON出力を期待するプロンプト形式に整形する。
     29     MistralのInstructionフォーマット([INST]...[/INST])を使用。
     30     """
     31 
     32     # 指示: Typstコードをレビューし、JSON形式で指摘事項を出力せよ
     33     prompt = f"""[INST]
     34 以下のTypstコードのレビューを行い、文書のフォーマット、論理、文法に関するすべての指摘事項を、定義されたJSON形式のリストとして出力してください。
     35 
     36 Typstコード:
     37 ---
     38 {example["instruction"]}
     39 ---
     40 
     41 JSON形式の指摘リスト:
     42 [/INST]"""
     43 
     44     # LLMの学習データは 'Instruction' と 'Output' を結合した形式にする
     45     example["text"] = prompt + example["output"]
     46     return example
     47 
     48 
     49 # データセットをプロンプト形式に変換
     50 dataset = dataset.map(format_prompt, remove_columns=["instruction", "output"])
     51 
     52 # トークナイザをロード(修正済みセクション)
     53 tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME)
     54 tokenizer.pad_token = tokenizer.eos_token
     55 
     56 
     57 def tokenize_function(examples):
     58     tokenized = tokenizer(
     59         examples["text"], truncation=True, padding="max_length", max_length=1024
     60     )
     61     # 【✅ 修正箇所】
     62     # input_idsを複製してlabelsとする
     63     # Data Collatorがinput_ids(モデル入力)とlabels(教師データ)の両方を見つけられるようにする
     64     tokenized["labels"] = tokenized["input_ids"].copy()
     65     return tokenized
     66 
     67 
     68 tokenized_dataset = dataset.map(
     69     tokenize_function, batched=True, remove_columns=["text"]
     70 )
     71 
     72 # --- 2. 量子化設定とモデルのロード ---
     73 # QLoRAのための4bit量子化設定
     74 bnb_config = BitsAndBytesConfig(
     75     load_in_4bit=True,
     76     bnb_4bit_quant_type="nf4",
     77     bnb_4bit_compute_dtype=torch.bfloat16,
     78     bnb_4bit_use_double_quant=False,
     79 )
     80 
     81 # モデルとトークナイザをロード
     82 model = AutoModelForCausalLM.from_pretrained(
     83     MODEL_NAME,
     84     quantization_config=bnb_config,
     85     device_map="auto",
     86 )
     87 tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME)
     88 tokenizer.pad_token = tokenizer.eos_token  # トークナイザ設定
     89 
     90 # 4bit学習のためのモデル準備
     91 model.gradient_checkpointing_enable()
     92 model = prepare_model_for_kbit_training(model)
     93 
     94 
     95 # --- 3. LoRA設定とモデル適用 ---
     96 lora_config = LoraConfig(
     97     r=LORA_R,
     98     lora_alpha=LORA_ALPHA,
     99     lora_dropout=LORA_DROPOUT,
    100     bias="none",
    101     task_type="CAUSAL_LM",  # テキスト生成タスク
    102     target_modules=[
    103         "q_proj",
    104         "k_proj",
    105         "v_proj",
    106         "o_proj",
    107     ],  # Mistralの主要なAttention層
    108 )
    109 
    110 # PEFTモデルの取得
    111 model = get_peft_model(model, lora_config)
    112 model.print_trainable_parameters()  # 学習対象のパラメータ数を確認(非常に少ないはず)
    113 
    114 
    115 # --- 4. 学習の実行 ---
    116 # 【✅ 修正 2: TrainingArgumentsの設定変更】
    117 training_args = TrainingArguments(
    118     output_dir=OUTPUT_DIR,
    119     per_device_train_batch_size=BATCH_SIZE,
    120     gradient_accumulation_steps=4,
    121     warmup_steps=10,
    122     max_steps=20,
    123     learning_rate=2e-4,
    124     fp16=True,
    125     logging_steps=5,
    126     # 【ここを修正】データセットの列名がTrainerと完全に一致しなくても許容する
    127     remove_unused_columns=False,
    128 )
    129 
    130 trainer = Trainer(
    131     model=model,
    132     # 【修正 3: トークン化後のデータセットを使用】
    133     train_dataset=tokenized_dataset,
    134     args=training_args,
    135     tokenizer=tokenizer,
    136 )
    137 
    138 # 学習開始
    139 trainer.train()
    140 
    141 # 学習済みアダプターの保存
    142 trainer.model.save_pretrained(OUTPUT_DIR)