Skip to content

Commit ef13247

Browse files
Enderfgaclaude
andcommitted
Add AnyFlow algorithm
AnyFlow is an any-step video diffusion method that trains a single model u_theta(x_t, t, r) to predict the average velocity from t back to r, so the same checkpoint supports arbitrary inference NFE. Training has two stages, switched via config.loss_config.training_stage: * pretrain — flow-map prediction with a central-difference target target = (eps - x0) - (t - r) * dF/dt with dF/dt estimated by central differences at (t ± delta). Per-batch sampling assigns r=t to a `diffusion_ratio` fraction (pure flow matching) and r=0 to a `consistency_ratio` fraction (consistency to clean data). * onpolicy — distribution-matching distillation with r=0 conditioning on top of the pretrained flow-map weights. Inherits DMD2's alternating fake_score / teacher / discriminator updates. The backbone requirement (a secondary timestep r) is already satisfied by the Wan transformer with r_timestep=True, which MeanFlow also exercises; no Wan-side changes are needed. New files: fastgen/methods/distribution_matching/anyflow.py fastgen/methods/distribution_matching/anyflow_scheduler.py fastgen/configs/methods/config_anyflow.py fastgen/configs/experiments/WanT2V/config_anyflow.py tests/test_anyflowmodel.py Modified: fastgen/methods/__init__.py (+1 import) fastgen/methods/distribution_matching/README.md (+1 algorithm entry) The multi-step rollout-with-gradient training (matching self_forcing.py's rollout_with_gradient) is intentionally left for a follow-up PR — the on-policy stage here uses single-step student generation. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Signed-off-by: Enderfga <qq2639135175@gmail.com>
1 parent 123e6a2 commit ef13247

7 files changed

Lines changed: 1032 additions & 0 deletions

File tree

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
"""Reference AnyFlow experiment config on Wan-1.3B T2V.
5+
6+
Mirrors the AnyFlow paper's pretrain configuration: 1.3B student initialised
7+
from a Wan2.1-T2V checkpoint, flow-matching shift=5, beta08 loss weighting,
8+
6k iterations with batch_size_global=32 and lr=5e-5.
9+
10+
Switching to the on-policy stage:
11+
12+
config.model.loss_config.training_stage = "onpolicy"
13+
config.model.pretrained_student_net_path = "<path-to-pretrain-ckpt>"
14+
15+
and adjust ``student_update_freq`` / ``gan_loss_weight_gen`` to taste.
16+
"""
17+
18+
import fastgen.configs.methods.config_anyflow as config_anyflow_default
19+
from fastgen.configs.data import VideoLoaderConfig
20+
from fastgen.configs.discriminator import Discriminator_Wan_1_3B_Config
21+
from fastgen.configs.net import Wan_1_3B_Config
22+
23+
24+
def create_config():
25+
config = config_anyflow_default.create_config()
26+
27+
# Default to the pretrain stage; flip the switch to "onpolicy" once the
28+
# flow-map pretrain checkpoint is available.
29+
config.model.loss_config.training_stage = "pretrain"
30+
config.model.loss_config.jvp_finite_diff_eps = 5e-3
31+
config.model.loss_config.diffusion_ratio = 0.5
32+
config.model.loss_config.consistency_ratio = 0.25
33+
config.model.loss_config.weight_type = "beta08"
34+
config.model.loss_config.shift = 5.0
35+
36+
config.model.net = Wan_1_3B_Config
37+
config.model.net.r_timestep = True
38+
39+
# The on-policy stage uses these too, but they are harmless in pretrain.
40+
config.model.discriminator = Discriminator_Wan_1_3B_Config
41+
config.model.discriminator.disc_type = "multiscale_down_mlp_large"
42+
config.model.discriminator.feature_indices = [15, 22, 29]
43+
config.model.gan_loss_weight_gen = 0.0 # disabled by default in pretrain
44+
config.model.guidance_scale = 5.0
45+
46+
config.model.precision = "bfloat16"
47+
# VAE compress ratio: (1 + T/4) * H/8 * W/8. 81-frame, 480p clips.
48+
config.model.input_shape = [16, 21, 60, 104]
49+
50+
config.model.net_optimizer.lr = 5e-5
51+
config.model.fake_score_optimizer.lr = 5e-5
52+
config.model.discriminator_optimizer.lr = 5e-5
53+
54+
config.model.sample_t_cfg.time_dist_type = "shifted"
55+
config.model.sample_t_cfg.min_t = 0.001
56+
config.model.sample_t_cfg.max_t = 0.999
57+
58+
config.model.student_sample_type = "ode"
59+
# Any-step model — multiple NFEs validated at inference time.
60+
config.model.student_sample_steps = 4
61+
config.model.sample_t_cfg.t_list = [0.999, 0.937, 0.833, 0.624, 0.0]
62+
63+
config.dataloader_train = VideoLoaderConfig
64+
config.dataloader_train.img_size = (config.model.input_shape[-1] * 8, config.model.input_shape[-2] * 8)
65+
config.dataloader_train.sequence_length = (config.model.input_shape[1] - 1) * 4 + 1
66+
config.dataloader_train.batch_size = 1
67+
68+
config.trainer.max_iter = 6000
69+
config.trainer.logging_iter = 100
70+
config.trainer.save_ckpt_iter = 500
71+
config.trainer.batch_size_global = 32
72+
73+
config.log_config.group = "wan_anyflow"
74+
return config
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
"""Config schema for the AnyFlow method.
5+
6+
AnyFlow inherits the DMD2 model config (so the on-policy stage gets fake_score
7+
/ discriminator / alternating-step machinery for free) and adds a
8+
``LossConfig`` describing the flow-map pretrain hyperparameters.
9+
"""
10+
11+
import attrs
12+
from omegaconf import DictConfig
13+
14+
from fastgen.configs.callbacks import (
15+
EMA_CALLBACK,
16+
GPUStats_CALLBACK,
17+
GradClip_CALLBACK,
18+
ParamCount_CALLBACK,
19+
TrainProfiler_CALLBACK,
20+
WANDB_CALLBACK,
21+
)
22+
from fastgen.configs.config import BaseConfig
23+
from fastgen.configs.methods.config_dmd2 import ModelConfig as DMD2ModelConfig
24+
from fastgen.methods import AnyFlowModel
25+
from fastgen.utils import LazyCall as L
26+
27+
28+
@attrs.define(slots=False)
29+
class LossConfig:
30+
"""Hyperparameters for the AnyFlow flow-map loss and on-policy switch."""
31+
32+
# Which stage to train. "pretrain" runs the central-difference flow-map
33+
# objective; "onpolicy" inherits DMD2's alternating distillation with
34+
# dual-timestep r=0 conditioning.
35+
training_stage: str = "pretrain"
36+
37+
# Central-difference step size for estimating dF/dt. Lives in the same
38+
# units as the noise scheduler's timesteps. The default (5e-3) matches the
39+
# AnyFlow paper's choice of epsilon=5 with num_train_timesteps=1000.
40+
jvp_finite_diff_eps: float = 5e-3
41+
42+
# Per-batch fraction with r = t (recovers pure flow matching).
43+
diffusion_ratio: float = 0.5
44+
# Per-batch fraction with r = min_t (forces consistency to clean data).
45+
consistency_ratio: float = 0.25
46+
47+
# Per-timestep loss weighting scheme — passed through to the flow-map
48+
# scheduler. One of "gaussian", "beta08", "uniform".
49+
weight_type: str = "beta08"
50+
# Flow-matching schedule shift for the weighting / sampling scheduler.
51+
# Wan video defaults use 5.0; image use 1.0.
52+
shift: float = 1.0
53+
# Resolution of the discrete weighting grid; matches the AnyFlow reference.
54+
num_train_timesteps: int = 1000
55+
56+
57+
@attrs.define(slots=False)
58+
class ModelConfig(DMD2ModelConfig):
59+
"""AnyFlow model config — inherits DMD2 fields, adds the flow-map loss config."""
60+
61+
loss_config: LossConfig = attrs.field(factory=LossConfig)
62+
63+
64+
@attrs.define(slots=False)
65+
class Config(BaseConfig):
66+
model: ModelConfig = attrs.field(factory=ModelConfig)
67+
model_class: DictConfig = L(AnyFlowModel)(
68+
config=None,
69+
)
70+
71+
72+
def create_config():
73+
config = Config()
74+
config.trainer.callbacks = DictConfig(
75+
{
76+
**GradClip_CALLBACK,
77+
**EMA_CALLBACK,
78+
**GPUStats_CALLBACK,
79+
**TrainProfiler_CALLBACK,
80+
**ParamCount_CALLBACK,
81+
**WANDB_CALLBACK,
82+
}
83+
)
84+
85+
# Pretrain stage relies on a flow-matching net_pred_type and dual-timestep input.
86+
config.model.use_ema = True
87+
config.model.net.r_timestep = True
88+
config.model.net_scheduler.warm_up_steps = [0]
89+
config.model.fake_score_scheduler.warm_up_steps = [0]
90+
config.model.discriminator_scheduler.warm_up_steps = [0]
91+
92+
return config

fastgen/methods/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
from fastgen.methods.distribution_matching.causvid import CausVidModel as CausVidModel
1111
from fastgen.methods.distribution_matching.self_forcing import SelfForcingModel as SelfForcingModel
12+
from fastgen.methods.distribution_matching.anyflow import AnyFlowModel as AnyFlowModel
1213

1314
from fastgen.methods.consistency_model.CM import CMModel as CMModel
1415
from fastgen.methods.consistency_model.TCM import TCMModel as TCMModel

fastgen/methods/distribution_matching/README.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,31 @@ DMD2 extended for causal video generation with autoregressive chunk-by-chunk pro
8585

8686
---
8787

88+
## AnyFlow
89+
90+
**File:** [`anyflow.py`](anyflow.py) | **Reference:** AnyFlow — any-step video diffusion framework on flow maps
91+
92+
Single model that supports arbitrary inference NFE by learning a flow map `u_θ(x_t, t, r)` (average velocity from `t` back to `r`). Trained in two stages:
93+
94+
1. **Pretrain** — flow-map prediction with a central-difference target that reuses the network's own forward at `(t ± δ, r)` to estimate `dF/dt`. Per-batch sampling assigns `r = t` to a `diffusion_ratio` fraction (recovering plain flow matching) and `r = 0` to a `consistency_ratio` fraction (forcing consistency to clean data).
95+
2. **On-policy** — distribution-matching distillation with `r = 0` conditioning on top of the pretrained flow-map weights. Inherits DMD2's alternating fake_score / discriminator / VSD machinery.
96+
97+
**Key Parameters:**
98+
- `loss_config.training_stage`: `"pretrain"` or `"onpolicy"`
99+
- `loss_config.jvp_finite_diff_eps`: central-difference step δ (in noise scheduler t-units)
100+
- `loss_config.diffusion_ratio` / `loss_config.consistency_ratio`: per-batch fraction with `r=t` / `r=0`
101+
- `loss_config.weight_type`: `gaussian` | `beta08` | `uniform` per-timestep loss weight
102+
- `loss_config.shift`: flow-matching schedule shift (5.0 for Wan video)
103+
- See also key parameters of DMD2 above (used by the on-policy stage)
104+
105+
**Backbone requirement:** the student network must accept a secondary timestep `r` (Wan with `r_timestep=True`).
106+
107+
**Note:** the on-policy stage in this PR uses single-step student generation. Multi-step rollout-with-gradient (matching `self_forcing.py`'s `rollout_with_gradient`) is intentionally deferred to a follow-up PR.
108+
109+
**Configs:** [`WanT2V/config_anyflow.py`](../../configs/experiments/WanT2V/config_anyflow.py)
110+
111+
---
112+
88113
## Self-Forcing
89114

90115
**File:** [`self_forcing.py`](self_forcing.py) | **Reference:** [Huang et al., 2025](https://arxiv.org/abs/2506.08009)

0 commit comments

Comments
 (0)