1. はじめに
今回は、1Bクラスの軽量ローカルLLM「Llama 3.2 1B-Instruct」を、より自然な文章を生成できるモデルへ育てるための実験を始めます。
まずはファインチューニング……の前に、学習に使うデータをどう集めるかが問題になります。
そこで今回は、Llamaに大量の文章を生成させ、AI Detectorに評価させて、Human判定されたものだけを自動で回収する仕組みを作りました。
今回の記事では、まず生成した文章をAIで評価し、良質なデータだけを自動収集する仕組みを完成させます。
2. 今回作るもの
今回は、Llama 3.2 1B-Instructに英語で50 words程度のラーメン店レビューを生成させ、その文章をAI Detectorで評価するという実験を行います。
生成したレビューのうち、Detectorで Humanと判定されたものだけを採用し、ファインチューニング用データとして蓄積します。
┌──────────────┐
│ Llama 3.2 1B │
│ 文章生成 │
└──────┬───────┘
↓
┌──────────────┐
│ AI Detector │
│ 自動判定 │
└──────┬───────┘
↓
良品だけ保存
生成モデルにはLlama 3.2 1B-Instruct、判定には Hello-SimpleAI/chatgpt-detector-roberta を使用します。
Detectorの判定を絶対的な正解とは考えず、今回は「Humanと判定された文章を集めるためのスコアラー」として利用します。
3. Llamaをローカルで読み込む
今回はGoogle Driveに置いたモデルをColabから直接読み込みます。
また、ローカルモデルを確実に利用するため local_files_only=True を指定します。
import os
import torch
from transformers import AutoTokenizer, AutoModelForCausalLM, AutoModelForSequenceClassification, pipeline
from google.colab import drive
drive.mount('/content/drive', force_remount=True)
# -----------------------------
# 1. Llama 3.2 1B をロード
# -----------------------------
# Googleドライブ上にモデルを保存している前提のコードです
model_path = os.path.abspath(
"/content/drive/MyDrive/models/Llama-3.2-1B-Instruct"
)
tokenizer = AutoTokenizer.from_pretrained(
model_path,
local_files_only=True
)
model = AutoModelForCausalLM.from_pretrained(
model_path,
local_files_only=True
)
これで「ローカルにあるはずなのに、裏でHFへ取りに行く」といった事故も防げます。
4. 生成 → 判定 → 保存
次はLlamaに文章を生成させ、Detectorで判定します。
今回は temperature=0.9 として、ある程度バリエーションのある文章を生成させます。
import json
import torch
from transformers import (
AutoTokenizer,
AutoModelForCausalLM,
pipeline
)
# -----------------------------
# 1. detector をロード
# -----------------------------
detector_tokenizer = AutoTokenizer.from_pretrained(detector_save_dir, local_files_only=True)
detector_model = AutoModelForSequenceClassification.from_pretrained(detector_save_dir, local_files_only=True)
local_detector = pipeline("text-classification", model=detector_model, tokenizer=detector_tokenizer)
# -----------------------------
# 2. 文章生成
# -----------------------------
dataset = []
# 40-60単語を狙う短いプロンプト
prompt = "Write a short, enthusiastic restaurant review for chilled cold ramen. Keep it exactly 40-60 words."
messages = [{"role": "user", "content": prompt}]
inputs = tokenizer.apply_chat_template(
messages,
return_tensors="pt",
add_generation_prompt=True,
return_dict=True
).to(device)
for _ in range(100):
# ① Llamaで生成
outputs = model.generate(
**inputs,
max_new_tokens=80,
temperature=0.9,
do_sample=True
)
text = tokenizer.decode(
outputs[0][inputs["input_ids"].shape[1]:],
skip_special_tokens=True
).strip()
# ② AI Detectorで評価
result = local_detector(text)[0]
# ③ Human判定だけ採用
if result["label"] == "Human":
dataset.append({
"text": text,
"score": result["score"]
})
# ④ 逐次保存
with open(output_file, "w") as f:
json.dump(dataset, f, ensure_ascii=False, indent=2)
単純なループですが、途中でColabが落ちてもデータが消えないよう、採用したデータは1件ずつ逐次保存するようにしています。
既存JSONを読み込んで途中から再開できるようにもしておきます。
5. 実験結果
まず100回生成してみたところ、約17%がHuman判定になりました。
つまり100個の文章を生成すると、約17個を自動的に学習候補として回収できます。が、基本的にはほとんどボット判定を喰らって弾かれてしまいます。
比較対象としてGemini Proにも文章を生成させてみたところ、今回のDetectorでは Humanスコア 0.9996 という非常に高い値を一発で記録しました。
「じゃあLlama 1Bでもこの領域を狙えるのか?」というのが、次の実験になります。
6. 次回:集めたデータでLlamaを育てる
ここまでで、Llama自身に文章を大量生成させ、そこから「良さそうなもの」だけを自動で集めるところまで完成しました。
次回は、このデータをそのまま使ってLlama 3.2 1Bのファインチューニングに挑戦します。
最終的には、
生成
↓
評価・選別
↓
Fine-Tuning
↓
改善モデル
というループを作り、モデルを自動で育てられるところまで持っていく予定です。
果たして1Bモデルは、こんな雑な自己選別データでも本当に変わるのか?