「3元(約60円)と2時間で、64Bパラメータではなく64Mパラメータの言語モデルをゼロから作れる」——minimind はそう掲げる教材リポジトリで、GitHub star は 59,466(2026-09-08 実測)に達している。LLMを「使う」記事は無数にあるが「作る」側の日本語情報は薄く、llm 自作LLM 作り方 で検索しても上位はQiita・Zenn・note の個人記事と書籍が並ぶだけだ。

そこで、READMEの数字をそのまま紹介する代わりに、「2時間」が何を指しているのかをREADME自身の費用表と突き合わせ、さらに16GB MacBook Air (M2) で実際に学習を回してどこまで到達できるかを測った。モデルの仕組みや選び方そのものから押さえたい場合は、LLMとは?仕組み・主要モデル比較・ローカル実行・量子化を一気にまとめる2026年版 を先に読むと本記事の位置づけが掴みやすい。

minimindのREADME脚注と費用表が食い違っていることを示す比較図
READMEの脚注は「2時間=SFT 1エポック」と定義するが、同じREADMEの費用表ではSFTは1.10h。約2時間に一致するのは事前学習+SFTの合計2.31hのほうだった。
この記事のポイント
  • 「2時間」の定義がREADME内で食い違う。脚注は「SFT段階の1エポック」と書くが、費用表のSFTは1.10h。約2時間に一致するのは事前学習1.21h+SFT 1.10h=2.31hのほうだった。
  • 2時間はRTX 3090の話。ここから逆算すると3090は1ステップ0.110秒で回している計算になる。
  • Macには経路が無い--device 既定は「cudaが無ければcpu」でMPSを選ぶ分岐が存在しない。強制すると学習1ステップがCPUの21倍遅い(107秒 vs 5.06秒)。
  • 16GB M2でのCPU学習は1エポック11.5〜24日の外挿。3090の1.21hに対して229〜476倍。完走はしていない(どこで止めたかを本文に明記)。
  • データは約3.0GB(1.24GB+1.74GB)。事前学習コーパスは99.77%が中国語で、かなを含む文書は0.23%。
  • Python 3.14では動かないdatasets==3.6.0 が dill 経由で落ちる。3.12.9 で解消。

minimindとは——LLM 自作の教材として何を提供しているのか

minimind は jingyaogong 氏が2024年7月に公開したリポジトリで、約64Mパラメータの言語モデルを事前学習からRLHFまで一通り自分で回せることを目的にしている。特徴は「PyTorch のネイティブ実装だけで書かれている」点だ。transformers や trl の高レベルAPIに任せず、モデル定義・学習ループ・DPO/PPO/GRPO までリポジトリ内のコードで完結している。

項目 実測値(2026-09-08)
GitHub star 59,466
fork 7,711
公開日 2024-07-27
最終 push 2026-09-04
ライセンス Apache-2.0
既定ブランチ master
モデルパラメータ数 63.91M(実測。READMEの「約64M」と一致)
学習スクリプト 11本(pretrain / full_sft / lora / dpo / ppo / grpo / distillation / agent ほか)

パラメータ数は実際にモデルを構築して数えた。hidden_size=768 / num_hidden_layers=8 の既定設定で 63,912,000 前後、READMEの「64M」表記と齟齬は無い。看板の数字が実体と合っているOSSは意外と少ないので、ここは素直に評価できる。

対象読者は明確で、READMEにも「レゴで飛行機を組み立てるほうが、ファーストクラスに座っているより面白い」という趣旨の一文がある。動くLLMが欲しい人ではなく、学習パイプラインの各段を自分の手で通したい人のための教材だ。

minimindのモデル構造を示す公式図
モデル構造(公式 images/LLM-structure.jpg)。Transformer の各要素がリポジトリ内のコードに対応する。出典: jingyaogong/minimind

64Mに収まっている理由——語彙6,400、学習ループ172行

「64Mパラメータ」がどう成立しているかを実際のファイルから確認しておくと、この教材の設計思想が分かりやすい。

同梱トークナイザの語彙数を数えると 6,400 だった。一般的なLLMの語彙は3万〜15万なので、1桁以上小さい。語彙が小さければ埋め込み層と出力層のパラメータが激減する(6,400 × 768 ≒ 490万)。隠れ層768・8層という本体の小ささと合わせて、64Mという数字はここから来ている。裏を返せば、語彙6,400では表現できる語が限られるということでもあり、教材としての割り切りがはっきり出ている部分だ。

そしてコード量も小さい。学習スクリプト9本の行数を数えるとこうなる。

スクリプト 行数 段階
train_pretrain.py 172 事前学習
train_full_sft.py 173 教師ありファインチューニング
train_lora.py 185 LoRA
train_dpo.py 227 DPO
train_distillation.py 247 蒸留
train_grpo.py 333 GRPO
train_ppo.py 450 PPO
train_agent.py 492 Agentic RL
train_tokenizer.py 168 トークナイザ学習

事前学習の全体が172行に収まっている。データ読み込み・学習率スケジュール・勾配累積・チェックポイント保存まで含めてこの行数なので、腰を据えれば1日で読み切れる。transformersTrainer を使えば同じことが10行で書けるが、その10行の内側で何が起きているかは見えない。この172行を読むことが minimind の主目的であって、学習を完走させることは必ずしも目的ではない——この点は後の判断にも効いてくる。

「2時間」の中身を数え直す——READMEの脚注と費用表が食い違う

まず言葉の定義から確認する。READMEの冒頭にはこうある(要旨)。

約3元のコストと2時間の学習時間だけで、約64Mパラメータの超小型言語モデル MiniMind をゼロから訓練することを目指す。

そして少し下の脚注が、この「2時間」を次のように限定している(要旨)。

「2時間」とは、SFT段階を単体のNVIDIA 3090で1エポック回したときの実測時間を指す。「3元」はその時間帯のGPUレンタル費用。

ここまで読むと「SFTだけで2時間」と理解する。ところが同じREADMEの Experiments 節にある費用表は、別のことを言っている。

モデル パラメータ pretrain_t2t_mini sft_t2t_mini
minimind-3 64M ≈1.21h(≈1.57元) ≈1.10h(≈1.43元)
minimind-3-moe 198M-A64M ≈1.69h(≈2.20元) ≈1.54h(≈2.00元)

SFT は1.10時間である。2時間ではない。そして表の直下には「事前学習+SFTで1エポックあたり約2.31時間、費用約3.0元」と明記され、さらに別の箇所には「単体3090で2時間で再現できる」とも書かれている。

つまり、約2時間・約3元という看板の数字に対応するのは「事前学習+SFTの合計(2.31h・3.0元)」であって、脚注が言う「SFT単体」ではない。脚注のほうが誤っている、と読むのが自然だ。実際、費用「3元」も表の1.57+1.43=3.00元と正確に一致する。

これは重箱の隅ではない。「SFTだけで2時間」と理解すると、事前学習にかかる1.21時間を見落とすからだ。ゼロから作ると言っている以上、事前学習は省略できない工程である。日本語で minimind に言及している記事の中には、この脚注の表現をそのまま引き写して「SFT段階、単独3090での1エポック」と紹介しているものもあるが、費用表と突き合わせた形跡は見当たらなかった。

3090は1ステップ0.110秒で回している

以降の比較のために、READMEの数字を1ステップあたりに直しておく。事前学習データ pretrain_t2t_mini.jsonl は実測 1,270,238件、学習スクリプトの既定 batch_size=32 なので、1エポックは 39,695ステップになる。

READMEの1.21時間(4,356秒)をこれで割ると、3090の1ステップは約0.110秒という計算になる。この数字が、以降のMac側の実測と比べる基準線になる。

なお学習スクリプトの --epochs の既定値は 2 である。README の見積もりは1エポック基準なので、何も指定せずに走らせると単純に倍かかる点も押さえておきたい。

実測①:導入でつまずく2点——Python 3.14 とデータ3.0GB

実際に手元で動かす。環境は MacBook Air (M2) / メモリ16GB / SSD 256GB、CUDA GPUは無い。

datasets==3.6.0 は Python 3.14 で動かない

Homebrew の既定 Python(3.14.4)で requirements の指定どおり導入し、学習を起動すると、モデル構築までは進んでからデータ読み込みで落ちた。

TypeError: Pickler._batch_setitems() takes 2 positional arguments but 3 were given

datasets が内部で使う dill が、Python 3.14 で変更された標準ライブラリ pickle のシグネチャに追随していないために起きる。リポジトリ側の問題ではないが、2026年時点で最新のPythonを入れている人はここで必ず止まる。Python 3.12.9 で仮想環境を作り直したところ解消した。以降の計測はすべて 3.12.9 / PyTorch 2.14.0 で行っている。

「mini」データセットで約3.0GB

READMEは「まず pretrain_t2t_mini.jsonlsft_t2t_mini.jsonl だけ落とせば速く再現できる」と案内している。この2つのサイズを実測した。

ファイル バイト数 件数
pretrain_t2t_mini.jsonl 1,241,043,656(約1.24GB) 1,270,238
sft_t2t_mini.jsonl 1,739,201,170(約1.74GB)
合計 約3.0GB

「mini」と付いていても3GBある。しかも SFT用のほうが事前学習用より大きい(1.74GB > 1.24GB)。加えて HuggingFace datasets は読み込み時に Arrow 形式のキャッシュを別途作るので、実効的には倍の空き容量を見ておくべきだ。SSD 256GBのMacBook Airでは無視できない。

作ったモデルは日本語を話さない

日本語圏の読者に効いてくる点を1つ。事前学習コーパスの先頭40,000件を取り出して文字種を数えた。

分類 件数 割合
漢字のみ(中国語とみなす) 39,908 99.77%
かなを含む 92 0.23%
ラテン文字のみ 0 0.00%

99.77%が中国語である。minimind は中国語コーパスで学ぶ教材なので、これは欠陥ではなく仕様だ。ただし「LLMを自作する」動機が「日本語で動く小さなモデルが欲しい」ことにある場合、このリポジトリをそのまま回しても目的は達成できない。学べるのはパイプラインであって、成果物のモデルではない。データ差し替えが前提になる。

minimindの学習データセット構成を示す公式図
データセット構成(公式 images/dataset.jpg)。出典: jingyaogong/minimind

実測②:Apple SiliconにはMPSの経路が用意されていない

ここが本記事の中心だ。MacBook で学習を回そうとすると、まずデバイス指定の壁に当たる。trainer/train_pretrain.py の該当行はこうなっている。

parser.add_argument("--device", type=str,
    default="cuda:0" if torch.cuda.is_available() else "cpu")
...
device_type = "cuda" if "cuda" in args.device else "cpu"
autocast_ctx = nullcontext() if device_type == "cpu" else torch.cuda.amp.autocast(dtype=dtype)

読み取れることは2つある。

既定は「CUDAがあれば cuda:0、無ければ cpu」。Apple Silicon の MPS は選択肢に入っていない
--device mps と明示すれば .to("mps") は通るが、device_type の判定が文字列 “cuda” の有無なので mps は cpu 扱いになる。結果として、CUDA経路では有効になる混合精度(autocast)が無効のまま実行される

つまり MPS は「非対応」ではなく「想定されていない」。動くには動くが、CUDA向けに書かれた最適化経路からは外れる。

GPU自体は健全で、CPUの32倍速い

ここで公平を期すために、MPSというハードウェアそのものが遅いのかを切り分けた。モデルと無関係な2048角の行列積で両デバイスを比べる。

デバイス 1回あたり 実効性能
CPU 761.86 ms 23 GFLOP/s
MPS 23.37 ms 735 GFLOP/s

MPSはCPUの約32倍速い。GPUは正常に働いている。モデルの順伝播だけを比べても同じ傾向で、バッチ2・系列長340で CPU 0.44秒に対し MPS 0.13秒と、MPS が3.4倍速かった。

したがって「Macだから学習できない」のではない。使えるGPUがそこにあるのに、学習スクリプトがそれを使う前提で書かれていない、というのが正確な状況だ。この差を埋めるにはコード側に mps 分岐を足す改修が要る。

実測③:どこまで到達できたか——1エポックは日単位になる

正直に書く。1エポックは完走していない。 完走できないと判断した根拠が以下である。

計測は16GB MacBook Air (M2) のCPU学習で、1ステップ(順伝播+逆伝播+オプティマイザ更新)の所要時間を複数回サンプリングした。このマシンは計測中ずっと他プロセスと共有されており、load average は13〜56の範囲で変動していた(8コア機なので過負荷状態)。したがって以下の数値は上振れした上限側の値であり、専有環境ならもっと速い。最も速かったサンプルを「最良ケース」として併記する。

条件 1ステップ 1サンプルあたり 計測時のload
CPU / batch 2 5.06 秒 2.53 秒 23
CPU / batch 8(最良サンプル) 6.28 秒 0.785 秒 約27
CPU / batch 8(典型) 13.07 秒 1.634 秒 約27
CPU / batch 8(高負荷時) 24.4〜88.4 秒 3.05〜11.0 秒 46〜56

この1サンプルあたりの秒数を、事前学習1エポック分の 1,270,238件に掛けたのが下の外挿だ。

前提 1エポックの外挿 3090(1.21h)比
最良サンプル(0.785 秒/件) 約277時間=11.5日 約229倍
典型サンプル(1.634 秒/件) 約577時間=24.0日 約476倍

最良ケースを採っても11.5日である。しかもこれは事前学習1エポックのみで、SFTは含まない。既定の --epochs 2 ならさらに倍になる。3GBのデータを1周させる計算量に対して、CPUの23 GFLOP/s では桁が足りない、というだけの話だ。

そして --device mps を強制した場合が、この記事でいちばん奇妙な数字になった。順伝播・逆伝播・オプティマイザ更新を含む1ステップまるごとを、同じバッチ2で両デバイス比較する。

条件(バッチ2・系列長340) 1ステップ 計測時のload
CPU 5.06 秒 23
MPS 強制 107.21 秒 39

MPSのほうが21倍遅い。 行列積で32倍速く、順伝播だけなら3.4倍速かったはずのGPUが、学習1ステップになると20倍以上遅くなる。loadが23と39で違うが、この差では21倍は説明できない。

順伝播が速くて学習ステップが遅い以上、逆伝播かオプティマイザ更新のどこかがMPS上で極端に遅いことになる。ただしどの演算が原因かの特定までは行っていない——ここは未検証として残す。いずれにせよ実用上の結論は変わらず、--device mps は現状の minimind では選ぶ意味が無い。

参考:この規模の学習に何が要るか

比較のため、READMEが挙げる環境と手元の環境を並べる。

環境 事前学習1エポック 備考
NVIDIA 3090 ×1 1.21時間 READMEの値。レンタル約1.57元
8×H100 数分 READMEの記述(当サイト未検証)
MacBook Air M2 / 16GB(CPU) 11.5〜24日(外挿) 本記事の実測。完走せず
MacBook Air M2 / 16GB(MPS強制) CPUより21倍遅い 学習1ステップがバッチ2で107秒(CPUは5.06秒)

ローカルでモデルを動かすこと自体はMacでも十分現実的で、Apple Silicon 向けの実行環境はomlx徹底解説|Apple Silicon専用・OpenAI/Anthropic両対応のローカルLLMサーバーを実測にまとめている。メモリを超える規模のモデルをMacで動かす工夫としてはslotstream実測|104GBのMoEを48GB Macで動かすSSDストリーミングの仕組みと限界も対照になる。「動かす」と「学習する」で必要な計算資源は桁が違うという、当たり前だが混同されやすい線引きが、今回の数字ではっきり出た。

minimindの事前学習における損失曲線の公式グラフ
事前学習の損失曲線(公式 images/pretrain_loss.jpg)。この曲線を自分で引くには上表の計算量が要る。出典: jingyaogong/minimind
flowchart LR A["データ 約3.0GB
1,270,238件"] --> B["事前学習
39,695ステップ / epoch"] B --> C["SFT
sft_t2t_mini"] C --> D["RLAIF / DPO / GRPO
任意"] B -.->|"3090: 1.21h"| E["GPU経路
autocast 有効"] B -.->|"M2 CPU: 11.5〜24日"| F["CPU経路
autocast 無効"] B -.->|"mps: 測定不能"| F

結局どう使うべきか——LLM 自作の入口として見たときの向き不向き

実測を踏まえた判断はこうなる。

状況 判断 理由
CUDA GPU(3090級以上)がある ◎ そのまま進める READMEの2.31時間はこの前提の値。素直に再現できる
GPUは無いがクラウドを借りられる ◎ 3元=約60円で済む 学習だけレンタルGPUに出すのが最も合理的。これがREADMEの想定
Macでコードを読んで理解したい ○ 目的は達成できる ネイティブPyTorch実装なので読む価値は高い。学習は回さない
Macで実際に学習を完走したい ✕ 現実的でない 最良ケースで11.5日。MPS経路も未整備
日本語で動く小型モデルが欲しい ✕ 目的が違う コーパスの99.77%が中国語。データ差し替えが前提

minimind の価値は「2時間」という数字そのものではなく、学習パイプラインの全段が読める形で置かれていることにある。事前学習・SFT・LoRA・DPO・PPO・GRPO・蒸留がそれぞれ独立したスクリプトになっていて、高レベルAPIに隠れていない。この構成の教育的価値は、手元のマシンで完走できるかどうかとは独立している。

逆に、「2時間で自作できる」という一文だけを見て手元のノートPCで試すと、導入(Python 3.14 の非互換)とデータ容量(3GB)と計算時間(日単位)の3か所で止まる。止まる場所が事前に分かっていれば、GPUを借りるという正しい判断に最初から行ける——本記事の実測はそのためのものだ。

小さなモデルを実際に動かす側の話は、1ビット量子化で推論を軽くするbitnet.cpp(BitNet)とは|Microsoftの1ビットLLM推論フレームワークをCPUだけで動かすが対になる。学習を小さくする方向と、推論を小さくする方向の両方を見ておくと、64Mという規模の意味が掴みやすい。

まとめ

llm 自作 を検索して minimind に辿り着いた人が、着手前に知っておくと得をする事実を6点にまとめる。

「2時間」の定義がREADME内で食い違う。脚注は「SFT 1エポック」と言うが、費用表のSFTは1.10h。約2時間に対応するのは事前学習+SFTの合計2.31h
その2時間はRTX 3090の値。逆算すると1ステップ0.110秒で回している
モデルは実測63.91Mパラメータで、READMEの「64M」と一致している
Apple SiliconにはMPSの経路が無い--device 既定は cuda か cpu の二択で、mps を渡しても混合精度は無効のまま
GPU自体は健全(行列積でCPUの32倍・735 GFLOP/s)。使えるGPUがあるのにスクリプトが使わない、という状態
16GB M2でのCPU学習は1エポック11.5〜24日の外挿。完走はしていない。データは約3.0GBで、コーパスの99.77%が中国語

「ゼロからLLMを作る」という体験自体は、3元=約60円のGPUレンタルで確かに手が届く。ただしそれは手元のMacで完結する話ではない。この記事の数字が、その線引きを事前に済ませる助けになれば十分だ。

参照ソース

jingyaogong/minimind — 公式リポジトリ・README(2026-09-08 参照)
minimind README_en.md — 英語版。学習コストの表と「2時間」の脚注(2026-09-08 参照)
minimind_dataset — ModelScope・学習データ配布元(2026-09-08 参照)
trainer/train_pretrain.py — デバイス指定と混合精度の分岐(2026-09-08 参照)