(まとめ)= # まとめ:Mojo と機械学習スタックの全体像 ## Mojo という言語を振り返る 本書を通じて Mojo のコードを書き続けてきた感想を一言で表すなら、 **「Python に似ているが、非なる言語」** です。 ### Python と何が同じで、何が違うか Mojo のコードを初めて見ると、Python に見えます。 `def`、`for`、`if`、インデント構文、`import`——これらは Python と共通です。 しかし一歩踏み込むと、Mojo は根本的に異なる言語だとわかります。 **似ている点:** - 構文のほとんど(インデント、`def`、`for`/`if`/`while`) - `from x import y` スタイルのモジュールシステム - Python との相互運用性(`from std.python import Python`) **非なる点:** | Python | Mojo | |--------|------| | 動的型付け(実行時に型が決まる) | 静的型付け(コンパイル時に型が決まる) | | `x = 42`(型なし変数) | `var x: Int = 42`(型付き変数) | | オブジェクト参照のセマンティクス | 値・参照・所有権を明示的に制御 | | GC(ガベージコレクション) | 確定的なメモリ解放(RAII) | | インタープリタで実行 | MLIR → LLVM IR → ネイティブコードにコンパイル | | クラスの多重継承 | `struct`(値型) + `trait`(インターフェース) | | GIL(Global Interpreter Lock) | `parallelize` でロックなし並列実行 | Python を知っている人にとって Mojo の学習曲線は緩やかに始まりますが、 `var`/`alias`、値の所有権、関数の引数規約(`read`/`mut`/`var` など)に 踏み込んだあたりで「これは Python ではない」と実感します。 --- ### コンパイルの仕組み 第 2 章で触れたように、Mojo のコードは次の経路でネイティブバイナリになります。 ```{mermaid} flowchart LR A["Mojo ソース\n(.mojo)"] B["MLIR\n(中間表現)"] C["LLVM IR"] D["ネイティブバイナリ\n(x86 / ARM)"] A -->|"Mojo コンパイラ"| B B -->|"LLVM"| C C -->|"最適化 + コード生成"| D ``` MLIR(Multi-Level Intermediate Representation)は、 Google が LLVM コミュニティと共同で開発した中間表現のフレームワークです。 Mojo はこれを活用することで、CPU・GPU・特殊アクセラレータへの最適化を **同じコンパイラパイプライン上** で扱えます。 第 5 章で `mojo build` + `llvm-objdump` によるアセンブリの確認を行いました。 Python で 100 行かかる処理が、数命令の SIMD 演算に最適化される様子は 「これはインタープリタではない」と実感させてくれます。 --- ### 書き心地は Rust に似ている Mojo を書いていると、Python よりも **Rust** に近いと感じる場面があります。 **所有権と引数規約:** ```mojo def process(read data: List[Float64]): # 読み取り専用(デフォルトに近い) ... def modify(mut data: List[Float64]): # 変更可能な参照 data.append(1.0) def take(var data: List[Float64]): # 所有権を受け取る(関数内で変更可) ... ``` `read`(読み取り)・`mut`(変更)・`var(所有権を受け取る)・`ref`(参照)などの引数規約で意図を明示します。 コンパイラが不正なメモリアクセスをコンパイル時に弾きます。 **型システムと`struct`:** Python の `class` が参照型・動的型であるのに対し、 Mojo の `struct` は **値型** でフィールドの型は静的に決まります。 ```mojo struct GPTConfig: # ← Python の class とは異なる値型 var vocab_size: Int var n_embd: Int ... ``` **エラー処理:** `def main() raises:` のように、例外を投げる可能性のある関数を 型シグネチャで表明します。Rust の `Result` ほど厳格ではありませんが、 「この関数は失敗しうる」という情報がシグネチャに現れる点は似ています。 Rust と比べたときの Mojo の利点は、**Python のエコシステムをそのまま使える**点です。 `from std.python import Python` の一行で、NumPy・PyTorch・MLX など 既存の Python ライブラリをすべて利用できます。 --- ## microgpt:7 つのバリエーション 本書では microgpt という小さな GPT モデルを題材に、 実装を段階的に進化させてきました。 ### バリエーション一覧 | # | 実装 | 学習エンジン | 推論エンジン | 主な学び | |---|------|------------|------------|---------| | 1 | `microgpt.py` | Python スカラー Value | Python スカラー Value | autograd の仕組みをゼロから理解 | | 2 | `microgpt_mojo` | Mojo Tape(スカラー) | Mojo Tape(スカラー) | Mojo の型安全・struct・SoA 設計 | | 3 | `microgpt_mojo_max` | Mojo Tape(スカラー) | MAX Graph(行列演算) | Python interop + MAX 推論最適化 | | 4 | `microgpt_torch.py` | PyTorch autograd | PyTorch(MPS) | PyTorch の `nn.Module` / `optim` | | 5 | `microgpt_torch_mojo` | PyTorch autograd | PyTorch(MPS) | Mojo から PyTorch を操る interop パターン | | 6 | `microgpt_mlx.py` | MLX autograd | MLX(Unified Memory) | Lazy Evaluation + `value_and_grad` | | 7 | `microgpt_mlx_mojo` | MLX autograd | MLX(Unified Memory) | Mojo から MLX を操る interop パターン | ### 実装の系譜 ```{mermaid} flowchart TD A["microgpt.py\nPython スカラー autograd"] --> B["microgpt_mojo\nMojo Tape autograd"] B --> C["microgpt_mojo_max\nMojo Tape + MAX 推論"] A --> D["microgpt_torch.py\nPyTorch MPS"] D --> E["microgpt_torch_mojo\nPyTorch + Mojo interop"] A --> F["microgpt_mlx.py\nMLX Lazy Evaluation"] F --> G["microgpt_mlx_mojo\nMLX + Mojo interop"] ``` --- ## 実行時間比較 ### 計測環境 | 項目 | 内容 | |------|------| | マシン | Apple M2 Pro | | コア数 | 10 コア(パフォーマンス 6 + 効率 4) | | メモリ | 32 GB | | OS | macOS Sequoia 15(Darwin 24.6) | | Mojo | `magic` 経由の最新安定版 | | Python | 3.12(`uv` 管理) | | PyTorch | 2.11.0(MPS バックエンド有効) | | MLX | 0.31.1 | ### 学習 1000 ステップの壁時計時間 モデルサイズは `n_layer=1, n_embd=16, n_head=4, block_size=16`(全実装共通)。 データセットは `names.txt`(32,033 文書)。乱数シード `seed=42`。 Mojo 版は `mojo build` でコンパイル済みバイナリを生成してから実行し、 **純粋な計算時間のみ**を計測しました。 | 実装 | 壁時計 | 計測方法 | |------|--------|---------| | `microgpt.py` | **99.5 秒** | `python microgpt.py` | | `microgpt_mojo` | **52.0 秒** | `mojo build` → `./main_bin` | | `microgpt_mojo_max` | **52.2 秒** | `mojo build` → `./main_bin` | | `microgpt_torch.py` | **12.4 秒** | `python microgpt_torch.py` | | `microgpt_torch_mojo` | **11.5 秒** | `mojo build` → `./main_bin` | | `microgpt_mlx.py` | **3.0 秒** | `python microgpt_mlx.py` | | `microgpt_mlx_mojo` | **3.1 秒** | `mojo build` → `./main_bin` | ```{note} `mojo run` で直接実行する場合はコンパイル時間(1〜3 秒)が加算されます。 繰り返し実行する本番シナリオでは `mojo build` でビルドしたバイナリを使うことで オーバーヘッドを排除できます。 ``` ### 考察 **スカラーループ vs 行列演算:** `microgpt.py`(99.5 秒)と `microgpt_torch.py`(12.4 秒)の差は約 **8 倍**です。 同じアルゴリズムでも、スカラーループと行列演算では計算ハードウェアの活用効率が まったく異なります。PyTorch は 1 ステップを 1 回の行列乗算として GPU に渡せるのに対し、 Python スカラー版はトークンごとにループを回します。 **Mojo Tape vs Python スカラー:** `microgpt_mojo`(52.0 秒)は `microgpt.py`(99.5 秒)の約 **1.9 倍高速**です。 同じスカラーループでも、Mojo の静的型付けとネイティブコンパイルにより 約 2 倍の速度差が生じます。 **MLX の優位性:** MLX(3.0 秒)が PyTorch MPS(12.4 秒)の **4 倍以上高速**な理由は、 Unified Memory アーキテクチャにあります。PyTorch の MPS バックエンドは CPU-GPU 間のデータコピーが発生しますが、MLX は M2 の統合メモリを前提に設計されており コピーが不要です。 **Mojo interop のオーバーヘッド:** `microgpt_torch_mojo`(11.5 秒)は `microgpt_torch.py`(12.4 秒)より若干**速い**です。 `microgpt_mlx_mojo`(3.1 秒)は `microgpt_mlx.py`(3.0 秒)とほぼ**同等**です。 Mojo の Python interop は呼び出しあたりのオーバーヘッドがごく小さく、 純粋な計算時間で比べると Python 版との差はほとんどありません。 --- ## Mojo を使うべき場面 本書の実装を経て、Mojo が真に輝くユースケースが見えてきました。 **Mojo が得意なこと:** - 型安全なシステムコード(NumPy ライクなカスタム配列演算) - Python と同じエコシステムを活用しつつ、ホットパスを Mojo で高速化 - SIMD・`parallelize` を使った CPU 最適化 - 数値計算の関数を型制約で安全に定義する **Python + PyTorch/MLX が得意なこと:** - プロトタイピング(型アノテーションなしで高速に書ける) - フレームワークの `autograd` をそのまま使う学習全般 - 大規模モデルのファインチューニング **現在の Mojo の立ち位置:** Mojo はまだ発展途上の言語です。標準ライブラリは Python ほど充実しておらず、 `torch.autograd` や `mlx.nn` に相当するフル機能のフレームワークは まだ存在しません。しかし「Python とのシームレスな相互運用」という設計思想のもと、 既存の Python ML エコシステムをそのまま活かしながら、 パフォーマンスが要求される部分だけを Mojo で書く、という使い方は今日から可能です。 --- ## スタック役割分担のまとめ 本書で登場した各ツールの役割を一表に整理します。 | ツール | 主な役割 | 強み | |--------|---------|------| | Mojo | ホットパスの型安全実装・ループ制御 | 静的型・所有権・Python interop | | MAX | 推論の最適化(Graph API) | グラフコンパイル・ハードウェア抽象化 | | PyTorch | 学習フレームワーク(MPS 対応) | autograd・`nn.Module`・大規模エコシステム | | MLX | Apple Silicon 特化の学習 | Unified Memory・Lazy Evaluation | --- ## 最後に 本書では「autograd の仕組みをゼロから実装する」という一貫したテーマのもと、 Value クラスのスカラー演算から始まり、Mojo への移植、MAX・PyTorch・MLX への拡張と 段階的に実装を発展させてきました。 Mojo は「Python のような書き心地で、C のような速度を」というビジョンを持つ言語です。 型システムや所有権モデルを通じて安全性と性能を両立しながら、Python の豊富な エコシステムに乗り続けられるのが最大の強みです。 microgpt のコードは小さいですが、その中に transformer・autograd・ オプティマイザという現代の大規模モデルの核心が詰まっています。 本書を通じて学んだ仕組みは、より大きなモデルを読み解く際の 確かな土台となるはずです。