dwehr's picture
Migrate action viewer to local Cosmos generation
9f818c5
Raw
History Blame Contribute Delete
4.8 kB
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: OpenMDW-1.1
"""FLOPs estimation for the Wan 2.2 VAE encoder (Encoder3d)."""
from decimal import Decimal
def compute_wan_vae_encoder_flops(
B: int | Decimal,
T: int,
H: int,
W: int,
*,
dim: int = 160,
z_dim: int = 48,
dim_mult: list[int] | None = None,
num_res_blocks: int = 2,
temperal_downsample: list[bool] | None = None,
) -> Decimal:
"""Compute forward-pass FLOPs for the Wan 2.2 VAE encoder (Encoder3d).
The encoder converts a pixel-space video [B, 3, T, H, W] into a latent
[B, z_dim, T//4, H//16, W//16]. It is frozen during training so only
forward-pass FLOPs are counted (no backward).
The architecture: patchify(2) -> conv1 -> 4 downsample stages (each with
``num_res_blocks`` residual blocks + optional spatial/temporal downsample)
-> middle block (ResBlock + single-head spatial attention + ResBlock)
-> head (RMSNorm + SiLU + conv) -> pointwise 1x1 conv.
Args:
B: Batch size.
T: Number of pixel-space temporal frames.
H: Pixel-space height (must be divisible by 16).
W: Pixel-space width (must be divisible by 16).
dim: Base channel dimension of the encoder (default 160).
z_dim: Latent channel dimension (default 48, encoder outputs 2*z_dim).
dim_mult: Channel multiplier per stage (default [1, 2, 4, 4]).
num_res_blocks: Residual blocks per downsample stage (default 2).
temperal_downsample: Per-stage temporal downsampling flags (default
[False, True, True]).
Returns:
Total forward-pass FLOPs as a Decimal.
"""
if dim_mult is None:
dim_mult = [1, 2, 4, 4]
if temperal_downsample is None:
temperal_downsample = [False, True, True]
B = int(B)
flops = Decimal(0)
def _causalconv3d_flops(c_in: int, c_out: int, kt: int, kh: int, kw: int, bt: int, bh: int, bw: int) -> int:
return 2 * c_out * c_in * kt * kh * kw * B * bt * bh * bw
def _resblock_flops(in_dim: int, out_dim: int, bt: int, bh: int, bw: int) -> int:
vol = B * bt * bh * bw
f = 0
f += 5 * in_dim * vol # RMS_norm(in_dim)
f += 2 * out_dim * in_dim * 27 * vol # CausalConv3d(in_dim, out_dim, 3)
f += 5 * out_dim * vol # RMS_norm(out_dim)
f += 2 * out_dim * out_dim * 27 * vol # CausalConv3d(out_dim, out_dim, 3)
if in_dim != out_dim:
f += 2 * out_dim * in_dim * vol # shortcut CausalConv3d(in_dim, out_dim, 1)
return f
def _attnblock_flops(d: int, bt: int, bh: int, bw: int) -> int:
vol = B * bt * bh * bw
seq = bh * bw
f = 0
f += 5 * d * vol # RMS_norm
f += 2 * (d * 3) * d * vol # to_qkv Conv2d(d, 3d, 1)
f += 4 * B * bt * seq * seq * d # QK^T + Attn*V
f += 2 * d * d * vol # proj Conv2d(d, d, 1)
return f
# After patchify(patch_size=2): [B, 12, T, H/2, W/2]
t, h, w = T, H // 2, W // 2
# conv1: CausalConv3d(12, dims[0], 3)
dims = [dim * u for u in [1] + dim_mult] # [160, 160, 320, 640, 640]
flops += _causalconv3d_flops(12, dims[0], 3, 3, 3, t, h, w)
# Downsample stages
for i, (in_d, out_d) in enumerate(zip(dims[:-1], dims[1:])):
t_down = temperal_downsample[i] if i < len(temperal_downsample) else False
down_flag = i != len(dim_mult) - 1
cur_in = in_d
for _ in range(num_res_blocks):
flops += _resblock_flops(cur_in, out_d, t, h, w)
cur_in = out_d
if down_flag:
if t_down:
h_new, w_new = h // 2, w // 2
flops += 2 * out_d * out_d * 9 * B * t * h_new * w_new # spatial conv2d
t_new = t // 2
flops += 2 * out_d * out_d * 3 * B * t_new * h_new * w_new # temporal conv3d(3,1,1)
t, h, w = t_new, h_new, w_new
else:
h_new, w_new = h // 2, w // 2
flops += 2 * out_d * out_d * 9 * B * t * h_new * w_new
h, w = h_new, w_new
# Middle block: ResBlock + AttentionBlock + ResBlock
mid_dim = dims[-1]
flops += _resblock_flops(mid_dim, mid_dim, t, h, w)
flops += _attnblock_flops(mid_dim, t, h, w)
flops += _resblock_flops(mid_dim, mid_dim, t, h, w)
# Head: RMS_norm + SiLU + CausalConv3d(mid_dim, z_dim*2, 3)
enc_out_dim = z_dim * 2
flops += 5 * mid_dim * B * t * h * w # RMS_norm
flops += _causalconv3d_flops(mid_dim, enc_out_dim, 3, 3, 3, t, h, w)
# WanVAE_.conv1: CausalConv3d(z_dim*2, z_dim*2, 1) — pointwise 1x1
flops += _causalconv3d_flops(enc_out_dim, enc_out_dim, 1, 1, 1, t, h, w)
return Decimal(flops)