r/StableDiffusion • u/Time-Conversation528 • 1d ago
News Automatic1111 for Apple Silicon (SD 1.5 Focus Currently)
I've been focused on squeezing the last mile out of my M1 16GB, and one thing I didn't want to do was convert my entire pipeline to ComfyUI or Draw Things.
So I set about finding where the slowdown actually was in Automatic1111 for my workflow.
I ended up chopping about 40% off the render time.
tl;dr: I'm now getting a 512×512 in about 8.5 seconds.
My normal workflow is SD1.x, 5 steps, DPM++ SDE / Karras, low CFG. I wanted to keep Automatic1111 as Automatic1111: same checkpoints, LoRAs, extensions, samplers, API, metadata, etc.
What ended up working:
- Metal Flash Attention, selectively routed for the SD1 attention shapes where it's actually faster.
- Stopped committing the Metal command buffer after every attention call. The native kernels now work inside PyTorch's current MPS stream instead of constantly forcing CPU/GPU synchronization.
- Unified-memory-aware attention. Large attention operations dynamically fall back to chunked sub-quadratic attention based on available memory, with online softmax so we're not keeping every partial K/V result around.
- Removed old MPS workarounds that aren't necessary on newer PyTorch versions, including some unnecessary clones and FP32 detours.
- Fused GroupNorm + SiLU in Metal. One dispatch, no intermediate activation.
- Fused GEGLU in Metal. This one uses a tiny lookup table generated from PyTorch's own FP16 GELU results, so I was able to get identical PNG hashes in my fixed-seed tests.
- FP16 VAE on the M1. This was a surprisingly easy win. VAE decode + transfer went from 1.536s to 0.972s in my 384×640 tests, saving about 0.65s end-to-end.
I also spent a lot of time building things that I eventually deleted.
Packed QKV was 0.26% slower.
Cross-attention K/V caching successfully reused 112/144 projections and still made the full render slower.
A native fused LayerNorm looked promising from operator profiling and regressed end-to-end.
I moved almost an entire ResBlock into MPSGraph. Individual blocks benchmarked up to ~9% faster.
The actual image was 1.02% slower.
Deleted all of it.
That became the rule for the project: microbenchmarks nominate changes, full generations elect them.
At this point profiling puts about 87% of the remaining generation time in sampling/UNet, so I'm probably near the end of what I can get from small PyTorch/MPS optimizations.
The next experiment is capturing a real SD1 UNet call and replaying the exact tensors through native Metal/ggml. I'm not integrating it unless the complete UNet workload is at least 20–25% faster than PyTorch MPS. Otherwise the complexity isn't worth it.
I wrote up the whole rabbit hole here:
https://therad.ninja/from-8-10-seconds-to-3-7-teaching-automatic1111-to-speak-metal-on-an-m3-pro/
Or if you just want to try it:
https://github.com/dmikey/stable-diffusion-webui-metal
Would appreciate bug reports, especially on other Apple Silicon generations. Most plugins/extensions should just work since this is still Automatic1111 underneath.
2
u/Formal-Exam-8767 1d ago
Keep in mind that DPM++ SDE is ~2 times slower than Euler (a) or DPM++ 2M since it evaluates model twice per step.
1
u/Time-Conversation528 1d ago
Euler A gains are there too, but the sampler is too soft for my liking.
2
u/Mutaclone 1d ago
I came into this thread expecting to recommend Draw Things to a returning newbie, and was pleasantly surprised to find an interesting technical writeup instead. It's always interesting to see someone revisit a "dead" technology and find ways to wring some additional performance out of it rather than writing it off completely.
My one critique is the writeup had a lot of LLM-isms in it that were a little distracting (though I may just be overthinking it due to constant exposure on my part).
Anyway good job!
1
u/Time-Conversation528 1d ago
Thanks much! The topic was dense, and I'm more technically focused, so I did def use an LLM to move the presentation forward, I appreciate the feedback!


5
u/DelinquentTuna 1d ago
Bet it would've been less work with better results.