ArtificialGuyBR

Home / Blog / Models of 2026

Z-Image Turbo: Local Setup & Training

Learn to run Z-Image Turbo locally, build img2img and inpainting workflows in ComfyUI, and train character LoRAs with the ostris training adapter.

10 sources cited Models of 2026

TL;DR


Z-Image Turbo is a 6-billion-parameter distilled model from Tongyi-MAI that generates images in 8 NFEs (number of function evaluations) while matching or exceeding larger competitors on quality benchmarks. It ranks #1 among open-source models on the Artificial Analysis leaderboard and renders bilingual Chinese/English text natively. This guide covers local inference, ComfyUI img2img and inpainting workflows that avoid ControlNet, and a reproducible LoRA training recipe using the ostris de-distillation adapter.

Local inference setup

pip install git+https://github.com/huggingface/diffusers
import torch
from diffusers import ZImagePipeline

pipe = ZImagePipeline.from_pretrained(
    "Tongyi-MAI/Z-Image-Turbo",
    torch_dtype=torch.bfloat16,
).to("cuda")

prompt = "Young woman in red Hanfu, intricate embroidery, neon lightning-bolt lamp above palm, pagoda silhouette at night"

image = pipe(
    prompt=prompt,
    height=1024,
    width=1024,
    num_inference_steps=9,
    guidance_scale=0.0,
    generator=torch.Generator("cuda").manual_seed(42),
).images[0]

image.save("zimage_turbo.png")

Key settings: guidance_scale=0.0, num_inference_steps=9 (yields 8 forwards), bfloat16 on CUDA. The model fits in 16 GB VRAM; enable pipe.enable_model_cpu_offload() if you need to run on less.

Text encoder Qwen 3 Diffusion model z_image_turbo Sampler few steps VAE decode Distilled model: the guidance scale sits at 0 — there is no CFG pass to run. The three files live in different folders (text_encoders/, diffusion_models/, vae/); a "model not found" error is almost always a file in the wrong one.
Z-Image Turbo: what loads and in what order


ComfyUI img2img workflow (no ControlNet)

The Civitai community has converged on a lightweight img2img graph that controls input/output resolution without ControlNet. Start from the default ZiT Text to Image template and rewire as follows.

Nodes to add

Node | Purpose

|------|---------

Load Image | Source image input ImageScaleToMaxDimension | Resize to a max edge while preserving aspect ratio VAE Encode | Encode pixels to latent Repeat Latent Batch | Match batch size for KSampler

Connections

  1. Load VAEVAE input of VAE Encode
  2. Load ImageImage input of ImageScaleToMaxDimension
  3. ImageScaleToMaxDimensionPixels input of VAE Encode
  4. VAE EncodeSamples input of Repeat Latent Batch
  5. Repeat Latent Batchlatent_image input of KSampler

ImageScaleToMaxDimension defaults to 512 max edge; raise it to 1024 or 1536 for higher fidelity. Supported upscale_method values: area, lanczos, bilinear, nearest-exact, bicubic.

Denoise sweet spot

Community testing reports the best img2img results with denoise 0.75–0.90 on the KSampler: Denoise | Behavior | Source

|---------|----------|--------

< 0.75 | Strict adherence to source; only minor prompt-driven changes | https://civitai.com/articles/24793/lightweight-image-to-image-workflow-for-z-image-turbo-no-controlnet-wip 0.75 – 0.90 | Balanced: keeps composition, follows prompt strongly | https://civitai.com/articles/24793/lightweight-image-to-image-workflow-for-z-image-turbo-no-controlnet-wip

0.90 | Drifts toward pure text-to-image; source influence fades | https://civitai.com/articles/24793/lightweight-image-to-image-workflow-for-z-image-turbo-no-controlnet-wip

Lower denoise = more source fidelity; higher = more prompt adherence. Start at 0.85 and adjust.


ComfyUI inpainting workflow

Inpainting uses the VAE Encode (for inpainting) node, which accepts both the image and a mask. The same ImageScaleToMaxDimension node can drive resolution.

Nodes to add

Node | Purpose

|------|---------

Load Image | Source image + mask (alpha channel or separate mask input) VAE Encode (for inpainting) | Encodes pixels + mask to latent Repeat Latent Batch | Batch alignment for KSampler ImageScaleToMaxDimension (optional) | Resolution control

Connections

  1. Load ImagePixels + MaskVAE Encode (for inpainting)
  2. Load ImagePixelsImageScaleToMaxDimensionimageVAE Encode (for inpainting)
  3. Load VAEvaeVAE Encode (for inpainting)
  4. VAE Encode (for inpainting)Latent → **Repeat Latent BatchSamples`
  5. **Repeat Latent BatchLatent → **KSampler** → latent_image`

Optional: add the Image Compare node (via ComfyUI Manager) to preview image_a (scaled input) vs image_b (VAE Decode output) side-by-side.


Training a character LoRA with AI Toolkit

Z-Image Turbo is a distilled model; training a LoRA directly on it breaks the 8-step speed ("Turbo Drift"). The ostris zimage_turbo_training_adapter_v2 solves this: it is a 324 MB de-distillation LoRA trained on thousands of Z-Image Turbo outputs at lr 1e-5. You train your LoRA on top of this adapter, then **remove the adapter at inference` — your LoRA retains 8-step speed.

Prerequisites

Item | Spec | Source

|------|------|--------

GPU (NVIDIA) | 12 GB VRAM minimum, 24 GB recommended | https://kawaiipromptlab.com/en/tutorials/lora-training-guide/ GPU (Apple Silicon) | 32 GB unified minimum, 64 GB recommended | https://kawaiipromptlab.com/en/tutorials/lora-training-guide/ Disk | 50 GB free (100 GB recommended) | https://github.com/ostris/ai-toolkit Python | 3.10+ | https://github.com/ostris/ai-toolkit PyTorch | 2.0+ (2.8+ for MPS) | https://github.com/ostris/ai-toolkit Install AI Toolkit:

git clone https://github.com/ostris/ai-toolkit.git
cd ai-toolkit
git submodule update --init --recursive
pip install -r requirements.txt

Download the adapter:

huggingface-cli download ostris/zimage_turbo_training_adapter zimage_turbo_training_adapter_v2.safetensors
# Place in your weights folder, e.g. ./weights/zimage_turbo_training_adapter_v2.safetensors

Dataset preparation

Folder layout:

datasets/
└── my_character/
    ├── img_001.jpg
    ├── img_001.txt   # contains only: sks
    ├── img_002.jpg
    ├── img_002.txt   # contains only: sks
    └── ...

Training config (YAML)

Save as config/my_zimage_lora.yaml:

job: extension
config:
  name: "my_zimage_lora_v1"
  process:
    - type: "sd_trainer"
      training_folder: "output"
      device: "cuda:0"
      trigger_word: "sks"
      network:
        type: "lora"
        linear: 16
        linear_alpha: 16
      save:
        dtype: "float16"
        save_every: 250
        max_step_saves_to_keep: 4
      datasets:
        - folder_path: "/path/to/datasets/my_character"
          caption_ext: "txt"
          caption_dropout_rate: 0.05
          cache_latents_to_disk: true
          resolution: [512, 768, 1024]
      train:
        batch_size: 1
        steps: 3000
        gradient_accumulation_steps: 1
        train_unet: true
        train_text_encoder: false
        gradient_checkpointing: true
        noise_scheduler: "flowmatch"
        optimizer: "adamw8bit"
        lr: 1e-4
        ema_config:
          use_ema: true
          ema_decay: 0.99
        dtype: "bf16"
      model:
        name_or_path: "Tongyi-MAI/Z-Image-Turbo"
        arch: "zimage"
        assistant_lora_path: "./weights/zimage_turbo_training_adapter_v2.safetensors"
        quantize: true
      sample:
        sampler: "flowmatch"
        sample_every: 250
        width: 1024
        height: 1024
        prompts:
          - "sks, portrait photo, natural lighting"
        seed: 42
        guidance_scale: 1
        sample_steps: 8

Apple Silicon (MPS) adjustments: change device: &quot;mps:0&quot;, optimizer: &quot;adamw&quot; (adamw8bit is CUDA-only), quantize: false, add num_workers: 0 under datasets.

Run training

cd ai-toolkit
python run.py config/my_zimage_lora.yaml

Expected wall-clock times (3,000 steps): Hardware | Time | Source

|----------|------|--------

RTX 5090 (RunPod) | ~15–22 min ($0.89/hr) | https://x.com/ostrisai/status/1995504226295009558 RTX 4090 | ~8–12 hours | https://kawaiipromptlab.com/en/tutorials/lora-training-guide/ Apple M4 Pro (64 GB) | ~21 hours | https://kawaiipromptlab.com/en/tutorials/lora-training-guide/ Monitor loss decay and sample images every 250 steps. Stop early if identity stabilizes; push to 5,000 steps only with clean data and captions.

Inference with the trained LoRA

ComfyUI: place my_zimage_lora_v1.safetensors in ComfyUI/models/loras/, add a Load LoRA node between the model loader and KSampler, set strength 0.8–1.0.

Python (Diffusers):

from diffusers import ZImagePipeline
import torch

pipe = ZImagePipeline.from_pretrained(
    "Tongyi-MAI/Z-Image-Turbo",
    torch_dtype=torch.bfloat16,
).to("cuda")

pipe.load_lora_weights("./output/my_zimage_lora_v1.safetensors", adapter_name="character")
pipe.set_adapters(["character"], adapter_weights=[0.9])

image = pipe(
    prompt="sks, portrait photo, natural lighting, 85mm lens",
    num_inference_steps=9,
    guidance_scale=0.0,
    width=1024,
    height=1024,
    generator=torch.Generator("cuda").manual_seed(42),
).images[0]
image.save("lora_result.png")

Critical: do not load the training adapter at inference. Your LoRA alone preserves the distilled 8-step speed.


Sources

URL | Contribution

|-----|--------------

https://github.com/Tongyi-MAI/Z-Image/blob/main/README.md | Z-Image Turbo model specs: 6B parameters, 8 NFEs, bilingual text rendering, sub-second latency https://huggingface.co/ostris/zimage_turbo_training_adapter | Training adapter v2: 324 MB de-distillation LoRA, essential for LoRA training https://huggingface.co/blog/content-and-code/training-a-lora-for-z-image-turbo | LoRA training config template, single-word captions for Z-Image Turbo https://kawaiipromptlab.com/en/tutorials/lora-training-guide/ | Training recommendations: 70–80 images for character LoRAs, 1024×1024 resolution https://docs.comfy.org/built-in-nodes/ImageScaleToMaxDimension | ComfyUI node documentation for resolution control in img2img/inpainting https://github.com/ostris/ai-toolkit | AI Toolkit installation, YAML config format, training scheduler settings https://x.com/ostrisai/status/1995504226295009558 | Training time benchmarks: 15–22 min on RTX 5090, $0.89/hr https://civitai.com/articles/23863/z-image-turbo-lora-training-setup-full-precision-adapter-v2-massive-quality-jump | Full precision training benefits, v2 adapter quality improvements https://civitai.com/articles/24764/simple-inpainting-workflow-for-z-image-turbo-comfyui | Inpainting workflow node connections (VAE Encode for inpainting) https://civitai.com/articles/24793/lightweight-image-to-image-workflow-for-z-image-turbo-no-controlnet-wip | img2img workflow: denoise 0.75–0.90 sweet spot, ImageScaleToMaxDimension usage


Common errors and fixes

Symptom | Likely cause | Fix | Source

|---------|--------------|-----|--------

LoRA has no visible effect | Trigger word missing or misspelled in prompt | Use exact trigger token from captions (e.g., sks) | https://huggingface.co/blog/content-and-code/training-a-lora-for-z-image-turbo Faces look melted / "mushy" | Over-captioning (descriptive sentences) | Switch to single-word captions; re-train | https://huggingface.co/blog/content-and-code/training-a-lora-for-z-image-turbo VRAM OOM on 12–16 GB cards | quantize: true not set, or batch > 1 | Enable quantization, batch_size: 1, gradient_checkpointing: true | https://github.com/ostris/ai-toolkit Training stalls at step 0 | Adapter path wrong or file missing | Verify assistant_lora_path points to zimage_turbo_training_adapter_v2.safetensors | https://huggingface.co/ostris/zimage_turbo_training_adapter Generated images ignore prompt | Denoise too low (< 0.7) on img2img | Raise KSampler denoise to 0.75–0.90 | https://civitai.com/articles/24793/lightweight-image-to-image-workflow-for-z-image-turbo-no-controlnet-wip Inpainting ignores mask | Mask not connected to VAE Encode (for inpainting) | Wire Load ImageMaskVAE Encode (for inpainting) | https://civitai.com/articles/24764/simple-inpainting-workflow-for-z-image-turbo-comfyui LoRA file huge (> 500 MB) | Rank set too high (e.g., 64) | Use linear: 16, linear_alpha: 16 | https://huggingface.co/blog/content-and-code/training-a-lora-for-z-image-turbo Training adapter not downloaded | Used v1 URL instead of v2 | Download zimage_turbo_training_adapter_v2.safetensors (324 MB) from ostris repo | https://huggingface.co/ostris/zimage_turbo_training_adapter


FAQ

How many images do I need for a character LoRA? 15+ images and 1,000+ steps for a working test; 70–80 images at 1024×1024 for production quality that reproduces skin texture.

What denoise value should I use for img2img? Start at 0.85. Below 0.75 keeps the source nearly unchanged; above 0.90 drifts toward pure text-to-image.

Do I need ControlNet for img2img or inpainting? No. The lightweight workflows above use only native ComfyUI nodes (ImageScaleToMaxDimension, VAE Encode, Repeat Latent Batch) and match ControlNet-style control for most use cases.

Why does my LoRA training produce artifacts after 4,000+ steps? The training adapter's de-distillation effect wears off over long runs. Stay at 3,000 steps unless you have pristine data and captions; beyond 5,000 steps distillation breakdown causes artifacts.

Can I train on Apple Silicon? Yes. Use device: mps:0, optimizer: adamw, quantize: false, num_workers: 0. Expect ~21 hours for 3,000 steps on M4 Pro 64 GB.

What resolution should I train at? Multi-resolution buckets [512, 768, 1024] with 1024×1024 as the target. The 512 bucket is the training bucket size, not a downscale of your dataset.

Is fp32 (full precision) required? Community reports fp32 saves eliminate hallucinations and boost quality at 5,000+ steps. If VRAM allows, keep quantize: false and save in fp32; otherwise bf16 with quantization is the practical default.

How do I remove the training adapter at inference? Simply don't load it. Your trained LoRA is the only extra weight you load on top of the base Z-Image Turbo model.