Vai al contenuto principale

Tutorial Qwen Image 2512: crea uno Studio Poster con Gradio

Impara a creare un'app Gradio Poster Studio con Qwen-Image-2512 che genera creatività per e-commerce con tipografia solida, layout pulito e scene di prodotto fotorealistiche.
· 7 min leggi

Scopri con l'IA

Qwen-Image-2512 è un potente modello open-source di text-to-image particolarmente efficace con visual realistici e composizioni ricche di testo. In questo tutorial lo useremo per costruire uno Studio Poster, un'app Gradio dove inserisci i dettagli del prodotto come nome, offerta, prezzo, CTA e vantaggi, scegli un rapporto d’aspetto per la piattaforma e generi un’immagine promozionale con un solo clic.

Dato che Qwen-Image-2512 è un modello grande, ci concentreremo anche sul lato pratico dell’esecuzione in modo fluido. Imparerai a caricarlo in modo stabile su una A100 usando le impostazioni di precisione corrette, evitare modalità di errore comuni e adattarti a qualsiasi workflow iterando a risoluzioni più piccole, riducendo gli step o esplorando un modello quantizzato per hardware più limitato.

Cos’è Qwen-Image-2512?

Qwen-Image-2512 è un aggiornamento del modello base di text-to-image Qwen, con un salto di qualità rispetto alla precedente release Qwen-Image. Sotto il cofano, Qwen-Image è un modello di diffusione MMDiT da 20B, progettato per una forte aderenza ai prompt e il rendering di testo nelle immagini.

È supportato anche da una valutazione su larga scala in stile preferenza con oltre 10.000 round ciechi su AI Arena, dove il modello si è distinto come il migliore open-source, restando competitivo con i sistemi chiusi.

image2.png

I tre upgrade che contano di più nei flussi di lavoro reali sono:

  • Ritratti umani più realistici: i volti sembrano meno “da IA”, con tratti più definiti, pelle più naturale e realismo complessivamente migliore.
  • Trame naturali più ricche: scene ricche di texture come paesaggi, acqua, pelliccia e materiali sono renderizzate con dettagli più fini e micro-texture più convincenti.
  • Tipografia e layout più solidi: il rendering del testo è più accurato e le composizioni sono più simili a pagine, particolarmente utili per poster, slide, banner e infografiche.

Progetto d’esempio con Qwen Image 2512: crea uno Studio Poster

In questa sezione creeremo una semplice app Gradio che:

  • Raccoglie nome prodotto, descrizione, offerta, prezzo, CTA e vantaggi
  • Permette di scegliere un preset di piattaforma come post/storia Instagram, banner, poster o slide
  • Fornisce un pannello per steps, true_cfg_scale, seed e un negative prompt opzionale.
  • Infine, genera un’immagine poster usando QwenImagePipeline.

image4.png

Costruiamola passo dopo passo.

Passaggio 1: Prerequisiti

Per prima cosa, installa l’ultima versione di Diffusers da GitHub (la model card di Qwen lo consiglia per il supporto della pipeline) insieme alle dipendenze principali:

!pip -q install --upgrade pip
!pip -q install git+https://github.com/huggingface/diffusers
!pip -q install transformers accelerate safetensors gradio pillow psutil

Poi fai un rapido sanity check per confermare che CUDA sia disponibile e per identificare la GPU:

import torch, diffusers
print("diffusers:", diffusers.__version__)
print("CUDA available:", torch.cuda.is_available())
!nvidia-smi

Se vedi CUDA available: True e la tua GPU in nvidia-smi, sei pronto a caricare il modello.

Nota: QwenImagePipeline non è un unico blocco in stile UNet. In Diffusers è uno stack completo che comprende un text encoder Qwen2.5-VL-7B-Instruct, il trasformatore di diffusione MMDiT e un Variational Auto-Encoder (VAE) per il decoding. Il text encoder 7B è un motivo importante per cui RAM/VRAM possono impennarsi durante il caricamento del modello e la generazione, specialmente su GPU più piccole. 

Ho eseguito questo tutorial su Google Colab con una A100, che gestisce comodamente una risoluzione di immagine di 1328×1328 a ~50 step. Su GPU della classe T4/16GB, in genere devi ridimensionare (a circa 768×768 e meno step) o usare varianti quantizzate tramite runtime alternativi (come GGUF/ComfyUI).

Passaggio 2: Import e utility di base

Prima di caricare il modello, vale la pena impostare un piccolo harness di runtime che renda Colab prevedibile. Qwen-Image-2512 è pesante e i carichi di lavoro di generazione immagini possono consumare silenziosamente sia RAM di sistema che memoria GPU. 

import os, gc, random, psutil, torch
from diffusers import QwenImagePipeline
import gradio as gr
os.environ["HF_HOME"] = "/content/hf"
os.makedirs("/content/hf", exist_ok=True)
def mem(tag=""):
    ram = psutil.virtual_memory().used / 1e9
    v_alloc = torch.cuda.memory_allocated()/1e9 if torch.cuda.is_available() else 0
    v_res   = torch.cuda.memory_reserved()/1e9 if torch.cuda.is_available() else 0
    print(f"[{tag}] RAM={ram:.1f}GB | VRAM alloc={v_alloc:.1f}GB reserved={v_res:.1f}GB")
def cleanup(tag="cleanup"):
    gc.collect()
    if torch.cuda.is_available():
        torch.cuda.empty_cache()
    mem(tag)
assert torch.cuda.is_available(), "GPU runtime required"
print("GPU:", torch.cuda.get_device_name(0))
torch.backends.cuda.matmul.allow_tf32 = True
torch.set_float32_matmul_precision("high")
cleanup("startup")

Una volta installate le dipendenze, impostiamo import, caching, monitoraggio della memoria e un paio di flag di performance per la GPU. Ecco cosa fa il codice:

  • QwenImagePipeline: è la classe di pipeline principale che useremo più avanti per caricare ed eseguire Qwen-Image-2512 per la generazione di immagini.
  • gradio: questa libreria alimenta la semplice UI web così possiamo generare poster dentro Colab.
  • HF_HOME=/content/hf: lo usiamo per fissare la cache di Hugging Face in una cartella nota, così download e pesi sono archiviati in modo coerente tra le esecuzioni.
  • Funzione mem(): tiene traccia della RAM di sistema e della VRAM GPU allocata vs riservata. 
  • Funzione cleanup(): una piccola utility di reset per liberare i riferimenti Python e rilasciare la memoria GPU in cache, utile quando si itera su risoluzione/step.
  • Controlli GPU: falliamo subito se CUDA non è disponibile, poi abilitiamo TF32 e impostiamo la precisione di matmul su "high" per accelerare le moltiplicazioni di matrici su GPU Ampere come A100.

Questo setup non genera ancora immagini, ma rende i prossimi passaggi (caricamento e inferenza) molto più stabili e facili da fare debug.

Passaggio 3: Caricare Qwen-Image-2512 

Ora che il runtime è impostato, è il momento di caricare il modello in una pipeline Diffusers. Su una A100, il punto ideale è eseguire la maggior parte dei pesi in BF16 per le performance, mantenendo però il decoding del VAE in FP32 per evitare NaN che possono apparire come immagini completamente nere.

DTYPE = torch.bfloat16 
pipe = QwenImagePipeline.from_pretrained(
    "Qwen/Qwen-Image-2512",
    torch_dtype=DTYPE,
    low_cpu_mem_usage=True,
    use_safetensors=True,
).to("cuda")
if hasattr(pipe, "vae") and pipe.vae is not None:
    pipe.vae.to(dtype=torch.float32)
cleanup("after pipe load")

Ecco cosa vogliamo ottenere con il codice qui sopra:

  • Su GPU Ampere/Hopper (A100/H100), BF16 è di solito la scelta migliore perché è più veloce e più efficiente in memoria rispetto a FP32, ed è più stabile numericamente di FP16 per modelli grandi.
  • Poi carichiamo l’intera pipeline Qwen-Image-2512 da Hugging Face e colleghiamo i componenti del modello in un’unica interfaccia richiamabile. Usiamo alcuni argomenti chiave:
    • torch_dtype=DTYPE: carica la maggior parte dei pesi in BF16 per ridurre la VRAM e accelerare l’inferenza.
    • low_cpu_mem_usage=True: riduce la duplicazione lato CPU durante il caricamento (importante per checkpoint grandi).
    • use_safetensors=True: garantisce l’uso del formato safetensors, più sicuro/veloce quando disponibile.
  • Infine, pipe.vae.to(torch.float32) converte le uscite nello spazio latente in pixel. Se quel passaggio di decode incappa in NaN/Inf a precisione più bassa, l’immagine finale può diventare tutta nera. Quindi forziamo il VAE a FP32, seguito da una chiamata a cleanup() per confermare l’impronta di RAM/VRAM dopo il caricamento.

Ora definiremo i preset di rapporto d’aspetto delle piattaforme e collegheremo la pipeline a una UI Gradio minimale per la generazione interattiva dei poster.

Passaggio 4: Preset e funzione di generazione immagine

Ora costruiamo il motore della demo, cioè un piccolo layer che trasforma gli input della UI in un prompt ben strutturato, sceglie una risoluzione di output in base ai preset di piattaforma e chiama la pipeline Qwen Image per generare un’immagine. 

ASPECT_PRESETS = {
    "Instagram Post (1:1) — 1328×1328": (1328, 1328),
    "Instagram Story (9:16) — 928×1664": (928, 1664),
    "YouTube / Banner (16:9) — 1664×928": (1664, 928),
    "Poster (3:4) — 1104×1472": (1104, 1472),
    "Slides (4:3) — 1472×1104": (1472, 1104),
    "Fast Draft (1:1) — 768×768": (768, 768),
}
DEFAULT_NEG = " " 
def build_prompt(product_name, product_desc, offer, price, cta, benefits, tone, style_keywords, language):
    return f"""
Create a high-converting e-commerce promotional poster in {language}. Clean grid layout, strong hierarchy.
- Product name: "{product_name}"
- Product description: "{product_desc}"
- Offer headline (exact): "{offer}"
- Price (exact): "{price}"
- CTA button text (exact): "{cta}"
- Benefits (use these exact phrases, no typos):
{benefits}
- Tone: {tone}
- Style keywords: {style_keywords}
- Text must be legible and correctly spelled.
- Do not add extra words, fake prices, or random letters.
- Align typography to a neat grid with consistent margins.
""".strip()
@torch.inference_mode()
def generate_image(product_name, product_desc, offer, price, cta, benefits, tone, style_keywords,
                   language, preset, negative_prompt, steps, true_cfg_scale, seed, show_seed):
    w, h = ASPECT_PRESETS[preset]
    prompt = build_prompt(product_name, product_desc, offer, price, cta, benefits, tone, style_keywords, language)
    if seed is None or int(seed) < 0:
        seed = random.randint(0, 2**31 - 1)
    seed = int(seed)
    gen = torch.Generator(device="cuda").manual_seed(seed)
    img = pipe(
        prompt=prompt,
        negative_prompt=negative_prompt,
        width=int(w),
        height=int(h),
        num_inference_steps=int(steps),
        true_cfg_scale=float(true_cfg_scale),
        generator=gen,
    ).images[0].convert("RGB")
    return (seed if show_seed else None), img

La mappa dei preset e le due funzioni qui sopra costituiscono il motore del nostro Poster Studio.

  • Il dizionario ASPECT_PRESETS definisce diverse dimensioni canvas per piattaforme (es. 1:1 per i post Instagram, 9:16 per le Storie, 16:9 per i banner). L’utente sceglie un preset e noi lo traduciamo nelle corrette width × height per la generazione.
  • La funzione build_prompt() trasforma input semplici del prodotto come nome, offerta, prezzo, CTA e vantaggi in un brief per l’immagine. Considera layout e regole del testo, così il modello riceve vincoli coerenti ogni volta e non deraglia con copy casuali.
  • La funzione generate_image() è il layer di esecuzione. Legge il preset scelto per ottenere width/height e chiama la pipeline Qwen-Image con steps, true_cfg_scale e negative_prompt selezionati. Infine restituisce il poster generato (e facoltativamente il seed). Gli steps controllano la durata del processo di diffusione (più step significa più lento ma in genere risultati più puliti), mentre true_cfg_scale controlla quanto il modello segue il prompt (valori più alti migliorano l’aderenza, ma troppo alti possono introdurre artefatti).

Ora incorporeremo la funzione generate_image() in un’interfaccia Gradio così gli utenti possono generare poster senza dover fare prompt engineering a mano.

Passaggio 5: UI Gradio

Infine impacchettiamo il motore di generazione dei poster in un’interfaccia Gradio. L’app consente di digitare i dettagli del prodotto, scegliere un rapporto d’aspetto per la piattaforma e premere Generate. 

with gr.Blocks(title="Qwen Poster Studio (Simple)") as demo:
    gr.Markdown("## Qwen Poster Studio — Qwen-Image-2512")
    with gr.Row():
        with gr.Column(scale=1):
            product_name = gr.Textbox(value="RÅSKOG Utility Cart", label="Product name")
            product_desc = gr.Textbox(value="Compact rolling cart for small spaces. Durable metal frame.", lines=2, label="Product description")
            offer = gr.Textbox(value="NEW YEAR SALE — 20% OFF", label="Offer headline")
            price = gr.Textbox(value="$29.99", label="Price")
            cta = gr.Textbox(value="Shop now", label="CTA button text")
            benefits = gr.Textbox(value="- Compact\n- Easy to move\n- Fits small spaces", lines=4, label="Benefits")
            tone = gr.Dropdown(["Premium", "Minimal", "Bold", "Playful", "Tech"], value="Premium", label="Tone")
            style_keywords = gr.Textbox(value="modern Scandinavian minimal, clean grid, soft warm lighting, premium product photography", label="Style keywords")
            language = gr.Dropdown(["English", "中文"], value="English", label="Language")
            preset = gr.Dropdown(list(ASPECT_PRESETS.keys()), value="Instagram Post (1:1) — 1328×1328", label="Platform preset")
            with gr.Accordion("Advanced (optional)", open=False):
                negative_prompt = gr.Textbox(value=DEFAULT_NEG, label="Negative prompt", lines=2)
                steps = gr.Slider(10, 80, value=50, step=1, label="Steps")
                true_cfg_scale = gr.Slider(1.0, 10.0, value=4.0, step=0.1, label="true_cfg_scale")
                seed = gr.Number(value=-1, precision=0, label="Seed (-1 = random)")
                show_seed = gr.Checkbox(value=False, label="Show seed in output")
            btn = gr.Button("Generate", variant="primary")
        with gr.Column(scale=1):
            used_seed_out = gr.Number(label="Used seed (optional)", precision=0)
            image_out = gr.Image(label="Generated poster")
    btn.click(
        fn=generate_image,
        inputs=[product_name, product_desc, offer, price, cta, benefits, tone, style_keywords,
                language, preset, negative_prompt, steps, true_cfg_scale, seed, show_seed],
        outputs=[used_seed_out, image_out]
    )
demo.launch(share=True, debug=True)

Ecco come costruiamo l’app Gradio:

  • La colonna a sinistra definisce tutti i controlli interattivi per il brief del poster. L’utente compila i campi del prodotto, poi sceglie un tono, aggiunge parole chiave di stile, seleziona una lingua e un preset di piattaforma. Il preset è importante perché mappa direttamente sulle dimensioni finali width × height usando ASPECT_PRESETS.
  • I controlli “Advanced” includono parametri chiave come steps e true_cfg_scale, che regolano rispettivamente quante iterazioni di denoising esegue il modello e quanto fortemente il modello segue il prompt. Il seed controlla la riproducibilità e show_seed mostra facoltativamente il seed finale.
  • La colonna a destra contiene l’immagine del poster generato e, facoltativamente, il seed usato per quella generazione.
  • Infine, la chiamata btn.click() collega tutto. Gradio prende tutti i widget di input in ordine, li passa a generate_image() e inoltra i valori restituiti ai widget di output. Infine, demo.launch(share=True, debug=True) avvia il server Gradio, ci fornisce un link pubblico condivisibile per le demo e stampa i log di debug nel notebook per aiutare a diagnosticare i problemi.

Ecco un video che mostra la nostra app finale Qwen Image 2512 in azione:

Conclusione

Qwen-Image-2512 è adatto sia per generare visual fotorealistici sia per layout affidabili ricchi di testo. In questo tutorial abbiamo costruito uno Studio Poster end-to-end sopra Diffusers. Abbiamo caricato il modello su una A100, aggiunto i preset di rapporto d’aspetto per le piattaforme e impacchettato tutto in una UI Gradio che trasforma semplici input di prodotto in creatività e-commerce rifinite.

Se lavori su GPU più piccole, lo stesso workflow si applica comunque: itera a risoluzione 768×768, riduci gli step e valuta runtime quantizzati quando devi scalare.

Qwen-Image-2512 FAQ

Posso eseguire Qwen-Image-2512 su una GPU consumer (come una RTX 4090)?

Sì, ma probabilmente non riuscirai a eseguire l’intero modello alla precisione originale. La versione completa in BF16 richiede circa 48 GB+ di VRAM, il che la rende fuori portata per le schede consumer standard (anche la RTX 4090 da 24 GB). Tuttavia, puoi eseguirla su schede da 24 GB usando la quantizzazione FP8 o formati GGUF (simile a come si esegue Llama 3 in locale). Per schede da 16 GB, quasi certamente dovrai usare varianti GGUF a 4 bit (Q4_K_M) per far entrare il modello in memoria senza crash.

Qwen-Image-2512 è gratuito per uso commerciale?

Sì. A differenza di alcuni concorrenti che usano licenze comunitarie restrittive "solo per ricerca" o "non commerciali", Qwen-Image-2512 è stato rilasciato con licenza Apache 2.0. In generale questo ti consente di usare il modello per applicazioni commerciali, integrarlo in prodotti e costruire servizi (come questo Poster Studio) senza pagare royalty, a patto di rispettare i termini della licenza.

Come si confronta con FLUX.2?

Sono concorrenti con punti di forza diversi.

  • FLUX.2 (e FLUX.1 Pro) è generalmente considerato il re di fotorealismo ed estetica. Se ti servono “vibes”, stile artistico o risoluzione nativa 4MP per fotografia, FLUX.2 è di solito superiore.
  • Qwen-Image-2512 vince su rendering del testo e rispetto delle istruzioni. Poiché usa un enorme text encoder da 7B parametri, segue layout di prompt complessi ("metti il testo X qui, fai il pulsante Y lì") con molta più accuratezza rispetto a FLUX. È anche migliore con il testo bilingue (cinese/inglese) e nel generare immagini di tipo documentale (poster, grafici, fatture).
Devo installare Diffusers dalla sorgente?

Sì, per Qwen-Image-2512, la stessa model card indica di installare Diffusers da GitHub per il supporto più recente della pipeline.

`guidance_scale` è il parametro giusto?

Non per Qwen-Image al momento. Nell’integrazione corrente di Diffusers, guidance_scale è sostanzialmente un placeholder, quindi non fornirà classifier-free guidance. Per questo abbiamo usato true_cfg_scale insieme a un negative_prompt (anche solo uno spazio " ") per controllare la guidance. Un true_cfg_scale più alto aumenta l’aderenza al prompt, ma spingerlo troppo in alto può introdurre artefatti.

Qual è la dimensione del modello Qwen-Image-2512?

Secondo il repo HF, la dimensione di Qwen-Image-2512 è di circa 57,7 GB, piuttosto grande per l’inferenza locale.

Perché l’uso di memoria è così alto?

L’uso di memoria è elevato perché la pipeline include un grande text encoder (Qwen2.5-VL-7B Instruct) insieme al trasformatore di diffusione e al Variational Auto-Encoder (VAE).

Aashi Dutt

Autore

Aashi Dutt

Sono una Google Developers Expert in ML (Gen AI), una Kaggle 3x Expert e una Women Techmakers Ambassador con oltre 3 anni di esperienza nel tech. Ho co-fondato una startup health-tech nel 2020 e sto conseguendo un master in informatica al Georgia Tech, con specializzazione in machine learning.

Argomenti

Correlato