Local AI Image Generation on an AMD Mini PC: ComfyUI + Z-Image Turbo
- Category
- AI & Local LLM
- Posted
- July 11, 2026
- By
- Jacob Lloyd — written with AI assistance, post-project
- Read time
- 7 min read
In plain terms: How I set up my small AMD computer to create AI-generated images at home — about 27 seconds per picture, with no subscription and no per-image fee. The guide walks through the setup so it starts automatically and just works. It proves you don't need an expensive cloud service or a specific graphics card brand to make AI art.
My mini PC turns a text prompt into a finished 1024×1024 image in about 27 seconds: no cloud account, no per-image charge, no queue behind a thousand other people's prompts. And it's an AMD chip most people assume can't do this at all.
TL;DR
- What it is: ComfyUI + Z-Image Turbo, generating images entirely on local hardware — OpenAI and Midjourney are nowhere in the loop.
- What it costs: $0 per image, however many you make. There isn't even an account to sign up for.
- What you need: an AMD APU or GPU with real VRAM (mine has 64GB), a Linux box, and one session of ROCm setup pain. Once.
- What you end up with: ~27 seconds per 1024×1024 image, an always-on systemd service, and a one-line command to batch-generate images headless.
What you end up with
The setup talk can wait. Day to day, I open a browser tab or fire it off from a terminal. Either way:
| Metric | Value |
|---|---|
| Resolution | 1024×1024 |
| Steps / CFG | 8 steps, CFG 1.0 |
| Warm generation time | ~27s (measured range: 26.5–30.4s) |
| Cold start (first image after boot) | ~43.5s while ~20GB of weights load |
The real use case on this box isn't art for art's sake. It's a script that batch-generates avatar variations for a chatbot project: 222 PNGs in the output folder and counting. Boring, reliable infrastructure, which is exactly what you want from something you built for fun and then started depending on.
The hardware
This is a 128GB unified-memory box: an AMD Ryzen AI Max+ 395 ("Strix Halo") with a Radeon 8060S iGPU on the same package as the CPU. No discrete GPU anywhere.
Here's the part that matters. Firmware carves out 64 GiB of that 128GB and hands it to the iGPU as dedicated "VRAM" — ComfyUI's own startup log reads Total VRAM 65536 MB, total RAM 63920 MB. That's more VRAM than any consumer NVIDIA card sells, because it isn't expensive GDDR soldered to a graphics card. It's just system memory the firmware assigned to the GPU, with another ~31GB of GPU-accessible GTT behind it if needed.
| Component | Spec |
|---|---|
| CPU | AMD Ryzen AI Max+ 395, 16 cores / 32 threads |
| iGPU | Radeon 8060S, ROCm arch gfx1151 |
| Memory | 128GB unified LPDDR5X — 64GiB carved out as VRAM, ~62GiB left for Linux |
| OS | Bazzite (immutable, Fedora Silverblue based) |
| Discrete GPU | None |
The model weights for this whole setup add up to about 20.7GB. Comfortable inside 64GB; hopeless on a typical 8–16GB consumer card unless you offload layers to system RAM and eat the speed penalty.
Software stack
The versions that make this work, as installed right now:
| Component | Version |
|---|---|
| ComfyUI | v0.27.0 (git checkout) |
| Python | 3.12.13, in a venv built with uv |
| PyTorch | 2.12.1+rocm7.2 |
| torchvision | 0.27.1+rocm7.2 |
| torchaudio | 2.11.0+rocm7.2 |
| pytorch-triton-rocm | 3.5.1 |
| ROCm | 7.2, native gfx1151 support |
The fun detail: ROCm's PyTorch build masquerades as CUDA. The startup log literally says Device: cuda:0 AMD Radeon 8060S : native. Python written for an NVIDIA card just runs, because it thinks it's talking to one. ComfyUI also auto-disables cuDNN on this hardware and falls back to plain PyTorch attention (no xformers, no flash-attn), and it works fine without them.
Getting ROCm to behave
The setup pain lives in a handful of environment variables in the launch script:
HSA_OVERRIDE_GFX_VERSION=11.5.1
PYTORCH_HIP_ALLOC_CONF=expandable_segments:True
HIP_VISIBLE_DEVICES=0
HSA_OVERRIDE_GFX_VERSIONtells ROCm the GPU is gfx1151. On ROCm 7.2 it's redundant (the log already says "native") but I keep it as a safeguard, because on older ROCm builds this exact override was mandatory for iGPUs like this one to run at all.PYTORCH_HIP_ALLOC_CONF=expandable_segments:Truestops the allocator from fragmenting VRAM on unified memory. Without it you can hit out-of-memory errors with plenty of memory technically free.HIP_VISIBLE_DEVICES=0pins to the one GPU. Not exciting, but there if you ever add hardware.
One more thing: the server's listen address is hard-pinned to 127.0.0.1 in the launch script — not a config toggle, a hardcoded value. The comment there calls it "the whole security model," which is accurate. Want it reachable from another device? That's your own reverse proxy or VPN, deliberately not a flag you can flip.
How a prompt becomes a picture
People picture this part as mysterious and it isn't. It's a short, fixed pipeline that ComfyUI wires up from its official template:
Z-Image Turbo settings
Z-Image Turbo is the distilled, fast variant of Alibaba's Z-Image model (from what I understand it's out of their Tongyi Lab, roughly 6 billion parameters, Apache-2.0). "Distilled" means something concrete here: 8 steps and CFG 1.0 produce a finished image, instead of the 20–30+ steps older models want. These are the settings from my saved workflow, and they're just the official template defaults. No magic combination to hunt for.
| Setting | Value |
|---|---|
| Steps | 8 |
| CFG | 1.0 |
| Sampler | res_multistep |
| Scheduler | simple |
| ModelSamplingAuraFlow shift | 3 |
| Resolution | 1024×1024 |
| CLIPLoader type | lumina2 |
| Negative prompt | zeroed out (ConditioningZeroOut) |
That last row is worth explaining: at CFG 1.0 a negative prompt has nothing to push against, so the workflow zeroes it out with a ConditioningZeroOut node instead of encoding text that does nothing. Type a negative prompt if it makes you feel more in control. It won't change the image.
The three files doing the actual work:
| File | Size | Role |
|---|---|---|
| z_image_turbo_bf16.safetensors | 12.3GB | diffusion transformer (bf16) |
| qwen_3_4b.safetensors | 8.0GB | text encoder |
| ae.safetensors | 0.34GB | VAE |
Measured performance
These aren't numbers from a release blog post; they're from the journal on this machine. A run of 20 consecutive prompts logged times between 26.62s and 30.41s, so "~27 seconds" is a boring, repeatable average, not a best-case cherry pick. That works out to roughly 2.5–3 seconds per sampling step once you fold in text encoding and VAE decode.
The first image after a cold service start took 43.54 seconds, because that's the run where ~20GB of weights loads off disk. Everything after is warm. If your first image of the day feels sluggish, that's why, not a sign something's wrong.
Running it as a service
I don't want to babysit a Python process in a terminal every time I want an image, so this runs as a systemd user unit, started with the login session:
ExecStart=%h/comfy/start-comfyui.sh
WorkingDirectory=%h/comfy/ComfyUI
EnvironmentFile=-%h/comfy/comfy.env
Restart=on-failure
RestartSec=5
TimeoutStartSec=120
The env file keeps the port and extra launch args in one editable place. On top of that sits a small wrapper, comfyctl, so day-to-day use is:
comfyctl start # starts the service, waits for it to answer, opens the workflow
comfyctl status # server health + unit state + newest output file
comfyctl generate "a foggy harbor at dawn, cinematic"
comfyctl stop
comfyctl logs
If the process dies, Restart=on-failure brings it back after 5 seconds, up to 5 times a minute before systemd gives up (so a real crash loop doesn't spin forever). A weekly timer pulls updates with git pull --ff-only, restarts the service, and checks /system_stats before calling it a success. The desktop icon for this thing was generated by the model itself, which I like more than I probably should.
Doing it headless
The web UI is fine for one-offs, but the daily use here is scripted. A stdlib-only Python script builds the graph as JSON, posts it, polls for the result, and prints the path to the finished PNG:
python3 ~/comfy/comfy-generate.py "a foggy harbor at dawn, cinematic" \
--steps 8 --width 1024 --height 1024 --out ~/Pictures/harbor.png
The HTTP API, the control script, and secure remote access from other devices get a full write-up of their own: Headless ComfyUI: Run It as a Service, Use It from Anywhere.
Gotchas
- "cuda:0" in the logs is normal. ROCm's PyTorch reports the AMD GPU as a CUDA device. It's not a misconfiguration, and it's not secretly using an NVIDIA card.
- The first image after a restart is slow. ~43 seconds while weights load, then it settles to ~27. Don't restart mid-session and then panic that something broke.
- Negative prompts do nothing here. CFG 1.0 zeroes them out by design. If you're debugging a bad image, the negative prompt isn't where the problem is.
- You can't just open this to your phone. The listen address is hardcoded to 127.0.0.1 on purpose. Remote access means setting up your own reverse proxy or VPN, not editing a config file.
- It updates itself weekly. Handy until the week it isn't. The fast-forward-only pull stops silent merges, but a breaking upstream change can still land while you weren't watching.
- 64GB sounds like a lot until you load more. This workflow uses about 20.7GB of weights. Load several large models at once, or run something else GPU-hungry alongside, and the headroom disappears fast.