Skip to content

Commit b0006c8

Browse files
committed
anyflow: split co-train sampling cfg, factor time_shift and train_mode
1 parent f455211 commit b0006c8

16 files changed

Lines changed: 393 additions & 180 deletions

File tree

fastgen/configs/data.py

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,3 +125,78 @@
125125
shuffle=True,
126126
sampler_start_idx=None,
127127
)
128+
129+
# ################################################################################
130+
# VidProM / Wan 480p (832x480, 81 frames)
131+
# ################################################################################
132+
# WDS shards of VidProM prompts rendered with Wan2.1. Two flavors:
133+
# * ``vidprom_wan_480p_latents`` — precomputed Wan-VAE latents [16, 21, 60, 104]
134+
# plus UMT5 text embeddings [512, 4096]; no VAE/T5 needed at train time
135+
# (set ``config.model.enable_preprocessors = False``).
136+
# * ``vidprom_wan_res720_ar16_9_f121_clean`` — the raw 720p mp4 source shards.
137+
# Both live under ``$VIDPROM_ROOT_DIR`` (default ``$DATA_ROOT_DIR/vidprom_wan``).
138+
VIDPROM_ROOT_DIR = os.getenv("VIDPROM_ROOT_DIR", f"{DATA_ROOT_DIR}/vidprom_wan")
139+
_VIDPROM_CLEAN_DIR = f"{VIDPROM_ROOT_DIR}/vidprom_wan_res720_ar16_9_f121_clean"
140+
141+
# Curation lists (json: {shard: [fname, ...]}) applied to both the raw and the
142+
# latent shards so the two stay index-consistent.
143+
VidProM_Wan_Ignore_Index_Paths = [
144+
# captions containing an <img tag
145+
f"{_VIDPROM_CLEAN_DIR}/ignore_index/img_tag_23.json",
146+
# lowest 5% by avg. rank over HPSv2, ClipScore, VideoAlign VQ/MQ/TA, InternVideo2
147+
f"{_VIDPROM_CLEAN_DIR}/ignore_index/lowest_5_perc_weighted_rank_25473.json",
148+
# nsfw captions
149+
f"{_VIDPROM_CLEAN_DIR}/ignore_index/nsfw_375.json",
150+
# split-screen captions
151+
f"{_VIDPROM_CLEAN_DIR}/ignore_index/split_screen_606.json",
152+
# prompts carrying "ar" / "gs" / "seed" / "neg" commands
153+
f"{_VIDPROM_CLEAN_DIR}/ignore_index/prompt_cmd_4507.json",
154+
# samples absent from the latent shards (keeps raw and latent in sync)
155+
f"{_VIDPROM_CLEAN_DIR}/ignore_index/missing_files_165.json",
156+
]
157+
158+
# Shared across the raw and latent loaders. Video-only options (sequence_length,
159+
# img_size) are not listed here: WDSLoader/BaseWDSLoader reject them, only
160+
# VideoWDSLoader accepts them.
161+
VidProM_Wan_Loader_Kwargs = dict(
162+
batch_size=2,
163+
num_workers=2,
164+
deterministic=False,
165+
sampler_start_idx=None,
166+
shard_count_file=f"{_VIDPROM_CLEAN_DIR}/shard_count.json",
167+
ignore_index_paths=VidProM_Wan_Ignore_Index_Paths,
168+
)
169+
170+
_VIDPROM_NEG_PROMPT_EMB = f"{VIDPROM_ROOT_DIR}/vidprom_wan_480p_latents/neg_prompt_emb.npy"
171+
172+
# Precomputed Wan-VAE latents + UMT5 text embeddings.
173+
VidProM_Wan_Latent_Loader_Config = L(WDSLoader)(
174+
datatags=[f"WDS:{VIDPROM_ROOT_DIR}/vidprom_wan_480p_latents"],
175+
**VidProM_Wan_Loader_Kwargs,
176+
key_map={"real": "latent.pth", "condition": "txt_emb.pth"},
177+
files_map={"neg_condition": _VIDPROM_NEG_PROMPT_EMB},
178+
)
179+
180+
# Raw 720p mp4 shards (needs the VAE + text encoder, i.e. enable_preprocessors=True).
181+
VidProM_Wan_Loader_Config = L(VideoWDSLoader)(
182+
datatags=[f"WDS:{_VIDPROM_CLEAN_DIR}"],
183+
**VidProM_Wan_Loader_Kwargs,
184+
sequence_length=81,
185+
img_size=(832, 480),
186+
key_map={"real": "mp4"},
187+
presets_map={"neg_condition": "neg_prompt_wan", "condition": "empty_string"},
188+
)
189+
190+
# Validation shards: 10 hand-crafted prompts in shard 0, 10 random VBench prompts
191+
# per shard afterwards, with Wan-1.3B (cfg=5, shift=5, skip_layers=[10]) renders
192+
# as the reference "real" sample.
193+
VidProM_Wan_Latent_Val_Loader_Config = L(WDSLoader)(
194+
datatags=[f"WDS:{VIDPROM_ROOT_DIR}/validation_latent"],
195+
batch_size=1,
196+
num_workers=1,
197+
train=False,
198+
sampler_start_idx=None,
199+
shards_per_worker=1,
200+
key_map={"real": "latent.pth", "condition": "txt_emb.pth"},
201+
files_map={"neg_condition": _VIDPROM_NEG_PROMPT_EMB},
202+
)

fastgen/configs/experiments/WanT2V/config_anyflow.py

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,26 @@
66
AnyFlow's pretrain objective is MeanFlow's with a fixed ``beta08`` per-timestep
77
weighting, a finite-difference JVP, shifted timestep sampling, and a
88
``consistency_ratio`` fraction of the batch pinned to ``r = 0`` — so this config
9-
runs``MeanFlowModel`` directly. The values below mirror the reference recipe
9+
runs ``MeanFlowModel`` directly. The values below mirror the reference recipe
1010
``train_wan1b_student_shift5_81f_480p_lr5e-5_6k_b32.yml``.
11-
Known deviations from the reference: full-rank fine-tuning instead of the paper's
12-
rank-256 LoRA — the same deviation applies to the on-policy stage;
11+
12+
Known deviations from the reference, both of which also apply to the on-policy stage:
13+
full-rank fine-tuning instead of the paper's rank-256 LoRA; and under
14+
``guidance_fuse_scale`` the 1/g rescaling of dF/dt is applied only to the samples that
15+
kept their condition, where the reference's ``compute_central_difference`` rescales the
16+
whole batch. A dropped sample's fused prediction is plain ``u_uncond``, so an ungated
17+
1/g would regress it onto a different fixed point -- ours is gated on ``keep``.
1318
1419
The on-policy stage (paper Stage 2) lives in ``config_anyflow_onpolicy.py``.
1520
"""
1621

1722
import copy
1823

24+
1925
import fastgen.configs.methods.config_mean_flow as config_mean_flow
2026
from fastgen.configs.data import VideoLoaderConfig
2127
from fastgen.configs.net import Wan_1_3B_Config
28+
from fastgen.methods import AnyFlowModel
2229

2330

2431
def create_config():
@@ -99,8 +106,11 @@ def create_config():
99106
# ------ inference / validation ------
100107
config.model.student_sample_type = "ode"
101108
config.model.student_sample_steps = 4
102-
# 4-step shifted schedule shift*s/(1+(shift-1)*s) on s=linspace(1,0,5)
103-
config.model.sample_t_cfg.t_list = [1.0, 0.9375, 0.8333333333333334, 0.625, 0.0]
109+
# Shifted schedule under the same map the (t, r) sampling applies. The pretrain
110+
# stage has a single scheduler in the reference, so it shares that shift.
111+
config.model.sample_t_cfg.t_list = AnyFlowModel.rollout_t_list(
112+
config.model.student_sample_steps, config.model.sample_t_cfg.shift, config.model.net.max_t
113+
).tolist()
104114

105115
# ------ data / trainer ------
106116
config.dataloader_train = copy.deepcopy(VideoLoaderConfig)

fastgen/configs/experiments/WanT2V/config_anyflow_onpolicy.py

Lines changed: 34 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,23 @@
1717
1818
trainer.checkpointer.pretrained_ckpt_path=<stage1>/checkpoints/0006000.pth
1919
20-
Known deviation from the reference: full-rank fine-tuning instead of the paper's
21-
rank-256 LoRA.
20+
Known deviations from the reference: full-rank fine-tuning instead of the paper's
21+
rank-256 LoRA; the noising times for the DMD gradient and the fake score are drawn
22+
on [0.001, 0.999] rather than the reference's [0, 1] (its ``dmd_cfg`` sets no
23+
``min_timestep`` / ``max_timestep``, so it clamps to the full range) -- FastGen's
24+
convention for the other rectified-flow Wan configs; and, in the co-trained loss, the
25+
1/g rescaling of dF/dt under ``guidance_fuse_scale`` is gated on the samples that kept
26+
their condition, where the reference's ``compute_central_difference`` rescales the whole
27+
batch (see ``config_anyflow.py`` and ``FlowMapLossMixin._compute_mf_loss``).
2228
"""
2329

2430
import copy
2531

32+
2633
import fastgen.configs.methods.config_anyflow as config_anyflow_default
2734
from fastgen.configs.data import VideoLoaderConfig
2835
from fastgen.configs.net import Wan_1_3B_Config
36+
from fastgen.methods import AnyFlowModel
2937

3038

3139
def create_config():
@@ -77,11 +85,13 @@ def create_config():
7785
config.model.guidance_scale = 4.0
7886

7987
# DMD gradient noising time: reference `generator_loss` draws torch.rand
80-
# then applies the shift -> shifted-uniform.
88+
# then applies the shift -> shifted-uniform. The bounds keep the score models off
89+
# the degenerate endpoints (see the deviation note above); `fake_score_sample_t_cfg`
90+
# inherits them through the deepcopy below.
8191
config.model.sample_t_cfg.time_dist_type = "shifted"
8292
config.model.sample_t_cfg.shift = 5.0
83-
config.model.sample_t_cfg.min_t = 0.0
84-
config.model.sample_t_cfg.max_t = 1.0
93+
config.model.sample_t_cfg.min_t = 0.001
94+
config.model.sample_t_cfg.max_t = 0.999
8595

8696
# Fake-score noising time: reference `discriminator_loss` draws
8797
# logit_normal(0, 1) then applies the same shift. This is a DIFFERENT
@@ -92,13 +102,12 @@ def create_config():
92102
config.model.fake_score_sample_t_cfg.train_p_std = 1.0
93103

94104
# ------ student rollout (reference rollout_cfg) ------
105+
# The rollout grid's shift comes from `cotrain_sample_t_cfg` below: the reference
106+
# builds its rollout pipeline from the same `scheduler` it draws the co-trained
107+
# (t, r) from, separately from the DMD noising time above.
95108
config.model.student_sample_type = "ode"
96109
config.model.student_sample_steps_list = [2, 4, 8, 16, 50]
97110
config.model.student_sample_steps = 4
98-
# Validation schedule for `student_sample_steps = 4`: `shift * s / (1 + (shift
99-
# - 1) * s)` on `s = linspace(1, 0, 5)` -- the same grid the per-NFE rollout
100-
# builds. Recompute if `shift`, `max_t` or `student_sample_steps` changes.
101-
config.model.sample_t_cfg.t_list = [1.0, 0.9375, 0.8333333333333334, 0.625, 0.0]
102111

103112
# ------ co-trained Stage-1 flow-map loss (reference cotrain_forward_kl) ------
104113
# FastGen's VSD loss carries a 0.5 factor the reference's DMD loss does
@@ -115,9 +124,22 @@ def create_config():
115124
config.model.guidance_fuse_scale = 3.0
116125
config.model.cond_dropout_prob = 0.1
117126
config.model.precision_amp_jvp = "float32"
118-
config.model.sample_t_cfg.flow_matching_ratio = 0.5
119-
config.model.sample_t_cfg.consistency_ratio = 0.25
120-
config.model.sample_t_cfg.deterministic_buckets = True
127+
# (t, r) sampling for the co-trained loss, drawn from the reference's `scheduler`.
128+
# Its shift also drives the student's rollout grid, so it is independent of the DMD
129+
# noising-time shift above; the reference recipe sets both to 5.0.
130+
config.model.cotrain_sample_t_cfg.time_dist_type = "shifted"
131+
config.model.cotrain_sample_t_cfg.shift = 5.0
132+
config.model.cotrain_sample_t_cfg.min_t = 0.0
133+
config.model.cotrain_sample_t_cfg.max_t = 1.0
134+
config.model.cotrain_sample_t_cfg.flow_matching_ratio = 0.5
135+
config.model.cotrain_sample_t_cfg.consistency_ratio = 0.25
136+
config.model.cotrain_sample_t_cfg.deterministic_buckets = True
137+
138+
# Validation schedule at `student_sample_steps` -- the same grid the per-NFE rollout
139+
# builds, so it follows the co-trained sampling shift.
140+
config.model.sample_t_cfg.t_list = AnyFlowModel.rollout_t_list(
141+
config.model.student_sample_steps, config.model.cotrain_sample_t_cfg.shift, config.model.net.max_t
142+
).tolist()
121143

122144
# ------ optimization (reference: AdamW lr=2e-6, betas=(0.0, 0.999), wd=0,
123145
# grad clip 1.0, EMA 0.99) ------

fastgen/configs/experiments/WanT2V/config_mf.py

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -74,12 +74,8 @@ def create_config():
7474
config.model.sample_t_cfg.min_t = 0.001
7575
config.model.sample_t_cfg.max_t = 0.999
7676

77-
config.dataloader_train = VideoLatentLoaderConfig
77+
config.dataloader_train = copy.deepcopy(VideoLatentLoaderConfig)
7878
config.dataloader_train.batch_size = 1
7979

80-
# 480p (832x480) resolution
81-
config.dataloader_train.img_size = (config.model.input_shape[-1] * 8, config.model.input_shape[-2] * 8)
82-
config.dataloader_train.sequence_length = (config.model.input_shape[1] - 1) * 4 + 1
83-
8480
config.log_config.group = "wan_mf"
8581
return config

fastgen/configs/methods/config_anyflow.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,11 @@ class ModelConfig(DMD2ModelConfig):
4242
``cotrain_forward_kl``).
4343
"""
4444

45-
# MeanFlow-style (t, r) sampling for the co-trained flow-map loss; the
46-
# extra fields are ignored by the DMD2 noising-time sampling.
47-
sample_t_cfg: MeanFlowSampleTConfig = attrs.field(factory=MeanFlowSampleTConfig)
48-
sample_r_cfg: MeanFlowSampleRConfig = attrs.field(factory=MeanFlowSampleRConfig)
45+
# MeanFlow-style (t, r) sampling for the co-trained flow-map loss. Separate from
46+
# the inherited `sample_t_cfg`, which DMD2 uses for the noising time: the reference
47+
# draws these from its `scheduler` and the noising time from its `dmd_scheduler`.
48+
cotrain_sample_t_cfg: MeanFlowSampleTConfig = attrs.field(factory=MeanFlowSampleTConfig)
49+
cotrain_sample_r_cfg: MeanFlowSampleRConfig = attrs.field(factory=MeanFlowSampleRConfig)
4950
loss_config: MeanFlowLossConfig = attrs.field(factory=MeanFlowLossConfig)
5051

5152
# Weight of the co-trained Stage-1 flow-map loss in the student update.
@@ -70,7 +71,7 @@ class ModelConfig(DMD2ModelConfig):
7071
cond_dropout_prob: Optional[float] = None
7172
cond_keys_no_dropout: List[str] = attrs.field(factory=list)
7273

73-
# Precision for autocast in the co-trained loss JVP (None = training precision).
74+
# Precision for autocast in the co-trained loss JVP (None disables autocast there).
7475
precision_amp_jvp: str | None = None
7576

7677
# MeanFlow's target-side guidance knobs. AnyFlow typically guides on the

fastgen/configs/methods/config_mean_flow.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ class ModelConfig(BaseModelConfig):
129129
# guidance t end
130130
guidance_t_end: float = 1.0
131131

132-
# precision for autocast in JVP (none defaults to training precision)
132+
# precision for autocast in JVP (none disables autocast in the JVP region)
133133
precision_amp_jvp: str | None = None
134134

135135

fastgen/configs/methods/config_scm.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ class ModelConfig(BaseModelConfig):
7777
# optimizer
7878
net_optimizer: DictConfig = attrs.field(factory=lambda: copy.deepcopy(RAdamOptimizerConfig))
7979

80-
# precision for autocast in JVP (none defaults to training precision)
80+
# precision for autocast in JVP (none disables autocast in the JVP region)
8181
precision_amp_jvp: str | None = None
8282

8383

0 commit comments

Comments
 (0)