-
Notifications
You must be signed in to change notification settings - Fork 382
[feat] Add AnyFlow any-step video distillation (pretrain + on-policy) #1371
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
mergify
merged 16 commits into
hao-ai-lab:main
from
Enderfga:add-anyflow-pretrain-onpolicy
Jul 12, 2026
Merged
Changes from all commits
Commits
Show all changes
16 commits
Select commit
Hold shift + click to select a range
8363327
[feat] Add r_embedder config flags to Wan (defaults preserve bit-iden…
Enderfga 0e04210
[feat] Extend WanTimeTextImageEmbedding with optional r_timestep
Enderfga fba7170
[feat] Thread optional r_timestep through WanTransformer3DModel.forward
Enderfga aa5ce59
[feat] Add FlowMapEulerDiscreteScheduler
Enderfga ce23c5b
[feat] AnyFlowPretrainMethod skeleton + (t, r) per-batch sampling
Enderfga a8b99d2
[test] AnyFlow pretrain: cover (t, r) sampling distribution + validation
Enderfga f6d78fa
[feat] AnyFlow pretrain: central-difference target + full single_trai…
Enderfga 314a018
[feat] AnyFlowMethod (on-policy DMD2 with multi-step Euler-flow rollout)
Enderfga e8516c2
[feat] AnyFlow YAML configs (pretrain + on-policy) for Wan 2.1 T2V 1.3B
Enderfga fd98371
[test] AnyFlow GPU smoke (pretrain + on-policy, 2 iters each)
Enderfga ef1bf25
[docs] AnyFlow algorithm + usage guide
Enderfga eed1a45
[test] AnyFlow embedder tests: initialize ReplicatedLinear weights fo…
Enderfga acef1a9
[verify] AnyFlow↔FastVideo numerical parity script
Enderfga bbb1f97
[demo] AnyFlow 14B T2V inference demo (NFE=4 + NFE=50)
Enderfga b9e231f
[misc] Drive AnyFlow helper script paths from env vars + ruff SIM108
Enderfga 5cfcba0
[misc] Apply yapf/ruff pre-commit autofixes after rebase (main moved …
SolitaryThinker File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,116 @@ | ||
| # 🌊 AnyFlow Any-Step Video Distillation | ||
|
|
||
| **AnyFlow** ([paper](https://arxiv.org/abs/2605.13724), [project page](https://nvlabs.github.io/AnyFlow/), [official code](https://github.com/NVlabs/AnyFlow), [model weights](https://huggingface.co/collections/nvidia/anyflow)) is an any-step video diffusion framework built on flow maps. A single distilled checkpoint can be evaluated at NFE ∈ {1, 2, 4, 8, 16, 32} without retraining, and quality scales **monotonically** with steps — unlike consistency-based distillation, which often degrades as NFE grows. | ||
|
|
||
| The student network ``u_θ(x_t, t, r)`` predicts the *average velocity* from time ``t`` back to time ``r``, so one Euler step is | ||
|
|
||
| ``` | ||
| x_r = x_t - ((t - r) / N) · u_θ(x_t, t, r) | ||
| ``` | ||
|
|
||
| for any ``t > r``. | ||
|
|
||
| ## 📊 Model Overview | ||
|
|
||
| NVIDIA publishes four checkpoints under [`nvidia/anyflow`](https://huggingface.co/collections/nvidia/anyflow): | ||
|
|
||
| - `nvidia/AnyFlow-Wan2.1-T2V-1.3B-Diffusers` — bidirectional T2V, Wan2.1 1.3B base | ||
| - `nvidia/AnyFlow-Wan2.1-T2V-14B-Diffusers` — bidirectional T2V, Wan2.1 14B base | ||
| - `nvidia/AnyFlow-FAR-Wan2.1-1.3B-Diffusers` — frame-autoregressive variant, 1.3B | ||
| - `nvidia/AnyFlow-FAR-Wan2.1-14B-Diffusers` — frame-autoregressive variant, 14B | ||
|
|
||
| FastVideo currently supports the bidirectional T2V variants for training; the FAR variants can be loaded for inference through the diffusers integration. | ||
|
|
||
| ## ⚙️ Inference | ||
|
|
||
| For inference, load the published checkpoint directly through diffusers; FastVideo's training-side ``WanModel`` config maps the HF AnyFlow ``delta_embedder`` weights onto its internal layout via ``param_names_mapping`` so the same checkpoint can be used as the ``init_from`` for the on-policy YAML below. | ||
|
|
||
| ## 🧠 Algorithm | ||
|
|
||
| Training runs in two stages. Both use the dual-timestep Wan backbone — enabled by ``pipeline.dit_config.r_embedder: true`` in the YAML, which allocates a sibling ``condition_embedder.delta_embedder`` and fuses its embedding with the standard timestep embedding via either an additive or a gated mixer. | ||
|
|
||
| ### Stage 1 — Pretrain (flow-map central-difference) | ||
|
|
||
| Method: ``AnyFlowPretrainMethod`` (``fastvideo/train/methods/distribution_matching/anyflow_pretrain.py``) | ||
|
|
||
| For each batch, sample ``(t, r) ∈ [0, 1]`` as ``(max, min)`` of two uniform draws, then: | ||
|
|
||
| - a ``diffusion_ratio`` fraction (default 0.5) gets ``r = t`` — recovers plain flow matching; | ||
| - a ``consistency_ratio`` fraction (default 0.25) gets ``r = 0`` — forces consistency to clean data; | ||
| - the remainder is free. | ||
|
|
||
| The student forward at ``(t, r)`` is trained against the central-difference target | ||
|
|
||
| ``` | ||
| target = (eps - x_0) - (t - r) · dF/dt | ||
| ``` | ||
|
|
||
| where ``dF/dt`` is estimated from the student's own forward at ``(t ± δ, r)`` with the sample also moved along the flow trajectory by ``v_pred · (δ / N)``. Per-timestep weighting uses ``beta08`` (``w(t) = t · sqrt(1 - t)``, renormalized). A stop-gradient scale-balance keeps the non-diffusion branches' loss magnitude aligned with the diffusion branch. | ||
|
|
||
| ### Stage 2 — On-policy DMD | ||
|
|
||
| Method: ``AnyFlowMethod`` (``fastvideo/train/methods/distribution_matching/anyflow.py``) | ||
|
|
||
| Inherits ``DMD2Method``. The student is rolled out for ``student_sample_steps`` Euler-flow steps from pure noise; one randomly-chosen step is gradient-enabled (broadcast from rank 0 so every worker agrees), the rest run under ``torch.no_grad``. With ``use_mean_velocity: true`` (default) the rollout uses ``r = t_next`` at each step, matching AnyFlow's ``WanAnyFlowPipeline.training_rollout``. | ||
|
|
||
| The inherited ``_dmd_loss`` (VSD with fake-score critic) consumes the rollout output and the teacher's CFG prediction. The optional pinned ``t_list_override`` lets configs reproduce the paper's hand-tuned 4-step schedule ``[999, 937, 833, 624, 0]``. | ||
|
|
||
| ## 🚀 Training Scripts | ||
|
|
||
| ### Stage 1 — pretrain | ||
|
|
||
| ```bash | ||
| bash examples/train/run.sh \ | ||
| examples/train/configs/distribution_matching/wan/anyflow_pretrain_t2v.yaml | ||
| ``` | ||
|
|
||
| **Key configuration** (in ``examples/train/configs/distribution_matching/wan/anyflow_pretrain_t2v.yaml``): | ||
|
|
||
| - Global batch size: 32 (8 GPUs × 4 per-GPU) | ||
| - Learning rate: 5e-5 | ||
| - Flow shift: 5.0 | ||
| - ``diffusion_ratio`` / ``consistency_ratio``: 0.5 / 0.25 | ||
| - ``epsilon`` (finite-difference step): 5 (absolute train-timestep units) | ||
| - ``weight_type``: ``beta08`` | ||
| - ``fuse_guidance_scale``: 3.0 | ||
| - Training steps: 6000 | ||
|
|
||
| ### Stage 2 — on-policy | ||
|
|
||
| ```bash | ||
| bash examples/train/run.sh \ | ||
| examples/train/configs/distribution_matching/wan/anyflow_onpolicy_t2v.yaml \ | ||
| --models.student.init_from outputs/wan2.1_anyflow_pretrain/checkpoint-final | ||
| ``` | ||
|
|
||
| (Or point ``models.student.init_from`` directly at ``nvidia/AnyFlow-Wan2.1-T2V-1.3B-Diffusers`` to bootstrap from the paper weights and skip Stage 1.) | ||
|
|
||
| **Key configuration**: | ||
|
|
||
| - Global batch size: 8 (8 GPUs × 1 per-GPU) | ||
| - Learning rate: 2e-6 | ||
| - Flow shift: 5.0 | ||
| - ``student_sample_steps``: 4 | ||
| - ``t_list_override``: ``[999, 937, 833, 624, 0]`` | ||
| - ``use_mean_velocity``: ``true`` (i.e. ``r = t_next`` during rollout) | ||
| - ``real_score_guidance_scale``: 3.0 | ||
| - ``generator_update_interval``: 5 (DMD2 alternation) | ||
| - Training steps: 4000 | ||
|
|
||
| ## 🔌 Loading published AnyFlow checkpoints | ||
|
|
||
| The HF AnyFlow checkpoints expose ``condition_embedder.delta_embedder.*`` weights that FastVideo internally maps onto its ``condition_embedder.delta_embedder.mlp.*`` layout. This rename happens automatically through the regex in ``WanVideoArchConfig.param_names_mapping`` — no separate adapter is needed. The same regex is a no-op on plain Wan checkpoints (which don't contain any ``delta_embedder`` keys). | ||
|
|
||
| Set the YAML's ``pipeline.dit_config.r_embedder: true`` to allocate the ``delta_embedder`` module on the FastVideo side; when initializing from a plain Wan checkpoint the delta weights are deep-copied from ``time_embedder`` (matching AnyFlow's ``setup_flowmap_model()`` behavior). | ||
|
|
||
| ## 🧭 Note on ``fuse_guidance_scale`` | ||
|
|
||
| Stage 1 optionally fuses classifier-free guidance into the training target so the resulting checkpoint can be sampled at ``guidance_scale=1.0`` (no extra forward pass at inference time). The transformation is | ||
|
|
||
| ``` | ||
| noise_pred ← (noise_pred - (1 - g) · noise_pred_uncond) / g | ||
| ``` | ||
|
|
||
| with ``g = fuse_guidance_scale``. The negative prompt embedding comes from ``WanModel``'s ``ensure_negative_conditioning()`` — i.e. the dataset's configured ``sampling_param.negative_prompt``. Setting ``fuse_guidance_scale: 1.0`` skips the extra unconditional forward entirely. | ||
|
|
||
| The on-policy stage's ``real_score_guidance_scale`` (inherited from DMD2) follows the same parameterization conventions documented in [``dmd.md``](dmd.md#-note-on-real_score_guidance_scale). | ||
105 changes: 105 additions & 0 deletions
105
examples/train/configs/distribution_matching/wan/anyflow_onpolicy_t2v.yaml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,105 @@ | ||
| # AnyFlow on-policy DMD — Wan 2.1 T2V 1.3B. | ||
| # | ||
| # Stage 2 of the AnyFlow two-stage recipe. Continues from the pretrain | ||
| # checkpoint; refines the student via DMD2 with a multi-step Euler-flow | ||
| # rollout from pure noise. Teacher provides the real score, critic | ||
| # learns the fake score; both inherited from DMD2Method. | ||
| # | ||
| # Replace <PATH_TO_PRETRAIN_CKPT> with the output of the pretrain stage, | ||
| # or with the NVIDIA-released checkpoint | ||
| # nvidia/AnyFlow-Wan2.1-T2V-1.3B-Diffusers to bootstrap directly from | ||
| # the paper weights (the delta_embedder rename is handled by the | ||
| # param_names_mapping in WanVideoArchConfig). | ||
|
|
||
| models: | ||
| student: | ||
| _target_: fastvideo.train.models.wan.WanModel | ||
| init_from: <PATH_TO_PRETRAIN_CKPT> | ||
| trainable: true | ||
| teacher: | ||
| _target_: fastvideo.train.models.wan.WanModel | ||
| init_from: Wan-AI/Wan2.1-T2V-14B-Diffusers | ||
| trainable: false | ||
| disable_custom_init_weights: true | ||
| critic: | ||
| _target_: fastvideo.train.models.wan.WanModel | ||
| init_from: Wan-AI/Wan2.1-T2V-1.3B-Diffusers | ||
| trainable: true | ||
| disable_custom_init_weights: true | ||
|
|
||
| method: | ||
| _target_: fastvideo.train.methods.distribution_matching.anyflow.AnyFlowMethod | ||
| rollout_mode: simulate | ||
| generator_update_interval: 5 | ||
| real_score_guidance_scale: 3.0 | ||
| dmd_denoising_steps: [999, 937, 833, 624] | ||
| warp_denoising_step: false | ||
|
|
||
| # AnyFlow rollout knobs. | ||
| student_sample_steps: 4 | ||
| use_mean_velocity: true | ||
| t_list_override: [999.0, 937.0, 833.0, 624.0, 0.0] | ||
| dmd_score_r_value: 0.0 # DMD scoring conditioning is at r=0 (consistency target). | ||
|
|
||
| # Critic optimizer (DMD2 inherited). | ||
| fake_score_learning_rate: 8.0e-6 | ||
| fake_score_betas: [0.0, 0.999] | ||
| fake_score_lr_scheduler: constant | ||
|
|
||
| attn_kind: vsa | ||
|
|
||
| training: | ||
| distributed: | ||
| num_gpus: 8 | ||
| sp_size: 1 | ||
| tp_size: 1 | ||
| hsdp_replicate_dim: 1 | ||
| hsdp_shard_dim: 8 | ||
|
|
||
| data: | ||
| data_path: data/preprocessed | ||
| dataloader_num_workers: 4 | ||
| train_batch_size: 1 | ||
| training_cfg_rate: 0.0 | ||
| seed: 1000 | ||
| num_latent_t: 21 | ||
| num_height: 480 | ||
| num_width: 832 | ||
| num_frames: 81 | ||
|
|
||
| optimizer: | ||
| learning_rate: 2.0e-6 | ||
| betas: [0.0, 0.999] | ||
| weight_decay: 0.01 | ||
| lr_scheduler: constant | ||
| lr_warmup_steps: 0 | ||
|
|
||
| loop: | ||
| max_train_steps: 4000 | ||
| gradient_accumulation_steps: 1 | ||
|
|
||
| checkpoint: | ||
| output_dir: outputs/wan2.1_anyflow_onpolicy | ||
| training_state_checkpointing_steps: 500 | ||
| checkpoints_total_limit: 3 | ||
| resume_from_checkpoint: latest | ||
|
|
||
| tracker: | ||
| project_name: anyflow-wan | ||
| run_name: wan2.1_t2v_anyflow_onpolicy | ||
|
|
||
| model: | ||
| enable_gradient_checkpointing_type: full | ||
|
|
||
| callbacks: | ||
| grad_clip: | ||
| _target_: fastvideo.train.callbacks.grad_clip.GradNormClipCallback | ||
| max_grad_norm: 1.0 | ||
|
|
||
| pipeline: | ||
| flow_shift: 5.0 | ||
| dit_config: | ||
| r_embedder: true | ||
| r_embedder_fusion: gated | ||
| r_embedder_gate_value: 0.25 | ||
| r_embedder_deltatime_type: r |
83 changes: 83 additions & 0 deletions
83
examples/train/configs/distribution_matching/wan/anyflow_pretrain_t2v.yaml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,83 @@ | ||
| # AnyFlow pretrain (flow-map central-difference) — Wan 2.1 T2V 1.3B. | ||
| # | ||
| # Stage 1 of the AnyFlow two-stage recipe. Trains the dual-timestep | ||
| # u_θ(x_t, t, r) on the central-difference target so the same checkpoint | ||
| # can be sampled at arbitrary NFE in the on-policy stage. | ||
| # | ||
| # Initialize from base Wan 2.1 T2V 1.3B. No teacher or critic at this | ||
| # stage; AnyFlowPretrainMethod owns a single student + one optimizer. | ||
|
|
||
| models: | ||
| student: | ||
| _target_: fastvideo.train.models.wan.WanModel | ||
| init_from: Wan-AI/Wan2.1-T2V-1.3B-Diffusers | ||
| trainable: true | ||
|
|
||
| method: | ||
| _target_: fastvideo.train.methods.distribution_matching.anyflow_pretrain.AnyFlowPretrainMethod | ||
| diffusion_ratio: 0.5 | ||
| consistency_ratio: 0.25 | ||
| epsilon: 5 # finite-difference step in absolute train-timestep units | ||
| weight_type: beta08 # per-timestep loss weight = t * sqrt(1 - t), renormalized | ||
| fuse_guidance_scale: 3.0 | ||
| # shift is taken from pipeline.flow_shift below. | ||
|
|
||
| training: | ||
| distributed: | ||
| num_gpus: 8 | ||
| sp_size: 1 | ||
| tp_size: 1 | ||
| hsdp_replicate_dim: 1 | ||
| hsdp_shard_dim: 8 | ||
|
|
||
| data: | ||
| data_path: data/preprocessed | ||
| dataloader_num_workers: 4 | ||
| train_batch_size: 4 | ||
| training_cfg_rate: 0.0 | ||
| seed: 1000 | ||
| num_latent_t: 21 | ||
| num_height: 480 | ||
| num_width: 832 | ||
| num_frames: 81 | ||
|
|
||
| optimizer: | ||
| learning_rate: 5.0e-5 | ||
| betas: [0.9, 0.999] | ||
| weight_decay: 0.0 | ||
| lr_scheduler: constant | ||
| lr_warmup_steps: 0 | ||
|
|
||
| loop: | ||
| max_train_steps: 6000 | ||
| gradient_accumulation_steps: 1 | ||
|
|
||
| checkpoint: | ||
| output_dir: outputs/wan2.1_anyflow_pretrain | ||
| training_state_checkpointing_steps: 500 | ||
| checkpoints_total_limit: 3 | ||
| resume_from_checkpoint: latest | ||
|
|
||
| tracker: | ||
| project_name: anyflow-wan | ||
| run_name: wan2.1_t2v_anyflow_pretrain | ||
|
|
||
| model: | ||
| enable_gradient_checkpointing_type: full | ||
|
|
||
| callbacks: | ||
| grad_clip: | ||
| _target_: fastvideo.train.callbacks.grad_clip.GradNormClipCallback | ||
| max_grad_norm: 1.0 | ||
|
|
||
| pipeline: | ||
| flow_shift: 5.0 | ||
| dit_config: | ||
| # Enable AnyFlow dual-timestep conditioning. The student loads from | ||
| # base Wan 2.1 — its checkpoint has no delta_embedder weights, so they | ||
| # get initialized identically to time_embedder via deep-copy in | ||
| # WanTimeTextImageEmbedding.__init__. | ||
| r_embedder: true | ||
| r_embedder_fusion: gated | ||
| r_embedder_gate_value: 0.25 | ||
| r_embedder_deltatime_type: r |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The link to the AnyFlow paper appears to have a typo. The year-month part
2605is likely incorrect for a 2024 paper. The correct link should probably point toarxiv.org/abs/2405.13724.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The arxiv ID is correct as written. AnyFlow was posted to arxiv this month (2026-05), so the prefix is 2605, not 2405. https://arxiv.org/abs/2605.13724 resolves to the right paper; https://arxiv.org/abs/2405.13724 is a different (2024) submission that this suggestion has been pattern-matched to.