LLMの学習方法(事前学習、FineTuning, RLHF)

LLMの学習方法は大きく分けて3つある

1. 事前学習(Pre-training)
目的:
「言語の基礎的な知識」を身につける段階
文法・語彙・一般常識・文脈の理解などを、膨大なテキストから学ぶ

方法:
教師なし学習(Self-supervised learning)
入力文の一部を隠して、隠された部分を予測する(=マスク言語モデル、例:BERT)
次の単語を予測する(=自己回帰モデル、例:GPT系列)

データ:
インターネット上のテキスト(Webページ、書籍、Wikipediaなど)
数百億〜数兆トークン規模

2. ファインチューニング(Fine-tuning)
目的:
事前学習で得た「言語の基礎力」を、特定の目的や用途に合わせて調整

方法:
教師あり学習(Supervised fine-tuning)
入力と正解(出力)のペアを与える。
例:「質問 → 回答」「命令 → 応答」
少量の高品質データで調整。

3.人間のフィードバックによる強化学習(RLHF: Reinforcement Learning from Human Feedback)
目的:
モデルの出力を「人間にとって好ましい形」にする。
(=有用で、正確で、安全で、自然な応答にする)

① SFTモデル(ファインチューニング済)を使って、複数の応答候補を生成。
② 人間の評価者が「どの回答が良いか」を順位付け。
**③ 報酬モデル(Reward Model)**を学習。
→ 「この応答が好ましい」と判断するスコア関数を作る。
**④ 強化学習(PPOなど)**でモデルを更新し、報酬が高い出力を出すように最適化。

### Pretraining

import torch
import torch.nn as nn
import torch.optim as optim

text = "I love AI . AI loves people ."
vocab = list(set(text.split()))
word2idx = {w:i for i,w in enumerate(vocab)}
idx2word = {i:w for w,i in word2idx.items()}

def make_data(text):
    words = text.split()
    X, Y = [], []
    for i in range(len(words)-2):
        X.append([word2idx[words[i]], word2idx[words[i+1]]])
        Y.append(word2idx[words[i+2]])
    return torch.tensor(X), torch.tensor(Y)


X, Y = make_data(text)

class TinyLM(nn.Module):
    def __init__(self, vocab_size, hidden_size=8):
        super().__init__()
        self.emb = nn.Embedding(vocab_size, hidden_size)
        self.fc = nn.Linear(hidden_size*2, vocab_size)

    def forward(self, x):
        x = self.emb(x).view(x.size(0), -1)
        return self.fc(x)

model = TinyLM(len(vocab))
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.01)

for epoch in range(200):
    output = model(X)
    loss = criterion(output, Y)
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

test = torch.tensor([[word2idx["I"], word2idx["love"]]])
pred = torch.argmax(model(test), dim=1)
print("Predicted next word:", idx2word[pred.item()])

### Fine tuning

train_data = [
    ("Hello", "Hi there!"),
    ("How are you?", "I'm fine, thank you."),
    ("Bye", "Goodbye!")
]

from transformers import AutoTokenizer, AutoModelForCausalLM, Trainer, TrainingArguments

tokenizer = AutoTokenizer.from_pretrained("gpt2")
model = AutoModelForCausalLM.from_pretrained("gpt2")

# データを整形
inputs = [tokenizer(f"User: {q}\nAI:", return_tensors="pt") for q, _ in train_data]
labels = [tokenizer(a, return_tensors="pt")["input_ids"] for _, a in train_data]

# 学習っぽいループ
for i, (inp, lab) in enumerate(zip(inputs, labels)):
    out = model(**inp, labels=lab)
    loss = out.loss
    loss.backward()
print("Fine-tuning step complete ✅")

### RLHF

import random

# モデルの応答候補
responses = ["Sure, here’s an example.", "I don’t know.", "You’re stupid."]

# 人間が選んだランキング(良い順)
human_ranking = {"Sure, here’s an example.": 1, "I don’t know.": 0, "You’re stupid.": -1}

# 報酬モデル(スコア関数)を模擬
def reward(response):
    return human_ranking[response]

# 強化学習っぽい更新(高報酬応答を強化)
policy = {r: 0.0 for r in responses}
for _ in range(10):
    r = random.choice(responses)
    policy[r] += reward(r) * 0.1

print("Learned policy:", policy)