MiniMax H3をApple Siliconで動かすためのMPS必須パッチと実測

  • #MiniMax H3
  • #Apple Silicon
  • #MPS
  • #ComfyUI
  • #bf16
MiniMax H3をApple Siliconで動かすためのMPS必須パッチと実測

今回やったこと

MiniMax H3をApple SiliconのM5 Pro・メモリ64GB環境で動かし、MPSで詰まる箇所をパッチで回避した。対象のワークフローでは、ComfyUI側のINT8経路が torch._int_mm を無条件に呼び出す。しかしMPSにはこの演算のカーネルがなく、素の状態ではサンプリングの1層目で NotImplementedError: aten::_int_mm ... MPS が発生して停止する。

問題はモデルの読み込み失敗ではなく、量子化された重みを処理する演算経路と、MPSが提供する演算の差にある。そこで registry.get_implementation をフックし、MPS上ではINT8重みをbf16へ展開して通常のLinearを実行する mps_int8_patch.py を用意した。site-packagesを直接変更しないため、環境を作り直したときもパッチの有無を追跡しやすい。

fp32エミュレーションを採用しなかった理由

最初は torch._int_mm をfp32行列積で厳密にエミュレートする案を試した。互換性を優先した考え方だが、MPSでのfp32 matmulはbf16より明らかに遅く、体感できるほどの差があった(具体的な計測値は記録していない)。

この差を許容してINT8を名目上維持するより、ComfyUIの動作前提に合わせてbf16へ展開する方が実用的だった。パッチの目的はINT8という表記を守ることではなく、MPSで処理を完走させ、速度と結果を確認できる経路を作ることにある。

INT8重み
   ↓ MPS上の実装を判定
bf16へ展開
   ↓
通常のLinearで計算

動作を確認した設定

パッチv2、INT8 TE、gpu-only なしの条件で複数の設定を試し、完走することを確認した。解像度・フレーム数・ステップ数を変えると、同じモデルでも処理時間は大きく変わる。具体的な所要時間はログを残していないため、ここでは数値を示さない。 傾向として、解像度とフレーム数が増えるほど待ち時間は体感で伸びた。また、後述の --gpu-only を外すと、待ち時間は長くなる方向だった。

条件処理時間・メモリへの影響(傾向)
解像度を上げる処理時間は伸びる方向
フレーム数を増やす処理時間は伸びる方向
stepsを増やす処理時間は伸びる方向
--gpu-only を付ける処理時間は短くなる方向。ただしスワップ使用量が増え、メモリ圧迫を伴う
--gpu-only を外す(既定)処理時間は長くなる方向。メモリ圧迫は小さい

音声を伴う出力では、話者の声質記述 (S1) says: <d>[Japanese] セリフ</d> の形式が必要だった。声質の記述を省くと叫び声に寄り、促音や長音を含む表現は意図と異なる音へ変化することがある。そのため、プロンプトは映像だけでなく音声の書式も、確認できた挙動に合わせて固定する必要がある。

Apple Siliconで避ける設定

text_encoder_device() は常にCPUを返す構成だった。--gpu-only を付けると確認時にはスワップ使用量が明らかに増え、処理時間は短くなる方向に動いたものの、メモリ圧迫を伴う結果になった(具体的な数値は記録していない)。Apple Siliconでは、GPUへ寄せられる処理を増やすこと自体を目的にせず、CPUに残る処理とメモリの余裕を含めて測るべきである。

実装ステータスと適用範囲

パッチは作成済みで、M5 Pro・64GB環境での動作検証まで完了している。一方、MPS以外のバックエンドや別バージョンのComfyUIで同じ結果になるとは限らない。torch._int_mm の実装有無、重みの型、メモリ容量を確認してから適用する必要がある。エラーを見てモデルを諦める前に、失敗している演算と実行デバイスを切り分けるのが今回の要点である。

更新履歴

  • 2026-09-08: 初稿。MPSのINT8経路、bf16回避策、実測値を整理。
  • 2026-09-17: Issue #3993 対応。独立した根拠を確認できない実測値(fp32/bf16比較、処理時間表、スワップ量の数値)を削除し、記録していない数値を断定しない表現に修正。あわせて「動作を確認した設定」章に数値なしの傾向表を追加し(§5-0対応)、--gpu-onlyの二値条件の表現を修正。