Qwen-Image-Edit-2511 en 24 GB: Benchmark Multi-GPU y Setup de Producción
El equipo de investigación de Screen Art ha sometido a prueba el modelo de edición de imágenes de Qwen en todas sus configuraciones posibles sobre hardware consumer. Tres métodos fallaron. El cuarto funcionó — y encontramos comportamientos que no están en la documentación oficial.
Cuando Qwen lanzó Qwen-Image-Edit-2511 en noviembre de 2025, la promesa era clara: edición semántica de imagen sin necesidad de máscaras, controlada únicamente mediante texto. El problema también era inmediato: el modelo pesa 55 GB en bf16, muy por encima de lo que cabe en cualquier GPU de consumo.
Lo que sigue documenta tres meses de pruebas: los tres callejones sin salida, el setup que finalmente funcionó, y varios descubrimientos que no aparecen en el README oficial del modelo.
El modelo: tres componentes con necesidades de VRAM muy distintas
Qwen-Image-Edit-2511 es un MMDiT (Multimodal Diffusion Transformer) de Alibaba/Qwen. No es un LLM: es un modelo de edición de imágenes con tres piezas bien diferenciadas. Entender qué hace cada una y con qué frecuencia se ejecuta es clave para gestionar la VRAM correctamente.
| Componente | Tamaño bf16 | Función | Ejecuciones por imagen |
|---|---|---|---|
| Transformer (DiT) | 39 GB | Motor principal de denoising | 4–40 iteraciones en bucle |
| Text Encoder (Qwen2.5-VL) | 16 GB | Procesa el prompt de texto | 1 vez únicamente |
| VAE | 243 MB | Encode/decode píxeles ↔ latentes | 1 vez al final |
La clave: el transformer es el cuello de botella real — se ejecuta en bucle en cada step de denoising. El text encoder solo se ejecuta una vez por imagen, lo que lo convierte en el candidato idóneo para moverlo fuera de la GPU principal sin impacto grave en velocidad.
Los métodos que no funcionan: tres callejones documentados
bitsandbytes INT4 dinámico
El primer intento fue cuantizar el modelo en runtime con bitsandbytes. El resultado fue inmediato y definitivo:
UserWarning: "no linear modules were found in the model"
# bitsandbytes busca capas nn.Linear estándar.
# El DiT de Qwen usa arquitectura custom — no las expone.
# El modelo carga en bf16 completo ignorando la cuantización.
Con 55 GB de modelo y 24 GB de GPU, diffusers cargó los primeros 17 GB en VRAM y el resto quedó en RAM del sistema. Durante la inferencia los pesos no se movían correctamente entre RAM y GPU — las imágenes generadas eran ruido puro.
torchao FP8/INT4
Incompatible con torch 2.5 (torch.int1 no existe). Con torch 2.6 aparecen conflictos con diffusers 0.37. Callejón sin salida independientemente de la versión de partida.
DiffSynth-Studio
Bug en preparing_device: recibe un dtype en lugar de un device. El text encoder bf16 (16 GB) llenaba la GPU solo al intentar cargarlo — sin llegar a la inferencia.
La solución: NF4 pre-cuantizado con estrategia por zonas
El repo ovedrive/Qwen-Image-Edit-2511-4bit resuelve el problema con una cuantización selectiva que no trata todas las capas por igual:
# Cuantización selectiva por zonas del transformer
Capas 0–29 (entrada): bf16 completo → preserva calidad perceptual
Capas 30–N-30 (centro): NF4 4-bit → máxima compresión
Capas N-30–N (salida): bf16 completo → preserva reconstrucción
Resultado: transformer 39 GB bf16 → ~12 GB NF4 en VRAM
NF4 (Normal Float 4-bit) es superior a INT4 uniforme: sus 16 valores posibles siguen una distribución normal, que coincide con la distribución real de los pesos en redes neuronales. El error de cuantización se minimiza donde más afecta a la calidad de salida.
Los pesos ya están convertidos a NF4 en disco. Se cargan directamente sin que bitsandbytes necesite detectar ni cuantizar nada — por eso funciona con arquitecturas DiT custom donde el cuantizador dinámico falla.
Gestión de VRAM: el text encoder fuera de la GPU principal
Con el modelo NF4 funcionando en una sola GPU, el consumo en reposo era de 18.1 GB — demasiado para convivir con otros modelos en producción. El siguiente paso: mover el text encoder (4.5 GB) fuera de la 3090 Ti.
Intento 1: text encoder en CPU
enable_model_cpu_offload() mueve todos los componentes a RAM del sistema y los sube a GPU solo cuando se necesitan. Libera mucha VRAM — pero a un coste de velocidad demasiado alto:
| Modo | VRAM reposo | VRAM pico | Tiempo/img |
|---|---|---|---|
| Todo en GPU | 18.1 GB | 22.6 GB | 15.7s |
| CPU offload completo | 0 GB | 14.6 GB | 23.0s (+7.3s) |
La penalización de 7.3 segundos viene del movimiento CPU↔GPU de todos los componentes en cada step. El transformer sube, procesa y baja — igual que el text encoder. Inviable para producción.
Intento 2: text encoder en la RTX 3060 (misma placa base)
La RTX 3060 está conectada en la misma placa por PCIe. La transferencia de embeddings entre GPUs es órdenes de magnitud más rápida que desde CPU RAM. Los embeddings de texto son apenas unos pocos MB — la transferencia tarda menos de 50ms.
| Modo | 3090 reposo | 3090 pico | 3060 | Tiempo |
|---|---|---|---|---|
| Todo en 3090 | 18.1 GB | 22.6 GB | — | 15.7s |
| Text enc. en CPU | 0 GB | 14.6 GB | — | 23.0s |
| ✓ Text enc. en 3060 | 13.0 GB | 17.5 GB | 5.15 GB | 16.7s (+1s) |
Solo 1 segundo de penalización a cambio de liberar 5 GB en la 3090 Ti. Con 11 GB libres en reposo, otros modelos conviven sin problema. Este es el sweet spot.
diffusers asume que todos los componentes están en el mismo device. Para que funcione con multi-GPU se necesita un patch que redirige el routing de embeddings:
# Distribuir componentes entre GPUs
pipe.transformer = pipe.transformer.to("cuda:0") # RTX 3090 Ti
pipe.vae = pipe.vae.to("cuda:0")
pipe.text_encoder = pipe.text_encoder.to("cuda:1") # RTX 3060
# Patch: execution device siempre cuda:0
QwenImageEditPipeline._execution_device = property(
lambda self: torch.device("cuda:0")
)
# Patch: routing de embeddings cuda:1 → cuda:0
_orig = pipe._get_qwen_prompt_embeds
def _patched(prompt, image=None, device=None, dtype=None):
e, m = _orig(prompt, image=image, device=torch.device("cuda:1"), dtype=dtype)
return e.to("cuda:0"), m.to("cuda:0") if m is not None else m
pipe._get_qwen_prompt_embeds = _patched
Lightning LoRA: 4 steps con una regla que no se puede ignorar
El repo lightx2v/Qwen-Image-Edit-2511-Lightning incluye una LoRA de destilación que reduce la inferencia de 40 a 4 steps — una ganancia de ~10× en velocidad.
Lightning está diseñado para true_cfg_scale=1.0 sin negative_prompt. Con cfg alto y negative_prompt a resoluciones ≥1024px los colores se rompen: tonos de piel rojos y metálicos, ropa con reflejos amarillos. Con solo 4 steps el modelo no puede reconciliar la doble pasada positivo/negativo.
# ✓ Configuración correcta con Lightning
output = pipe(
image=input_image,
prompt="change background to sunset beach",
num_inference_steps=4,
true_cfg_scale=1.0, # Sin double-pass CFG
guidance_scale=None, # Ignorado con Lightning
# NO usar negative_prompt — rompe colores a ≥1024px
)
# Para cambios difíciles (pelo, barba) — desactivar Lightning
output = pipe(
image=img,
prompt="change beard and hair to completely black",
negative_prompt="white hair, gray hair, blurry",
num_inference_steps=20,
true_cfg_scale=12.0, # ~120s, VRAM pico 21.5 GB
)
Benchmarks: velocidad, VRAM y el efecto torch.compile
| Configuración | Tiempo | 3090 reposo | 3090 pico | 3060 |
|---|---|---|---|---|
| Todo en 3090 Ti | 15.7s | 18.1 GB | 22.6 GB | — |
| Multi-GPU + torch.compile ✓ | 14.3s | 13.0 GB | 17.5 GB | 5.15 GB |
| Multi-GPU sin compile | 16.7s | 13.0 GB | 17.5 GB | 5.15 GB |
| CPU offload completo | 23.0s | 0 GB | 14.6 GB | — |
| 20 steps cfg=12 sin Lightning | ~120s | 18.1 GB | 21.5 GB | — |
torch.compile añade ~6.7 GB extra en VRAM para cachear los kernels compilados (19.7 GB vs 13 GB sin compile). En entornos multi-modelo puede ser preferible operar sin compile (16.7s) para tener más margen. La ganancia de 2.5s no siempre justifica el coste en VRAM.
La resolución no afecta al tiempo de generación
Generando a 512×512, 1024×1024 o 1920×1080, el tiempo es prácticamente idéntico (~14–16s). El transformer opera sobre un espacio latente de tamaño fijo gracias al VAE que comprime la imagen antes de la difusión. El VAE encode/decode sí escala con la resolución, pero es irrelevante frente al transformer.
Conclusión práctica: genera siempre a la resolución final deseada, sin penalización. 1024×1024 es gratis frente a 512×512.
| Resolución | Tiempo | VRAM pico |
|---|---|---|
| 512×512 | 14.3s | 17.46 GB |
| 1024×1024 | 14.3s | 17.46 GB |
| 1280×720 | 14.2s | 17.49 GB |
| 1080×1080 | 14.3s | 17.46 GB |
| 1920×1080 | 15.7s | 22.60 GB |
Casos de uso: edición semántica, qué funciona y qué no
Qwen-Image-Edit es un modelo de edición semántica, no de generación desde cero. Necesita una imagen de entrada y modifica partes de ella según el prompt. Su caso de uso natural es "cambia el fondo a París" — no "pon esta cara en París".
LoRA Multiple-Angles: vista 360° desde una sola fotografía
La LoRA de fal/Qwen-Image-Edit-2511-Multiple-Angles-LoRA define 96 posiciones de cámara mediante tokens especiales: 4 elevaciones × 8 azimuths × 3 distancias.
# Formato: [azimuth] [elevation] [distancia]
" front view eye-level shot medium shot"
" right side view eye-level shot medium shot"
" back view eye-level shot medium shot"
" high-angle shot front view medium shot"
# Combinar Lightning + Angles (mejor que Angles solo con 20 steps)
pipe.set_adapters(["angles", "lightning"], adapter_weights=[0.9, 1.0])
La combinación Lightning + Angles produce mejor calidad que Angles solo con 20 steps. Con 4 steps el modelo hace cambios conservadores que no generan anatomía errónea. Una vuelta completa de 360° (8 azimuths + 3 elevaciones = 11 imágenes) se completa en menos de 3 minutos.
Boceto a imagen: seguimiento geométrico sin ControlNet
El modelo respeta la geometría del boceto como guía estructural
Al pasar un boceto simple como imagen de entrada, el modelo lo interpreta simultáneamente como contenido a transformar y como guía de composición — sin ControlNet como componente separado, sin VRAM adicional, sin configuración especial.
El tejado, ventanas y puerta de un boceto de casa aparecen en la misma posición y proporciones en todas las variantes generadas. Es un comportamiento emergente del entrenamiento del MMDiT: el modelo fue entrenado para preservar la estructura de la imagen de entrada, y eso incluye bocetos simples. Esto no está documentado en el README oficial del modelo.
| Qwen-Edit boceto | ControlNet Canny | |
|---|---|---|
| Mecanismo | Implícito en el MMDiT | Componente separado |
| VRAM extra | 0 GB | ~2–4 GB |
| Modelo adicional | No | Sí |
| Geometría / arquitectura | Excelente | Excelente |
| Personas y animales orgánicos | Limitado | Excelente |
| Tiempo (Lightning, 1024px) | ~14s | ~10–20s |
Stack recomendado para producción en 24 GB VRAM
| Caso de uso | Configuración | Tiempo | VRAM 3090 | Notas |
|---|---|---|---|---|
| Edición semántica | NF4 + Lightning + Multi-GPU | 14–17s | 17.5 GB pico | Permanente en memoria entre requests |
| Vista 360° | Lightning + Angles LoRA | ~16s/vista | 17.5 GB pico | 11 vistas en <3 min |
| Boceto → objeto | Lightning 4-step | ~14s | 17.5 GB pico | Sin ControlNet necesario |
| Cambio de pelo/barba | 20 steps cfg=12 | ~120s | 21.5 GB pico | Incompatible con otros modelos activos |
¿Tiene imagen de entrada?
├── SÍ
│ ├── Editar fondo / ropa / estilo → Lightning 4-step (~14s)
│ ├── Cambiar ángulo de cámara → Lightning + Angles (~16s)
│ ├── Boceto → objeto / arquitectura → Lightning 4-step (~14s)
│ └── Cambio color pelo / barba → 20 steps cfg=12 (~120s)
└── NO
├── Generar desde prompt → Flux Schnell / RealVisXL
└── Boceto → persona / animal → RealVisXL + ControlNet Canny
Qwen-Image-2.0: el sucesor que cambia la ecuación de hardware
Mientras realizábamos estos benchmarks, Alibaba lanzó el 10 de febrero de 2026 Qwen-Image-2.0 — un modelo que unifica generación y edición en una sola arquitectura de 7B parámetros, frente a los 20B del modelo que hemos estado usando en este benchmark. El cambio de escala es dramático.
| Qwen-Image-Edit-2511 | Qwen-Image-2.0 | |
|---|---|---|
| Parámetros | ~20B | 7B |
| Tamaño estimado bf16 | ~55 GB | ~14–16 GB |
| VRAM mínima estimada | 16 GB con offload | 8–12 GB sin cuantizar |
| Generación T2I (texto a imagen) | No | Sí |
| Edición I2I (imagen a imagen) | Sí | Sí |
| Resolución nativa | 1024px | 2048px (2K nativo) |
| Pesos descargables | Sí — Apache 2.0 | No publicados aún |
Recursos: dónde descargar cada pieza
Todos los checkpoints usados en este benchmark son Apache 2.0 y están disponibles en HuggingFace. El orden de descarga importa: el modelo base primero, las LoRAs después.
Modelo base NF4 — transformer + text_encoder + VAE
Creado por Abhishek Dujari (ovedrive/Qwen-Image-Edit-2511-4bit). Cuantizado desde el modelo oficial Qwen/Qwen-Image-Edit-2511. Ocupa ~17 GB en disco frente a los 55 GB del original.
huggingface-cli download ovedrive/Qwen-Image-Edit-2511-4bit \
--local-dir /workspace/qwen-image-edit/model-4bit
LoRA Lightning — 4-step y 8-step
De ModelTC / lightx2v/Qwen-Image-Edit-2511-Lightning. El repo incluye también un split FP8 de 19 GB que no hemos usado — se puede ignorar descargando solo los .safetensors sueltos:
# Descarga completa del repo (incluye el split FP8 de 19 GB — no necesario)
huggingface-cli download lightx2v/Qwen-Image-Edit-2511-Lightning \
--local-dir /workspace/qwen-image-edit/lora-lightning
# Recomendado: solo el 4-step bf16 (811 MB)
huggingface-cli download lightx2v/Qwen-Image-Edit-2511-Lightning \
--include "Qwen-Image-Edit-2511-Lightning-4steps-V1.0-bf16.safetensors" \
--local-dir /workspace/qwen-image-edit/lora-lightning
El split FP8 es un formato alternativo para hardware con soporte nativo FP8 (H100, RTX 4090 con driver reciente). En una RTX 3090 Ti no aporta nada y ocupa 19 GB adicionales. Para el pipeline con diffusers + NF4, el bf16.safetensors de 811 MB es suficiente.
Resumen de archivos en disco
| Archivo / directorio | Tamaño | Repo HuggingFace | Autor |
|---|---|---|---|
| model-4bit/ | ~17 GB | ovedrive/Qwen-Image-Edit-2511-4bit | Abhishek Dujari · JustLab.ai |
| lora-lightning/ *-4steps-V1.0-bf16.safetensors |
811 MB | lightx2v/Qwen-Image-Edit-2511-Lightning | ModelTC / lightx2v |
| lora-lightning/ *-8steps-V1.0-bf16.safetensors |
811 MB | lightx2v/Qwen-Image-Edit-2511-Lightning | ModelTC / lightx2v |
| split FP8 (19 GB) | 19 GB | mismo repo | No descargar — no necesario |
Los hallazgos clave: lo que no encontrarás documentado en ningún otro sitio
true_cfg_scale=1.0 sin negative_prompt. Los resultados son completamente diferentes.Investigación realizada por Screen Art S.L. sobre hardware propio. Todos los benchmarks son mediciones reales, no estimaciones. Hardware: RTX 3090 Ti (24 GB) + RTX 3060 (12 GB) + 94 GB RAM. Marzo 2026.