Qwen-Image-2.1 est le modèle d'image à poids ouverts qu'Alibaba a publié le 20 septembre 2026 : un générateur de 7 milliards de paramètres qui gère la conversion texte-image, l'édition avec jusqu'à 10 images de référence, et la sortie transparente native (RGBA). Ce guide vous mène de l'installation pip à un point de terminaison HTTP fonctionnel. Il couvre les quatre chemins de code de référence du README GitHub, les paramètres importants, un petit wrapper FastAPI pour que le modèle soit appelable comme toute autre API d'image, et comment tester ce point de terminaison dans Apidog afin que les changements de prompt et les mises à jour du modèle ne cassent pas votre application.
Si vous souhaitez d'abord connaître le contexte, Qu'est-ce que Qwen-Image-2.1 couvre l'architecture et la licence. La version courte de la licence : utilisation à des fins de recherche et non-commerciale uniquement, sauf si vous obtenez un accord commercial distinct de Qwen. Tout ce qui suit est acceptable pour l'évaluation.
Avant de commencer
| Exigence | Détail |
|---|---|
| Paquets Python | torch>=2.4.0, transformers>=5.17, diffusers depuis GitHub main, accelerate, pillow |
| Classe de pipeline | QwenImage21Pipeline (une classe pour la génération et l'édition) |
| Poids | Qwen/Qwen-Image-2.1, bf16 safetensors |
| GPU | Non spécifié par Qwen ; le code de référence cible un périphérique CUDA en bfloat16, avec enable_model_cpu_offload() comme solution de repli |
| Sortie par défaut | 2048 x 2048 ; 40 étapes d'inférence |
| Optionnel | Modèles de réécriture de prompt Qwen-Image-2.1-PE-T2I / PE-I2I |
Installation :
pip install "torch>=2.4.0" "transformers>=5.17" accelerate pillow
pip install git+https://github.com/huggingface/diffusers
L'intégration de diffusers a été finalisée dans une pull request dédiée le jour du lancement, donc une version PyPI antérieure au 20 septembre ne disposera pas de la classe de pipeline.
Étape 1 : texte vers image
import torch
from diffusers import QwenImage21Pipeline
pipe = QwenImage21Pipeline.from_pretrained(
"Qwen/Qwen-Image-2.1", torch_dtype=torch.bfloat16
).to("cuda")
image = pipe(
prompt='A neon shop sign that reads "QWEN IMAGE 2.1", rainy night, reflections on wet pavement',
num_inference_steps=40,
generator=torch.Generator("cuda").manual_seed(42),
).images[0]
image.save("t2i_example.png")
Deux choses à noter. Le prompt met le texte du panneau entre guillemets ; le rendu de texte de Qwen est la raison pour laquelle les gens choisissent cette gamme de modèles, et la mise entre guillemets de la chaîne de caractères littérale est la convention des versions précédentes. Et la graine (seed) est explicite. Gardez-la ainsi dans chaque requête que vous avez l'intention de tester, car une graine fixe est ce qui rend un point de terminaison d'image suffisamment reproductible pour y faire des assertions.
Passez width et height du tableau pris en charge lorsque vous avez besoin d'une sortie non carrée :
| Ratio | Taille |
|---|---|
| 1:1 | 2048 x 2048 |
| 4:3 / 3:4 | 2400 x 1792 / 1792 x 2400 |
| 3:2 / 2:3 | 2528 x 1696 / 1696 x 2528 |
| 16:9 / 9:16 | 2752 x 1536 / 1536 x 2752 |
Étape 2 : sortie transparente
La transparence est basée sur le prompt. La formulation recommandée du README est littérale, alors utilisez-la :
image = pipe(
prompt=(
"This is an RGBA image with transparency. A cute cartoon dragon sticker. "
"The image has alpha channel and the background is transparent."
),
num_inference_steps=40,
generator=torch.Generator("cuda").manual_seed(42),
).images[0]
image.save("transparent_example.png")
Vérifiez le résultat plutôt que de vous y fier :
assert image.mode == "RGBA", image.mode
alpha = image.getchannel("A")
print("transparent pixels:", sum(1 for p in alpha.getdata() if p == 0))
Cette assertion est le premier test que vous importerez plus tard dans Apidog. Un modèle qui renvoie silencieusement du RGB alors que vous avez demandé du RGBA est un bug que vos utilisateurs trouveront avant vous.
Étape 3 : édition, avec une ou jusqu'à dix images
Le même pipeline édite lorsque vous passez image :
from PIL import Image
input_image = Image.open("input.png")
edited = pipe(
prompt="Change the background to a sunset beach",
image=input_image,
num_inference_steps=40,
generator=torch.Generator("cuda").manual_seed(42),
).images[0]
edited.save("edit_example.png")
Pour plusieurs références, passez une liste (la limite du billet de lancement est de 10) :
refs = [Image.open(f"ref_{i}.png") for i in range(3)]
result = pipe(
prompt="These three characters are sitting around a campfire in a forest",
image=refs,
num_inference_steps=40,
generator=torch.Generator("cuda").manual_seed(42),
).images[0]
result.save("multi_ref_example.png")
L'édition locale fonctionne de trois manières dans le billet de lancement : des cercles colorés que vous référencez par couleur dans le prompt, des annotations peintes, ou l'original non modifié plus une image de masque séparée passée comme deux entrées. Le README ne fournit pas d'exemple de masque dédié, donc la forme à deux entrées est celle à essayer en premier : image=[original, mask] avec un prompt qui décrit ce qui se trouve dans la région masquée [À VÉRIFIER par rapport au README une fois qu'un exemple de masque sera disponible].
L'édition est aussi l'endroit où le travail de vitesse de la version 2.1 se manifeste. Les images de référence et l'instruction sont statiques à travers les étapes de débruitage, de sorte que le modèle calcule leur cache clé-valeur une seule fois et le réutilise. Dix références coûtent nettement moins que dix fois une seule.
Étape 4 : faites-le tenir sur votre GPU
Qwen n'a pas publié de chiffres concernant la VRAM. Si le pipeline bf16 ne convient pas, le README propose :
pipe = QwenImage21Pipeline.from_pretrained("Qwen/Qwen-Image-2.1", torch_dtype=torch.bfloat16)
pipe.enable_model_cpu_offload()
Pour le déploiement, le README indique vLLM-Omni (avec FP8), SGLang et LightX2V. ComfyUI offre un support natif avec un workflow de modèle si vous préférez ne pas du tout écrire de Python. Et si vous n'avez pas de GPU, les options gratuites incluent la démo hébergée et Qwen Chat.
Étape 5 : encapsulez-le en tant qu'API HTTP
Le code de l'application ne devrait pas importer `diffusers`. Placez le pipeline derrière un petit service afin qu'il dispose d'un contrat que vous pouvez versionner, simuler et tester. Ce wrapper FastAPI fait environ 40 lignes et renvoie des octets PNG :
# server.py
import io, torch
from fastapi import FastAPI, UploadFile, File, Form
from fastapi.responses import Response
from PIL import Image
from diffusers import QwenImage21Pipeline
app = FastAPI()
pipe = QwenImage21Pipeline.from_pretrained(
"Qwen/Qwen-Image-2.1", torch_dtype=torch.bfloat16
).to("cuda")
SIZES = {"1:1": (2048, 2048), "16:9": (2752, 1536), "9:16": (1536, 2752)}
@app.post("/v1/images")
async def generate(
prompt: str = Form(...),
aspect: str = Form("1:1"),
transparent: bool = Form(False),
seed: int = Form(42),
steps: int = Form(40),
references: list[UploadFile] = File(default=[]),
):
if transparent and not prompt.startswith("This is an RGBA image"):
prompt = ("This is an RGBA image with transparency. " + prompt +
" The image has alpha channel and the background is transparent.")
refs = [Image.open(io.BytesIO(await f.read())) for f in references[:10]]
w, h = SIZES.get(aspect, SIZES["1:1"])
kwargs = dict(prompt=prompt, num_inference_steps=steps,
generator=torch.Generator("cuda").manual_seed(seed))
if refs:
kwargs["image"] = refs if len(refs) > 1 else refs[0]
else:
kwargs.update(width=w, height=h)
image = pipe(**kwargs).images[0]
buf = io.BytesIO()
image.save(buf, format="PNG")
return Response(buf.getvalue(), media_type="image/png",
headers={"X-Image-Mode": image.mode, "X-Seed": str(seed)})
Exécutez-le avec uvicorn server:app --port 8000. Les deux en-têtes de réponse, X-Image-Mode et X-Seed, existent afin qu'un test puisse vérifier la transparence et la reproductibilité sans décoder le PNG. C'est le seul choix spécifique au produit dans le wrapper ; le reste est un simple point de terminaison multipartie.
Étape 6 : testez le point de terminaison dans Apidog
Maintenant c'est une API, et la même discipline que vous appliqueriez à l'API gpt-image-2.5 ou à l'API Nano Banana 2 s'applique ici. Dans Apidog :
- Créez le point de terminaison en tant que
POST {{base_url}}/v1/imagesavec un corps multipartie :prompt,aspect,transparent,seed,steps, et un champ de fichierreferencesrépétable. Placezbase_urldans un environnement afin que la même collection pointe vers votre ordinateur portable, la boîte GPU ou une simulation. - Envoyez une requête texte-vers-image avec
seed=42et le prompt du panneau néon. Confirmez200,Content-Type: image/png, etX-Image-Mode: RGB. - Ajoutez des assertions dans le post-processeur : le statut est 200,
X-Image-Modeest égal àRGBAlorsquetransparent=true, la taille du corps de la réponse est supérieure à un seuil (un PNG de 2K qui revient à 2 Ko est une image vide), etX-Seedrenvoie ce que vous avez envoyé. - Envoyez le cas de transparence et une édition à trois références de la même manière, en joignant les images dans le champ de fichier. Enregistrez chaque cas comme un cas de test.
- Exécutez-les comme un scénario de test selon un calendrier ou en CI. Lorsque vous remplacez par une version quantifiée ou une future version 2.2, la suite vous indique en quelques minutes si la transparence fonctionne toujours et si la graine est toujours reproductible.
- Simulez-le pendant que le GPU est occupé. La simulation intelligente d'Apidog renvoie un PNG pré-enregistré pour le même contrat, de sorte que le frontend continue de se construire.
Parce qu'Apidog génère également la spécification et la documentation OpenAPI à partir du point de terminaison que vous avez défini, le contrat du wrapper devient partageable dès qu'il fonctionne. Téléchargez Apidog et importez le point de terminaison ci-dessus pour commencer.
Optionnel : réécriture de prompt avec PE-T2I
L'espace de démonstration transforme les requêtes d'une seule ligne en longs prompts structurés à l'aide de Qwen-Image-2.1-PE-T2I, un Qwen3.5-VL 9B affiné qui renvoie du JSON avec un prompt anglais étendu et un rapport d'aspect recommandé. Exécutez-le comme un deuxième service devant /v1/images, ou ignorez-le et écrivez vous-même des prompts complets. Si vous l'ajoutez, testez-le séparément : c'est une API textuelle avec un contrat JSON, et un réécriveur défectueux produit de mauvaises images qui ressemblent à un bug de générateur.
FAQ
Un seul pipeline gère-t-il à la fois la génération et l'édition ? Oui. QwenImage21Pipeline génère lorsqu'elle est appelée avec un prompt seul et édite lorsque vous passez image (une seule image PIL ou une liste de jusqu'à 10 images).
Comment obtenir un PNG transparent ? Commencez le prompt par « Ceci est une image RGBA avec transparence » et dites que l'arrière-plan est transparent. Vérifiez image.mode == "RGBA" sur le résultat.
Quels sont les paramètres recommandés ? 40 étapes d'inférence et bfloat16, selon le README. Les valeurs de guidance ne sont pas listées pour la version 2.1 ; les versions précédentes de Qwen-Image utilisaient true_cfg_scale=4.0, alors essayez cela si les sorties semblent sous-guidées [À VÉRIFIER].
Puis-je l'utiliser dans un produit commercial ? Pas sous la licence par défaut. Qwen-Image-2.1 est distribué sous la Qwen Research License ; l'utilisation commerciale nécessite une licence distincte de Qwen. Détails dans Qu'est-ce que Qwen-Image-2.1.
Existe-t-il une API hébergée à la place ? Qwen Image 3.0 et 3.0 Pro sont les modèles d'images hébergés d'Alibaba avec une tarification par image. La comparaison 2.1 vs 3.0 couvre quand auto-héberger et quand louer.
Où aller ensuite
Vous disposez maintenant de quatre appels fonctionnels, d'un wrapper avec un contrat stable et d'une suite de tests qui vérifie les deux propriétés les plus importantes pour ce modèle : la transparence et la reproductibilité. Ensuite, décidez si la licence de recherche correspond à votre utilisation, ou si l'API 3.0 hébergée est mieux adaptée, et conservez les deux derrière la même collection Apidog afin que le changement soit une modification de l'URL de base, et non une réécriture.
