# Wan2.1 Video

Générez des vidéos de haute qualité avec les modèles texte-à-vidéo et image-à-vidéo Wan2.1 d'Alibaba sur les GPU CLORE.AI.

{% hint style="success" %}
Tous les exemples peuvent être exécutés sur des serveurs GPU loués via [CLORE.AI Marketplace](https://clore.ai/marketplace).
{% endhint %}

## Pourquoi Wan2.1 ?

* **Haute qualité** - Génération vidéo à la pointe de la technologie
* **Plusieurs modes** - Texte vers vidéo, image vers vidéo
* **Différentes tailles** - De 1,3B à 14B de paramètres
* **Vidéos longues** - Jusqu'à 81 images
* **Poids ouverts** - Licence Apache 2.0

## Variantes de modèle

| Modèle          | Paramètres | VRAM  | Résolution | Images |
| --------------- | ---------- | ----- | ---------- | ------ |
| Wan2.1-T2V-1.3B | 1,3B       | 8 Go  | 480p       | 81     |
| Wan2.1-T2V-14B  | 14B        | 24 Go | 720p       | 81     |
| Wan2.1-I2V-14B  | 14B        | 24 Go | 720p       | 81     |

## Déploiement rapide sur CLORE.AI

**Image Docker :**

```
pytorch/pytorch:2.5.1-cuda12.4-cudnn9-devel
```

**Ports :**

```
22/tcp
7860/http
```

**Commande :**

```bash
pip install diffusers transformers accelerate gradio && \
python -c "
import gradio as gr
import torch
from diffusers import WanPipeline
from diffusers.utils import export_to_video

pipe = WanPipeline.from_pretrained('alibaba-pai/Wan2.1-T2V-1.3B', torch_dtype=torch.float16)
pipe.to('cuda')
pipe.enable_model_cpu_offload()

def generate(prompt, steps, frames, seed):
    generator = torch.Generator('cuda').manual_seed(seed) if seed > 0 else None
    output = pipe(prompt, num_frames=frames, num_inference_steps=steps, generator=generator)
    export_to_video(output.frames[0], 'output.mp4', fps=16)
    return 'output.mp4'

gr.Interface(
    fn=generate,
    inputs=[
        gr.Textbox(label='Prompt'),
        gr.Slider(20, 100, value=50, label='Steps'),
        gr.Slider(16, 81, value=49, step=8, label='Frames'),
        gr.Number(value=-1, label='Seed')
    ],
    outputs=gr.Video(),
    title='Wan2.1 - Text to Video'
).launch(server_name='0.0.0.0', server_port=7860)
"
```

## Accéder à votre service

Après le déploiement, trouvez votre `http_pub` URL dans **Mes commandes**:

1. Aller à la **Mes commandes** page
2. Cliquez sur votre commande
3. Trouvez l' `http_pub` URL (par ex., `abc123.clorecloud.net`)

Utilisez `https://VOTRE_HTTP_PUB_URL` au lieu de `localhost` dans les exemples ci-dessous.

## Exigences matérielles

| Modèle   | GPU minimum   | Recommandé    | Optimal   |
| -------- | ------------- | ------------- | --------- |
| T2V 1,3B | RTX 3070 8GB  | RTX 3090 24GB | RTX 4090  |
| T2V 14B  | RTX 4090 24GB | A100 40GB     | A100 80GB |
| I2V 14B  | RTX 4090 24GB | A100 40GB     | A100 80GB |

## Installation

```bash
pip install diffusers transformers accelerate torch
```

## Texte vers Vidéo

### Utilisation de base (1,3B)

```python
import torch
from diffusers import WanPipeline
from diffusers.utils import export_to_video

pipe = WanPipeline.from_pretrained(
    "alibaba-pai/Wan2.1-T2V-1.3B",
    torch_dtype=torch.float16
)
pipe.to("cuda")
pipe.enable_model_cpu_offload()

prompt = "Un chat jouant avec une balle dans un jardin ensoleillé"

output = pipe(
    prompt=prompt,
    num_frames=49,
    num_inference_steps=50,
    guidance_scale=7.0
)

export_to_video(output.frames[0], "cat_video.mp4", fps=16)
```

### Haute qualité (14B)

```python
import torch
from diffusers import WanPipeline
from diffusers.utils import export_to_video

pipe = WanPipeline.from_pretrained(
    "alibaba-pai/Wan2.1-T2V-14B",
    torch_dtype=torch.float16
)
pipe.to("cuda")
pipe.enable_model_cpu_offload()
pipe.enable_vae_tiling()

prompt = "Plan cinématographique d'un dragon volant au-dessus des montagnes au coucher du soleil, 4K, détaillé"

output = pipe(
    prompt=prompt,
    negative_prompt="flou, basse qualité, déformé",
    num_frames=81,
    height=720,
    width=1280,
    num_inference_steps=50,
    guidance_scale=7.0
)

export_to_video(output.frames[0], "dragon.mp4", fps=24)
```

## Image vers Vidéo

### Animer une image

```python
import torch
from diffusers import WanI2VPipeline
from diffusers.utils import load_image, export_to_video

pipe = WanI2VPipeline.from_pretrained(
    "alibaba-pai/Wan2.1-I2V-14B",
    torch_dtype=torch.float16
)
pipe.to("cuda")
pipe.enable_model_cpu_offload()

# Load input image
image = load_image("input.jpg")

prompt = "La personne sur l'image commence à marcher en avant"

output = pipe(
    prompt=prompt,
    image=image,
    num_frames=49,
    num_inference_steps=50,
    guidance_scale=7.0
)

export_to_video(output.frames[0], "animated.mp4", fps=16)
```

## Image vers Vidéo avec Wan2.1-I2V-14B

{% hint style="info" %}
Wan2.1-I2V-14B anime une image statique en utilisant un prompt textuel pour guider le mouvement. Nécessite **24GB de VRAM** (RTX 4090 ou A100 40GB recommandé).
{% endhint %}

### Détails du modèle

| Propriété               | Valeur                            |
| ----------------------- | --------------------------------- |
| ID du modèle            | `Wan-AI/Wan2.1-I2V-14B-480P`      |
| Paramètres              | 14 milliards                      |
| VRAM requise            | **24 Go**                         |
| Résolution maximale     | 480p (854×480) ou 720p (1280×720) |
| Nombre maximal d'images | 81                                |
| Licence                 | Apache 2.0                        |

### Exigences matérielles

| GPU       | VRAM  | Statut              |
| --------- | ----- | ------------------- |
| RTX 4090  | 24 Go | ✅ Recommandé        |
| RTX 3090  | 24 Go | ✅ Pris en charge    |
| A100 40GB | 40Go  | ✅ Optimal           |
| A100 80GB | 80GB  | ✅ Meilleure qualité |
| RTX 3080  | 10Go  | ❌ Insuffisant       |

### Script CLI rapide

Enregistrer sous `generate_i2v.py` et exécutez :

```bash
python generate_i2v.py --model Wan-AI/Wan2.1-I2V-14B-480P --image input.jpg --prompt "la caméra recule lentement"
```

### generate\_i2v.py — Script complet

```python
#!/usr/bin/env python3
"""
Script CLI Wan2.1 Image-to-Video.
Utilisation : python generate_i2v.py --model Wan-AI/Wan2.1-I2V-14B-480P \
           --image input.jpg --prompt "la caméra recule lentement"
"""

import argparse
import os
import sys
import torch
from diffusers import WanImageToVideoPipeline
from diffusers.utils import load_image, export_to_video
from PIL import Image


def parse_args():
    parser = argparse.ArgumentParser(description="Générateur Wan2.1 Image-to-Video")
    parser.add_argument(
        "--model",
        type=str,
        default="Wan-AI/Wan2.1-I2V-14B-480P",
        help="ID du modèle depuis Hugging Face (par défaut : Wan-AI/Wan2.1-I2V-14B-480P)",
    )
    parser.add_argument(
        "--image",
        type=str,
        required=True,
        help="Chemin vers l'image d'entrée (JPEG ou PNG)",
    )
    parser.add_argument(
        "--prompt",
        type=str,
        required=True,
        help='Prompt textuel décrivant le mouvement souhaité (ex. "la caméra recule lentement")',
    )
    parser.add_argument(
        "--negative-prompt",
        type=str,
        default="flou, basse qualité, déformé, mouvement saccadé, artefacts",
        help="Prompt négatif pour éviter les artefacts indésirables",
    )
    parser.add_argument(
        "--frames",
        type=int,
        default=49,
        help="Nombre d'images vidéo à générer (par défaut : 49, max : 81)",
    )
    parser.add_argument(
        "--steps",
        type=int,
        default=50,
        help="Nombre d'étapes de diffusion (par défaut : 50)",
    )
    parser.add_argument(
        "--guidance",
        type=float,
        default=7.0,
        help="Échelle de guidance sans classificateur (par défaut : 7.0)",
    )
    parser.add_argument(
        "--seed",
        type=int,
        default=-1,
        help="Graine aléatoire pour reproductibilité (-1 = aléatoire)",
    )
    parser.add_argument(
        "--fps",
        type=int,
        default=16,
        help="FPS de la vidéo de sortie (par défaut : 16)",
    )
    parser.add_argument(
        "--output",
        type=str,
        default="output_i2v.mp4",
        help="Chemin du fichier vidéo de sortie (par défaut : output_i2v.mp4)",
    )
    parser.add_argument(
        "--height",
        type=int,
        default=480,
        help="Hauteur de la vidéo de sortie en pixels (par défaut : 480)",
    )
    parser.add_argument(
        "--width",
        type=int,
        default=854,
        help="Largeur de la vidéo de sortie en pixels (par défaut : 854)",
    )
    parser.add_argument(
        "--cpu-offload",
        action="store_true",
        default=True,
        help="Activer le déchargement du modèle vers le CPU pour économiser la VRAM (par défaut : True)",
    )
    parser.add_argument(
        "--vae-tiling",
        action="store_true",
        default=False,
        help="Activer le tiling VAE pour des sorties haute résolution",
    )
    return parser.parse_args()


def load_and_resize_image(image_path: str, width: int, height: int) -> Image.Image:
    """Charger l'image depuis le chemin et redimensionner aux dimensions cibles."""
    if not os.path.exists(image_path):
        print(f"[ERROR] Image non trouvée : {image_path}", file=sys.stderr)
        sys.exit(1)

    img = Image.open(image_path).convert("RGB")
    original_size = img.size
    img = img.resize((width, height), Image.LANCZOS)
    print(f"[INFO] Image chargée : {image_path} ({original_size[0]}x{original_size[1]}) → redimensionnée en {width}x{height}")
    return img


def load_pipeline(model_id: str, cpu_offload: bool, vae_tiling: bool):
    """Charger le pipeline Wan I2V avec des optimisations mémoire."""
    print(f"[INFO] Chargement du modèle : {model_id}")
    print(f"[INFO] CUDA disponible : {torch.cuda.is_available()}")
    if torch.cuda.is_available():
        vram_gb = torch.cuda.get_device_properties(0).total_memory / 1e9
        print(f"[INFO] GPU : {torch.cuda.get_device_name(0)} ({vram_gb:.1f} GB de VRAM)")
        if vram_gb < 23:
            print("[WARN] Moins de 24GB de VRAM détectés — activez --cpu-offload ou utilisez le modèle 1.3B")

    pipe = WanImageToVideoPipeline.from_pretrained(
        model_id,
        torch_dtype=torch.float16,
    )

    if cpu_offload:
        print("[INFO] Activation du déchargement du modèle sur le CPU")
        pipe.enable_model_cpu_offload()
    else:
        pipe.to("cuda")

    if vae_tiling:
        print("[INFO] Activation du tiling VAE pour la génération haute résolution")
        pipe.enable_vae_tiling()

    return pipe


def generate_video(pipe, args) -> None:
    """Exécuter le pipeline I2V et sauvegarder la vidéo de sortie."""
    image = load_and_resize_image(args.image, args.width, args.height)

    generator = None
    if args.seed >= 0:
        generator = torch.Generator("cuda").manual_seed(args.seed)
        print(f"[INFO] Utilisation de la graine : {args.seed}")
    else:
        print("[INFO] Utilisation d'une graine aléatoire")

    print(f"[INFO] Génération de {args.frames} images à {args.width}x{args.height}")
    print(f"[INFO] Étapes : {args.steps} | Guidance : {args.guidance} | FPS : {args.fps}")
    print(f"[INFO] Prompt : {args.prompt}")

    output = pipe(
        prompt=args.prompt,
        negative_prompt=args.negative_prompt,
        image=image,
        num_frames=args.frames,
        height=args.height,
        width=args.width,
        num_inference_steps=args.steps,
        guidance_scale=args.guidance,
        generator=generator,
    )

    export_to_video(output.frames[0], args.output, fps=args.fps)
    print(f"[INFO] Vidéo sauvegardée dans : {os.path.abspath(args.output)}")
    duration = args.frames / args.fps
    print(f"[INFO] Durée : {duration:.1f}s à {args.fps}fps ({args.frames} images)")


def main():
    args = parse_args()

    if not torch.cuda.is_available():
        print("[ERROR] GPU CUDA introuvable. Wan2.1-I2V-14B nécessite un GPU compatible CUDA.", file=sys.stderr)
        sys.exit(1)

    pipe = load_pipeline(args.model, args.cpu_offload, args.vae_tiling)
    generate_video(pipe, args)
    print("[DONE] Génération image-vidéo terminée !")


if __name__ == "__main__":
    main()
```

### Pipeline I2V avancé (API Python)

```python
import torch
from diffusers import WanImageToVideoPipeline
from diffusers.utils import load_image, export_to_video
from PIL import Image

# ── Charger le pipeline ──────────────────────────────────────────────────────────────
pipe = WanImageToVideoPipeline.from_pretrained(
    "Wan-AI/Wan2.1-I2V-14B-480P",
    torch_dtype=torch.float16,
)
pipe.enable_model_cpu_offload()   # maintient la VRAM en dessous de 24GB
pipe.enable_vae_tiling()          # optionnel : utile pour le 720p

# ── Charger & préparer l'image d'entrée ───────────────────────────────────────────────
image = load_image("input.jpg").resize((854, 480))

# ── Générer ─────────────────────────────────────────────────────────────────────────
prompt = "la caméra recule lentement, révélant le paysage complet"
negative_prompt = "flou, basse qualité, déformé, scintillement, artefacts"

generator = torch.Generator("cuda").manual_seed(42)

output = pipe(
    prompt=prompt,
    negative_prompt=negative_prompt,
    image=image,
    num_frames=49,          # ~3 secondes à 16fps
    height=480,
    width=854,
    num_inference_steps=50,
    guidance_scale=7.5,
    generator=generator,
)

export_to_video(output.frames[0], "i2v_output.mp4", fps=16)
print("Sauvegardé : i2v_output.mp4")
```

### Conseils de prompt I2V

| Objectif                | Exemple de prompt                                                   |
| ----------------------- | ------------------------------------------------------------------- |
| Mouvement de caméra     | `"la caméra recule lentement depuis le sujet"`                      |
| Effet de parallaxe      | `"mouvement parallax subtil, décalage de la profondeur de champ"`   |
| Animation de personnage | `"la silhouette tourne la tête et sourit"`                          |
| Animation de la nature  | `"les feuilles bruissent sous une brise légère, la lumière change"` |
| Mouvement abstrait      | `"les couleurs tourbillonnent et se mélangent, mouvement fluide"`   |

### Conseils mémoire pour I2V (GPU 24GB)

```python
# Obligatoire sur les GPU 24GB
pipe.enable_model_cpu_offload()

# Optionnel : réduit le pic de VRAM d'environ 10%
pipe.enable_vae_tiling()
pipe.enable_vae_slicing()

# Vider entre les exécutions
import gc
gc.collect()
torch.cuda.empty_cache()
```

## Exemples de prompts

### Nature & Paysages

```python
prompts = [
    "Timelapse de nuages se déplaçant au-dessus des sommets, éclairage dramatique",
    "Vagues de l'océan s'écrasant sur des rochers, ralenti, cinématographique",
    "Aurores boréales dansant dans le ciel nocturne, couleurs vibrantes",
    "Forêt en automne avec des feuilles tombant, atmosphère paisible"
]
```

### Animaux & Personnages

```python
prompts = [
    "Un golden retriever courant dans un champ de fleurs",
    "Un papillon sortant de son cocon, plan macro",
    "Un samouraï tirant son sabre, éclairage dramatique",
    "Un robot marchant dans des rues de ville futuriste"
]
```

### Abstrait & Artistique

```python
prompts = [
    "Peinture colorée tourbillonnant dans l'eau, art abstrait",
    "Formes géométriques se transformant et se métamorphosant, couleurs néon",
    "Gouttes d'encre se répandant dans du lait, photographie macro"
]
```

## Paramètres avancés

### Qualité vs Vitesse

```python
# Aperçu rapide
output = pipe(
    prompt=prompt,
    num_frames=17,
    num_inference_steps=25,
    guidance_scale=5.0
)

# Équilibré
output = pipe(
    prompt=prompt,
    num_frames=49,
    num_inference_steps=50,
    guidance_scale=7.0
)

# Qualité maximale
output = pipe(
    prompt=prompt,
    num_frames=81,
    num_inference_steps=100,
    guidance_scale=7.5
)
```

### Options de résolution

```python
# 480p (modèle 1.3B)
output = pipe(prompt, height=480, width=854, num_frames=49)

# 720p (modèle 14B)
output = pipe(prompt, height=720, width=1280, num_frames=49)

# 1080p (modèle 14B, VRAM élevée)
output = pipe(prompt, height=1080, width=1920, num_frames=33)
```

## Génération par lot

```python
import os
import torch
from diffusers import WanPipeline
from diffusers.utils import export_to_video

pipe = WanPipeline.from_pretrained("alibaba-pai/Wan2.1-T2V-1.3B", torch_dtype=torch.float16)
pipe.to("cuda")
pipe.enable_model_cpu_offload()

prompts = [
    "Un lanceur de fusée s'envolant dans l'espace",
    "Poissons nageant dans un récif corallien",
    "Pluie tombant dans une rue de ville la nuit"
]

output_dir = "./videos"
os.makedirs(output_dir, exist_ok=True)

for i, prompt in enumerate(prompts):
    print(f"Génération {i+1}/{len(prompts)} : {prompt[:40]}...")

    output = pipe(
        prompt=prompt,
        num_frames=49,
        num_inference_steps=50
    )

    export_to_video(output.frames[0], f"{output_dir}/video_{i:03d}.mp4", fps=16)
    torch.cuda.empty_cache()
```

## Interface Gradio

```python
import gradio as gr
import torch
from diffusers import WanPipeline
from diffusers.utils import export_to_video
import tempfile

pipe = WanPipeline.from_pretrained("alibaba-pai/Wan2.1-T2V-1.3B", torch_dtype=torch.float16)
pipe.to("cuda")
pipe.enable_model_cpu_offload()

def generate_video(prompt, negative_prompt, frames, steps, guidance, seed):
    generator = torch.Generator("cuda").manual_seed(seed) if seed > 0 else None

    output = pipe(
        prompt=prompt,
        negative_prompt=negative_prompt,
        num_frames=frames,
        num_inference_steps=steps,
        guidance_scale=guidance,
        generator=generator
    )

    with tempfile.NamedTemporaryFile(suffix=".mp4", delete=False) as f:
        export_to_video(output.frames[0], f.name, fps=16)
        return f.name

demo = gr.Interface(
    fn=generate_video,
    inputs=[
        gr.Textbox(label="Prompt", lines=2),
        gr.Textbox(label="Negative Prompt", value="flou, basse qualité"),
        gr.Slider(17, 81, value=49, step=8, label="Images"),
        gr.Slider(20, 100, value=50, step=5, label="Étapes"),
        gr.Slider(3, 12, value=7, step=0.5, label="Guidance"),
        gr.Number(value=-1, label="Graine")
    ],
    outputs=gr.Video(label="Vidéo générée"),
    title="Wan2.1 - Génération Texte vers Vidéo",
    description="Générez des vidéos à partir de prompts textuels. Exécution sur CLORE.AI."
)

demo.launch(server_name="0.0.0.0", server_port=7860)
```

## Optimisation de la mémoire

```python
# Activer toutes les optimisations
pipe.enable_model_cpu_offload()
pipe.enable_vae_tiling()
pipe.enable_vae_slicing()

# Pour une VRAM très faible
pipe.enable_sequential_cpu_offload()

# Vider le cache entre les générations
torch.cuda.empty_cache()
```

## Performances

| Modèle | Résolution | Images | GPU       | Temps     |
| ------ | ---------- | ------ | --------- | --------- |
| 1,3B   | 480p       | 49     | RTX 4090  | \~2 min   |
| 1,3B   | 480p       | 49     | A100 40GB | \~1,5 min |
| 14B    | 720p       | 49     | A100 40GB | \~5 min   |
| 14B    | 720p       | 81     | A100 80GB | \~8 min   |

## Estimation des coûts

Tarifs typiques du marketplace CLORE.AI :

| GPU           | Tarif horaire | \~49 vidéos d'images/heure |
| ------------- | ------------- | -------------------------- |
| RTX 3090 24GB | \~$0.06       | \~20 (1,3B)                |
| RTX 4090 24GB | \~$0.10       | \~30 (1,3B)                |
| A100 40GB     | \~$0.17       | \~40 (1,3B) / \~12 (14B)   |
| A100 80GB     | \~$0.25       | \~8 (14B haute résolution) |

*Les prix varient. Vérifiez* [*CLORE.AI Marketplace*](https://clore.ai/marketplace) *pour les tarifs actuels.*

## Dépannage

### Mémoire insuffisante

```python
# Utiliser un modèle plus petit
pipe = WanPipeline.from_pretrained("alibaba-pai/Wan2.1-T2V-1.3B")

# Activer toutes les optimisations
pipe.enable_model_cpu_offload()
pipe.enable_vae_tiling()

# Réduire le nombre d'images
output = pipe(prompt, num_frames=17)

# Réduire la résolution
output = pipe(prompt, height=480, width=854)
```

### Mauvaise qualité

* Augmenter les étapes (75-100)
* Rédiger des prompts plus détaillés
* Utiliser des prompts négatifs
* Essayer le modèle 14B pour une meilleure qualité

### Vidéo trop courte

* Augmentez `num_frames` (max 81)
* Utiliser l'interpolation RIFE pour l'interpolation d'images
* Chainer plusieurs générations

### Artefacts / Scintillement

* Augmenter l'échelle de guidance
* Utiliser une graine fixe pour la cohérence
* Post-traiter avec stabilisation vidéo

## Wan2.1 vs autres

| Fonction                | Wan2.1     | Hunyuan   | SVD    | CogVideoX |
| ----------------------- | ---------- | --------- | ------ | --------- |
| Qualité                 | Excellent  | Excellent | Bon    | Excellent |
| Vitesse                 | Rapide     | Moyen     | Rapide | Lent      |
| Nombre maximal d'images | 81         | 129       | 25     | 49        |
| Résolution              | 720p       | 720p      | 576p   | 720p      |
| Support I2V             | Oui        | Oui       | Oui    | Oui       |
| Licence                 | Apache 2.0 | Ouvrir    | Ouvrir | Ouvrir    |

**Utiliser Wan2.1 lorsque :**

* Besoin de génération vidéo open-source
* Souhaitez une vitesse de génération rapide
* Licence Apache 2.0 requise
* Qualité/vitesse équilibrée nécessaire

## Prochaines étapes

* [Hunyuan Video](https://docs.clore.ai/guides/guides_v2-fr/generation-video/hunyuan-video) - Alternative T2V
* [OpenSora](https://docs.clore.ai/guides/guides_v2-fr/generation-video/opensora) - Alternative Open Sora
* [Stable Video Diffusion](https://docs.clore.ai/guides/guides_v2-fr/generation-video/stable-video-diffusion) - Animation d'image
* [Interpolation RIFE](https://docs.clore.ai/guides/guides_v2-fr/traitement-video/rife-interpolation) - Interpolation d'images
