さとまたwiki
🧪

OLMoE 完全ガイド

完全オープン MoE の OLMoE-1B-7B を徹底解剖。AllenAI 製・訓練データまで全公開・RTX 4070 Super で LoRA 学習可能な唯一の MoE

OLMoE-1B-7B Mixture of Experts LoRA fine-tune 完全オープン RTX 4070 Super 対応

🧪 OLMoE-1B-7B-Instruct — 全体アーキテクチャ

AllenAI (Allen Institute for AI) 製の完全オープン MoE。訓練データ・コード・中間チェックポイント全て公開。 このモデルは あなたが実際に LoRA 学習できる唯一の MoE

7B
総パラメータ
1.3B
毎回動く (Active)
64
Expert 総数
8
毎回選ぶ (top-K)

⚖ Qwen3-30B との比較

項目Qwen3-30B-A3B🧪 OLMoE-1B-7Bあなたへの影響
GGUF サイズ18 GB4.2 GBVRAM 余裕
層数4816学習 3 倍速
Expert 数12864構造は同じ
訓練データ公開❌ 非公開✅ 完全公開研究最強
LoRA 学習 (RTX 4070)❌ 困難 (VRAM 不足)✅ 数時間で完走個人で fine-tune 可能

🔄 推論フロー

入力 "hello"
  │
  ▼  [① Tokenize] BPE で 50,304 語彙に分割
  │    "hello" → [19659]   ← 1 トークンに収まる (英語が得意)
  ▼
[② Embedding]  token_embd [2048 × 50304]
  │  各 token → 2048 次元ベクトル
  ▼
┌─────── 16 層ブロックをループ (Qwen3 は 48) ──────┐
│                                                      │
│ [③ Self-Attention (MHA)]                      │
│    q/k/v 全て 16 head                                │
│    ※ GQA なし → KV cache が Qwen3 より大きい         │
│                                                      │
│ [④ Router]  ffn_gate_inp [2048 × 64]          │
│    2048 次元 → 64 スコア → softmax                   │
│                                                      │
│ [⑤ top-8 選出]                                │
│    64 人から最適な 8 人を選ぶ                         │
│                                                      │
│ [⑥ Expert 8 人実行]                           │
│    選ばれた 8 expert だけ FFN (1024 dim)             │
│    残り 56 expert は計算しない = 高速                │
│                                                      │
│ [⑦ 重み付き合成]                              │
│    8 人の出力 × routing_weight で足し合わせ          │
└───────────────────────────────────────────────────┘
  │
  ▼  [⑧ Final Norm + LM Head]
  │    2048 次元 → 50,304 次元ロジット
  ▼  [⑨ Sampling] top-p=0.9 で次 token 決定
  │
"お"  次のトークン!

📖 OLMoE ソースコードの歩き方 (1500 行)

HuggingFace transformers の modeling_olmoe.py1,500 行しかない。 MoE の実装を読む上で最短の教材。読む順番をクラス単位で示します。

クラス / 関数行数何をするか
1OlmoeRMSNorm15 行LayerNorm の軽量版。RMS で正規化
2OlmoeRotaryEmbedding40 行RoPE 位置埋め込み。token の順序情報を付与
3OlmoeMLP20 行Expert 1 個の実装。SwiGLU FFN。こいつが 64 個並ぶ
4OlmoeAttention150 行Multi-Head Attention。MoE 前の token 間コミュニケーション
⭐ 5OlmoeSparseMoeBlock70 行★ MoE の心臓。ここだけ読めば OK ★ Router → top-K → expert 実行 → 合成
6OlmoeDecoderLayer50 行Attention + MoE + Residual を 1 層にまとめる。これが 16 回ループ
7OlmoeModel200 行Embedding → 16 層ループ → Final Norm の全体制御
8OlmoeForCausalLM150 行OlmoeModel + LM Head。loss 計算も含む (学習時)
9load_balancing_loss_func40 行expert 偏り防止の補助損失。学習時だけ使用

💡 最短ルート: OlmoeSparseMoeBlock の 70 行だけ読めば MoE は理解できる。 他 800 行 (Attention / RoPE / RMSNorm) は普通の LLM と同じ。

🔬 MoE の心臓 70 行を擬似コードで

class OlmoeSparseMoeBlock:
    # 入力: [B, T, 2048]   ← T トークン分の隠れ状態
    # 出力: [B, T, 2048]   ← MoE 処理後の隠れ状態

    def forward(self, x):
        B, T, H = x.shape
        x_flat = x.view(B*T, H)                     # [B*T, 2048]

        ### ① Router: 64 expert のスコアを計算 ###
        router_logits = self.gate(x_flat)           # [B*T, 64]
        weights       = softmax(router_logits, -1)  # 確率化

        ### ② top-K: 上位 8 人を選ぶ ###
        w, idx = torch.topk(weights, k=8, dim=-1)   # idx: [B*T, 8]

        ### ③ 選ばれた expert だけ実行 ###
        out = torch.zeros_like(x_flat)
        for e_id in range(64):                      # 64 expert 全部ループ
            mask = (idx == e_id)                    # この expert が選ばれた位置
            if not mask.any():
                continue                            # 呼ばれなければ skip (高速化)

            tok_idx, topk_idx = mask.nonzero(as_tuple=True)
            expert_out = self.experts[e_id](x_flat[tok_idx])  # FFN 実行

            ### ④ 重み付きで元の位置に足し戻す ###
            out.index_add_(0, tok_idx,
                           expert_out * w[tok_idx, topk_idx, None])

        return out.view(B, T, H), router_logits

# ★ この 30 行が MoE の全て。Mixtral も Qwen3 も同じパターン。expert 数 (64 or 128) と top-K (8 or 2) が違うだけ。

🔰 よくある疑問: 「2048 次元」って何? — 基礎用語 7 つ

「2048 次元ベクトル」「パラメータ」などが出てきたけど意味が分からない…という時の早見表。

スカラー数字 1 つ。例: 3.14
ベクトル数字の並び。例: [3.14, 0.5, -1.2] ← これは 3 次元ベクトル
次元 (dim)ベクトルの長さ。「2048 次元」= 数字が 2048 個並んでいること。次元が多いほど単語の意味を細かく表現できるが計算・メモリも増える
テンソルベクトルを何重にも積んだ箱。行列 (2D) → 3D → 4D と積める。例: [50304, 2048] は「2048 次元ベクトルが 50,304 個並んだ行列」= Embedding
パラメータテンソルの中の「1 個 1 個の数字」= 重み。6.9B パラメータ = 69 億個の数字が GGUF に詰まっている
Tokenテキストをちぎった最小単位 (≈ 単語や音節)。各 token は整数 ID (0〜50303) に変換されてモデルに入る
Embedding整数 ID → 2048 次元ベクトルに変換する辞書。似た単語は近いベクトルになる

🌐 よくある疑問: 他のモデル (DeepSeek-R1) と比べると?

同じ MoE でも桁が違う。OLMoE は勉強・個人用、DeepSeek-R1 は研究所・企業用

項目OLMoE-1B-7BQwen3-30B-A3BDeepSeek-R1意味
Total パラメータ6.9 B30.5 B671 B全体の重みの数
Active パラメータ1.3 B3.3 B37 B1 token 生成で実際に動く量
層数164861推論の「深さ」
Expert 総数64128256 + 1 shared専門家の人数
GGUF Q4 サイズ4.2 GB18 GB404 GBディスクに置くファイルサイズ

🔍 部品別の役割 — 何がどこで何をしているか

OLMoE-1B-7B を動かす 8 つの部品と、その中で「どこに何が入っているか」を表で整理。「無いとどうなる?」列が初心者の理解に効きます。

部品役目パラメータ数無いとどうなる?
Embedding
token_embd
50,304 語彙 → 2048 次元ベクトルに変換103 M
(50304 × 2048)
文字を計算できない
Self-Attention (MHA)
attn_q/k/v/out
文脈を混ぜる。OLMoE は 16 head 全部 MHA (GQA なし)67 M / 層 × 16 層前後の関係が消える
Router (Gate)
ffn_gate_inp
64 expert のスコアを計算 → top-8 を選ぶ131 K / 層
(2048 × 64)
MoE にならない (全員発火)
Expert (SwiGLU FFN) × 64
ffn_*_exps
知識を詰め込む場所。64 人の専門家、毎回 8 人が発火6.3 M × 64 × 16 = 6.5 B
(全パラの 90%)
賢くならない
RMSNorm
attn_norm / ffn_norm
各層の計算を安定化 (爆発防止)2 K / 層学習が発散して壊れる
LM Head
output.weight
最終層 2048 次元 → 50,304 語彙の logit に射影103 M次 token を選べない

💡 重要: パラメータの 90% は Expert の中

7B パラメータのうち 約 6.5 B が Expert FFN の中。 LoRA 学習で target_modules を Expert (ffn_*_exps) に集中させると、 少ない追加重みで効率的に知識を書き換えられます。

🔤 語彙 50,304 個はどこ?

「50,304」は OLMoE が知っている語彙の種類数。3 つの場所に散らばっています。

場所中身サイズ
GGUF メタデータ
tokenizer.ggml.tokens
50,304 個の文字列配列。["!", "#", …, "hello", …]約 1.5 MB
GGUF tensor
token_embd.weight
各 ID の意味ベクトル。[2048 × 50,304] の行列Q4_K_M: 52 MB
GGUF tensor
output.weight (LM head)
最終層から語彙 50,304 次元に射影する行列Q4_K_M: 52 MB

📊 4.2 GB の内訳 (Q4_K_M)

OLMoE-1B-7B-0125-Instruct-Q4_K_M.gguf  (4.2 GB)
├── ヘッダ                 ~1 KB    // "GGUF" magic + version
├── メタデータ             ~2 MB    // tokenizer + architecture info
│   ├── tokenizer.ggml.tokens          // 50304 文字列
│   ├── tokenizer.ggml.merges          // BPE 規則
│   └── architecture="olmoe", layers=16, experts=64, …
│
├── テンソル本体          ~4.2 GB
│   │
│   ├── token_embd.weight          52 MB   // 埋め込み
│   ├── output.weight              52 MB   // LM head
│   │
│   ├── blk.0 〜 blk.15 (16 層)
│   │   ├── attn_q/k/v/output         17 MB × 16  // Attention
│   │   ├── attn_norm / ffn_norm          8 KB × 16
│   │   │
│   │   ├── ffn_gate_inp              0.5 MB × 16  // Router ★小さい
│   │   ├── ffn_gate_exps (×64)        50 MB × 16   // Expert gate
│   │   ├── ffn_up_exps   (×64)        50 MB × 16   // Expert up
│   │   └── ffn_down_exps (×64)        50 MB × 16   // Expert down
│   │
│   └── output_norm.weight             8 KB

📊 よくある疑問: 「1B-7B」って何? Total と Active の違いは?

「1B-7B」の数字はモデル名そのもの。→ Total 6.92 B (全 expert を数えた合計) / Active 1.28 B (推論 1 トークンで実際に動く量)

部品TotalActive
Token Embedding103 M103 M
Attention × 16 層268 M268 M
Experts × 16 層6.44 B805 M (top-8)
合計6.92 B1.28 B

💪 強くする方法の選び方 — 7 つの手法と意思決定

「モデルを賢くする」には目的別に 7 つの選択肢。何をしたいかで選び方が変わる。まず自分のゴールを決めてから手法を選ぶこと。

手法何ができるVRAM所要時間RTX 4070S で可能?
① Full fine-tune全パラメータ (7B) を更新。最強だが一番重い80 GB+数日❌ 無理
② LoRA (QLoRA)追加の小さな重みで style/知識を学習6 GB数時間✅ 余裕
③ Continued Pre-training生テキストを追加学習。ドメイン知識注入24 GB+数日❌ ほぼ無理
④ SFT (Instruct)質問→回答ペアで対話能力を強化6 GB数時間✅ OK (LoRA と併用)
⑤ DPO「こっちの回答の方が良い」で選好を教える8 GB半日✅ OK
⑥ ORPOSFT + DPO を一発で (1 段階)8 GB半日✅ OK
⑦ RLHF (PPO)報酬モデル + 強化学習。ChatGPT の手法60 GB+数週間❌ 無理

💡 RTX 4070 Super で現実的な選択肢: ② LoRA / ④ SFT / ⑤ DPO / ⑥ ORPO の 4 つ。 このうち LoRA + SFT の組み合わせが 最も費用対効果が高い

🌲 意思決定フローチャート

Q1: 新しい知識を追加したい? それとも style/振る舞いだけ?
  │
  ├─ style だけ (敬語変更 / キャラ付け / 分野特化返答)
  │       │
  │       └─→ LoRA + SFT
  │           (100〜1000 サンプル、3〜6 時間、VRAM 6GB)
  │           ★ 最小コスト、最初に試すべき ★
  │
  ├─ 知識追加 (ドメイン特化・専門用語)
  │       │
  │       ├─ データが 1 万件未満  →  LoRA + SFT (Q&A 形式)
  │       ├─ データが 10 万件以上 →  Continued Pre-training (クラウド推奨)
  │       └─ 最新情報で常に更新したい → RAG (検索連携) が正解
  │
  ├─ 応答の品質/安全性を高めたい
  │       │
  │       └─→ DPO or ORPO
  │           (選好ペア 1000 組、VRAM 8GB)
  │
  └─ ChatGPT レベルを自作したい
          │
          └─→ RLHF (PPO)
              → ローカル GPU 不可能、クラウドで 100 万円規模

🏗 プロ級の組み合わせレシピ

Recipe A (シンプル): SFT のみ — チャットボット化。3 時間 / VRAM 6GB

Recipe B (バランス): SFT → DPO の 2 段階 — 品質↑。半日 / VRAM 8GB

Recipe C (最新): ORPO 1 段階 — SFT + DPO 同等の結果を早く。半日 / VRAM 8GB

Recipe D (知識特化): SFT (ドメイン Q&A) + RAG (外部検索) — 事実性↑

🇯🇵 日本語データセット集

OLMoE を日本語で強化するための実際に使える日本語データセット 10 種類。 全て HuggingFace datasets ライブラリで 1 行ダウンロード可能。

名前内容件数ライセンス用途
kunishou/databricks-dolly-15k-jaDolly の日本語翻訳版。指示→応答15,015CC-BY-SA 3.0⭐ 最初に使うならこれ
llm-jp/oasst1-21k-jaOpenAssistant の日本語会話21,000Apache 2.0⭐ マルチターン対話
llm-jp/magpie-sft-v1.0LLM-JP 公式 SFT データ241,000Apache 2.0⭐ 大規模で品質良
cyberagent/chatbot-arena-ja-calm2-7b-chat-experimental選好ペア (chosen/rejected)10,000CC-BY-4.0⭐ DPO 用
kunishou/hh-rlhf-49k-jaAnthropic HH-RLHF の日本語版49,000MITDPO / RLHF 用

📗 整形レシピ ① Dolly-15k-ja

指示→回答 15,015 件。この 1 つだけで初回 LoRA は完走できる

# prepare_dolly_ja.py
from datasets import load_dataset
import json

ds = load_dataset("kunishou/databricks-dolly-15k-ja", split="train")

with open("my_data.jsonl", "w", encoding="utf-8") as f:
    for row in ds:
        user_content = row["instruction"]
        if row.get("input"):
            user_content += "\n" + row["input"]
        messages = [
            {"role": "user",      "content": user_content},
            {"role": "assistant", "content": row["output"]},
        ]
        f.write(json.dumps({"messages": messages}, ensure_ascii=False) + "\n")

print("✅ my_data.jsonl done:", len(ds), "件")
# → ✅ my_data.jsonl done: 15015 件

🎯 初心者推奨コース

  1. Dolly-15k-ja をダウンロード (30 MB)
  2. レシピ ① で my_data.jsonl 生成
  3. 自作 50〜100 件を混ぜる (キャラ付け)
  4. 次の「LoRA チュートリアル」セクションで実行

2 時間で完走できる。結果が良ければ Magpie で本格学習へ。

🎓 LoRA 学習チュートリアル — RTX 4070 Super 完全手順

あなたの RTX 4070 Super 12GB で実際に動く完全手順。 所要時間 3〜6 時間 (データセット次第)。 OLMoE は個人が本格 fine-tune できる唯一の MoE

設定合計 VRAM結果
FP16 フル fine-tune22 GB❌ OOM
LoRA (FP16)17 GB❌ OOM
QLoRA (4-bit)6.5 GB✅ 余裕
Unsloth (最適化)5.8 GB✅ 最速

① 環境構築 (5 分)

Windows の場合は WSL2 Ubuntu 推奨。ネイティブ Windows も可だが bitsandbytes で詰まりやすい。

# venv を作る (Python 3.11 推奨)
python3.11 -m venv ~/olmoe-env
source ~/olmoe-env/bin/activate     # Windows: .\olmoe-env\Scripts\activate

# PyTorch (CUDA 12.1 版)
pip install torch --index-url https://download.pytorch.org/whl/cu121

# 方式 A: Unsloth (速い。推奨)
pip install "unsloth[cu121-torch230] @ git+https://github.com/unslothai/unsloth.git"

# 方式 B: 素の HF transformers + PEFT + bitsandbytes
pip install transformers peft datasets accelerate bitsandbytes trl

# 動作確認
python -c "import torch; print('CUDA:', torch.cuda.is_available(), torch.cuda.get_device_name(0))"
# → CUDA: True NVIDIA GeForce RTX 4070 SUPER

③ 学習スクリプト (train_lora.py)

Unsloth 版。コピペでそのまま動く。target_modules は Expert FFN + Attention を指定。

# train_lora.py
from unsloth import FastLanguageModel
from datasets import load_dataset
from trl import SFTTrainer, SFTConfig

# ① モデル読み込み (4-bit 量子化で VRAM 4GB)
model, tok = FastLanguageModel.from_pretrained(
    model_name = "allenai/OLMoE-1B-7B-0125-Instruct",
    max_seq_length = 2048,
    load_in_4bit = True,
    dtype = None,  # 自動 (bf16 on Ampere+)
)

# ② LoRA 設定 (target_modules に expert を含める)
model = FastLanguageModel.get_peft_model(
    model,
    r = 16,               # LoRA rank (8〜32 が定石)
    lora_alpha = 32,
    lora_dropout = 0.05,
    target_modules = [
        "q_proj", "k_proj", "v_proj", "o_proj",  # Attention
        "gate_proj", "up_proj", "down_proj",       # ★ Expert FFN ★
    ],
    use_gradient_checkpointing = "unsloth",
    random_state = 3407,
)

# ③ データロード (JSONL → chat template)
def fmt(sample):
    return {"text": tok.apply_chat_template(sample["messages"], tokenize=False)}

ds = load_dataset("json", data_files="my_data.jsonl", split="train").map(fmt)

# ④ 学習設定
trainer = SFTTrainer(
    model = model,
    tokenizer = tok,
    train_dataset = ds,
    dataset_text_field = "text",
    max_seq_length = 2048,
    args = SFTConfig(
        output_dir = "./olmoe-lora-out",
        per_device_train_batch_size = 2,
        gradient_accumulation_steps = 4,
        num_train_epochs = 3,
        learning_rate = 2e-4,
        warmup_steps = 10,
        logging_steps = 5,
        save_steps = 100,
        bf16 = True,
        optim = "adamw_8bit",
    ),
)

# ⑤ 実行!
trainer.train()
model.save_pretrained("./olmoe-lora-out")

⑤ LoRA マージ & GGUF 変換

# ① LoRA をベースにマージ
python -c "
from unsloth import FastLanguageModel
model, tok = FastLanguageModel.from_pretrained('./olmoe-lora-out', load_in_4bit=False)
model.save_pretrained_merged('./olmoe-merged', tok, save_method='merged_16bit')
"

# ② GGUF 変換 (llama.cpp の convert スクリプト)
git clone https://github.com/ggerganov/llama.cpp
cd llama.cpp && make LLAMA_CUDA=1

python convert_hf_to_gguf.py ../olmoe-merged \
    --outfile olmoe-mytuned.gguf \
    --outtype f16

# ③ Q4_K_M 量子化 (4.2 GB に圧縮)
./llama-quantize olmoe-mytuned.gguf olmoe-mytuned-Q4_K_M.gguf Q4_K_M

# ④ Ollama 登録
ollama create my-olmoe -f Modelfile
ollama run my-olmoe "自己紹介して"

💎 MoE 特有のチューニング Tips

Router は凍結: ffn_gate_inp を LoRA 対象に入れると expert 選択が崩れやすい。触らないのが安全。

全 Expert に同じ LoRA: Unsloth は 64 個の expert に対して共通の LoRA を適用するので、ファイル数が爆発しない。

rank 16 が sweet spot: 8 だと表現力不足、32 以上は過学習リスク。16 から試す。

epoch 3 まで: それ以上は過学習で style が崩れる。validation loss をモニターして early stop。

🚨 よくあるエラーと対処

エラー原因対処
CUDA out of memoryVRAM 不足per_device_train_batch_size=1max_seq_length=1024
loss が nan学習率が高すぎlearning_rate=5e-5 に下げる
loss が下がらないtarget_modules 不足Expert (gate_proj / up_proj / down_proj) を追加
GGUF 変換失敗OLMoE 未対応の古い llama.cppllama.cpp を最新版に (git pull)

🔬 Expert 作成・強化 — MoE 特有の深い改造 (上級)

MoE 特有の改造術。単なる LoRA を超えて、Expert そのものを操作する方法。 Expert を新規追加・特定 expert だけ強化・不要 expert を剪定。フルオープンの OLMoE だからこそ可能

🧬 Expert 1 個の中身 (SwiGLU FFN)

Expert i の forward (入力 x [2048] → 出力 [2048])

        x  [2048]
        │
        ├──→  gate_proj[i]  ──→  gate  [1024]
        │     (重み [2048→1024])
        │                          │
        ├──→  up_proj[i]    ──→  up    [1024]
        │     (重み [2048→1024])    │
        │                           ▼
        │           silu(gate) * up  ── hidden [1024]
        │                           │
        │     down_proj[i]    │
        │     (重み [1024→2048])    ▼
        └───────────────────── output [2048]

# OLMoE の場合: Expert 1 個 = 3 × 2048 × 1024 = 6.3M パラ
# × 64 expert × 16 層 = 6.5 B パラ (全体の 90%)

🔧 改造① 特定 Expert だけ強化する

「数学が苦手なモデル」を直したい → 数学で発火する expert を特定して LoRA をかぶせる。

# Step 1: どの expert が何で発火してるか調べる
from transformers import AutoModelForCausalLM, AutoTokenizer
import torch

model = AutoModelForCausalLM.from_pretrained("allenai/OLMoE-1B-7B-0125-Instruct",
                                             output_router_logits=True)
tok = AutoTokenizer.from_pretrained("allenai/OLMoE-1B-7B-0125-Instruct")

prompts = ["2+2=?", "Solve x^2=4", "derivative of sin(x)"]
expert_count = torch.zeros(16, 64)  # 16 層 × 64 expert

for p in prompts:
    inputs = tok(p, return_tensors="pt")
    with torch.no_grad():
        out = model(**inputs)
    for layer, logits in enumerate(out.router_logits):
        topk_idx = logits.topk(8, dim=-1).indices
        for e in topk_idx.flatten():
            expert_count[layer, e] += 1

top_math_experts = expert_count.view(-1).topk(20).indices
print("数学エキスパート候補:", [(i//64, i%64) for i in top_math_experts])
# Step 2: その expert だけに LoRA
from peft import LoraConfig, get_peft_model

cfg = LoraConfig(
    r=32,
    target_modules=["gate_proj","up_proj","down_proj"],
    layers_to_transform=[8,9,10],          # 数学で発火した層だけ
    task_type="CAUSAL_LM",
)
model = get_peft_model(model, cfg)
# → 数学データで SFT 実行

🧪 改造② 新しい Expert を追加する (上級)

OLMoE は 64 expert。これを 80 にしたい → Router と Expert テンソルをコード側で拡張。

import torch
from transformers import AutoModelForCausalLM

model = AutoModelForCausalLM.from_pretrained("allenai/OLMoE-1B-7B-0125-Instruct")
config = model.config
NEW_N = 80                                 # 64 → 80 に増やす

for i, layer in enumerate(model.model.layers):
    mlp = layer.mlp  # OlmoeSparseMoeBlock

    # ① Router (ffn_gate_inp) 拡張 [2048 × 64] → [2048 × 80]
    old_w = mlp.gate.weight.data     # [64, 2048]
    new_w = torch.zeros(NEW_N, old_w.size(1))
    new_w[:64] = old_w
    new_w[64:] = old_w[:16].clone()        # 新 16 個は既存の複製
    mlp.gate = torch.nn.Linear(2048, NEW_N, bias=False)
    mlp.gate.weight.data = new_w

    # ② Expert (ModuleList) を 16 個追加
    for j in range(16):
        src = mlp.experts[j % 64]
        import copy
        mlp.experts.append(copy.deepcopy(src))

    mlp.num_experts = NEW_N

config.num_experts = NEW_N
model.save_pretrained("./olmoe-80experts")
# ★ 続いて SFT で新 expert を分化させる学習が必要

✂ 改造③ 使われていない Expert を削除 (モデル圧縮)

# ② 各層で下位 16 個を削除 (64 → 48 expert)
for layer_idx, layer in enumerate(model.model.layers):
    mlp = layer.mlp
    usage = expert_count[layer_idx]              # [64]
    keep_idx = usage.topk(48).indices             # 上位 48 残す

    mlp.experts = torch.nn.ModuleList([mlp.experts[i] for i in keep_idx])
    mlp.gate.weight.data = mlp.gate.weight.data[keep_idx]
    mlp.num_experts = 48

# ③ 再微調整 (剪定の穴埋め)
# → SFT を軽く回す (2000 サンプル程度)

# 結果: 7B → 5.4B (25% 削減)、品質はほぼ維持

💎 Expert 改造のベストプラクティス

やること理由
Router は基本凍結LoRA で触ると expert 選択が崩壊する
Expert LoRA は全 64 に適用特定 expert だけ触ると他が相対的に劣化
Aux loss は 0.01〜0.02大きいと本タスクが犠牲、小さいと偏る
Expert 追加は複製からゼロ初期化は学習が発散する
剪定は必ず再学習付き穴埋めしないと精度劇落ち

🔬 Expert 改造の意義

  • LoRA ではできない、構造的な改造が可能
  • MoE 研究の最先端は OLMoE のフルオープン性があって初めて触れる
  • 学術論文級の実験ができる個人 PC 環境 (他の MoE はクローズド)

初心者はまず「LoRA 学習チュートリアル」から始めて、慣れたらこのページの改造を 1 つずつ試すこと。