Repository navigation
Mac (MPS) support: CUDA templates run unchanged on Apple Silicon - #470
Conversation
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…n MPS A CUDA-authored template names quantization_device "cuda"; SDNQ moved weights to it during load and failed on a Mac. Device arguments now go through resolve_device, and use_quantized_matmul(_conv) is turned off on MPS, where it falls back to torch._int_mm (~500x slower than bf16). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
diffusers refuses use_stream off CUDA/XPU, and record_stream without use_stream, so every LTX-2.5/H3 template failed to load on a Mac. Both are dropped together, with a warning, when the onload device is neither. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every real segment run raised KeyError on the SAM v1 'reshaped_input_sizes' key; the mocked tests supplied it. Adds a test on the real processor. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
device_memory_stats reported zeros on MPS, so pipeline_released events, the REPL and the UI all showed 0 GB. torch.mps reports allocated, driver and recommended-max figures; use them. Adds device_capacity_gb(). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…card A 64 GB Mac was refused against the catalog's 24 GB RTX 3090 entry. The check now uses the serving backend's own cost entries, else its measured capacity, else (capacity unreadable) every entry - so the guard is never switched off. The #265 refusal had no tests; this adds them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Automatic slicing on MPS replaced SDPA with sliced bmm, measured 12.8 vs 5.4 ms per SDXL-sized attention block in bf16. disable_attention_slicing is kept in the schema and ignored. Also fixes the fp16-on-MPS warning text, which ran two sentences together and recommended float32. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…lter With PYTORCH_ENABLE_MPS_FALLBACK set, an op the MPS backend lacks runs on the CPU and torch says so with a UserWarning - which dw ignored along with every other UserWarning, so the slowdown had no trace. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…awn repos - upscale-*, image-to-image: default image is diffusers' docs cat.png (was example.com, and a third-party 'sage-permission-probe' repo) - audio-trim-fade, transcribe-audio: default audio is the transformers docs ASR sample (was example.com) - flux-torchao: one spelling of FLUX.1-dev (two spellings = two ~23 GB cache entries) - attention-processor, controlnet-component: stable-diffusion-v1-5 repo - dw.test's workflow runs in bfloat16, which is safe on MPS too Adds a catalog test for placeholder hosts, withdrawn repos and repo spellings. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
End to end, SD 1.5 (the quick-start) ran 17.3s without slicing and 14.1s with it: MPS SDPA is slow at head dims 40/48/160 and fast at 32/64-128, so slicing helps SD 1.5 and hurts SDXL (2.4x in attention). Restores the automatic default and documents disable_attention_slicing for SDXL. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
segment and segment-and-inpaint pointed at a removed HF docs image (404), controlnet-component at a host that no longer answers, image-variation at a deleted tweet image. All now use diffusers' documentation-images. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
GroundingDINO scores a lowercase, period-terminated query. The task passed the raw prompt, so 'cat' scored 0.20 against a photo of a cat - under the 0.3 threshold - and segment returned an empty mask on every backend. 'cat.' scores 0.40, and the template now detects at 0.64. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
LTX-2.5's SDNQ transformer load segfaulted (exit 139) on a Mac: diffusers' per-shard loader threads were all inside copy_ onto MPS at once. With parallel loading off the same load took 39s and succeeded. diffusers reads HF_ENABLE_PARALLEL_LOADING at import, so the default is chosen by platform (macOS has no CUDA); CUDA boxes keep the parallel load, and an explicit setting still wins. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
LTX-2's transformer and text connectors build RoPE frequencies in float64 when their double_precision flag is set (the default); MPS has no float64, so LTX-2.5 loaded on a Mac and failed its first step. diffusers already makes this fallback for Wan, Lumina2, SkyReels-V2, ChronoEdit and Sana-Video; dw applies it to any module exposing the flag, on MPS only. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The skill told an agent to stop on an mps server because none of the templates fit. With the engine's MPS adaptations, ltx2/text-to-video ran on a 64 GB M5 Pro (6.5 min cold-cache end to end, 23.5 GB peak). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Whisper refuses more than 30 s of audio ("more than 3000 mel input
features") unless it predicts timestamps, so transcribe_audio failed on
any clip longer than one window - found transcribing a 110 s Music 3
song. Asked for only past 30 s, since CTC models read the flag
differently.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The skill told an agent to stop on an mps server. templates/minimax/music ran on a 64 GB M5 Pro (11.7 min end to end, 28.6 GB peak, a 110 s song whose lyrics transcribe back). music-video also runs H3 and is unverified. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
transformers raises for a CTC model unless return_timestamps is "char" or "word", and for a non-Whisper seq2seq model at all, so a wav2vec2-style model_name on a clip over 30 s failed where it used to return text. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Review of the code changes (the plan doc and other docs-only changes skipped). Fixed in 171fae9: These parts are correct as written:
Before merging: the branch is meant for macOS, but once it's on
The loop's tester will pick up the skill edits too. Follow-ups in the harness: dkackman/harnest#15 (an MCP target other than lem) and dkackman/harnest#16 (an MPS regression level). 🤖 Generated with Claude Code |
Makes the catalog's CUDA-authored workflows run on Apple Silicon without editing them, and fixes the defects the Mac review turned up. The engine now adapts each CUDA-only setting to the serving machine and logs a warning each time, so templates stay backend-agnostic and an MCP agent doesn't need to know which backend is serving. CUDA behaviour is unchanged. Every adaptation is keyed on the serving device, and each has a test pinning the CUDA path.
Verified end to end on an M5 Pro with 64 GB:
ltx2/text-to-video(LTX-2.5, SDNQ uint4 + group offload)minimax/music(Music 3)text-to-image(SD 1.5)segmentaudio-trim-fadetranscribe-audioPlan:
docs/superpowers/plans/2026-09-25-mac-mps-support.md. Its Task 6 was reversed during verification; see Decisions below.Engine: CUDA settings adapted to the serving device
quantization_device: "cuda"(all 31ltx2/*+minimax/*files)AssertionError: Torch not compiled with CUDA enabledduring loadresolve_device()(portable_quantization_arguments,config_objects.py)use_quantized_matmul(_conv)torch._int_mm: 1096 ms against 2.1 ms for a bf16 matmul (~500x)group_offload.use_stream/record_streamvram_estimatecostentries, elsedevice_capacity_gb()(Metal's recommended working set), else every entry. So an unreadable capacity never turns the guard off. The #265 refusal had no tests until nowHF_ENABLE_PARALLEL_LOADINGcopy_onto MPS at once_parallel_loading_default). diffusers reads the variable at import, before dw can ask torch for a device, so the choice is by platform. An explicit setting still wins. CUDA boxes keep the parallel loaddouble_precisionCannot convert a MPS Tensor to float64on the first stepapply_mps_rope_precision). diffusers already does this for Wan, Lumina2, SkyReels-V2, ChronoEdit and Sana-Video; LTX-2's transformer and connectors never got the check. Upstream gap, not filedAlso:
device_memory_stats()reports real MPS figures (allocated, driver-reserved, recommended max) and the chip name. They were zeros before, sopipeline_releasedevents, the REPL and the UI showed 0 GB.UserWarningnow gets through dw's blanketUserWarningfilter. A silent CPU fallback now shows in the log.Fixes that apply on every backend
segmentnever worked. Two separate causes:reshaped_input_sizes, which the SAM2 processor doesn't return, so every run raised KeyError. The mocked tests supplied the key; a new test uses the realSam2Processor, which builds offline.grounding_query()normalizes the prompt; the template now detects at 0.64.transcribe_audiofailed on any clip over 30 s. Whisper needsreturn_timestamps=Truefor long-form audio. It's passed only past 30 s, since CTC models read the flag differently.tests/test_template_defaults.py):example.complaceholders:upscale-diffusion,upscale-spandrel,audio-trim-fade,transcribe-audio.segment,segment-and-inpaint(HF 404),controlnet-component(host gone),image-variation(deleted tweet).image-to-imagepulled its default from a third-party repo namedsage-permission-probe.flux-torchaospelledFLUX.1-devtwo ways, which means two HF cache entries and ~23 GB downloaded twice.runwayml/stable-diffusion-v1-5in two templates.dw.test's workflow ran fp16; it now runs bf16.httpdefault in the catalog returned 200.Mac results
ltx2/text-to-video, defaults (960x544, 121 frames)cost: 1.8)minimax/music, defaultstranscribe-audioon MPStext-to-image(SD 1.5)segmentWall clock is with weights already downloaded.
The
ltx-2.5andminimax-music3skills told agents to stop on anmpsserver. They now say those templates run there, slower than the CUDAcostfigures, and name what hasn't been run on a Mac.Decisions a reviewer should weigh
disable_attention_slicing.Disty0/Z-Image-Turbo-SDNQ-uint4-svd-r32, ships with it off in both components, andsdnq_optimizewas already limited to CUDA/XPU.devicevariable was considered, but it would push the backend choice onto every caller, an MCP agent included.Deferred (from the final review, all minor)
tryindevice_memory_stats. Every caller catches the error, and torch >= 2.13 has both calls.portable_quantization_argumentsuses the process device, so acpu-pinned SDNQ step on a Mac also loses quantized matmul. It runs slower but stays correct.device_capacity_gb()is computed on every validation even when a matchingcostentry exists.dw/worker.py:708anddw/server/observed_cost.py:302.dw.testin bf16 is slow on pre-Ampere CUDA cards (T4/V100).Follow-ups
minimax-h3skill still says CUDA-only.flux2-dev,multi-image-reference,community-pipeline,flux-torchao).install.shshould keep auto-loadingfp4-fp8-for-torch-mps. It overridesmm/linear/copy_on MPS and setsPYTORCH_ENABLE_MPS_FALLBACK=1, and nothing in the catalog uses it.basis: "other_device"), so they're optimistic.Release-note items
segment,segment-and-inpaintandtranscribe-audioon clips over 30 s now work. None did before.disable_attention_slicingis the switch for SDXL-family models on a Mac.dw.test's workflow runs in bf16.Testing
tests/test_vram_estimate.pytests/test_template_defaults.pytests/test_attention_slicing.pytests/test_mps_fallback_warning.pytests/test_parallel_loading_default.pytests/test_mps_rope_precision.pytest_config_objects.pytest_device_helpers.pytest_segment.py, including one on the real SAM2 processortest_transcribe_audio.pyTorch not compiled with CUDA enabled.🤖 Generated with Claude Code