SSMoELM-it / technical_notes.md
brulee-1's picture
docs: add shared-only ablation
a270f6e verified
|
Raw
History Blame Contribute Delete
16.4 kB

SSMoELM Technical Notes

2026-05-27

アーキテクチャ確定

モデル仕様

  • 47.04M total params / 25.80M active per token
  • d_model=768, L=6, n_heads=12 (kv_heads=3), head_dim=64
  • MoE: 8 routed experts + 1 shared, top-2 routing, d_ff=256
  • vocab=8192, context=2048, tie_word_embeddings=True

パラメータ内訳

Component Params Active
Embedding 6.29M 6.29M
Attention (全6層) 8.85M 8.85M
Shared Expert (全6層) 3.54M 3.54M
Routed Experts (top-2/8) 28.31M 7.08M
Norm 等 0.05M 0.05M
合計 47.04M 25.80M

ストレージ(sb3)

Component Precision Size
Embedding 4-bit 3.00 MB
Attention L1+L6 4-bit 1.41 MB
Attention L2-5 1-bit 0.70 MB
Shared Expert 4-bit 1.69 MB
Routed Experts 1-bit 3.38 MB
Router+Norm bf16 0.09 MB
合計 10.27 MB binary / ~9.04 MB sb3

学習方針

QAT (BitNet b1.58 スタイル)

  • master weights を bf16 で保持
  • forward pass で layer-wise 精度に量子化(STE)
  • bf16 勾配で master weights を更新
  • 推論時に master weights を破棄

STE 実装

# 1-bit: binary * row_scale, gradient は w をそのまま通す
return w + mx.stop_gradient(quantized - w)

選定理由: Bonsai (PTQ) は 8B モデルの冗長性を活用する手法。 47M params / Chinchilla 付近では冗長性が不足し PTQ 品質が壊滅的になるリスクがある。 Bonsai スケール別の性能低下: 8B→-11%, 4B→-19%, 1.7B→-26%(スケール縮小で加速)。


訓練環境

  • M2 Mac MLX (mlx==0.31.2)
  • Python 3.12
  • uv でパッケージ管理

データセット

Pretraining: 1B tokens(当初 4B 予定→ M2 Mac 16日超のため 1B に変更、約 4.2日)

  • FineWeb-Edu sample-10BT: 60% (2.4B tokens)
  • FineWeb sample-10BT: 40% (1.6B tokens)
  • 保存形式: jsonl.gz, 100M tokens/shard × 40 shards, 6.3 GB
  • シャッフル: 訓練時に shard 単位でランダム順 + shard 内シャッフル(方式 B)

Tokenizer 訓練データ

  • 全 40 shard から均一サンプリング (25M tokens/shard × 40 = 1B tokens)
  • 目的: 時代的偏りを排除

Tokenizer

仕様

  • BPE, byte-level, vocab=8192
  • ライブラリ: HuggingFace tokenizers
  • 保存先: tokenizer/tokenizer.json

特殊トークン

Token ID 用途
<bos> 0 系列開始
<eos> 1 会話全体の終了
<pad> 2 バッチパディング
<|system|> 3 system ターン開始
<|user|> 4 user ターン開始
<|assistant|> 5 assistant ターン開始
<|eot|> 6 ターン終了 (end of turn)

Chat template

<bos><|system|>
{system}<|eot|>
<|user|>
{user}<|eot|>
<|assistant|>
{response}<|eot|><eos>

効率測定 (Wikipedia EN + UltraChat 各5M chars)

Tokenizer chars/tok (wiki) chars/tok (chat) tok/word (wiki)
SSMoELM (8,192) 3.667 3.925 1.738
GPT-2 (50,257) 4.570 4.670 1.394
  • GPT-2 比 +19〜25% 多くトークンを消費(vocab 縮小の代償)
  • 会話テキストの方が効率が良い(訓練データに会話を含めた効果)
  • context 2048 tokens ≈ 会話で ~1300 words(許容範囲)

Ablation 計画(スキップ・2026-05-27)

当初 A/B/C の 3 run ablation を予定していたが、下記理由でスキップして Run C 構成で直接本番学習へ。

  • Q/K 4-bit は安全側の設定(1-bit Q/K より精度劣化リスクが低い)
  • MoE > Dense は文献上ほぼ確実(routing overhead が Dense より有利)
  • ablation 3 run × 50M = 150M tokens ≈ 7.5時間 の節約

採用構成: attn-4bit-qk(L2-5 の Q/K を 4-bit、V/O は 1-bit のまま)

ストレージ影響: binary +1.06 MB → sb3 推定 ~9.97 MB(10 MB ギリギリ)

本番学習設定(2026-05-27 開始)

run          = attn-4bit-qk
tokens       = 1B
batch_size   = 2,  grad_accum = 16
eff_batch    = 65,536 tokens/step
total_steps  ≈ 15,259
warmup_frac  = 5% ≈ 763 steps
lr_max = 3e-4 → lr_min = 1e-5 (cosine)
router_lr    = 1e-4
optimizer    = AdamW (β=0.9/0.95, wd=0.1, clip=1.0)
save_every   = 1526 steps ≈ 100M tokens
速度見込み   ≈ 2800 tok/s → 約 4.2 日

ファイル構成

SSMoELM/
  specification.md          仕様書
  technical_notes.md        ← 本ファイル
  pyproject.toml
  data/
    prepare_dataset.py      4B tokens 収集(完了)
    make_tokenizer_sample.py 均一サンプリング(完了)
    raw/                    shard_000〜039.jsonl.gz (6.3 GB)
    tokenizer_sample/       sample.jsonl.gz (1.4 GB)
  tokenizer/
    train_tokenizer.py      訓練スクリプト(完了)
    eval_tokenizer.py       効率測定(完了)
    tokenizer.json          訓練済み tokenizer
  train/
    config.py               ModelConfig / DenseConfig
    quantize.py             QAT (1-bit, 4-bit, STE)
    model.py                SSMoELM / Dense (MLX)
    data.py                 (未実装)
    train.py                (未実装)
  tasks/
    ablation.md             Ablation 計画

未解決の設計リスク(Ablation で検証予定)

  1. 1-bit Attention (L2-5): Q/K が precision-sensitive かどうか未検証
  2. MoE vs Dense at 47M: routing overhead がペイするか未検証
  3. d_ff=256 (0.33×d_model): 通常の 2.67×〜4× より大幅に小さい


2026-06-03

Pretraining 完了

  • 採用チェックポイント: step 013734(900M tokens)— 800M・900M・1B比較で900Mが最良
  • 学習スループット: ~3,000 tok/s(Flash Attention + QAT cache)
  • 実際のパックサイズ: 12.1 MB(理論 11.49 MB、safetensors形式)

ベンチマーク結果(0-shot, 500 samples)

Task Metric Score Random
HellaSwag acc_norm 33.4% 25%
LAMBADA acc 13.8% N/A
PIQA acc_norm 53.2% 50%
WinoGrande acc 49.6% 50%
ARC-Easy acc_norm 35.0% 25%
ARC-Challenge acc_norm 21.0% 25%
BoolQ acc 36.2% 50%
MMLU acc avg (57 tasks, ≤500/task) 23.4% 25%

推論コード(PyTorch)

  • ファイル: inference_pytorch.py(スタンドアロン、MLX依存なし)
  • dtype: fp32(CPU/MPS)— MPS の bf16 は PyTorch で未対応
  • メモリ: ディスク 12.1 MB → ランタイム ~188 MB(fp32展開)
  • 正確な推論には packed safetensors が必須(raw bf16 master weights は QAT適用前の値のため不正確、LAMBADA ppl: 606 vs 6366)
  • PyTorch/MLX スコア差: ±1%以内(サンプリング誤差範囲)

MoEルーティング統計(136トークン)

Layer CV 特徴
0 0.32 E4/E5偏り
1 0.15 最も均一
2 0.22 E1偏り
3 0.42 最も不均一、E6突出(22.8%)
4 0.25 E5偏り
5 0.25 E0偏り

エキスパート崩壊なし。aux loss + z-loss が効果的。


SFT計画

  • データセット: databricks/databricks-dolly-15k(CC BY-SA 3.0、商用利用可)
  • 選定理由: 商用OK、人手アノテーション15K件、短い入出力、英語のみ
  • 除外候補:
    • LIMA: CC BY-NC-SA(非商用のみ)
    • Alpaca: OpenAI ToS制約あり

TurboWarp 速度推定

Barynsor-1 実測 (21M dense, 8 tok/s) から逆算: ~151M MACs/sec

SSMoELM active compute per token:

  • Attention: ~402M MACs/token
  • Shared Expert: ~9.4M MACs/token
  • Routed (top-2): ~18.9M MACs/token
  • 推定 ~7.8 tok/s(Barynsor-1 の 151M MACs/sec 基準)

2026-06-08

公開モデル

  • Base: hf.co/brulee-1/SSMoELM-Base
  • Instruct: hf.co/brulee-1/SSMoELM-it

hf CLI で取得確認済み:

hf models info brulee-1/SSMoELM-Base
hf models info brulee-1/SSMoELM-it
hf download brulee-1/SSMoELM-Base README.md --local-dir /tmp/ssmoelm-hf/base
hf download brulee-1/SSMoELM-it README.md --local-dir /tmp/ssmoelm-hf/it

公開先のモデルカードは checkpoints/README.md(Base)と checkpoints/README_it.md(Instruct)を元に管理する。 HuggingFace 上では packed safetensors の uint8 配列を直接読むため、約12M params / 8-bit のように表示される場合があるが、実際は 47.04M params の 1-bit + 4-bit mixed precision MoE


SFT 完了

  • Base checkpoint: checkpoints/attn-4bit-qk_step013734.safetensors
  • Final SFT checkpoint: checkpoints/sft_final.safetensors
  • Packed Instruct weights:
    • checkpoints/ssmoelm_it_packed.safetensors (~12 MB)
    • checkpoints/ssmoelm_it_packed.npz (~11 MB)
  • SFT log: checkpoints/sft2_log.csv
  • 最終ログ行: step 177050, loss 1.592862, 2636.6 tok/s

SFT 実装は train/sft.py。assistant tokens only loss を使い、user/prompt 部分と特殊トークンの prefix は loss mask で無視する。

SFT データセット

Dataset 用途 備考
databricks/databricks-dolly-15k instruction following CC BY-SA 3.0
OpenAssistant/oasst1 EN dialogue / assistant response Apache 2.0
trivia_qa QA factuality CLI 既定に含む
natural_questions short-answer QA streaming
Open-Orca/FLAN instruction mixture streaming, default limit 70K

checkpoints/README_it.md の公開モデルカードでは Dolly-15k + oasst1 EN を主要 SFT データとして記載している。追加 QA/FLAN 系は train/sft.py の CLI 既定データセットに含まれるため、再現性メモとして本ファイルに残す。


Instruct 評価結果

SSMoELM-it は SFT 後も base の知識ベンチを概ね維持し、BoolQ / ARC-Challenge / PIQA が改善。

Task Base Instruct Δ
HellaSwag acc_norm 33.4% 33.2% -0.2%
LAMBADA acc 13.8% 14.8% +1.0%
PIQA acc_norm 53.2% 55.4% +2.2%
WinoGrande acc 49.6% 49.6% 0.0%
ARC-Easy acc_norm 35.0% 35.2% +0.2%
ARC-Challenge acc_norm 21.0% 24.0% +3.0%
BoolQ acc 36.2% 44.4% +8.2%
MMLU avg 23.4% 23.2% -0.2%

現在のファイル構成

SSMoELM/
  specification.md              最終仕様
  technical_notes.md            実装・実験ログ
  pyproject.toml                uv project dependencies
  data/
    prepare_dataset.py          FineWeb/FineWeb-Edu shard 作成
    make_tokenizer_sample.py    tokenizer 訓練サンプル作成
    raw/                        shard_000〜039.jsonl.gz(git ignore)
    tokenizer_sample/           sample.jsonl.gz(git ignore)
  tokenizer/
    train_tokenizer.py          tokenizer 訓練
    eval_tokenizer.py           tokenizer 効率測定
    tokenizer.json              訓練済み tokenizer
  train/
    config.py                   ModelConfig / DenseConfig
    quantize.py                 QAT 1-bit/4-bit + STE
    model.py                    SSMoELM / Dense MLX model
    data.py                     pretraining data loader
    train.py                    pretraining script
    lm_eval_adapter.py          lm-eval adapter
    sft.py                      supervised fine-tuning script
  inference.py                  packed PyTorch inference / chat entrypoint
  inference_packed.py           packed inference implementation
  inference_pytorch.py          PyTorch reference inference
  chat.py                       interactive chat helper
  export_packed.py              pack/export weights
  eval_benchmark.py             MLX evaluation
  eval_benchmark_pt.py          PyTorch evaluation
  eval_mmlu.py                  MMLU evaluation
  analyze_routing.py            MoE routing analysis
  checkpoints/
    README.md                   Base model card
    README_it.md                Instruct model card
    ssmoelm_it_packed.safetensors  Instruct packed weights(git ignore)
    ssmoelm_it_packed.npz          Instruct packed weights(git ignore)

TurboWarp / goboscript MVP

goboscript で開ける .sb3 artifact を生成開始。

  • 生成スクリプト: scripts/generate_turbowarp_demo.py
  • goboscript source: turbowarp/ssmoelm_mvp/main.gs, stage.gs
  • 生成済み sb3: turbowarp/ssmoelm_mvp/ssmoelm_mvp.sb3
  • 検証テスト: tests/test_goboscript_export.py

現時点の sb3 は UI/input loop + deterministic response shell + quantized dot-product kernel + packed uint8 decoder を含む。

実装済み Scratch kernels

Kernel goboscript proc 入力 出力
1-bit dot dot1_kernel activation list, bit list, scale dot1_result
4-bit dot dot4_kernel activation list, signed nibble list, scale dot4_result
packed 1-bit decode get_packed1_bit uint8 list, 0-based bit index packed1_bit
packed signed int4 decode get_packed4_signed uint8 list, 0-based nibble index packed4_value
packed 1-bit dot dot1_packed_kernel activation list, packed uint8 bit list, scale dot1_packed_result
packed 4-bit dot dot4_packed_kernel activation list, packed uint8 nibble list, scale dot4_packed_result
self test kernel_self_test, packed_decode_self_test, packed_kernel_self_test toy vectors / bytes kernel_status, decode_status, packed_kernel_status

Self-test toy values:

  • 1-bit dot: raw dot -1.5, scale 0.25-0.375
  • 4-bit dot: raw dot 9, scale 0.1251.125
  • packed 1-bit decode: byte 13 (0b00001101, LSB-first) → bits 1,0,1,1
  • packed int4 decode: bytes 195 (0xC3) and 47 (0x2F), low-nibble-first → signed nibbles 3,-4,-1,2
  • packed 1-bit / 4-bit dot は decoder 経由で pre-expanded dot と同じ toy result(-0.375, 1.125)を返す。

Build command:

/Users/scratchbrulee/.cargo/bin/goboscript build turbowarp/ssmoelm_mvp

Build result:

Emitted 361 blocks
ssmoelm_mvp.sb3 size: 7348 bytes
main sprite: 292 blocks
lists: packed1_bytes, k1_x, k1_w_bits, packed4_bytes, k4_w_nibbles, k4_x

Next step is 1-token projection verification: compare a tiny Scratch packed matmul/projection fixture against the Python reference, then extend it toward attention and MoE expert rows.


Decoding sweep(2026-06-08)

SSMoELM-it の生成設定を小規模 prompt sweep と手動確認で比較。

temperature top_k repetition_penalty 傾向
0.0 1 1.0 最も文法的だが同じ句を繰り返しやすい
0.0 1 1.15 反復は減るが bullet/list 系で引用符反復が残る
0.0 1 1.3 低品質語の混入を抑えつつ反復も比較的少ないため採用
0.55 20 1.15 多様だが固有名詞・断片語の混入が増える
0.7 30 1.15 ヒューリスティックスコアは高いが意味崩壊が多い

採用値:

temperature = 0.0
top_k = 1
top_p = 0.9
repetition_penalty = 1.3

理由: 47M / 8k vocab の小型モデルでは sampling の多様性より greedy + 強め repetition penalty の方が破綻しにくい。top_ptemperature=0.0 では実質未使用だが、sampling に切り替える場合の互換既定として 0.9 を維持。


Shared expert only ablation(2026-06-08)

PyTorch lm-eval adapter に --shared-only を追加し、routed experts を無効化して shared expert だけで短い 0-shot ベンチを実行。

Command:

/etc/profiles/per-user/scratchbrulee/bin/uv run python eval_benchmark_pt.py \
  --ckpt checkpoints/ssmoelm_it_packed.safetensors \
  --tasks hellaswag,lambada_openai \
  --limit 100

/etc/profiles/per-user/scratchbrulee/bin/uv run python eval_benchmark_pt.py \
  --ckpt checkpoints/ssmoelm_it_packed.safetensors \
  --tasks hellaswag,lambada_openai \
  --limit 100 \
  --shared-only
Mode HellaSwag acc_norm HellaSwag acc LAMBADA acc LAMBADA ppl
Full MoE 40.0% 35.0% 11.0% 732.20
Shared only 30.0% 31.0% 7.0% 2742.00

結論: shared expert だけでも HellaSwag は random を少し超えるが、LAMBADA perplexity が大きく悪化。routed experts は品質に効いている。