31. まとめ:Mojo と機械学習スタックの全体像

31.1. Mojo という言語を振り返る

本書を通じて Mojo のコードを書き続けてきた感想を一言で表すなら、 「Python に似ているが、非なる言語」 です。

31.1.1. Python と何が同じで、何が違うか

Mojo のコードを初めて見ると、Python に見えます。 defforif、インデント構文、import——これらは Python と共通です。 しかし一歩踏み込むと、Mojo は根本的に異なる言語だとわかります。

似ている点:

  • 構文のほとんど(インデント、deffor/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 ではない」と実感します。


31.1.2. コンパイルの仕組み

第 2 章で触れたように、Mojo のコードは次の経路でネイティブバイナリになります。

diagram

MLIR(Multi-Level Intermediate Representation)は、 Google が LLVM コミュニティと共同で開発した中間表現のフレームワークです。 Mojo はこれを活用することで、CPU・GPU・特殊アクセラレータへの最適化を 同じコンパイラパイプライン上 で扱えます。

第 5 章で mojo build + llvm-objdump によるアセンブリの確認を行いました。 Python で 100 行かかる処理が、数命令の SIMD 演算に最適化される様子は 「これはインタープリタではない」と実感させてくれます。


31.1.3. 書き心地は Rust に似ている

Mojo を書いていると、Python よりも Rust に近いと感じる場面があります。

所有権と引数規約:

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値型 でフィールドの型は静的に決まります。

struct GPTConfig:           # ← Python の class とは異なる値型
    var vocab_size: Int
    var n_embd: Int
    ...

エラー処理:

def main() raises: のように、例外を投げる可能性のある関数を 型シグネチャで表明します。Rust の Result<T, E> ほど厳格ではありませんが、 「この関数は失敗しうる」という情報がシグネチャに現れる点は似ています。

Rust と比べたときの Mojo の利点は、Python のエコシステムをそのまま使える点です。 from std.python import Python の一行で、NumPy・PyTorch・MLX など 既存の Python ライブラリをすべて利用できます。


31.2. microgpt:7 つのバリエーション

本書では microgpt という小さな GPT モデルを題材に、 実装を段階的に進化させてきました。

31.2.1. バリエーション一覧

#

実装

学習エンジン

推論エンジン

主な学び

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 パターン

31.2.2. 実装の系譜

diagram

31.3. 実行時間比較

31.3.1. 計測環境

項目

内容

マシン

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

31.3.2. 学習 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

注釈

mojo run で直接実行する場合はコンパイル時間(1〜3 秒)が加算されます。 繰り返し実行する本番シナリオでは mojo build でビルドしたバイナリを使うことで オーバーヘッドを排除できます。

31.3.3. 考察

スカラーループ 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 版との差はほとんどありません。


31.4. Mojo を使うべき場面

本書の実装を経て、Mojo が真に輝くユースケースが見えてきました。

Mojo が得意なこと:

  • 型安全なシステムコード(NumPy ライクなカスタム配列演算)

  • Python と同じエコシステムを活用しつつ、ホットパスを Mojo で高速化

  • SIMD・parallelize を使った CPU 最適化

  • 数値計算の関数を型制約で安全に定義する

Python + PyTorch/MLX が得意なこと:

  • プロトタイピング(型アノテーションなしで高速に書ける)

  • フレームワークの autograd をそのまま使う学習全般

  • 大規模モデルのファインチューニング

現在の Mojo の立ち位置:

Mojo はまだ発展途上の言語です。標準ライブラリは Python ほど充実しておらず、 torch.autogradmlx.nn に相当するフル機能のフレームワークは まだ存在しません。しかし「Python とのシームレスな相互運用」という設計思想のもと、 既存の Python ML エコシステムをそのまま活かしながら、 パフォーマンスが要求される部分だけを Mojo で書く、という使い方は今日から可能です。


31.5. スタック役割分担のまとめ

本書で登場した各ツールの役割を一表に整理します。

ツール

主な役割

強み

Mojo

ホットパスの型安全実装・ループ制御

静的型・所有権・Python interop

MAX

推論の最適化(Graph API)

グラフコンパイル・ハードウェア抽象化

PyTorch

学習フレームワーク(MPS 対応)

autograd・nn.Module・大規模エコシステム

MLX

Apple Silicon 特化の学習

Unified Memory・Lazy Evaluation


31.6. 最後に

本書では「autograd の仕組みをゼロから実装する」という一貫したテーマのもと、 Value クラスのスカラー演算から始まり、Mojo への移植、MAX・PyTorch・MLX への拡張と 段階的に実装を発展させてきました。

Mojo は「Python のような書き心地で、C のような速度を」というビジョンを持つ言語です。 型システムや所有権モデルを通じて安全性と性能を両立しながら、Python の豊富な エコシステムに乗り続けられるのが最大の強みです。

microgpt のコードは小さいですが、その中に transformer・autograd・ オプティマイザという現代の大規模モデルの核心が詰まっています。 本書を通じて学んだ仕組みは、より大きなモデルを読み解く際の 確かな土台となるはずです。