18 KiB
ComfyUI + Z-Image Turbo on AMD BC-250 — Complete Setup Guide¶
Hardware: AMD BC-250 (Cyan Skillfish, gfx1013→gfx1010, 24 CUs, shared RAM)
Backend: ROCm 7.2.0 / PyTorch 2.5.1+rocm6.2
OS: CachyOS, kernel 6.18.8-3-cachyos
ComfyUI Version: 0.15.1
Date: 2026-03-02
Table of Contents¶
- Overview
- Architecture
- Prerequisites
- Installation — Step by Step
- Model Setup
- Launch Script
- ComfyUI Workflow — Z-Image Turbo
- BC-250 Specific Tuning
- Troubleshooting
- File Inventory
- Performance Notes
1. Overview¶
ComfyUI is a node-based Stable Diffusion GUI that runs Z-Image Turbo (a Lumina2-architecture model) via PyTorch with ROCm/HIP on the AMD BC-250 GPU. The model uses a GGUF-quantized diffusion model (Q5_K_S) loaded via the ComfyUI-GGUF custom node, with a Gemma 2 2B text encoder and a Flux-compatible VAE.
What's Running¶
| Component | File | Size | Format |
|---|---|---|---|
| Diffusion Model | z_image_turbo-Q5_K_S.gguf |
5.2 GB | GGUF Q5_K_S |
| Text Encoder | gemma2_2b_lumina2.safetensors |
9.8 GB | Safetensors (f32) |
| VAE | ae.safetensors |
335 MB | Safetensors (f32) |
Pipeline¶
[ComfyUI WebUI :8188] → [PyTorch] → [ROCm/HIP] → [AMD BC-250 GPU]
↓
[Gemma 2 2B Text Encoder] → CLIP Encode → [Z-Image Turbo Diffusion] → [VAE Decode] → Image
2. Architecture¶
Z-Image Turbo Details¶
- Architecture: Lumina2 (Lumina-Image 2.0 family)
- Base: Z-Image by Freepik, turbo-distilled variant
- Text Encoder: Gemma 2 2B (Google, 2304-dim embeddings)
- VAE: Flux-compatible autoencoder (
ae.safetensors) - Sampler: Euler with SGM Uniform scheduler, 8 steps (turbo)
- CFG Scale: 3.0 (turbo models use low CFG)
- Latent Format: Flux-style latent space
Why GGUF?¶
The BC-250 has ~14.7 GB shared system RAM. The full FP16 diffusion model would be too large. GGUF Q5_K_S quantization reduces the model from ~12+ GB to 5.2 GB, making it feasible alongside the text encoder and VAE.
3. Prerequisites¶
Before starting, you need ROCm working on the BC-250. See ROCm_BC250_Documentation.md for the full ROCm setup.
Required¶
- ROCm 7.2.0 installed and working (
rocminfodetects BC-250) - Python 3.11 (
/usr/bin/python3.11) - Git
- ~30 GB free disk space
Verify ROCm¶
4. Installation — Step by Step¶
4.1 Clone ComfyUI¶
4.2 Create Python 3.11 Virtual Environment¶
Python 3.11 is required — Python 3.14 (system default) is too new for PyTorch ROCm wheels.
4.3 Install PyTorch with ROCm Support¶
This downloads ~4 GB. The ROCm 6.2 PyTorch wheel is compatible with the ROCm 7.2 runtime.
Verify installation:
python -c "import torch; print(torch.version.cuda); print(torch.cuda.is_available())"
# Should print: 6.2 and True
4.4 Install ComfyUI Dependencies¶
4.5 Install ComfyUI-GGUF Custom Node¶
This enables loading GGUF-quantized models in ComfyUI.
cd ~/ComfyUI/custom_nodes
git clone https://github.com/city96/ComfyUI-GGUF.git
source ~/ComfyUI/venv/bin/activate
pip install gguf
4.6 Install huggingface-hub (for model downloads)¶
5. Model Setup¶
5.1 Directory Structure¶
ComfyUI looks for models in ~/ComfyUI/models/. Our models live in ~/sd-models/ and are symlinked.
~/ComfyUI/models/
├── unet/
│ └── z_image_turbo-Q5_K_S.gguf → ~/sd-models/diffusion_models/z_image_turbo-Q5_K_S.gguf
├── text_encoders/
│ └── gemma2_2b_lumina2.safetensors (merged from 3 shards, 9.8 GB)
├── vae/
│ └── ae.safetensors → ~/sd-models/vae/ae.safetensors
└── ...
5.2 Symlink Diffusion Model (GGUF)¶
The Z-Image Turbo GGUF model must go in models/unet/ (ComfyUI-GGUF's UnetLoaderGGUF node reads from there):
ln -sf /home/dars/sd-models/diffusion_models/z_image_turbo-Q5_K_S.gguf \
~/ComfyUI/models/unet/z_image_turbo-Q5_K_S.gguf
5.3 Text Encoder — Gemma 2 2B¶
Z-Image Turbo uses the Gemma 2 2B text encoder from the Lumina-Image-2.0 family. The original model is sharded into 3 safetensors files. We merge them into a single file for ComfyUI.
Download from Alpha-VLLM (not gated, no login required):
source ~/ComfyUI/venv/bin/activate
python3 -c "
from huggingface_hub import hf_hub_download
import os
repo = 'Alpha-VLLM/Lumina-Image-2.0'
dest = os.path.expanduser('~/sd-models/text_encoders/lumina2_gemma2_2b')
os.makedirs(dest, exist_ok=True)
files = [
'text_encoder/config.json',
'text_encoder/model.safetensors.index.json',
'text_encoder/model-00001-of-00003.safetensors',
'text_encoder/model-00002-of-00003.safetensors',
'text_encoder/model-00003-of-00003.safetensors',
]
for f in files:
print(f'Downloading {f}...')
hf_hub_download(repo, f, local_dir=dest)
print('Done!')
"
Merge shards into single file:
source ~/ComfyUI/venv/bin/activate
python3 << 'EOF'
import safetensors.torch
import torch
import os, json
base_dir = os.path.expanduser("~/sd-models/text_encoders/lumina2_gemma2_2b/text_encoder")
output = os.path.expanduser("~/ComfyUI/models/text_encoders/gemma2_2b_lumina2.safetensors")
os.makedirs(os.path.dirname(output), exist_ok=True)
with open(os.path.join(base_dir, "model.safetensors.index.json")) as f:
index = json.load(f)
all_tensors = {}
shards = set(index["weight_map"].values())
print(f"Loading {len(shards)} shards with {len(index['weight_map'])} tensors...")
for shard in sorted(shards):
path = os.path.join(base_dir, shard)
print(f" Loading {shard}...")
tensors = safetensors.torch.load_file(path, device="cpu")
all_tensors.update(tensors)
print(f"Total tensors: {len(all_tensors)}")
print(f"Saving merged file...")
safetensors.torch.save_file(all_tensors, output)
print(f"Done! Size: {os.path.getsize(output)/1e9:.2f} GB")
EOF
Clean up shards (optional):
5.4 VAE¶
5.5 Verify All Models in Place¶
ls -lh ~/ComfyUI/models/unet/*.gguf \
~/ComfyUI/models/text_encoders/*.safetensors \
~/ComfyUI/models/vae/*.safetensors
Expected output:
9.8G ~/ComfyUI/models/text_encoders/gemma2_2b_lumina2.safetensors
5.2G ~/ComfyUI/models/unet/z_image_turbo-Q5_K_S.gguf (symlink)
335M ~/ComfyUI/models/vae/ae.safetensors (symlink)
6. Launch Script¶
Location: ~/start-comfyui.sh¶
#!/bin/bash
# =============================================================
# ComfyUI Launch Script for AMD BC-250 (ROCm / gfx1013)
# =============================================================
set -euo pipefail
echo "=========================================="
echo " ComfyUI — BC-250 ROCm Launcher"
echo "=========================================="
# --- GPU Health Check ---
if dmesg 2>/dev/null | tail -50 | grep -qi "KIQ fence timeout"; then
echo "[ABORT] KIQ fence timeout detected in dmesg — reboot required!"
exit 1
fi
echo "[OK] GPU health check passed"
# --- ROCm Environment for BC-250 (gfx1013 → gfx1010 spoof) ---
export HSA_OVERRIDE_GFX_VERSION=10.1.0
export HSA_ENABLE_SDMA=0
export HIP_VISIBLE_DEVICES=0
export ROCM_PATH=/opt/rocm
export HSA_TOOLS_LIB=""
export HSA_TOOLS_REPORT_LOAD_FAILURE=0
export PATH="/opt/rocm/bin:$PATH"
export LD_LIBRARY_PATH="/opt/rocm/lib"
# --- Unset old workaround variables that destroy performance ---
unset GPU_MAX_HW_QUEUES 2>/dev/null || true
unset HIP_LAUNCH_BLOCKING 2>/dev/null || true
unset GGML_CUDA_ENABLE_UNIFIED_MEMORY 2>/dev/null || true
unset GGML_HIP_HOST_ALLOC 2>/dev/null || true
unset GGML_CUDA_NO_PINNED 2>/dev/null || true
unset GGML_HIP_NO_COARSE_GRAIN 2>/dev/null || true
unset HSA_DISABLE_FRAGMENT_ALLOCATOR 2>/dev/null || true
# --- PyTorch ROCm tuning ---
export PYTORCH_HIP_ALLOC_CONF="expandable_segments:False"
echo "[OK] ROCm environment configured"
# --- Activate venv ---
cd ~/ComfyUI
source venv/bin/activate
# --- Launch ComfyUI ---
echo "[START] Launching ComfyUI on http://0.0.0.0:8188"
echo "=========================================="
python main.py \
--listen 0.0.0.0 \
--port 8188 \
--force-fp32 \
--lowvram \
"$@"
Usage¶
# Foreground (see logs):
bash ~/start-comfyui.sh
# Background with logging:
nohup bash ~/start-comfyui.sh > /tmp/comfyui.log 2>&1 &
# Check if running:
curl -s http://localhost:8188/system_stats | python3 -m json.tool
CLI Flags Explained¶
| Flag | Why |
|---|---|
--listen 0.0.0.0 |
Accept connections from any interface (access from other machines) |
--port 8188 |
Default ComfyUI port |
--force-fp32 |
BC-250 gfx1010 has limited FP16 support in PyTorch ROCm; FP32 prevents crashes |
--lowvram |
Enables aggressive model offloading — essential for 14.7 GB shared RAM |
7. ComfyUI Workflow — Z-Image Turbo¶
Access the WebUI¶
Open in browser: http://localhost:8188 (or http://<machine-ip>:8188 from another machine)
Pre-made Workflow¶
A ready-to-use workflow is saved at:
Load it via: Menu → Load → select z_image_turbo_bc250.json
Manual Node Setup¶
If building the workflow from scratch, create these nodes:
Node 1: UnetLoaderGGUF¶
- Type:
UnetLoaderGGUF(from ComfyUI-GGUF custom node, category: bootleg) - unet_name:
z_image_turbo-Q5_K_S.gguf - Output: MODEL → connect to KSampler's "model" input
Node 2: CLIPLoader¶
- Type:
CLIPLoader(built-in, category: advanced/loaders) - clip_name:
gemma2_2b_lumina2.safetensors - type:
lumina2← CRITICAL: must be set to lumina2 - Output: CLIP → connect to both CLIP Text Encode nodes
Node 3: CLIP Text Encode (Positive)¶
- Type:
CLIPTextEncode - text: Your prompt (e.g., "a beautiful sunset over the ocean")
- Input: clip ← from CLIPLoader
- Output: CONDITIONING → connect to KSampler's "positive" input
Node 4: CLIP Text Encode (Negative)¶
- Type:
CLIPTextEncode - text: Empty string
""(turbo models work best with empty negative) - Input: clip ← from CLIPLoader
- Output: CONDITIONING → connect to KSampler's "negative" input
Node 5: Empty Latent Image¶
- Type:
EmptyLatentImage - width:
512 - height:
512 - batch_size:
1 - Output: LATENT → connect to KSampler's "latent_image" input
Node 6: KSampler¶
- Type:
KSampler - seed: Any number (42)
- control_after_generate:
fixed(orrandomizefor variety) - steps:
8(turbo — more steps won't improve quality) - cfg:
3.0(turbo models use low CFG guidance) - sampler_name:
euler - scheduler:
sgm_uniform - denoise:
1.0 - Inputs: model, positive, negative, latent_image
- Output: LATENT → connect to VAEDecode
Node 7: VAELoader¶
- Type:
VAELoader - vae_name:
ae.safetensors - Output: VAE → connect to VAEDecode's "vae" input
Node 8: VAE Decode¶
- Type:
VAEDecode - Inputs: samples (from KSampler), vae (from VAELoader)
- Output: IMAGE → connect to SaveImage
Node 9: Save Image¶
- Type:
SaveImage - filename_prefix:
ComfyUI - Input: images ← from VAEDecode
- Output images saved to:
~/ComfyUI/output/
Wiring Summary¶
UnetLoaderGGUF ───MODEL──→ KSampler
CLIPLoader ───CLIP──→ CLIPTextEncode (positive) ──CONDITIONING──→ KSampler
CLIPLoader ───CLIP──→ CLIPTextEncode (negative) ──CONDITIONING──→ KSampler
EmptyLatentImage ──LATENT──→ KSampler
KSampler ──LATENT──→ VAEDecode
VAELoader ──VAE──→ VAEDecode
VAEDecode ──IMAGE──→ SaveImage
8. BC-250 Specific Tuning¶
Environment Variables (set in launch script)¶
| Variable | Value | Why |
|---|---|---|
HSA_OVERRIDE_GFX_VERSION |
10.1.0 |
BC-250 (gfx1013) needs gfx1010 spoof for ROCm |
HSA_ENABLE_SDMA |
0 |
SDMA engine has hardware bugs on gfx1013 |
HIP_VISIBLE_DEVICES |
0 |
Select the BC-250 GPU |
ROCM_PATH |
/opt/rocm |
ROCm installation path |
HSA_TOOLS_LIB |
"" |
Disable profiling tools (stability) |
HSA_TOOLS_REPORT_LOAD_FAILURE |
0 |
Suppress tool warnings |
PYTORCH_HIP_ALLOC_CONF |
expandable_segments:False |
Prevent memory fragmentation |
Variables to NEVER Set¶
These old workarounds destroy performance and must NOT be set:
| Variable | Why it's bad |
|---|---|
GPU_MAX_HW_QUEUES=1 |
Serializes all GPU ops to 1 queue |
HIP_LAUNCH_BLOCKING=1 |
Forces synchronous kernel launches |
GGML_CUDA_ENABLE_UNIFIED_MEMORY=1 |
Page fault overhead |
GGML_HIP_HOST_ALLOC=1 |
Zero-copy over PCIe is slow |
Memory Considerations¶
- Total available: ~14.7 GB shared system RAM
- Diffusion model (GGUF Q5_K_S): ~5.2 GB
- Text encoder (Gemma 2 2B f32): ~9.8 GB
- VAE: ~335 MB
- Total model footprint: ~15.3 GB — exceeds available RAM
--lowvramis essential: it offloads models to CPU when not in active use- Only one component is on GPU at a time during inference
Resolution Recommendations¶
| Resolution | Latent Size | Notes |
|---|---|---|
| 512×512 | 64×64 | Fastest, recommended for testing |
| 768×768 | 96×96 | Good quality, slower |
| 1024×1024 | 128×128 | May OOM on BC-250 |
9. Troubleshooting¶
"KIQ fence timeout" in dmesg → Reboot¶
If this appears, the GPU is in a bad state. Reboot the machine.ComfyUI won't start — "No module named torch"¶
Make sure you activated the venv:
"CLIP type not found" or wrong model type¶
Make sure the CLIPLoader node type is set to lumina2 — NOT stable_diffusion.
OOM (Out of Memory) during generation¶
- Reduce resolution to 512×512
- Ensure
--lowvramis set - Close other programs using RAM
- Try
--use-split-cross-attentionflag
Model not showing in dropdown¶
Verify symlinks are not broken:
ls -la ~/ComfyUI/models/unet/z_image_turbo-Q5_K_S.gguf
ls -la ~/ComfyUI/models/vae/ae.safetensors
ls -la ~/ComfyUI/models/text_encoders/gemma2_2b_lumina2.safetensors
"UnetLoaderGGUF" node not found¶
Ensure ComfyUI-GGUF is installed:
PyTorch ROCm version mismatch¶
10. File Inventory¶
Installation Files¶
| File | Purpose |
|---|---|
~/ComfyUI/ |
ComfyUI installation directory |
~/ComfyUI/venv/ |
Python 3.11 virtual environment |
~/ComfyUI/custom_nodes/ComfyUI-GGUF/ |
GGUF model loader custom node |
~/ComfyUI/workflows/z_image_turbo_bc250.json |
Pre-made Z-Image Turbo workflow |
~/start-comfyui.sh |
Launch script with ROCm env vars |
Model Files¶
| File | Size | Format |
|---|---|---|
~/ComfyUI/models/unet/z_image_turbo-Q5_K_S.gguf |
5.2 GB | Symlink → ~/sd-models/diffusion_models/ |
~/ComfyUI/models/text_encoders/gemma2_2b_lumina2.safetensors |
9.8 GB | Merged from Alpha-VLLM/Lumina-Image-2.0 |
~/ComfyUI/models/vae/ae.safetensors |
335 MB | Symlink → ~/sd-models/vae/ |
Output¶
| File | Purpose |
|---|---|
~/ComfyUI/output/ |
Generated images saved here |
Python Packages (key ones)¶
| Package | Version |
|---|---|
| torch | 2.5.1+rocm6.2 |
| torchvision | 0.20.1+rocm6.2 |
| torchaudio | 2.5.1+rocm6.2 |
| pytorch-triton-rocm | 3.1.0 |
| transformers | 5.2.0 |
| safetensors | 0.7.0 |
| gguf | 0.18.0 |
| comfyui-frontend-package | 1.39.19 |
11. Performance Notes¶
Startup Output (successful launch)¶
Total VRAM 14750 MB, total RAM 15205 MB
pytorch version: 2.5.1+rocm6.2
AMD arch: gfx1010
ROCm version: (6, 2)
Forcing FP32
Set vram state to: LOW_VRAM
Device: cuda:0 AMD Radeon Graphics : native
ComfyUI version: 0.15.1
ComfyUI-GGUF: Partial torch compile only, consider updating pytorch
Expected Timing (BC-250, 512×512, 8 steps)¶
| Phase | Estimated Time |
|---|---|
| Model Loading (first run) | 30-60s |
| Text Encoding (Gemma 2 2B) | ~2-5s |
| Sampling (8 steps, Euler) | ~60-90s |
| VAE Decode | ~10-15s |
| Total (first image) | ~2-3 min |
| Total (subsequent) | ~1-2 min |
Comparison with sdcpp-restapi¶
| ComfyUI + PyTorch | sdcpp-restapi | |
|---|---|---|
| Frontend | Full node-based GUI | REST API + simple WebUI |
| Model format | GGUF + safetensors | GGUF only |
| Memory management | PyTorch (--lowvram) | ggml manual |
| Flexibility | Full workflow customization | Fixed pipeline |
| Turbo steps | Configurable per-run | Config-based |
Appendix: Quick Start Cheatsheet¶
# 1. Launch ComfyUI
bash ~/start-comfyui.sh
# 2. Open browser
# http://localhost:8188
# 3. Load workflow
# Menu → Load → z_image_turbo_bc250.json
# 4. Click "Queue Prompt" to generate
# 5. Images saved in ~/ComfyUI/output/
Document generated: 2026-03-02 | System: CachyOS + AMD BC-250 + ROCm 7.2.0