概要
- Swiftによる独自の 行列積(Matrix Multiplication)最適化 の試み
- Apple Silicon上の CPU、SIMD、AMX、GPU の性能比較
- C実装(llm.c)と Swift実装の性能差 とその原因分析
- Swift 6.2のMutableSpan や Relaxed演算 による最適化手法
- 今後の記事ではAppleの MLフレームワーク も検証予定
SwiftでLLMトレーニング用の行列積を最適化する
- 目的 :Swiftで手書きの行列積コードを高速化し、LLMトレーニングに活用する方法の解説
- 背景 :PythonのMLライブラリは計算を自前で行わないため、Swiftで「すべて自作」したい動機
- 参考実装 :Andrej Karpathyの llm.c (GPT2互換C実装)をSwiftに移植
- 計測対象 :行列積カーネルを含む 前向き・後向き伝播の全体反復時間 で性能比較
llm.cの行列積の構造
- matmul_forward 関数が前向き伝播のコア
- 入力inp、重みweight、バイアスbiasを使い、出力outに計算結果を格納
- 4重ループ構造だが、本質は val += inp[...] * weight[...] の繰り返し
- 1回の学習反復で約0.2兆回の浮動小数点演算 が必要
C実装とSwift実装の性能比較
- C実装(llm.c) :Releaseビルドで 1トークン/秒未満、1反復7秒
- 基本Swift実装 :Cに忠実に書き換え、配列境界チェックも除去
- 約15〜20倍遅い (1トークン19秒、20反復で30分以上)
- 2.8 Gflop/s 程度の低性能
Swift配列のボトルネック
- ArrayBuffer.beginCOWMutation() が最大の性能コスト
- Swift配列の「ユニーク性」判定が毎回発生し、最適化を阻害
- MutableSpan (Swift 6.2)を使うことで ほぼゼロオーバーヘッド で回避可能
- out = out.mutableSpanで配列を直接書き換え
- 前向き伝播には効果小 だが、 全体の学習反復は3倍以上高速化
Cの最適化とSwiftの違い
- Cは-ffast-math による FMA(fused-multiply-add)命令 を利用
- 1命令で掛け算+足し算を同時に実行
- アセンブリレベルで8回のfmadd命令に展開される
- SwiftはFMAを自動で使わない (-ffast-math相当がない)
- SIMDで4回の掛け算(fmul.4s)は使うが、加算が分離・mov命令も多い
- Relaxed演算(Swift-Numerics) で FMA利用を明示的に許可 できる
- Relaxed.multiplyAddやRelaxed.sumを活用
- 精度より速度を優先したい場面で有効
まとめと今後
-
Swift標準配列のユニーク性判定 が大きな性能低下要因
-
MutableSpanやRelaxed演算 の活用で C並みの最適化 が可能
-
今後はAppleの MLフレームワーク や Metal実装 も検証予定
- Karpathyの動画やPython実装 で理論を学び、本記事で Swiftでの実践的高速化手法 を習得できる流れ
- 「フレームワークなし」 の自作アプローチでLLMトレーニングを探求