z-image-turbo-p100a

Tongyi-MAI Z-Image-Turbo, ported to one Tenstorrent Blackhole p100a. Weights: Tongyi-MAI/Z-Image-Turbo (f332072) Β· Port: SunandBean/tt-z-image-turbo

Runs on p100a (mesh 1Γ—1). Configuration: Tensix (worker) dispatch, 1 command queue. The Qwen3-4B text encoder (35 layers), the DiT and the VAE all run on the card; only the scheduler and the image post-processing stay on the host.

What this port adds β€” the single-chip port itself, non-square splitting in the tt_dit VAE (which assumed square latents), and the standalone HTTP server and Hub weight resolution in code/. What it builds on β€” the changh95/qwen-image-2.1-p150 single-chip port, the tt-metal Z-Image demo and its tt_dit VAE, all Apache-2.0.

Quickstart (Python)

Prerequisite: a tt-metal / ttnn environment. ttnn is not on PyPI.

hf download sunandbean/z-image-turbo-p100a --include "code/*" --local-dir z-image-turbo-p100a && cd z-image-turbo-p100a
pip install -e code/                  # the Python API only
pip install -e "code/[server]"        # also the HTTP server (fastapi, uvicorn, pydantic)
from tt_z_image_turbo import ZImageTurboTT, open_device, close_device

dev = open_device()
try:
    model = ZImageTurboTT(dev)        # downloads Tongyi-MAI/Z-Image-Turbo@f332072 into your HF cache
    image, timing = model.generate("A croissant beside a cup of coffee, food photograph",
                                   width=1024, height=1024, seed=42)
    image.save("output.png")
    print(timing.values)
finally:
    close_device(dev)
Task Text to image only. There is no reference-image or editing path.
Size width / height 512–1920 px, 8 px steps, at most 1920Γ—1088 pixels. Sizes that are not a multiple of 16 are generated at the next multiple of 16 and center-cropped by up to 8 px per axis.
Steps Fixed at 9 scheduler steps (8 DiT forwards β€” the last sigma is 0).
Output (PIL.Image, Timing). Timing.values holds text_encoder_s, caption_s, dit_s, vae_decode_s.
Weights Tongyi-MAI/Z-Image-Turbo pinned to f332072aa78be7aecdf3ee76d5c247082da564a6, downloaded into the HF cache on first use. Z_IMAGE_SNAPSHOT points at a directory you manage instead.

The same prompt, size and seed reproduce the image pixel for pixel (verified by sha256 across runs).

Changing the size clears the program cache: conv2d keeps per-shape sliding-window configs in L1_SMALL inside cached programs, and after a few sizes they exhaust it. The model itself is not reloaded, so only the first image at a new size pays the compilation.

Serving (HTTP)

uvicorn tt_z_image_turbo.server:app --host 0.0.0.0 --port 20000
curl -s localhost:20000/predict -H 'Content-Type: application/json' \
  -d '{"prompt":"A croissant beside a cup of coffee, food photograph","width":1024,"height":1024,"seed":42}'
  • POST /predict: prompt, optional width (1024), height (1024), seed (42), num_steps (9). Returns image (base64 PNG), width, height, model, weights_revision, license, seed and timing_ms.
  • GET /health, GET /info.
  • Contract errors β€” a reference image, a step count other than 9, a size outside 512–1920 or off the 8-px grid β€” return 422 without touching the card.

Demo

All four were generated on the p100a through the HTTP server.

"A croissant beside a cup of coffee, food photograph" 1024Γ—1024, seed 42 "Portrait of a red fox in fresh snow, wildlife photography" 576Γ—1024, seed 9
"A cozy reading nook with a cat sleeping on a knitted blanket, warm afternoon light" 848Γ—624, seed 7 "λΉ„ μ˜€λŠ” λ°€ μ„œμšΈ 골λͺ©μ˜ λ”°λœ»ν•œ μ‘°λͺ…, μˆ˜μ±„ν™”" 512Γ—512, seed 3

Performance

Warm, batch 1, 9 steps, measured 2026-09-26 through the HTTP server on an idle p100a: Tensix (worker) dispatch, 1 command queue.

Metric 1024Γ—1024 512Γ—512 1920Γ—1080
End to end 7.76 s 1.44 s ~13 s
DiT (8 forwards) 6.24 s 1.09 s 10.2 s
VAE decode 1.20 s 0.30 s 2.6 s
Text encoder 0.05 s 0.05 s β€”
Caption projection 0.02 s 0.00 s β€”

A repeat of the same request took 7.73 s and produced a byte-identical PNG.

Model load 35.7 s (about 96 s for a full service start)
First image at a new size (compilation) 13–42 s; 40–60 s at 1920Γ—1080
Device DRAM after load 19.4 GB of 29.9 GB

From the published container

The same image anyone can tt-model pull, reached over its own HTTP server on an idle card (2026-10-09). Three requests at 1024Β², seed 42: the first compiles kernels for the shape, the rest are warm.

cold warm warm
End to end 38.85 s 7.68 s 7.68 s
DiT (8 forwards) 14.89 s 6.21 s 6.21 s
VAE decode 19.25 s 1.20 s 1.20 s

All three produced a byte-identical PNG (sha256 b10e7bb8d30b00b4, 1,283,985 bytes); seed 7 produced a different one, as it should.

Against an RTX 5070 Ti

The GPU runs the diffusers ZImagePipeline at bf16 β€” the reference implementation, not this port's precision configuration β€” with the same prompt, size, seed and 9-step schedule.

p100a RTX 5070 Ti
End to end, 1024Β² 7.68 s 22.8–24.9 s
Per DiT forward 0.776 s 1.578 s
Peak device memory 19.4 GB of 29.9 14.5 GB of 15.5

Read the end-to-end row carefully. Z-Image-Turbo at bf16 does not fit in 15.5 GB, so the GPU run offloads each stage onto the card as it is needed; the end-to-end figure includes that traffic. The per-forward figure does not β€” the transformer stays resident for the whole denoising loop β€” and it is the honest comparison: 2.0Γ— per DiT forward. The end-to-end gap is mostly a statement about 29.9 GB against 15.5 GB.

Accuracy

Against the diffusers reference run on CPU:

Size Final latent PCC Decoded image PCC
512Γ—512 0.9990 0.9987
848Γ—624 0.8948 0.8744

The 848Γ—624 figure is not a porting defect so much as a property of this model at that size: recomputing the same formula on CPU with nothing but different rounding already drops it to 0.985. The resulting images match in composition and quality and differ in fine detail.

Caveats

  • Single card only. Mesh 1Γ—1 with Tensix (worker) dispatch; no multi-chip scaling.
  • Text to image only. Reference images and editing are not supported and are rejected with 422.
  • 9 steps only. Other step counts are rejected.
  • At non-square sizes the latent PCC against the CPU reference falls to about 0.89–0.95. See Accuracy β€” the model is numerically sensitive at those shapes, and the images remain visually equivalent.
  • The official tt-metal Z-Image demo takes the text encoder's 36th-layer output and pads captions to a fixed 128 tokens, which does not match the upstream model. This port uses the 35th layer and the real caption length, so its output follows the original rather than the demo.
  • Sizes that are not a multiple of 16 are generated larger and center-cropped by up to 8 px per axis.
  • Changing the size clears the program cache, so the first image at each new size is slow.

Licensing

  • Weights: Tongyi-MAI/Z-Image-Turbo, Apache-2.0, revision f332072aa78be7aecdf3ee76d5c247082da564a6. Not redistributed here.
  • Port code (code/): Apache-2.0 (SPDX headers on the modules), from SunandBean/tt-z-image-turbo.
  • code/tt_z_image_turbo/vendor_tt_dit/: the tt_dit VAE from tt-metal at 01d6e7b (Apache-2.0), vendored because the runtime image ships only part of tt_dit. The only change is splitting support for non-square sizes.
  • Derived from the changh95/qwen-image-2.1-p150 single-chip port and the tt-metal Z-Image demo, both Apache-2.0.
  • code/THIRD-PARTY.md lists every directory under code/ that came from somewhere else, with its upstream commit and where its licence text sits in this repo.

Run it as a container

Everything below is generated by tt-model package from the manifest this image was built from.

tt-model pull  sunandbean/z-image-turbo-p100a --with-weights
tt-model serve sunandbean/z-image-turbo-p100a

pull --with-weights downloads the Docker image and the Tongyi-MAI/Z-Image-Turbo weights at f332072aa78be7aecdf3ee76d5c247082da564a6 (into your HF cache; they are not in the image). serve starts the model's own HTTP server on port 20000 (or the next free port, if that one is busy); the first start compiles kernels for your device, which takes several minutes, and the server is ready when it logs Application startup complete.

Request shape

POST /predict takes {"prompt": str, "width": int, "height": int, "seed": int} and returns {"image": base64 PNG, "width", "height", "model", "weights_revision", "license", "seed", "num_steps", "timing_ms"}. Dimensions must be multiples of 8 between 512 and 1920 and at most 1920x1088 pixels; anything else is a 422 and never touches the card. The turbo schedule fixes the step count at 9 (8 DiT forwards). GET /health reports load state and DRAM use.

Provenance

The exact sources the image was built from β€” the model code under code/ is byte-identical to what is inside the image (pyproject.toml, PYTHON.md and examples/ are packaging files this repo adds, and are not in the image):

component built from
tt-metal 58648d44443223041148125843ca7c7d4780463e
code/ digest 5482bf441850f764 (sha256, first 16 hex digits)
built 2026-10-10T02:31:46+00:00 by tt-model 0.1.0
Downloads last month

-

Downloads are not tracked for this model. How to track
Inference Providers NEW
This model isn't deployed by any Inference Provider. πŸ™‹ Ask for provider support

Model tree for sunandbean/z-image-turbo-p100a

Finetuned
(175)
this model