wan_s2v_audio ¶
Audio conditioning modules for Wan2.2-S2V.
These are the parts of the S2V checkpoint that plain Wan does not have: the audio bridge (casual_audio_encoder, upstream's spelling) that turns wav2vec2 features into DiT-width tokens, and the audio injector (audio_injector) that re-introduces those tokens into 12 of the 40 transformer blocks.
Shapes below are verified against Wan-AI/Wan2.2-S2V-14B: casual_audio_encoder.weights (1, 25, 1, 1) casual_audio_encoder.encoder.conv1_local.conv.weight (5120, 1024, 3) casual_audio_encoder.encoder.conv1_global.conv.weight (1280, 1024, 3) casual_audio_encoder.encoder.conv2.conv.weight (2560, 1280, 3) casual_audio_encoder.encoder.conv3.conv.weight (5120, 2560, 3) casual_audio_encoder.encoder.final_linear.weight (5120, 5120) casual_audio_encoder.encoder.padding_tokens (1, 1, 1, 5120) audio_injector.injector_adain_layers.N.linear.weight (10240, 5120)
The (1, 25, 1, 1) layer-weight tensor is load-bearing: 25 == the number of hidden states returned by wav2vec2-large (24 layers + embeddings). The bundled wav2vec2-large-xlsr-53-english is required; wav2vec2-base returns 13 and will not fit this tensor.
Classes¶
fastvideo.models.dits.wan_s2v_audio.AdaLayerNorm ¶
Bases: Module
Scale/shift a hidden state from a conditioning vector.
linear emits 2*dim (verified: 10240 for dim 5120) -- one shift and one scale. The norm itself is affine-free; all the affine behaviour comes from the audio, which is the point.
Source code in fastvideo/models/dits/wan_s2v_audio.py
fastvideo.models.dits.wan_s2v_audio.AudioCrossAttention ¶
Bases: Module
One audio hatch: video tokens query, audio tokens answer.
Structurally identical to Wan's own cross-attention (q/k/v/o + qk RMSNorm), which is why the checkpoint's injector tensors have the same shapes as blocks.N.cross_attn.*.
Source code in fastvideo/models/dits/wan_s2v_audio.py
fastvideo.models.dits.wan_s2v_audio.AudioInjector ¶
AudioInjector(dim: int, num_heads: int, inject_layers: tuple[int, ...], enable_adain: bool = True, adain_dim: int | None = None, eps: float = 1e-06)
Bases: Module
The 12 audio hatches bolted onto the 40-block tower.
injected_block_id maps block index -> dense injector index. The checkpoint stores injectors densely (injector.0 .. injector.11) with no record of which block each one serves; that correspondence exists only in audio_inject_layers. Getting it wrong loads cleanly and steers the wrong layers, so the mapping is built once here and asserted.
injector_pre_norm_feat / injector_pre_norm_vec are affine-free LayerNorms and therefore contribute no checkpoint tensors -- they are present so the module tree matches upstream.
Source code in fastvideo/models/dits/wan_s2v_audio.py
Methods:¶
fastvideo.models.dits.wan_s2v_audio.AudioInjector.forward ¶
forward(hidden_states: Tensor, block_idx: int, audio_emb: Tensor, audio_emb_global: Tensor | None, original_seq_len: int, adain_mode: str = 'attn_norm') -> Tensor
Residually inject audio into the video-token span of one block's output.
hidden_states [B, L, C] -- L covers video + ref + motion tokens. audio_emb [B, F, N, C] -- per-frame audio tokens. original_seq_len number of leading tokens that are video (the rest are ref/motion and must not be touched).
Source code in fastvideo/models/dits/wan_s2v_audio.py
fastvideo.models.dits.wan_s2v_audio.CausalAudioEncoder ¶
CausalAudioEncoder(dim: int = 1024, num_layers: int = 25, out_dim: int = 5120, num_token: int = 4, need_global: bool = False)
Bases: Module
The audio bridge: [B, 25, C_a, T] wav2vec2 stack -> DiT-width tokens.
weights is a learned softmax over wav2vec2's 25 hidden states -- the model decides for itself which depth of the audio encoder matters, rather than hardcoding "use the last layer".
Source code in fastvideo/models/dits/wan_s2v_audio.py
fastvideo.models.dits.wan_s2v_audio.CausalConv1d ¶
CausalConv1d(chan_in: int, chan_out: int, kernel_size: int = 3, stride: int = 1, pad_mode: str = 'replicate')
Bases: Module
Conv1d that only ever looks backwards in time.
Left-pads by kernel_size - 1 so output frame t depends on input frames <= t. Audio conditioning must not leak future sound into earlier video frames, which is what makes the whole stack streamable.
Source code in fastvideo/models/dits/wan_s2v_audio.py
fastvideo.models.dits.wan_s2v_audio.MotionEncoder ¶
Bases: Module
wav2vec2 features -> per-frame audio tokens (and a global summary).
Two parallel paths over the same input
- local --
num_heads(== num_audio_token) tokens per frame, the content the video tokens cross-attend to. - global -- one summary vector per frame, used by the AdaIN path.