Skip to content

Latest commit

 

History

History
83 lines (62 loc) · 4.09 KB

macos.md

File metadata and controls

83 lines (62 loc) · 4.09 KB

Experimental Apple silicon inference (MPS)

简体中文

This optional path runs MOSS-Image through PyTorch Metal/MPS. Recorded real-weight validation is on an M1 Max / 32 GB unified-memory Mac, with SFT. Other chips, lower-memory systems, Base and older dependency versions need testing. No quantization is applied.

Install and launch

Use native arm64 Python 3.12 and a compatible macOS/PyTorch installation. Allow about 40 GB free disk for one full model bundle (~25 GB), the environment and download files. From the cloned repository root:

MOSS_PYTHON=python3.12 bash scripts/setup-mac.sh
.venv/bin/hf download OpenMOSS-Team/MOSS-Image-SFT --local-dir models/MOSS-Image-SFT
bash scripts/gradio-mac.sh

Open http://127.0.0.1:7860. Start with 512×512, 10 steps and one image. Keep the terminal running; loading and inference can take minutes. Original PNGs and parameters.json are saved under outputs/gradio/. Stop with Ctrl+C. Subsequent runs only need the launch command. The Mac launcher uses local files only and disables Gradio analytics.

constraints-mac.txt lists the versions used for the recorded local runs: torch 2.14.1, diffusers 0.41.0, transformers 5.20.1, accelerate 1.15.0 and Gradio 6.30.0. These constraints apply to the optional Mac setup script, not to the existing installation path.

The launcher defaults the DiT to FP16. To compare BF16:

MOSS_MPS_DIT_DTYPE=bfloat16 bash scripts/gradio-mac.sh

The text encoder remains BF16 and the VAE FP32. Direct mps_runtime.load_pipeline defaults to BF16 unless MOSS_MPS_DIT_DTYPE is set before import. CUDA offload modes and Compile DiT do not apply to this staged MPS path; the UI disables those controls on MPS.

Implementation and review points

The Qwen encoder (~17 GB) and DiT (~10 GB) are staged so only one is resident on MPS at a time. Positive and negative prompts are encoded before the DiT is loaded. An eight-entry LRU prompt cache permits reuse when only seed, dimensions or sampling settings change.

The downloaded custom pipeline computes a timestep sinusoid in FP64, unsupported by MPS. The small sinusoid operation is moved to CPU at FP64 and its result copied back. Because the standalone pipeline is distributed in the model bundle, this currently uses a narrowly matched source replacement and stops explicitly if that source changes. The ComfyUI model has the equivalent conditional CPU calculation; the full ComfyUI path was not validated here.

A locally observed loading deadlock involved pending Metal copies and cache/synchronization calls holding the GIL. The current workaround drains copies through a CPU transfer before calling those methods. It wraps torch.mps.empty_cache and torch.mps.synchronize when MPS is available, including other callers in the process; that process-wide effect is an explicit review point for this experimental implementation.

Evidence and limits

Recorded SFT calls on M1 Max / 32 GB:

Output Settings Full recorded generation call
Chinese chalkboard 1024×1024, 20 steps, BF16, seed 42 320.362 s
English character posters 768×1024, 28 steps, FP16 395.150 / 367.596 / 344.072 s

Images, original metadata and prompts are available as validation evidence. These are end-to-end records, not controlled throughput, precision-equivalence or peak-memory measurements. CUDA execution is retained but was not hardware-regression-tested by this Mac contribution.

CPU regression checks, without downloading weights:

python -m pip install -e '.[ui]' -c constraints-mac.txt
python -m unittest discover -s tests -p test_mps_runtime.py -v

The checks cover staging order, prompt cache eviction, CPU sinusoid arithmetic, source-change failure, MPS routing and UI construction. Real MPS generation remains a separate hardware check. If MPS is unavailable, verify native arm64 Python and macOS compatibility. For memory pressure, reduce resolution/count and close heavy applications. For a source-patch mismatch, report the model revision and error rather than bypassing the check.