Buckets:
| # AnyFlow | |
| [AnyFlow](https://huggingface.co/papers/2605.13724) 是一个视频扩散**蒸馏**框架,把预训练的 Wan2.1 教师 | |
| 模型蒸馏成在标准 Euler 采样下支持*任意步数 (any-step)* 的学生模型。同一个蒸馏出来的 checkpoint 可以 | |
| 在 1、2、4、8、16... NFE 下推理,**质量随步数单调提升** —— 这一点和 consistency models 不同,后者 | |
| NFE 增加反而经常掉点。 | |
| 核心思路是学习 **flow map** $\Phi_{r\leftarrow t}: \mathbf{z}_t \to \mathbf{z}_r$(任意 $1 \ge t \ge r \ge 0$), | |
| 而不是 consistency models 学的固定端点映射 $\mathbf{z}_t \to \mathbf{z}_0$。Flow map 的可组合性消除了 | |
| 采样步之间的 re-noising;on-policy 蒸馏阶段额外用 **DMD 反向散度监督** + **Flow-Map backward simulation** | |
| (3 段 shortcut)补上 consistency 蒸馏遗留的 exposure-bias 缺口。 | |
| AnyFlow 由 NVIDIA、新加坡国立大学(NUS)和 MIT 合作完成,作者为 Yuchao Gu、Guian Fang、Yuxin Jiang、Weijia Mao、Song Han、Han Cai、Mike Zheng Shou。原始训练代码在 [`NVlabs/AnyFlow`](https://github.com/NVlabs/AnyFlow),项目主页是 [nvlabs.github.io/AnyFlow](https://nvlabs.github.io/AnyFlow),4 个发布 checkpoint 归在 [`nvidia/anyflow`](https://huggingface.co/collections/nvidia/anyflow) Hugging Face collection 里。 | |
| 本文档梳理实战要点:怎么选 pipeline、怎么用 any-step 采样、怎么把 AnyFlow 嵌进 T2V / I2V / V2V 工作流。 | |
| ## Bidirectional 还是 Causal —— 怎么选 pipeline | |
| AnyFlow 提供两个 pipeline 形态,scheduler 和蒸馏方法相同,区别在于**怎么对帧采样**: | |
| - [`AnyFlowPipeline`](../api/pipelines/anyflow#anyflowpipeline) —— **bidirectional** T2V。一次性对整个 | |
| 视频张量去噪,全局自注意力。**纯 prompt 输入、不要流式输出**时选这个。 | |
| - [`AnyFlowFARPipeline`](../api/pipelines/anyflow#anyflowfarpipeline) —— **causal (FAR)**。 | |
| 按 chunk 分段去噪,块稀疏因果注意力 + 跨 chunk 复用 KV cache。**图生视频 (I2V)**、**视频续写 (V2V)**、 | |
| 或任何受益于逐帧自回归采样的场景选这个。同一个模型通过 `video`(像素空间)或 `video_latents` | |
| (已编码 latent)这两个互斥 kwarg 来切换三种任务模式。 | |
| 简化对照表: | |
| | 场景 | Pipeline | 调用方式 | | |
| |------|----------|----------| | |
| | 纯文生视频,固定 NFE 求最大质量 | `AnyFlowPipeline` | `pipe(prompt, ...)` | | |
| | 图生视频(首帧给定) | `AnyFlowFARPipeline` | `pipe(prompt, video=<单帧 tensor>, ...)` | | |
| | 视频续写 / V2V | `AnyFlowFARPipeline` | `pipe(prompt, video=<多帧 tensor>, ...)` | | |
| | 流式 / 渐进式生成 | `AnyFlowFARPipeline` | — | | |
| 高分辨率下 bidirectional 单 token 更快;causal 牺牲一点单步速度,换来在所有 latent 帧分配前就能开始 | |
| 采样的能力,对超长序列尤其有用。 | |
| ## 加载 checkpoint | |
| NVIDIA 发布了 4 个 AnyFlow checkpoint,pipeline × 规模各一份: | |
| ```py | |
| import torch | |
| from diffusers import AnyFlowPipeline, AnyFlowFARPipeline | |
| # Bidirectional, 轻量 | |
| pipe = AnyFlowPipeline.from_pretrained( | |
| "nvidia/AnyFlow-Wan2.1-T2V-1.3B-Diffusers", torch_dtype=torch.bfloat16 | |
| ).to("cuda") | |
| # Bidirectional, 满血 | |
| pipe = AnyFlowPipeline.from_pretrained( | |
| "nvidia/AnyFlow-Wan2.1-T2V-14B-Diffusers", torch_dtype=torch.bfloat16 | |
| ).to("cuda") | |
| # Causal (FAR), 1.3B | |
| pipe = AnyFlowFARPipeline.from_pretrained( | |
| "nvidia/AnyFlow-FAR-Wan2.1-1.3B-Diffusers", torch_dtype=torch.bfloat16 | |
| ).to("cuda") | |
| # Causal (FAR), 14B | |
| pipe = AnyFlowFARPipeline.from_pretrained( | |
| "nvidia/AnyFlow-FAR-Wan2.1-14B-Diffusers", torch_dtype=torch.bfloat16 | |
| ).to("cuda") | |
| ``` | |
| 四个 checkpoint 共用同一份 [`FlowMapEulerDiscreteScheduler`](../api/schedulers/flow_map_euler_discrete), | |
| 默认 `shift=5.0`。 | |
| ## Any-step 采样 | |
| AnyFlow 最关键的特性是同一个 checkpoint **不需重新调度**,NFE 越大质量越高。固定 prompt、扫一下步数 | |
| 就能看出模型怎么在延迟和保真度之间权衡: | |
| ```py | |
| import torch | |
| from diffusers import AnyFlowPipeline | |
| from diffusers.utils import export_to_video | |
| pipe = AnyFlowPipeline.from_pretrained( | |
| "nvidia/AnyFlow-Wan2.1-T2V-1.3B-Diffusers", torch_dtype=torch.bfloat16 | |
| ).to("cuda") | |
| prompt = "森林里一只小熊猫在啃竹子,电影感光照" | |
| for nfe in [1, 2, 4, 8, 16, 32]: | |
| # 每轮重建 generator —— 这样跨步数对比时唯一变量是 NFE。 | |
| generator = torch.Generator("cuda").manual_seed(0) | |
| video = pipe(prompt, num_inference_steps=nfe, num_frames=81, generator=generator).frames[0] | |
| export_to_video(video, f"out_nfe{nfe}.mp4", fps=16) | |
| ``` | |
| paper 的 Tab 3 / Fig 1 表明:每个 AnyFlow checkpoint 在 4 → 32 NFE 范围 VBench Quality 都单调上升,而 | |
| consistency 类基线(rCM、Self-Forcing)在同区间反而掉点。 | |
| > [!TIP] | |
| > Classifier-free guidance (CFG) 已经在训练阶段融进权重。pipeline 推理 | |
| > 时**不会**再跑一次 unconditional 前向 —— guidance 直接由蒸馏后的权重带出。release 出来的 checkpoint | |
| > 都用默认的 `guidance_scale=1.0` 即可。 | |
| ## 图生视频 与 视频续写 | |
| Causal pipeline 用同一个蒸馏模型支持三种任务模式,**通过 `video` / `video_latents` 二选一来选**: | |
| - `video` —— 像素空间张量,形状 `(B, T, C, H, W)` ∈ `[0, 1]`,pipeline 内部会过一遍 `VideoProcessor` | |
| + VAE 编码; | |
| - `video_latents` —— 已经在模型布局下的 latent,跳过 VAE 编码; | |
| - 两者都不传 —— 纯文生视频; | |
| - 两者同时传 —— 抛 `ValueError`(互斥)。 | |
| Context tensor 的帧数必须满足 `T = 4n + 1`,跟 VAE 时间步长对齐。 | |
| > [!IMPORTANT] | |
| > FAR pipeline 是分块 (chunk) rollout,`num_frames` 必须配合 chunk 调度。发布的 checkpoint 在 | |
| > transformer config 里写入 `chunk_partition=[1, 3, 3, 3, 3, 3, 3, 2]`(求和 21),对应标准 | |
| > `num_frames=81`(21 = (81 − 1) // 4 + 1)。改 `num_frames` 时**必须**显式传匹配的 `chunk_partition`, | |
| > 使其求和等于 `(num_frames - 1) // 4 + 1`,否则 pipeline 会抛 `ValueError`。比如 `num_frames=33` 对应 | |
| > 9 个 latent 帧,可用 `chunk_partition=[1, 4, 4]`。 | |
| ```py | |
| import numpy as np | |
| import torch | |
| from diffusers import AnyFlowFARPipeline | |
| from diffusers.utils import export_to_video, load_image, load_video | |
| pipe = AnyFlowFARPipeline.from_pretrained( | |
| "nvidia/AnyFlow-FAR-Wan2.1-1.3B-Diffusers", torch_dtype=torch.bfloat16 | |
| ).to("cuda") | |
| def to_video_tensor(images, height=480, width=832): | |
| """把 PIL 列表转成 FAR pipeline 需要的 (B, T, C, H, W) [0, 1] 张量。""" | |
| frames = np.stack([np.asarray(img.resize((width, height))) for img in images]).astype("float32") / 255.0 | |
| # frames: (T, H, W, C) → (T, C, H, W) → 加 batch 维 → (1, T, C, H, W) | |
| return torch.from_numpy(frames).permute(0, 3, 1, 2).unsqueeze(0) | |
| # 1) 文生视频(无 context)。81 帧匹配默认 chunk_partition。 | |
| video = pipe(prompt="一只猫在夕阳下冲浪", num_inference_steps=4, num_frames=81).frames[0] | |
| export_to_video(video, "t2v.mp4", fps=16) | |
| # 2) 图生视频 —— 单帧 context 经过 VAE 是 1 个 latent,正好对上默认 chunk_partition 的第一项 (`[1, ...]`)。 | |
| first_frame = load_image("path/to/first_frame.png") | |
| context_tensor = to_video_tensor([first_frame]).to("cuda") # (1, 1, 3, 480, 832), [0, 1] | |
| video = pipe( | |
| prompt="一只猫走过阳光下的草坪", | |
| video=context_tensor, | |
| num_inference_steps=4, | |
| num_frames=81, | |
| ).frames[0] | |
| export_to_video(video, "i2v.mp4", fps=16) | |
| # 3) 视频续写。9 帧 raw context → 3 个 latent context;显式覆盖 chunk_partition,让第一块正好覆盖 context。 | |
| context_frames = load_video("path/to/context.mp4")[:9] # 9 = 4·2 + 1 | |
| context_tensor = to_video_tensor(context_frames).to("cuda") # (1, 9, 3, 480, 832) | |
| video = pipe( | |
| prompt="继续这个故事", | |
| video=context_tensor, | |
| num_inference_steps=4, | |
| num_frames=81, | |
| chunk_partition=[3, 3, 3, 3, 3, 3, 3], # 7 个 chunk × 3 = 21 latent;首块就是 context | |
| ).frames[0] | |
| export_to_video(video, "v2v.mp4", fps=16) | |
| ``` | |
| 底层 patchify chunk 调度根据 `video` / `video_latents` 是否给定自动调整:纯文生用 kernel 2 (full) 和 | |
| 4 (compressed);有 context 时第一个 chunk 改成 kernel 1,让条件帧保留全分辨率。 | |
| 如果你已经有 VAE 编码过的 latent,可以直接传 `video_latents=<tensor>` 跳过 `vae_encode` 步骤 | |
| (和 `video` 互斥)。 | |
| ## LoRA 微调 | |
| 两个 pipeline 都复用 [`WanLoraLoaderMixin`](../api/loaders/lora),因此为对应 Wan2.1 backbone 训练的 | |
| LoRA adapter 直接加载即可: | |
| ```py | |
| pipe.load_lora_weights("path/or/repo/with/wan_lora") | |
| ``` | |
| 如果要做**继续 on-policy 蒸馏微调**(用论文里相同的 DMD 反向散度监督配方训新 LoRA),请参考原始 | |
| AnyFlow 训练框架 [`NVlabs/AnyFlow`](https://github.com/NVlabs/AnyFlow),这套训练流程不在 | |
| diffusers 范围内。 | |
| ## 常见坑 | |
| - **永远 `guidance_scale=1.0`。** 蒸馏后的 checkpoint 已经把 CFG 融进权重。设 `> 1` 会多跑一遍 | |
| unconditional 前向、延迟翻倍、质量微降。 | |
| - **Bidirectional pipeline 不支持流式。** 所有 `num_frames` 一起去噪。需要边采边播请用 causal pipeline。 | |
| - **Causal pipeline KV cache 假设 chunk 调度跨调用一致。** 中途重建 cache 不被 release 模型支持。 | |
| - **`num_frames` 必须满足 VAE 时间步长。** release checkpoint 用 `(N - 1) % 4 == 0` 的值(如 9、17、33、81)。 | |
| ## 引用 | |
| ```bibtex | |
| @misc{gu2026anyflowanystepvideodiffusion, | |
| title={AnyFlow: Any-Step Video Diffusion Model with On-Policy Flow Map Distillation}, | |
| author={Yuchao Gu and Guian Fang and Yuxin Jiang and Weijia Mao and Song Han and Han Cai and Mike Zheng Shou}, | |
| year={2026}, | |
| eprint={2605.13724}, | |
| archivePrefix={arXiv}, | |
| primaryClass={cs.CV}, | |
| url={https://arxiv.org/abs/2605.13724}, | |
| } | |
| @article{gu2025long, | |
| title={Long-Context Autoregressive Video Modeling with Next-Frame Prediction}, | |
| author={Gu, Yuchao and Mao, Weijia and Shou, Mike Zheng}, | |
| journal={arXiv preprint arXiv:2503.19325}, | |
| year={2025} | |
| } | |
| ``` | |
Xet Storage Details
- Size:
- 10.2 kB
- Xet hash:
- 99de32cb8c5629aa89c2a77ec1901da6fd012041dede6b5b1c599146e113d576
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.