MiniMax H3 在 M5 Pro 實測:ComfyUI 安裝、M5 Kernel 與 64GB 記憶體調校
在 M5 Pro 64GB 上用 ComfyUI 跑通 MiniMax H3,整理模型下載、PyTorch nightly、M5 Metal Kernel、啟動參數與記憶體調校實測。
目錄展開
我在一台 64GB 統一記憶體的 M5 Pro MacBook Pro 上,用 ComfyUI 跑通了 MiniMax H3 的首末幀圖生影片,包含模型原生音軌。
我另外安裝 ComfyUI-AppleSilicon-FP8 自訂節點,目的是讓 int8 線性層走針對 M5 寫的 Metal TensorOps kernel,盡量用到 M5 GPU 每個 shader core 裡的 Neural Accelerator。這是 M5 新增、專門加速矩陣乘法的硬體單元,相關設計可參考 Apple 的 M5 GPU 技術說明。
最後的正式測試是 352×608、124 幀、10 步:產生 5.167 秒影片共花 8 分 22 秒。整個跑通過程最折騰的是原生 int8 kernel 建置失敗,以及 40GB 級權重帶來的記憶體壓力。
這篇先給可以直接採用的設定,再保留我一路判斷、測錯與修正的過程。
先看結論
實測時間
| 測試 | 輸出條件 | 產生時間 |
|---|---|---|
| 正式測試 | 352×608、124 幀、5.167 秒、10 步 | 501.6 秒(8 分 22 秒) |
| 9:16 較高負載測試 | 約 0.4M 解析度、5 秒 | 約 25 分鐘 |
兩組測試的輸出條件不同,不能直接拿時間推算效能倍率。解析度、幀數與步數都會影響實際耗時。
環境與建議
| 項目 | 本次結果 |
|---|---|
| 硬體 | MacBook Pro、M5 Pro、64GB 統一記憶體 |
| 測試環境 | macOS 26.5(25F71)、ComfyUI v0.31.0、Python 3.13.13 |
| 模型下載量 | 約 40GB |
| 建議啟動參數 | --disable-smart-memory --cache-none |
| 最重要的檢查 | 不要只看啟動 log,要確認 kernel loader 或比較穩態每步時間 |
| 輸入圖限制 | first_frame 會直接拉伸到畫布,最好先裁成目標長寬比 |
這些數字只適用於本文列出的硬體、版本、模型與參數,無法代表所有 M5 Pro 的效能。
圖 1 既有 ComfyUI Desktop 與 MiniMax H3 獨立環境。兩邊只透過 extra_model_paths.yaml 唯讀共用模型目錄。
只想照著做,可以先看這裡
1. 另建環境,不動原本的 ComfyUI Desktop
我原本的 ComfyUI Desktop 已經放了 373GB 模型和 11 個 custom node。MiniMax H3 當時需要 PyTorch nightly,直接升級既有環境的風險太高,所以我另外建立一套 ComfyUI,使用 8189 port。
mkdir -p ~/src/minimaxh3
cd ~/src/minimaxh3
git clone --filter=blob:none https://github.com/Comfy-Org/ComfyUI.git
cd ComfyUI
git checkout v0.31.0
uv venv --python 3.13 ../.venv
uv pip install --python ../.venv/bin/python -r requirements.txt
MiniMax H3 的核心支援在 2026 年 8 月 3 日合併,並收進 ComfyUI v0.30.0。我選 v0.31.0,是為了取得後續的 H3 VAE、音訊與取樣修正。
2. 下載需要的 4 個檔案
| 目錄 | 檔案 |
|---|---|
models/diffusion_models/ | minimax_h3_fl2va_pruned_int8_convrot.safetensors |
models/text_encoders/ | qwen3vl_32b_minimax_h3_nvfp4_awq.safetensors |
models/vae/ | minimax_h3_video_vae_fp16.safetensors |
models/vae/ | minimax_h3_audio_vae_fp32.safetensors |
合計約 40GB。不要直接下載完整的 Comfy-Org/MiniMax-H3 儲存庫;本文測試時,完整儲存庫約 465GB。
我這次使用 Hugging Face Xet 傳輸時,在下載約 12GB 後停止前進。改走傳統 HTTP CDN 才完成下載:
export HF_HUB_DISABLE_XET=1
這是我在當時環境遇到的故障,不代表所有連線都需要停用 Xet。若曾強制中止下載,而且下一次執行沒有輸出、CPU 使用率接近零,可以再檢查快取中的 .lock 檔。
3. 確認 nightly 套件真的對齊
只下 --upgrade 時,pip 可能保留 stable 版 torchaudio,因為正式版的 PEP 440 排序高於同版號的 .dev 套件。我最後明確指定當天的 nightly:
./.venv/bin/python -m pip install --pre --upgrade --force-reinstall --no-deps \
torchaudio==2.11.0.dev20260810 \
--index-url https://download.pytorch.org/whl/nightly/cpu
最後使用的版本是:
torch 2.14.0.dev20260810
torchvision 0.29.0.dev20260810
torchaudio 2.11.0.dev20260810
mps True
macOS 的 wheel 位於 PyTorch 的 cpu index,但安裝後仍可使用 MPS。
4. 不要把 capability summary 當成 kernel 已啟用
本次環境要讓 ComfyUI-AppleSilicon-FP8 的 M5 int8 kernel 建起來,需要處理兩個相容性問題:
- custom node 傳入的
-std=c++17蓋過 PyTorch nightly 要求的 C++20; - node 指定
MTLLanguageVersion4_1,但 macOS 26.5 的 SDK 與 runtime 最高接受 Metal 4.0。
我把相關 loader 的 C++ 標準改為 C++20,並讓缺少 MTLLanguageVersion4_1 的環境退回 MTLLanguageVersion4_0:
#ifndef MTLLanguageVersion4_1
#define MTLLanguageVersion4_1 MTLLanguageVersion4_0
#endif
這是針對本文版本組合的本機修改,不應直接套用到其他版本。修改後我跑了 custom node 自帶的測試,結果是 50 passed;仍要搭配 loader 的 available() 或實際每步時間確認路徑真的生效。
5. 啟動設定
#!/bin/zsh
export PYTORCH_ENABLE_MPS_FALLBACK=1
exec .venv/bin/python main.py --listen 127.0.0.1 --port 8189 \
--disable-smart-memory --cache-none
是否使用 --cache-none 要看工作內容。正式跑長片時,它能降低保留快取造成的記憶體壓力;反覆用相同提示詞測短片時,保留 conditioning 快取可能更省時間。
如果只想知道怎麼跑,到這裡已經足夠。下面是這套設定怎麼找出來的。
為什麼我沒有直接升級 ComfyUI Desktop
我原本以為 ~/Documents/ComfyUI 就是整套 ComfyUI,實際上 Desktop 版把程式與使用者資料分開:
| 項目 | 位置或版本 |
|---|---|
| Desktop app | /Applications/Comfy Desktop.app v1.0.28 |
| 使用者資料 | ~/Documents/ComfyUI |
| 核心程式碼 | ~/ComfyUI-Installs/ComfyUI/ComfyUI |
| 原有版本 | v0.27.0-29-g091b70ed |
| 原有 torch | 2.10.0 stable |
原有版本還沒有 H3 支援,而且 Desktop app 會管理自己的核心儲存庫。就地切換版本或安裝 nightly 可能影響現有 custom node,之後也可能被 Desktop 更新覆蓋。
因此我把新環境放在 ~/src/minimaxh3,既有模型則透過 extra_model_paths.yaml 唯讀共用。H3 自己的模型放在新環境,需要時可以整包移除。
第一個誤判:GitHub Release 不等於 git tag
參考資料建議 v0.30.1。我先查 GitHub Releases API,沒有看到它,就判定這個版本不存在。
clone 後執行 git tag -l 才發現:
v0.30.0
v0.30.1
v0.30.2
v0.31.0
v0.31.1
v0.30.1 有 tag,只是沒有獨立 GitHub Release。這次經驗讓我之後查版本時會同時看 release、tag 與實際 commit,不再只依賴其中一種介面。
第二個誤判:log 全通過,不代表 kernel 已經建好
裝好 ComfyUI-AppleSilicon-FP8 後,啟動訊息看起來很完整:
[AppleSilicon-FP8] capabilities: macOS=26.5, torch=2.14.0.dev20260810, mps=yes,
compile_shader=yes, tensor_ops(M5/Metal4)=yes, ninja=yes
[AppleSilicon-FP8/int8_kernel] INT8 convrot Linear routed through bit-exact Metal kernel on MPS
我看到 tensor_ops=yes 和 ninja=yes 就以為成功了。第一次跑到 int8 層時,才出現:
[int8_ext] build failed; int8-native disabled
error: C++20 or later compatible compiler is required to use PyTorch.
capability summary 檢查的是硬體與工具是否存在,不會替第一次實際編譯背書。
圖 2 M5 int8 kernel 的驗證鏈。啟動檢查只確認必要條件;實際編譯、測試、loader 狀態與穩態每步時間都通過後,才能確認加速路徑生效。
C++17 蓋掉 C++20
編譯指令同時帶了兩個標準:
c++ ... -fPIC -std=c++20 -std=c++17 -ObjC++ -c int8_gemm.mm
後面的 -std=c++17 生效,因此 PyTorch 2.14 header 拒絕編譯。我原本以為是 PyTorch 注入 C++17,後來才從 cpp_extension.py 和 custom node loader 的參數順序確認,C++17 是 node 自己加的。
Metal 4.1 改成 4.0 後才編譯過
C++20 修好後,主機端又卡在:
error: use of undeclared identifier 'MTLLanguageVersion4_1'
我一度認為只能等 macOS 27 或 Xcode beta。接著我試過自行補出 4.1 enum;ObjC++ 雖然能編譯,runtime 仍拒絕 metal4.1。最後直接退回 Metal 4.0,runtime shader 才順利編譯完成。
能編譯過的關鍵在於,這版 kernel 使用的 matmul2d 與 cooperative_tensor 在我的 macOS 26.5 runtime 上以 Metal 4.0 就已經可用。這是特定版本的實測結果,不宜外推到所有 node 或系統版本。
用每步時間確認 kernel 是否生效
同一組 608×352、5 幀、4 步測試:
| 狀態 | 穩態每步 | sampling | 總時間 |
|---|---|---|---|
| 修改前 | 11.02 s/it | 55 秒 | 212.5 秒 |
| 只修 C++20 | 11.08 s/it | 55 秒 | 192.1 秒 |
| 再修 Metal 4.0 | 6.29 s/it | 35 秒 | 169.0 秒 |
只修 C++20 時,總時間少了約 20 秒,但每步時間完全沒改善。可能是檔案快取造成了這段差異,loader 仍顯示 kernel 未啟用。
Metal 4.0 路徑生效後,穩態每步快 1.75 倍;整段 sampling 從 55 秒降到 35 秒,約快 1.57 倍。
跑通之後,下一個瓶頸是記憶體周轉
kernel 生效後,速度仍不穩定。我先看程序 RSS,峰值只有 13.4GB,和實際壓力明顯對不上;MPS 與檔案映射的記憶體不能只靠 RSS 理解。
接著我改為逐秒記錄 vm_stat,並用 ComfyUI log 對齊 text encoder、DiT、sampling 與 VAE 階段。這些是全系統計數器,因此以下歸因成立的前提是測試期間沒有其他明顯的記憶體重負載。
一次約 3.5 分鐘的測試期間,我觀察到:
| 指標 | 變化量 |
|---|---|
| 壓縮 | 119.6GB |
| 解壓縮 | 82.5GB |
| swap 寫出 | 46.9GB |
| swap 讀回 | 29.6GB |
| pagein | 40.8GB |
| 可用記憶體谷底 | 0.0GB |
| 壓縮記憶體峰值 | 34.0GB |
這些數字顯示系統在測試期間大量搬移記憶體,但不能單靠 vm_stat 證明所有 pagein 都是 H3 權重。
--disable-smart-memory 把壓力移出 sampling
text encoder 約 14.6GiB,只在開頭編碼提示詞時使用。--disable-smart-memory 讓 ComfyUI 更積極卸載不用的模型後,sampling 階段的可用記憶體明顯回升。
| 設定 | 總時間 | 穩態每步 | 解壓縮 | swap 讀回 |
|---|---|---|---|---|
| 預設 | 149.6 秒 | 5.51 s/it | 82.5GB | 29.6GB |
--disable-smart-memory | 104.4 秒 | 3.36 s/it | 55.7GB | 12.9GB |
再加 --cache-none | 72.2 秒 | 3.38 s/it | 48.4GB | 3.3GB |
這組對照是在 kernel 修復後進行。不同批次的總時間仍會受 seed、檔案快取與模型載入狀態影響,所以我把穩態每步和總時間分開看。
分階段量測顯示,記憶體壓力集中在模型載入階段;sampling 階段相對寬鬆:
| 階段 | 可用記憶體谷底 | 壓縮記憶體峰值 |
|---|---|---|
| text encoder 載入 | 0.1GB | 21.2GB |
| DiT 載入 | 0.0GB | 32.5GB |
| sampling | 16.8GB | 12.2GB |
| VAE 解碼 | 16.9GB | 6.9GB |
這不表示解析度與片長可以無限制提高;activation、attention 與 VAE 成本仍會隨畫面和幀數增加。它只說明在這組短片測試裡,最明顯的記憶體爭用發生在模型切換階段。
--cache-none 要看用途
短片連續跑第 2 次時,保留 conditioning 快取可以省掉 text encoder 載入:
| 設定 | 第 1 次 | 第 2 次 |
|---|---|---|
有 --cache-none | 66.8 秒 | 66.8 秒 |
無 --cache-none | 97.7 秒 | 33.5 秒 |
因此我的使用方式是:
- 正式跑長片:保留
--cache-none,降低記憶體壓力。 - 相同提示詞反覆測短片:可拿掉
--cache-none,利用 conditioning 快取。
若把省下的 64 秒直接套到 501.6 秒正式測試,總時間約縮短 13%;實際收益還要扣除保留快取可能造成的額外記憶體壓力。
最後跑出的結果
最終配置:
| 元件 | 版本或模型 |
|---|---|
| ComfyUI | v0.31.0(43cb4ff) |
| Python | 3.13.13 |
| torch | 2.14.0.dev20260810 |
| ComfyUI-AppleSilicon-FP8 | v1.3.0(3cc65dd),含本機相容性修改 |
| DiT | minimax_h3_fl2va_pruned_int8_convrot,約 19.5GiB |
| Text encoder | qwen3vl_32b_minimax_h3_nvfp4_awq,約 14.6GiB |
正式參數為 352×608、124 幀、24fps、10 步、res_multistep:
| 項目 | 結果 |
|---|---|
| 總時間 | 501.6 秒 |
| sampling | 416 秒,約 42.3 s/it |
| 其他載入與解碼 | 約 86 秒 |
| 輸出 | H.264 + AAC 32kHz 立體聲 |
我當時參考的測試紀錄寫 M4 Pro 64GB 約需 18 分鐘;若只用這個數字粗略換算,本次測試約快 2.15 倍。這項跨機器、跨環境比較僅供參考,沒有控制完整的 benchmark 條件。
音訊量測先排除近乎靜音
在沒有直接試聽的自動化檢查中,我先用以下方式排除近乎靜音:
正式影片量到 RMS −14.1dBFS、peak −4.2dBFS,至少可排除近乎無聲。zero-crossing rate 為 0.103,但 RMS 和 ZCR 都不足以單獨證明沒有噪音或內容失真;判斷音質仍需要實際試聽或頻譜分析。
0.2 秒煙霧測試的 RMS 只有 −72dBFS,幾乎無聲,因此太短的片段不適合拿來判斷 H3 音訊是否正常。
首幀會被直接拉伸
ComfyUI v0.31.0 的 nodes_minimax_h3.py 對首末幀採用不同策略:
if first_frame is not None:
img = _resize(first_frame[:1], width, height, "disabled")
if last_frame is not None:
img = _resize(last_frame[:1], width, height, "center")
first_frame 直接拉到目標畫布,last_frame 則保留比例後置中裁切。首幀又是整段影片的幾何基準,因此輸入圖最好先裁成和輸出相同的長寬比。
這次留下的檢查順序
回頭看,最浪費時間的是太早把「看起來成功」當成「真的成功」。下次我會照這個順序檢查:
- 先隔離環境,再安裝 nightly 與 custom node。
- 同時查 release、tag 和 commit,避免只依賴 GitHub Releases API。
- 檢查第一次實際 kernel 編譯;啟動 capability summary 只能當成初步資訊。
- 用 loader 狀態和穩態每步時間確認加速是否生效。
- 記憶體問題分階段量測,並把全系統計數器當成線索,不當成單一程序的直接證明。
- 比較效能時記錄 seed、冷/熱快取、模型載入狀態與是否重啟伺服器。
如果你更在意可預測的記憶體占用,也願意下載約 134 GiB 權重,可以接著看 h3.c 在同一台 M5 Pro 上的實測。
常見問題
M5 Pro 64GB 能在本機跑 MiniMax H3 嗎?
可以。本文在 M5 Pro 64GB 上透過 ComfyUI 產生 352×608、124 幀、24fps 的 5.167 秒影片,10 步總時間為 501.6 秒。這是特定版本與設定下的單機實測,不代表所有 M5 Pro 都會得到相同結果。
用 ComfyUI 跑 MiniMax H3 要下載多少模型?
本文使用的 DiT、文字編碼器、video VAE 與 audio VAE 合計約 40GB;不必下載當時約 465GB 的完整模型儲存庫。
啟動訊息顯示 M5 TensorOps 可用,是否代表 Kernel 已啟用?
不代表。啟動訊息只能確認硬體與工具等必要條件;仍要檢查第一次實際編譯、loader 的可用狀態,並比較穩態每步時間,才能判斷 int8 Kernel 是否真的生效。
參考來源
相關文章
h3.c 跑 MiniMax H3 實測:M5 Pro 64GB 記憶體與 VAE 接縫修正
在 M5 Pro 64GB 上用 h3.c 跑 MiniMax H3,整理 134 GiB 權重下載、Metal 建置、效能與尺寸限制,以及 Video VAE 接縫修正。
在 Mac 上查 SSD 健康與用量:怎麼查、怎麼看,以及 swap 會不會磨壞硬碟
用一行指令查 Mac 內建 SSD 的累計寫入量與健康狀態,帶你看懂 SMART 報告裡的關鍵欄位,並釐清 swap 對 SSD 壽命的實際影響。
提示詞快取失效解析:系統提示詞多一行日期,本機模型就重新預填
拆解本機模型的預填與前綴快取:為什麼系統提示詞多一行日期,就讓 250k context 的工作階段重新預填 20 分鐘,以及提示詞該怎麼排版才能穩定命中快取,並對照 Anthropic 商業 API 的快取規則。