19 KiB
Wan Latent Upsampler Training Guide
This document provides a complete workflow for training the Wan Latent Upsampler (WanLatentUpsamplerModel) against the Wan2.2 VAE, including environment setup, data preparation, training, and using the trained checkpoint for inference.
Note
: The Wan Latent Upsampler is a lightweight 3D-convolution model that spatially upsamples Wan2.2 VAE latents (default
1.5x, controlled byrational_spatial_scale) before VAE decoding. It lets the diffusion model generate at a lower latent resolution and then upsample the latents to a higher resolution, reducing the compute cost of high-resolution video generation. Unlike diffusion training, the upsampler is trained with pure supervised MSE regression on paired low/high-resolution latents:x_hr (high-res video, [-1, 1]) x_lr = spatial_downsample(x_hr, scale) # scale = rational_spatial_scale (1.5) z_hr = vae.encode(x_hr).mode() # frozen VAE -> target latent z_lr = vae.encode(x_lr).mode() # frozen VAE -> input latent z_pred = upsampler(z_lr) loss = MSE(z_pred, z_hr) # latent-space MSE (default)The VAE is frozen; only the upsampler is trained. The low/high-resolution pairs are created on-the-fly from ordinary videos, so no pre-paired data is needed. Optional switches add degradation, flow-matching noise, or a pixel-space loss (see 3.5).
The upsampler targets the Wan2.2 2.2VAE latent space (48 channels, 16x spatial compression). The --config_path must contain a latent_upsampler_kwargs block, which fixes the upsampler architecture and spatial scale:
| Latent | Full VAE | --config_path |
Spatial scale | Used at inference by |
|---|---|---|---|---|
| 48ch | AutoencoderKLWan3_8 (Wan2.2_VAE.pth) |
config/wan2.2/wan_civitai_t2v_2.2vae.yaml |
1.5 | Wan2.2-Fun-*-A14B-2.2VAE predict scripts |
config/wan2.2/wan_civitai_i2v_2.2vae.yamlshares the samelatent_upsampler_kwargsand can be used interchangeably for training.
Table of Contents
- 1. Environment Setup
- 2. Data Preparation
- 3. Latent Upsampler Training
- 4. Inference Testing
- 5. Additional Resources
1. Environment Setup
Option 1: Using requirements.txt
pip install -r requirements.txt
Option 2: Manual Installation
pip install Pillow einops safetensors timm tomesd librosa "torch>=2.1.2" torchdiffeq torchsde decord datasets numpy scikit-image
pip install omegaconf SentencePiece imageio[ffmpeg] imageio[pyav] tensorboard beautifulsoup4 ftfy func_timeout onnxruntime
pip install "peft>=0.17.0" "accelerate>=0.25.0" "gradio>=3.41.2" "diffusers>=0.30.1" "transformers>=4.46.2"
The upsampler is a lightweight convolutional model (far smaller than the diffusion transformer), so plain data parallelism is enough — DeepSpeed / FSDP is not required (but still supported by the script). The only large model in memory is the frozen Wan2.2 VAE; use
--low_vramto keep it on CPU between encode/decode steps if it does not fit together with the training activations.
2. Data Preparation
2.1 Quick Test Dataset
We provide a test dataset containing several training samples.
# Download official demo dataset
modelscope download --dataset PAI/X-Fun-Videos-Demo --local_dir ./datasets/X-Fun-Videos-Demo
2.2 Dataset Structure
📦 datasets/
├── 📂 my_dataset/
│ ├── 📂 train/
│ │ ├── 📄 video001.mp4
│ │ ├── 📄 video002.mp4
│ │ └── 📄 ...
│ └── 📄 metadata.json
2.3 metadata.json Format
Relative Path Format (example format):
[
{
"file_path": "train/video001.mp4",
"text": "A beautiful sunset over the ocean, golden hour lighting",
"type": "video",
"width": 1024,
"height": 1024
}
]
Absolute Path Format:
[
{
"file_path": "/mnt/data/videos/sunset.mp4",
"text": "A beautiful sunset over the ocean",
"type": "video",
"width": 1024,
"height": 1024
}
]
Key Field Descriptions:
file_path: Video path (relative or absolute path)text: Video description (not used by the upsampler loss, kept for meta format compatibility)type: Data type, should be"video"width/height: Video width and height (recommended to provide, used for bucket training).- You can use
scripts/process_json_add_width_and_height.pyto extract width and height from JSON files without these fields.
- You can use
2.4 Relative vs Absolute Path Usage
Relative Path:
export DATASET_NAME="datasets/X-Fun-Videos-Demo/"
export DATASET_META_NAME="datasets/X-Fun-Videos-Demo/metadata.json"
Absolute Path:
export DATASET_NAME=""
export DATASET_META_NAME="/mnt/data/metadata.json"
💡 Recommendation: If the dataset is small and stored locally, use relative paths. If the dataset is stored on external storage (e.g., NAS, OSS) or shared across multiple machines, use absolute paths.
3. Latent Upsampler Training
3.1 Download Pretrained Model
The training script only needs the Wan2.2 VAE weights (used as the frozen encoder/decoder), which ship inside the model directory:
mkdir -p models/Diffusion_Transformer
# Wan2.2 TI2V-5B (48ch latent, contains Wan2.2_VAE.pth) — only the frozen VAE is used for upsampler training
modelscope download --model Wan-AI/Wan2.2-TI2V-5B --local_dir models/Diffusion_Transformer/Wan2.2-TI2V-5B
At inference the upsampler is used with the
Wan2.2-Fun-*-A14B-2.2VAEmodels. They share the same Wan2.2 VAE latent space, so an upsampler trained against theWan2.2-TI2V-5BVAE is directly usable there. Any model directory that containsWan2.2_VAE.pthworks as--pretrained_model_name_or_path.
3.2 Quick Start
After downloading the dataset as in 2.1 and the pretrained model as in 3.1, copy and run the quick start command directly.
export MODEL_NAME="models/Diffusion_Transformer/Wan2.2-TI2V-5B"
export DATASET_NAME="datasets/X-Fun-Videos-Demo/"
export DATASET_META_NAME="datasets/X-Fun-Videos-Demo/metadata.json"
# NCCL_IB_DISABLE=1 and NCCL_P2P_DISABLE=1 are used in multi nodes without RDMA.
# export NCCL_IB_DISABLE=1
# export NCCL_P2P_DISABLE=1
NCCL_DEBUG=INFO
accelerate launch --mixed_precision="bf16" scripts/wan2.2_fun/train_upsampler.py \
--config_path="config/wan2.2/wan_civitai_t2v_2.2vae.yaml" \
--pretrained_model_name_or_path=$MODEL_NAME \
--train_data_dir=$DATASET_NAME \
--train_data_meta=$DATASET_META_NAME \
--video_sample_size=640 \
--video_sample_stride=2 \
--video_sample_n_frames=81 \
--train_batch_size=1 \
--gradient_accumulation_steps=1 \
--dataloader_num_workers=8 \
--num_train_epochs=100 \
--checkpointing_steps=50 \
--learning_rate=2e-05 \
--lr_scheduler="constant_with_warmup" \
--lr_warmup_steps=100 \
--seed=42 \
--output_dir="output_dir_wan2.2_fun_upsampler" \
--gradient_checkpointing \
--mixed_precision="bf16" \
--adam_weight_decay=3e-2 \
--adam_epsilon=1e-10 \
--vae_mini_batch=1 \
--max_grad_norm=0.05 \
--random_hw_adapt \
--enable_bucket \
--low_vram \
--trainable_modules "."
These hyper-parameters follow the standard Wan2.2 Fun video training settings.
scripts/wan2.2_fun/train_upsampler.shcontains the same command.
3.3 Training Parameter Reference
Key Parameter Descriptions:
| Parameter | Description | Example Value |
|---|---|---|
--config_path |
Model config yaml; must contain latent_upsampler_kwargs (fixes the upsampler architecture and spatial scale) |
config/wan2.2/wan_civitai_t2v_2.2vae.yaml |
--pretrained_model_name_or_path |
Model directory containing Wan2.2_VAE.pth (only the frozen VAE is used) |
models/Diffusion_Transformer/Wan2.2-TI2V-5B |
--latent_upsampler_path |
Optional upsampler weights to warm-start / resume from (file or directory) | None |
--vae_path |
Optional path to other full VAE weights | None |
--train_data_dir |
Training data directory | datasets/X-Fun-Videos-Demo/ |
--train_data_meta |
Training data metadata file | datasets/X-Fun-Videos-Demo/metadata.json |
--train_batch_size |
Batch size (per device) | 1 |
--video_sample_size |
Target high-resolution size; the low-res input is high_res / rational_spatial_scale |
640 |
--video_sample_stride |
Video sample stride | 2 |
--video_sample_n_frames |
Number of frames to sample. Must be 4k+1 (33, 49, 81, ...) | 81 |
--vae_mini_batch |
Mini batch size for VAE encoding | 1 |
--gradient_accumulation_steps |
Gradient accumulation steps | 1 |
--dataloader_num_workers |
Number of DataLoader workers | 8 |
--num_train_epochs |
Number of training epochs | 100 |
--checkpointing_steps |
Save a checkpoint every N steps | 50 |
--checkpoints_total_limit |
Max number of checkpoints to store | None |
--learning_rate |
Initial learning rate | 2e-05 |
--lr_scheduler |
Learning rate scheduler | constant_with_warmup |
--lr_warmup_steps |
Learning rate warmup steps | 100 |
--use_8bit_adam / --use_came |
Alternative optimizers | - |
--use_ema |
Keep an EMA copy of the upsampler (used for validation and final save) | - |
--seed |
Random seed | 42 |
--output_dir |
Output directory | output_dir_wan2.2_fun_upsampler |
--gradient_checkpointing |
Enable activation recompute for the upsampler (and the VAE decoder when --enable_pixel_loss) |
- |
--mixed_precision |
Mixed precision: fp16/bf16 |
bf16 |
--adam_weight_decay |
AdamW weight decay | 3e-2 |
--adam_epsilon |
AdamW epsilon value | 1e-10 |
--max_grad_norm |
Maximum gradient norm for clipping | 0.05 |
--enable_bucket |
Enable bucket training without cropping, groups by resolution | - |
--random_hw_adapt |
Randomly scale videos to a range of resolutions | - |
--low_vram |
Keep the frozen VAE on CPU and move it to GPU only when encoding/decoding | - |
--trainable_modules |
Trainable modules ("." means all modules) |
"." |
--trainable_modules_low_learning_rate |
Trainable modules with lr/2 | [] |
--resume_from_checkpoint |
Resume training from checkpoint, use "latest" to auto-select |
None |
--validation_steps / --validation_epochs |
Run validation every N steps / epochs | 2000 / 5 |
--validation_paths |
Video paths for validation (encode low-res -> upsample -> decode) | "asset/inpaint_video.mp4" |
Sample Size Configuration Guide:
video_sample_sizeis the high-resolution target. Whenrandom_hw_adaptis enabled, it represents the minimum resolution and the video may be scaled up to a larger bucket size.- The low-resolution input is derived automatically:
low_res = high_res / rational_spatial_scale, aligned to the VAE spatial compression ratio (16), so both resolutions are VAE-encodable. video_sample_n_framesmust satisfy4k+1(e.g. 33, 49, 81) because the Wan2.2 VAE is a causal4xtemporal compressor.
3.4 Training Validation
You can configure validation parameters to periodically run encode low-res -> upsample -> decode on test videos during training, so you can visually monitor super-resolution quality.
| Parameter | Description | Recommended Value |
|---|---|---|
--validation_steps |
Run validation every N steps | 2000 |
--validation_epochs |
Run validation every N epochs | 5 |
--validation_paths |
Validation video paths | "asset/inpaint_video.mp4" |
--validation_paths "asset/inpaint_video.mp4" \
--validation_steps=2000 \
--validation_epochs=5
Notes:
- Each validation video is resized to a square target derived from
--video_sample_size, then encoded, downsampled to the low-res input, upsampled by the model, and decoded. - Validation saves two videos per sample into
output_dir/sample/:step{N}_val{i}_upsampled.mp4(upsampler result) andstep{N}_val{i}_lowres.mp4(decoded low-res input, for comparison). - When
--use_emais enabled, validation runs with the EMA weights.
3.5 Advanced Training Options
These switches are off by default; the plain latent-MSE regression in 3.2 is the recommended starting point.
Degradation (restoration + super-resolution):
Apply random degradation to the high-res frames before the spatial downsample, so the upsampler learns to restore as well as upsample.
| Parameter | Description | Default |
|---|---|---|
--enable_degradation |
Enable random degradation of the high-res frames | off |
--degradation_ops_range MIN MAX |
Range of degradation operation count per clip | 1 4 |
Noisy training (match inference denoising steps):
At inference the upsampler may run on partially-denoised latents. Noisy training adds flow-matching noise to the latents so the upsampler works at arbitrary denoising steps.
| Parameter | Description | Default |
|---|---|---|
--enable_noisy_training |
Add flow-matching noise to the latents during training | off |
--noise_sample_mode |
scheduler samples sigma from the real schedule; uniform samples in [sigma_min, sigma_max] |
scheduler |
--noise_num_inference_steps |
Inference steps simulated when sampling sigma (scheduler mode) | 50 |
--noise_step_range MIN MAX |
Restrict sampling to a sub-range of step indices (scheduler mode) | None |
--noise_sigma_max / --noise_sigma_min |
Sigma range for uniform mode |
0.25 / 0.0 |
Pixel-space loss:
Decode the predicted latents through the frozen VAE decoder and compute an MSE in pixel space; the gradient flows through the frozen decoder back to the upsampler.
| Parameter | Description | Default |
|---|---|---|
--enable_pixel_loss |
Enable pixel-space MSE loss (replaces the latent-space MSE) | off |
--pixel_loss_weight |
Weight of the pixel-space loss | 1.0 |
--enable_pixel_losskeeps the VAE on GPU (it is not offloaded under--low_vram) and needs the VAE decoder gradients, so it uses more memory. Combine it with--gradient_checkpointingto enable VAE-decoder activation recompute.
3.6 Training Tips
- Default loss: latent-space MSE against the frozen VAE encoding of the high-res frames. The VAE is never updated.
- Memory: memory scales with
video_sample_sizeandvideo_sample_n_framesbecause the frozen VAE encodes/decodes full-resolution video. If you hit OOM, keep--low_vram+--gradient_checkpointingand reduce--video_sample_sizeor--video_sample_n_frames. - Warm start:
--latent_upsampler_pathloads existing upsampler weights. Keys whose shape mismatches the current architecture (e.g. after changingrational_spatial_scale) are skipped and re-initialized automatically. - EMA:
--use_emakeeps an EMA copy used for validation and the final save. It is not supported with DeepSpeed ZeRO-3. - Spatial scale: fixed by
latent_upsampler_kwargs.rational_spatial_scalein the config; it must match the inference config, otherwise the upsampler output resolution will be wrong.
3.7 Multi-Node Distributed Training
Suitable for: Large-scale datasets, faster training speed.
Assuming 2 machines with 8 GPUs each:
Machine 0 (Master):
export MASTER_ADDR="192.168.1.100" # Master machine IP
export MASTER_PORT=10086
export WORLD_SIZE=2 # Total number of machines
export NUM_PROCESS=16 # Total processes = machines × 8
export RANK=0 # Current machine rank (0 or 1)
# Without RDMA:
# export NCCL_IB_DISABLE=1
# export NCCL_P2P_DISABLE=1
NCCL_DEBUG=INFO
accelerate launch --mixed_precision="bf16" --main_process_ip=$MASTER_ADDR --main_process_port=$MASTER_PORT --num_machines=$WORLD_SIZE --num_processes=$NUM_PROCESS --machine_rank=$RANK scripts/wan2.2_fun/train_upsampler.py \
<same training arguments as the Quick Start>
Machine 1 (Worker): use the same command with export RANK=1.
Notes:
- Without RDMA, add
NCCL_IB_DISABLE=1andNCCL_P2P_DISABLE=1. - All machines must have access to the same data / model paths (NFS/shared storage).
4. Inference Testing
4.1 Checkpoint Layout
Each checkpoint is written as output_dir/checkpoint-{step}/, containing:
📦 output_dir_wan2.2_fun_upsampler/
├── 📂 checkpoint-50/
│ ├── 📂 latent_upsampler/ # upsampler weights + config.json (save_pretrained format)
│ ├── 📂 latent_upsampler_ema/ # only when --use_ema
│ └── 📄 sampler_pos_start.pkl
├── 📂 sample/ # validation videos
└── 📂 logs/ # tensorboard
The latent_upsampler subdirectory is a standard diffusers directory checkpoint and can be loaded directly by WanLatentUpsamplerModel.from_pretrained.
With DeepSpeed ZeRO-3 or FSDP
FULL_SHARD, the upsampler weights are saved as a singlediffusion_pytorch_model.safetensorsinside the checkpoint directory instead of thelatent_upsampler/subfolder.
4.2 Use the Trained Upsampler in Predict Scripts
The Wan2.2 2.2VAE predict scripts support latent upsampling. Set enable_latent_upsample = True and point latent_upsampler_path to the latent_upsampler subdirectory of your checkpoint:
| Script | Task |
|---|---|
examples/wan2.2_fun/predict_t2v_2.2vae.py |
Text-to-Video |
examples/wan2.2_fun/predict_i2v_2.2vae.py |
Image-to-Video |
examples/wan2.2_fun/predict_t2v_2.2vae_tae.py |
Text-to-Video + TAE fast decode |
examples/wan2.2_fun/predict_i2v_2.2vae_tae.py |
Image-to-Video + TAE fast decode |
# e.g. in examples/wan2.2_fun/predict_t2v_2.2vae_tae.py
enable_latent_upsample = True
latent_upsampler_path = "output_dir_wan2.2_fun_upsampler/checkpoint-50/latent_upsampler"
If latent_upsampler_path is None, the script falls back to the latent_upsampler subfolder of model_name. During inference the pipeline generates latents at the base resolution and the upsampler spatially upsamples them (1.5x) before VAE decoding.
5. Additional Resources
- Wan2.2 Fun Full Parameter Training Guide: README_TRAIN.md
- TAE (Tiny AutoEncoder) Training Guide: ../taehv/README_TRAIN.md
- Official GitHub: https://github.com/aigc-apps/VideoX-Fun