$

$ teds read --post from-prompt-to-pixels-qwen-image-diffusers-transformers

From Prompt to Pixels: Generate Images with Qwen-Image, Diffusers, and Transformers

A current text-to-image tutorial using Qwen-Image, Hugging Face Diffusers, and the latest Transformers stack, with reproducible prompts, aspect ratios, seeds, and a fast FLUX.1-schnell fallback.

From Prompt to Pixels: Generate Images with Qwen-Image, Diffusers, and Transformers

TL;DR

  • The old DeciDiffusion notebook is now a modern Diffusers tutorial built around Qwen/Qwen-Image.
  • Qwen-Image is a current Apache-2.0 text-to-image model with strong prompt following and unusually good text rendering.
  • You will install the latest Hugging Face stack, load the model with DiffusionPipeline, generate reproducible images, and use FLUX.1-schnell when you need a faster fallback.

Abstract

Text-to-image tutorials age quickly because the best model, pipeline class, scheduler defaults, and memory tricks change every few months. This post replaces an older DeciDiffusion notebook with a cleaner workflow based on Qwen/Qwen-Image, Hugging Face Diffusers, and the current Transformers ecosystem. You will learn how to set up the environment, choose safe generation defaults, control aspect ratio and seed, and save repeatable outputs from a Python script or notebook. By the end, you will have a practical baseline for prompt-to-image generation that you can adapt for product mockups, blog illustrations, signs, posters, and other text-heavy visuals.

Requirements

  • Python 3.10+
  • A CUDA GPU is strongly recommended
  • torch
  • diffusers>=0.38.0
  • transformers>=5.12.1
  • accelerate
  • safetensors
  • sentencepiece
  • protobuf
pip install -U torch "diffusers>=0.38.0" "transformers>=5.12.1" accelerate safetensors sentencepiece protobuf

If DiffusionPipeline cannot find the Qwen-Image pipeline class, install the newest Diffusers code from GitHub:

pip install -U git+https://github.com/huggingface/diffusers.git

Why Qwen-Image Now

The original notebook used Deci/DeciDiffusion-v1-0 and compared it with Stable Diffusion 1.5. That was useful at the time, but it is no longer the best default for a new tutorial.

For this update, the goal is not only “make an image.” The more useful target is:

  • a current Hugging Face model
  • native Diffusers support
  • a permissive license
  • strong prompt following
  • better rendering of text inside images
  • code that works with the current transformers package

Qwen/Qwen-Image fits that target well. It is a Diffusers text-to-image model released under Apache-2.0, and its model card emphasizes complex text rendering and precise image editing. That makes it a better default than older Stable Diffusion-era examples, especially if your prompt includes posters, labels, signs, UI mockups, or multilingual text.

There is one tradeoff: Qwen-Image is large. Use a CUDA machine when possible, enable CPU offload if memory is tight, and reach for black-forest-labs/FLUX.1-schnell when you need a faster few-step model.

How Diffusers and Transformers Fit Together

For image generation, you usually interact with Diffusers, not transformers.pipeline.

Diffusers owns the image-generation pipeline:

  • denoising transformer
  • scheduler
  • variational autoencoder (VAE)
  • prompt embedding flow
  • image decoding

Transformers still matters because modern image generators often depend on Transformer-based text encoders and tokenizers. Keeping transformers current helps the text side of the pipeline load cleanly, especially for newer model families.

Load Qwen-Image

from pathlib import Path

import torch
from diffusers import DiffusionPipeline

MODEL_ID = "Qwen/Qwen-Image"
OUTPUT_DIR = Path("outputs")
OUTPUT_DIR.mkdir(exist_ok=True)


def get_device_and_dtype() -> tuple[str, torch.dtype]:
    """Use CUDA with bfloat16 when available; otherwise fall back to CPU."""
    if torch.cuda.is_available():
        return "cuda", torch.bfloat16
    return "cpu", torch.float32


device, torch_dtype = get_device_and_dtype()

pipe = DiffusionPipeline.from_pretrained(
    MODEL_ID,
    torch_dtype=torch_dtype,
)

if device == "cuda":
    # Keeps peak VRAM lower than moving the whole pipeline to the GPU at once.
    pipe.enable_model_cpu_offload()
else:
    pipe = pipe.to(device)

The CPU path is there so the code is honest and importable on most machines. For real generation, use CUDA. Large text-to-image models can run on CPU, but the wait is usually not worth it.

Generate a Reproducible Image

Qwen-Image supports common aspect ratios. Start with a fixed seed and a normal number of inference steps, then tune after you have a baseline.

ASPECT_RATIOS = {
    "1:1": (1328, 1328),
    "16:9": (1664, 928),
    "9:16": (928, 1664),
    "4:3": (1472, 1140),
    "3:4": (1140, 1472),
    "3:2": (1584, 1056),
    "2:3": (1056, 1584),
}

STYLE_SUFFIX = ", Ultra HD, 4K, cinematic composition."


def slugify(text: str, max_length: int = 80) -> str:
    """Create a readable filename from a prompt."""
    chars = [char.lower() if char.isalnum() else "-" for char in text]
    slug = "".join(chars).strip("-")
    while "--" in slug:
        slug = slug.replace("--", "-")
    return slug[:max_length] or "image"


def generate_image(
    prompt: str,
    *,
    aspect_ratio: str = "16:9",
    seed: int = 42,
    steps: int = 50,
    true_cfg_scale: float = 4.0,
) -> Path:
    """Generate one image and save it to the outputs directory."""
    if aspect_ratio not in ASPECT_RATIOS:
        raise ValueError(f"Choose one of: {', '.join(ASPECT_RATIOS)}")

    width, height = ASPECT_RATIOS[aspect_ratio]
    generator_device = "cuda" if device == "cuda" else "cpu"
    generator = torch.Generator(device=generator_device).manual_seed(seed)

    result = pipe(
        prompt=prompt.strip() + STYLE_SUFFIX,
        negative_prompt=" ",
        width=width,
        height=height,
        num_inference_steps=steps,
        true_cfg_scale=true_cfg_scale,
        generator=generator,
    )

    image = result.images[0]
    output_path = OUTPUT_DIR / f"{slugify(prompt)}-{seed}.png"
    image.save(output_path)
    return output_path

Now try a prompt that stresses text rendering, layout, and composition:

prompt = (
    "A cozy coffee shop window at sunrise. A chalkboard sign on the door reads "
    "\"Qwen Coffee - Fresh Models Daily\". Warm light, plants near the window, "
    "soft reflections on the glass."
)

image_path = generate_image(prompt, aspect_ratio="16:9", seed=7)
print(image_path)

Prompt Examples Worth Testing

Good prompts describe the subject, the composition, and the parts that must not be lost. For text rendering, quote the exact words you want in the image.

prompts = [
    (
        "A travel poster for Amritsar at dawn. The Golden Temple reflects in calm "
        "water, and elegant small text at the bottom reads \"AMRITSAR\"."
    ),
    (
        "A clean product mockup for a reusable water bottle. The bottle label reads "
        "\"RAIN RIVER\" in crisp blue typography. Studio lighting, white background."
    ),
    (
        "A bookstore display table with a handwritten sign that reads "
        "\"New AI Books\". Warm interior lighting, shallow depth of field."
    ),
]

for index, prompt in enumerate(prompts, start=1):
    path = generate_image(prompt, aspect_ratio="4:3", seed=100 + index)
    print(path)

Use FLUX.1-schnell When Speed Matters

Qwen-Image is the main recommendation for this tutorial because it is current and strong at text-heavy prompts. If you want a fast, permissively licensed baseline, black-forest-labs/FLUX.1-schnell is still a great tool to keep nearby. It is an Apache-2.0, 12B rectified-flow model that can generate good images in one to four steps.

import torch
from diffusers import FluxPipeline

flux_pipe = FluxPipeline.from_pretrained(
    "black-forest-labs/FLUX.1-schnell",
    torch_dtype=torch.bfloat16,
)
flux_pipe.enable_model_cpu_offload()

prompt = "A cat holding a cardboard sign that says hello world"

image = flux_pipe(
    prompt=prompt,
    guidance_scale=0.0,
    num_inference_steps=4,
    max_sequence_length=256,
    generator=torch.Generator("cpu").manual_seed(42),
).images[0]

image.save("flux-schnell.png")

Use FLUX.1-schnell when you care most about fast iteration. Use Qwen-Image when the prompt includes readable text, poster-like layout, or multilingual visual details.

Practical Guidance

Start with a fixed seed. Change one thing at a time: prompt, seed, aspect ratio, steps, or guidance. If you change everything at once, you will not know what improved the image.

Keep text short. Image generators are better at a few exact words than a full paragraph of signage. If the words matter, put them in quotes inside the prompt and make the surrounding scene support the typography.

Use aspect ratio intentionally. A poster prompt usually wants 2:3 or 3:4; a hero image usually wants 16:9; a product shot often works well at 1:1 or 4:3.

Do not treat one image as the answer. Generate a small batch with different seeds, pick the strongest composition, then iterate on that prompt.

Failure Modes and Fixes

If the pipeline class is missing, your Diffusers version is behind the model. Upgrade Diffusers, and if needed install it from GitHub.

If CUDA runs out of memory, keep enable_model_cpu_offload() enabled, reduce the resolution, close other GPU processes, or run on a larger GPU. For fast drafts, switch to FLUX.1-schnell.

If text is misspelled, shorten the phrase, quote it, remove competing text from the prompt, and generate multiple seeds. Text rendering has improved a lot, but it is still probabilistic.

If images look generic, remove style clutter. Instead of stacking “cinematic, award-winning, ultra-realistic, trending” into every prompt, describe concrete objects, materials, lighting, and layout.

Sanity Check

Before you build on this workflow, verify that:

  • import diffusers and import transformers work in the same environment
  • DiffusionPipeline.from_pretrained("Qwen/Qwen-Image") resolves the pipeline
  • the first generated image is saved under outputs/
  • repeating the same prompt and seed gives you a comparable result
  • changing only the seed changes composition without changing the whole workflow

Summary

The biggest improvement over the old notebook is not just swapping one model name for another. The workflow is now built around a current Diffusers-native model, clear environment requirements, reproducible generation settings, and prompts that test what modern image models are actually good at. Qwen/Qwen-Image is the best default here because it is current, permissively licensed, and especially useful when your image needs legible text.

Next Steps

  • Try your own poster, product mockup, or blog hero prompt with three different seeds.
  • Compare the same prompt with Qwen/Qwen-Image and black-forest-labs/FLUX.1-schnell.
  • Move your best prompts into a small evaluation script so you can compare future models without rewriting the workflow.

Related reading:

If image generation is becoming part of a product, campaign, or demo workflow, talk to us. We can help with prompt systems, evaluation, safety checks, and the difference between a strong example and a repeatable process.

Resources