Vai al contenuto principale

Tutorial Qwen Image 2.1: crea un editor di immagini e un creator di GIF

Impara a modificare immagini con Qwen Image 2.1 su un Colab A100, guida i cambi con testo o disegni ed esporta i risultati selezionati come GIF.
Aggiornato 29 set 2026  · 12 min leggi

Scopri con l'IA

ChatGPTClaudePerplexity

Creare una GIF da un'unica immagine è piuttosto semplice. Chiedi a un modello di immagini una nuova posa, ripeti il processo e unisci le uscite a una certa velocità. In pratica, la strategia di input conta quanto il prompt. Quando ho dato in pasto ogni frame generato alla richiesta successiva, le immagini hanno iniziato ad accumulare artefatti.

In questo tutorial useremo Qwen Image 2.1 per costruire un editor interattivo che adotta un approccio più affidabile per questo esperimento. Ogni richiesta parte dall'immagine originale. L'utente può descrivere una modifica, segnare facoltativamente l'area rilevante e accettare o scartare il risultato prima di esportare una GIF.

Useremo Qwen Image 2.1 per l'editing, ComfyUI per l'inferenza, Gradio per l'interfaccia ed Pillow per l'export. L'accento è sulle scelte di design che hanno influenzato i miei risultati, come selezione della reference, risoluzione, parametri di sampling, decodifica VAE e istruzioni precise.

Alla fine, saprai come:

  • Eseguire un workflow Qwen Image 2.1 quantizzato su una GPU A100 su Google Colab.
  • Configurare le impostazioni di sampling e memoria usate in questa demo.
  • Combinare istruzioni testuali con annotazioni di area facoltative.
  • Mantenere una reference originale fissa mentre salvi più frame modificati.
  • Valutare modifiche indesiderate ed esportare una GIF.

Notebook

Che cos'è Qwen-Image-2.1?

Qwen Image 2.1 è un modello unificato di generazione e modifica di immagini.

La sua componente di generazione visiva contiene 7 miliardi di parametri. Il modello supporta generazione testo-immagine, trasparenza nativa, immagini di riferimento multiple ed editing locale guidato da annotazioni o maschere. Questo tutorial si concentra sull'editing RGB con una singola reference. 

Il modello fornisce già la capacità di editing. La nostra applicazione aggiunge il workflow attorno ad essa: selezionare l'input, rivedere i candidati, gestire i frame accettati ed esportarli. Non stiamo addestrando un nuovo modello né aggiungendo un modulo di movimento.

La GIF risultante riproduce immagini statiche generate in modo indipendente. Può mostrare cambi di posa e variazioni visive, ma non equivale a una generazione video temporalmente coerente.

Come funziona Qwen Image 2.1?

La descrizione ufficiale dell'architettura identifica quattro componenti principali:

Componente

Specifiche

Ruolo

Trasformatore visivo

Trasformatore di diffusione single-stream (DiT) a 32 livelli e 7B parametri

Elabora i token di condizionamento e dell'immagine target in uno stream condiviso

Encoder di testo e immagine

Qwen3-VL 8B

Codifica istruzioni e immagini di riferimento in una rappresentazione unificata

Autoencoder di immagini (VAE)

64 canali latenti, supporto RGBA, compressione spaziale 16×

Converte le immagini in latenti compatti e decodifica i latenti generati in pixel

Processo di generazione

Flow matching con scheduling Euler discreto e dynamic shifting

Aggiorna iterativamente i latenti dell'immagine target verso l'immagine generata

Il trasformatore visivo contiene 7 miliardi di parametri. Questo conteggio esclude l'encoder testo-immagine e il VAE. 

I 64 canali del VAE si riferiscono alla sua rappresentazione latente, non a 64 canali colore di output. 

L'output RGBA contiene i canali rosso, verde, blu e alpha. L'app appiattisce gli upload in RGB, quindi non dimostra il supporto nativo alla trasparenza del modello.

Lettura del diagramma dell'attenzione

Qwen Image 2.1 usa una maschera di attenzione a granularità mista in cui le celle colorate consentono l'attenzione, mentre quelle grigie la bloccano.

Architettura di attenzione a granularità mista di Qwen-Image-2.1

Figura 1: Architettura di attenzione a granularità mista di Qwen Image 2.1 (articolo sul blog di Qwen)

Leggi il diagramma per riga: Q rappresenta i token query e K rappresenta i token a cui possono prestare attenzione. La sequenza contiene un prefisso di sistema, un'eventuale immagine di input, un'istruzione di editing e l'immagine target.

Il testo usa attenzione causale perché un token testuale può prestare attenzione a sé stesso e alle posizioni precedenti. I token all'interno dello stesso blocco immagine possono prestare attenzione l'un l'altro in entrambe le direzioni. 

Questo produce le regioni testuali triangolari e i blocchi immagine pieni mostrati in figura 1.

La regola della maschera esprime quella combinazione come:

allowed = (q_idx >= kv_idx) or same_image_block

Questa è una regola concettuale per una coppia di posizioni di token, non un'impostazione aggiuntiva da incollare nel notebook. Consente l'attenzione alle posizioni precedenti e permette attenzione all-to-all all'interno di ogni blocco immagine.

Perché si può mettere in cache un prefisso?

Il prefisso di sistema, l'immagine di riferimento e l'istruzione non possono prestare attenzione al blocco immagine target successivo. 

Le loro rappresentazioni, quindi, non devono cambiare mentre l'immagine target viene aggiornata.

Qwen calcola una sola volta le chiavi e i valori di attenzione al primo step di denoising e li riutilizza nei passaggi successivi. I token dell'immagine target richiedono comunque calcolo a ogni step, prestando attenzione al prefisso in cache e tra loro. 

Con 40 step, il prefisso fisso può essere riutilizzato dopo il primo; questo non significa un'accelerazione di 40× perché rimane un notevole calcolo sull'immagine target.

Questo riuso della cache avviene tra gli step di denoising all'interno di una generazione. Non significa che il modello ricordi le richieste utente precedenti, né che la nostra app riutilizzi automaticamente la stessa cache tra modifiche inviate separatamente. 

Demo: creare un editor di immagini con Qwen Image 2.1 

Prima di costruire l'app, separiamo le impostazioni del modello dalle decisioni applicative. Nota che aumentare il numero di step non riparerà una pipeline che continua a reinserire nel modello immagini deteriorate.

Impostazione

Valore usato

Perché è importante

Immagine di riferimento

Immagine originale per ogni modifica nell'app finale

Evita di trasferire artefatti da un frame generato al successivo

Risoluzione

1024

Approssimativamente un target di editing da un megapixel in questo backend

Step di inferenza

40

Il budget di sampling usato in tutti gli esperimenti principali

Seed

42

Mantiene fisso il seed di sampling durante i test delle istruzioni

CFG

1.0

Corrisponde al workflow fornito; la classica guidance del ramo negativo non contribuisce a questo valore

Sampler/scheduler

Euler / simple

Mantiene invariata la configurazione di sampling fornita

Denoise

1.0

Si adatta a questo workflow di istruzioni per l'editing; non è una classica ricetta img2img a basso denoise

Decodifica VAE

Non tilata nella configurazione finale

Scelta dopo un miglioramento qualitativo durante lo sviluppo

Pesi

Modello immagine e encoder testuale INT8 ConvRot; VAE BF16

Il backend attento alla memoria usato per la demo

Offload encoder/cache reference su CPU

Disabilitato inizialmente

L'esecuzione su A100 è rientrata senza abilitare queste ulteriori opzioni di offload

Queste sono impostazioni funzionanti per questo progetto, ma non una configurazione ottimale globale. Non abbiamo eseguito una ricerca sistematica su step, CFG, sampler o formati di quantizzazione.

I valori del sampler provengono dal workflow di image-edit, che mi ha permesso di far girare questo modello con poca VRAM. 

Step 1: prepara l'ambiente Colab

Il runtime registrato ha usato una NVIDIA A100-SXM4-40GB, con 83,5 GiB di RAM host. 

Ho usato il pacchetto di installazione alesha-pro per installare ComfyUI e scaricare i pesi quantizzati.

Nota che devi prevedere circa 45 GB di spazio libero, inclusi ambiente, modelli, cache e output. 

Un runtime con molta RAM offre margine durante caricamento e offloading.

Per prima cosa, stabilisci i percorsi e controlla la GPU:

import sys, os, json, time, uuid, shutil, subprocess, copy, io, threading
from pathlib import Path
from PIL import Image, ImageDraw, ImageFilter, ImageOps
import numpy as np
import requests
import gradio as gr
from IPython.display import display, Image as DisplayImage

ROOT = Path('/content/qwen_gif_demo')
ROOT.mkdir(parents=True, exist_ok=True)
TOOLS = ROOT / 'tools'
COMFY = ROOT / 'ComfyUI'
RUNS = ROOT / 'runs'
RUNS.mkdir(exist_ok=True)
REPO_REV = 'dc0083c0d17581f04ebbca962771e36f82f31af8'
BASE = 'http://127.0.0.1:8188'

def run_cmd(args, **kwargs):
    print('Running:', ' '.join(map(str, args)), flush=True)
    subprocess.run(list(map(str, args)), check=True, **kwargs)

if not shutil.which('nvidia-smi'):
    raise RuntimeError('Select a GPU runtime before continuing.')
print(subprocess.check_output(['nvidia-smi'], text=True))

Il controllo GPU interrompe l'esecuzione se Colab sta ancora usando un runtime CPU, e inoltre stampiamo dettagli su RAM host e spazio su disco libero prima dell'installazione. 

Le importazioni sono piuttosto basilari, incluse le librerie standard di Python, che gestiscono percorsi dei file, workflow JSON, processi backend, timing e monitoraggio in background. 

Pillow e NumPy gestiscono l'elaborazione delle immagini, Requests comunica con ComfyUI, Gradio fornisce l'interfaccia e IPython mostra le immagini nel notebook.

Installa il backend separatamente dall'UI

ComfyUI gira nel proprio ambiente virtuale. Il kernel del notebook gestisce upload, richieste HTTP e Gradio.

if not TOOLS.exists():
    run_cmd(['git', 'init', TOOLS])
    run_cmd(['git', '-C', TOOLS, 'remote', 'add', 'origin', 'https://github.com/alesha-pro/tools.git'])
    run_cmd(['git', '-C', TOOLS, 'fetch', '--depth', '1', 'origin', REPO_REV])
    run_cmd(['git', '-C', TOOLS, 'checkout', '--detach', 'FETCH_HEAD'])
assert subprocess.check_output(['git', '-C', str(TOOLS), 'rev-parse', 'HEAD'], text=True).strip() == REPO_REV
PKG = TOOLS / 'qwen-image-2.1'
VERSIONS = json.loads((PKG / 'install/versions.json').read_text())
print('Pinned backend:', VERSIONS)
driver = subprocess.check_output(['nvidia-smi', '--query-gpu=driver_version', '--format=csv,noheader'], text=True).splitlines()[0]
# Conservative selector; the backend CUDA smoke test is authoritative.
TORCH_INDEX = 'https://download.pytorch.org/whl/cu130' if int(driver.split('.')[0]) >= 580 else 'https://download.pytorch.org/whl/cu128'
print('Driver:', driver, '| wheel index:', TORCH_INDEX)
run_cmd([sys.executable, PKG / 'install/setup.py', 'install', '--dir', COMFY, '--torch-index', TORCH_INDEX])
BACKEND_PY = COMFY / '.venv/bin/python'
run_cmd([BACKEND_PY, '-c', "import torch; print(torch.__version__, torch.version.cuda); print(torch.cuda.get_device_name(0)); x=torch.ones(16,device='cuda'); print(x.sum().item())"])
run_cmd([BACKEND_PY, PKG / 'install/download_models.py', '--models-dir', COMFY / 'models'])

Questo codice recupera il sorgente pinato, legge la sua configurazione di versione, installa il backend, testa un'operazione tensoriale CUDA e scarica i modelli.

La selezione della wheel CUDA usa la versione del driver come euristica iniziale. 

Il test "smoke" CUDA è una verifica importante perché una A100 da sola non garantisce compatibilità con ogni build di PyTorch. La mia sessione ha usato il driver 580.82.07.

Step 2: avvia il backend e imposta i parametri di inferenza

La cella di avvio lancia ComfyUI su 127.0.0.1:8188, attende la disponibilità e recupera le definizioni dei nodi disponibili. 

Il codice comunica con esso tramite un piccolo helper HTTP:

def api(path, body=None):
    r = requests.get(BASE + path, timeout=30) if body is None else requests.post(BASE + path, json=body, timeout=30)
    if not r.ok:
        raise RuntimeError(f'{path}: HTTP {r.status_code}: {r.text[:3000]}')
    return r.json()

Questo helper trasforma i fallimenti lato server in eccezioni leggibili. Dopo l'avvio, lo schema dei nodi è disponibile tramite:

INFO = api('/object_info')

Il codice di avvio verifica un server esistente prima di lanciarne un altro processo. Quindi in questa configurazione non c'è alcun tunnel pubblico separato di ComfyUI.

Ora imposta i parametri che useremo per l'editing:

CPU_ENCODER = False
CPU_REFERENCE_CACHE = False
TILED_VAE = False
STEPS = 40
SIZE = 1024
SEED = 42

Ecco come interpretare queste impostazioni:

  • STEPS: Più iterazioni di sampling in genere costano più tempo. Ne abbiamo usati 40.
  • SIZE: Nel grafo di editing, la risoluzione 1024 mira a circa un megapixel adattando le dimensioni alla reference. Non forza un output quadrato.
  • SEED: Un seed fisso rende i confronti più semplici nello stesso setup. Non garantisce conservazione dell'identità o transizioni fluide tra prompt diversi.
  • TILED_VAE: La decodifica non tilata elabora l'immagine senza il percorso di decodifica a tile piccoli configurato. Può richiedere più memoria. La nostra preferenza deriva da test visivi, non da una prova controllata che il tiling causasse ogni artefatto.
  • Flag di offload su CPU: Sono controlli di gestione memoria, non di qualità dell'immagine. Abilitali solo quando necessario e misura la latenza e l'uso di RAM risultanti.

Allo stesso modo, un prompt negativo non è il controllo principale da regolare con CFG 1. Lascialo vuoto invece di aspettarti che un lungo elenco di proprietà indesiderate ripari un editing debole.

Step 3: collega il prompt e l'immagine di riferimento al modello

Il builder del workflow carica un grafo API e sostituisce i suoi input specifici della richiesta. Il seguente snippet mostra il percorso di editing:

g = json.loads((PKG / 'workflows/api/03-image-edit.json').read_text())
g['4']['inputs'].update(prompt=prompt, resolution=SIZE)
g['6']['inputs'].update(seed=int(seed), steps=int(STEPS))
g['9']['inputs']['image'] = upload_image(image_path)

if CPU_REFERENCE_CACHE:
    g['11']['inputs']['device'] = 'cpu'
if CPU_ENCODER:
    g['2']['inputs']['device'] = 'cpu'

Qui, il Nodo 4 riceve l'istruzione di editing e la risoluzione. 

Il Nodo 6 controlla il sampling e il nodo 9 carica la reference inviata. 

Le altre due override spostano facoltativamente il lavoro di encoder o reference-cache verso la memoria dell'host.

L'helper di inferenza invia poi il grafo e attende il proprio ID richiesta:

response = api('/prompt', {
    'prompt': g,
    'client_id': uuid.uuid4().hex,
})
result = collect_result(response['prompt_id'], folder)

Qui, folder è la directory di output per richiesta creata dentro infer(). 

Il collector interroga la cronologia e scarica il PNG generato quando il job corrispondente termina.

Salviamo anche input, grafo, submission, cronologia e metriche. Questo rende possibile ispezionare la richiesta effettiva quando un output sembra sbagliato. 

Un timeout non annulla automaticamente il job GPU, quindi conserva l'ID richiesta prima di decidere di ritentare.

Step 4: prepara un'immagine originale

L'app finale ha sempre bisogno di una reference invariata a cui tornare. Il seguente percorso di upload applica la correzione dell'orientamento, appiattisce la trasparenza e aggiunge l'immagine su una tela quadrata prima di passarla al modello:

python
from google.colab import files
uploaded = files.upload()
assert len(uploaded) == 1, 'Upload exactly one image.'
with Image.open(io.BytesIO(next(iter(uploaded.values())))) as image:
    rgba = ImageOps.exif_transpose(image).convert('RGBA')
    background = Image.new('RGBA', rgba.size, (250, 240, 230, 255))
    original = Image.alpha_composite(background, rgba).convert('RGB')
    original = ImageOps.pad(original, (SIZE, SIZE), color=(250, 240, 230))

BASE_FRAME = ROOT / f'original-{uuid.uuid4().hex[:8]}.png'
original.save(BASE_FRAME)

Il padding preserva il rapporto d'aspetto anziché stirare il soggetto. Ma può introdurre bordi. 

Un upload diretto nell'editor Gradio segue il suo gestore di upload e può mantenere le dimensioni inviate. Ecco perché l'app controlla anche le dimensioni dei candidati prima dell'export.

Per l'editing della posa, scegli un'immagine con spazio sufficiente per il movimento richiesto e aggiungi un'istruzione in base ai limiti.

Step 5: guida le modifiche con testo e disegni

Un disegno è utile quando il target potrebbe essere ambiguo, ad esempio scegliere un braccio o un oggetto in una scena affollata. 

È del tutto facoltativo nella nostra applicazione. 

L'editor di Gradio fornisce sfondo, layer di disegno e immagine composita, e la regola importante per il nostro design finale è caricare l'originale e aggiungere solo i layer di disegno:

layers = editor_data.get('layers') or []
has_marks = any(
    np.any(np.asarray(layer.convert('RGBA'))[..., 3] > 0)
    for layer in layers if layer is not None
)
with Image.open(original_path) as image:
    source = image.convert('RGBA').copy()
if has_marks:
    for layer in layers:
        if layer is None:
            continue
        layer = layer.convert('RGBA')
        if layer.size != source.size:
            raise ValueError('Clear the drawing and redraw on the original.')
        source = Image.alpha_composite(source, layer)

Questa è la logica centrale dentro la callback di editing. 

Il canale alpha rivela se un layer contiene segni visibili, ad esempio hai disegnato un cerchio, un rettangolo o una pennellata grossolana, che possono tutti fungere da guida visiva.

Questi segni non sono una maschera di inpainting rigida. Indicano al modello dove concentrarsi, ma non garantiscono pixel invariati altrove.

Possiamo aggiungere la spiegazione della regione solo quando i segni esistono:

region_instruction = (
    'The red hand-drawn marks identify the target region. '
    'For an outline, edit the enclosed area; for painted strokes, '
    'edit the indicated area. Remove the annotation marks '
    'from the final result. '
) if has_marks else ''

prompt = (
    'Edit <image1>. '
    + region_instruction
    + f'Requested change: {instruction.strip()} '
    + "Preserve unrelated content and the image's framing. "
    + "Keep the subject's identity and visual style consistent "
    + 'unless the requested change explicitly alters them.'
)

La clausola di preservazione indica al modello cosa conta, ma resta un'istruzione, non una garanzia. 

Per un test più esplicito, specifica il lato relativo all'immagine e la posa finale, ad esempio:

instruction = (
    'Lower the arm on the right side of the image so it extends '
    'diagonally downward. Keep the other arm, face, body position, '
    'camera framing, and background unchanged.'
)

Evita "spostalo un po' di più" quando ogni richiesta parte dall'originale. 

Il modello non riceve la conversazione precedente né l'ultima posa accettata.

Step 6: genera ogni candidato dall'originale

La prima versione di questo progetto generava una sequenza dando in input ogni output alla richiesta successiva:

result = edit_frame(manifest['frames'][-1], POSES[pose_index])

image2.gif

È il comportamento che ho cambiato per l'app finale perché l'editing ripetuto può propagare artefatti, dato che ogni nuova richiesta inizia dall'output precedente del modello. 

Nella nostra sequenza iniziale della pianta, le immagini successive sono diventate sostanzialmente più rumorose.

Il percorso di generazione finale usa invece la reference originale, facoltativamente annotata:

input_path = ROOT / f'edit-input-{uuid.uuid4().hex[:8]}.png'
source.convert('RGB').save(input_path)
result_path = infer(
    'edit',
    prompt,
    seed=int(seed),
    image_path=input_path,
)

Questo rimuove il percorso di feedback attraverso le immagini generate in precedenza. 

Non elimina gli artefatti negli output individuali e non forza una corrispondenza perfetta tra frame generati indipendentemente.

Se un'immagine accettata tiene una rosa, la richiesta successiva non la eredita automaticamente. Per mantenere la rosa mentre si cambia la posa, dobbiamo includere entrambi i requisiti:

instruction = (
    'Make the character hold a red rose in the hand on the right '
    'side of the image, with that arm extended downward. '
    'Preserve the other hand, face, background, and camera framing.'
)

Questo compromesso è utile per generare variazioni da una reference comune. 

Per attività che richiedono modifiche cumulative, un workflow sequenziale può comunque essere appropriato, ma richiede aspettative diverse sugli accumuli di cambiamenti.

Step 7: rivedi i candidati prima di salvarli

L'app separa originale, sequenza accettata e risultato in sospeso usando la funzione State di Gradio:

original_state = gr.State(initial_path)
frames_state = gr.State(initial_frames)
pending_state = gr.State(None)

La sequenza inizia con l'originale e cresce solo quando l'utente accetta un candidato. Lo stato pending contiene un file generato non ancora accettato.

L'operazione centrale di accettazione è data da:

updated_frames = list(frames) + [pending_path]

Dopo questo aggiornamento, la callback completa cancella il candidato in sospeso e il prompt, riportando l'editor all'originale.

Discard elimina il risultato in sospeso senza cambiare i frame accettati. Reset riporta la sequenza a un singolo frame originale e cancella l'istruzione corrente e l'output di download. Nessuna delle due azioni richiede il ricaricamento del modello.

Step 8: costruisci l'app Gradio

L'interfaccia finale separa editing, frame salvati ed export in tre tab. 

App Gradio

Il componente chiave è l'editor di immagini:

editor = gr.ImageEditor(
    value=initial_editor,
    type='pil',
    image_mode='RGBA',
    label='Input',
    height=480,
    brush=gr.Brush(
        colors=['#ff0000'],
        color_mode='fixed',
        default_size=8,
    ),
    eraser=gr.Eraser(default_size=20),
    transforms=(),
)

Il colore fisso del pennello corrisponde all'istruzione di annotazione. 

La gomma consente agli utenti di rifinire aree grossolane, mentre le trasformazioni disabilitate tengono cropping e rotazione fuori da questa interazione.

L'evento di generazione passa lo stato dell'originale nella callback:

event_options = {
    'concurrency_id': 'edit_workflow',
    'concurrency_limit': 1,
}

generate_button.click(
    fn=generate_edit,
    inputs=[editor, instruction, seed, original_state],
    outputs=[candidate, pending_state, status],
    **event_options,
)

Questi snippet di codice appartengono al layout completo di Blocks. 

Il gruppo di concorrenza condiviso serializza generazione e cambi di stato in questa demo. Reset aspetta il suo turno; non è un controllo di cancellazione dei job GPU.

Una volta definiti handler e componenti, avvia l'app eseguendo:

demo.queue(default_concurrency_limit=1).launch(
    share=True,
    debug=True,
)

Il link share di Gradio espone il frontend, mentre il backend rimane in localhost. Tema e modifiche CSS migliorano la presentazione, ma non alterano la qualità dell'immagine.

Step 9: converti i frame accettati in una GIF

L'exporter usa solo i frame accettati perché crea una palette comune e riproduce facoltativamente la sequenza al contrario dopo il frame finale:

def export_gif(paths, destination, duration_ms=300, ping_pong=True):
    frames = []
    for path in paths:
        with Image.open(path) as image:
            frames.append(image.convert('RGB').copy())
    if len(frames) < 2:
        raise ValueError('Accept at least one edit first.')
    if len({frame.size for frame in frames}) != 1:
        raise ValueError('Frame dimensions must match.')

    atlas = Image.new('RGB', (128 * len(frames), 128))
    for i, frame in enumerate(frames):
        atlas.paste(frame.resize((128, 128)), (128 * i, 0))
    palette = atlas.quantize(colors=256)
    converted = [
        frame.quantize(palette=palette, dither=Image.Dither.NONE)
        for frame in frames
    ]
    if ping_pong:
        converted += converted[-2:0:-1]
    converted[0].save(
        destination,
        save_all=True,
        append_images=converted[1:],
        duration=int(duration_ms),
        loop=0,
        disposal=2,
        optimize=False,
    )
    return str(destination)

Una palette condivisa riduce una potenziale fonte di sfarfallio legato alla palette. 

Disabilitare il dithering evita di aggiungere un pattern di dithering durante la conversione, anche se la riduzione dei colori può comunque introdurre banding.

La durata è misurata in millisecondi e impostare loop=0 richiede la riproduzione continua. Per quattro frame, la riproduzione ping-pong usa l'ordine 0, 1, 2, 3, 2, 1. 

La slice inversa esclude gli endpoint ripetuti. Questo non interpola il movimento perché un'animazione più fluida richiede pose intermedie adeguate, non solo una velocità di riproduzione diversa.

Considerazioni finali

Abbiamo costruito un editor Qwen Image 2.1 che accetta istruzioni testuali e disegni facoltativi, consente agli utenti di curare i singoli risultati ed esportarli come GIF. 

La decisione chiave di qualità è stata mantenere una reference originale fissa invece di modificare ripetutamente gli output generati.

Parti dalla configurazione di sampling funzionante, rendi esplicita la modifica richiesta e ispeziona i candidati grezzi prima di cambiare altre impostazioni. 

Una volta che questi elementi sono stabili, sperimenta con risoluzione o decodifica, una variabile alla volta. Il risultato è un workflow di editing immagini utile, con un resoconto chiaro sia delle sue capacità sia dei suoi limiti.

FAQ su Qwen Image 2.1

Posso eseguire questa demo su un Colab A100?

Sì. Abbiamo eseguito il workflow quantizzato di ComfyUI su una A100 con 40 GB di VRAM. Le richieste finali hanno usato circa 19,6 GiB di memoria GPU del backend campionata a risoluzione 1024 e 40 step. Questa è una misurazione dalla nostra configurazione, non un requisito hardware minimo.

Devo disegnare una regione prima di modificare?

No. Puoi fornire un'immagine e una semplice istruzione di testo. Cerchi o contorni grossolani aiutano a identificare un oggetto o una parte del corpo specifica. Forniscono una guida visiva, ma non garantiscono che i pixel fuori dalla regione segnata rimangano invariati.

Perché ogni modifica parte dall'immagine originale?

Nei nostri primi esperimenti si accumulavano artefatti quando ogni immagine generata diventava il successivo input. Tornare all'originale evita di portare avanti quegli artefatti. Tuttavia, ogni prompt deve descrivere il risultato desiderato completo, perché le modifiche precedenti non vengono mantenute automaticamente.

Qwen Image 2.1 genera direttamente la GIF?

No. Qwen genera singole immagini modificate e Pillow combina i frame accettati in una GIF. Le impostazioni di riproduzione controllano tempi e direzione, ma non creano un movimento intermedio.

Quali impostazioni dovrei cambiare per migliorare l'output?

Inizia con un'istruzione chiara e una reference pulita. La nostra configurazione ha usato 40 step, seed 42, CFG 1, sampling Euler, scheduler simple e denoise 1. Queste sono impostazioni funzionanti, non valori provati come ottimali. Cambia una sola impostazione alla volta e confronta i PNG grezzi prima di giudicare la GIF.


Aashi Dutt's photo
Author
Aashi Dutt
LinkedIn
Twitter

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
Intelligenza artificiale
Large Language Models

I migliori corsi DataCamp

Corso

Programmazione assistita dall'AI per sviluppatori

1 ore 30 min
10.6K
Migliora il tuo modo di programmare con l'AI: fai in modo che il tuo assistente di programmazione scriva, provi e documenti il codice in modo efficace.
Vedi i dettagliRight Arrow
Inizia Il Corso
Mostra altroRight Arrow
Correlato

blog

I 15 migliori server MCP remoti che ogni AI builder dovrebbe conoscere nel 2026

Scopri i 15 migliori server MCP remoti che stanno trasformando lo sviluppo AI nel 2026. Scopri come migliorano automazione, ragionamento, sicurezza e velocità dei workflow.
Abid Ali Awan's photo

Abid Ali Awan

15 min

blog

Tokenizzazione nel NLP: come funziona, sfide e casi d'uso

Guida al preprocessing NLP nel machine learning. Copriamo spaCy, i transformer di Hugging Face e come funziona la tokenizzazione in casi d'uso reali.
Abid Ali Awan's photo

Abid Ali Awan

10 min

blog

Che cos'è Snowflake? Guida per principianti alla piattaforma dati cloud

Esplora le basi di Snowflake, la piattaforma dati cloud. Scopri la sua architettura, le sue funzionalità e come integrarla nelle tue pipeline di dati.
Tim Lu's photo

Tim Lu

12 min

Mostra AltroMostra Altro