---
title: qwen3
---

<div class="python-reference">
<a id="fastvideo.models.encoders.qwen3-classes"></a>
<a id="fastvideo.models.encoders.qwen3-functions"></a>
<a id="fastvideo.models.encoders.qwen3"></a>
<p>Qwen3 causal LM text encoder for FastVideo diffusion models (e.g. Flux2 Klein).</p>
<h2 id="fastvideo.models.encoders.qwen3.LocalAttention"><code>fastvideo.models.encoders.qwen3.LocalAttention</code></h2>
<pre class="doc-signature"><code>LocalAttention(num_heads: int, head_size: int, num_kv_heads: int | None = None, softmax_scale: float | None = None, causal: bool = False, supported_attention_backends: tuple&#91;AttentionBackendEnum, ...&#93; | None = None, default_backend: AttentionBackendEnum | None = None, **extra_impl_args)</code></pre>
<p>Attention layer.</p>

<h3 id="fastvideo.models.encoders.qwen3.LocalAttention.forward"><code>fastvideo.models.encoders.qwen3.LocalAttention.forward</code></h3>
<pre class="doc-signature"><code>forward(q: torch.Tensor, k: torch.Tensor, v: torch.Tensor, freqs_cis: tuple&#91;torch.Tensor, torch.Tensor&#93; | None = None) -&gt; torch.Tensor</code></pre>
<p>Apply local attention between query, key and value tensors.</p>
<h4>Parameters</h4>
<dl>
<dt><code>q: torch.Tensor</code></dt><dd><p>Query tensor of shape [batch_size, seq_len, num_heads, head_dim]</p></dd>
<dt><code>k: torch.Tensor</code></dt><dd><p>Key tensor of shape [batch_size, seq_len, num_heads, head_dim] </p></dd>
<dt><code>v: torch.Tensor</code></dt><dd><p>Value tensor of shape [batch_size, seq_len, num_heads, head_dim]</p></dd>
</dl>
<h4>Returns</h4>
<dl>
<dt><code>torch.Tensor</code></dt><dd><p>torch.Tensor: Output tensor after local attention</p></dd>
</dl>
<h2 id="fastvideo.models.encoders.qwen3.BaseEncoderOutput"><code>fastvideo.models.encoders.qwen3.BaseEncoderOutput</code></h2>
<pre class="doc-signature"><code>BaseEncoderOutput(last_hidden_state: torch.FloatTensor | None = None, pooler_output: torch.FloatTensor | None = None, hidden_states: tuple&#91;torch.FloatTensor, ...&#93; | None = None, attentions: tuple&#91;torch.FloatTensor, ...&#93; | None = None, attention_mask: torch.Tensor | None = None)</code></pre>


<h2 id="fastvideo.models.encoders.qwen3.Qwen3TextConfig"><code>fastvideo.models.encoders.qwen3.Qwen3TextConfig</code></h2>
<pre class="doc-signature"><code>Qwen3TextConfig(arch_config: TextEncoderArchConfig = Qwen3TextArchConfig(), prefix: str = &#x27;qwen3&#x27;, quant_config: QuantizationConfig | None = None, lora_config: Any | None = None, is_chat_model: bool = True, treat_empty_as_dot: bool = False, *, _resolved_attention_backend: AttentionBackendEnum | None = None, chat_template_enable_thinking: bool = False)</code></pre>
<p>Top-level config for Qwen3 text encoder.</p>

<h2 id="fastvideo.models.encoders.qwen3.get_tp_world_size"><code>fastvideo.models.encoders.qwen3.get_tp_world_size</code></h2>
<pre class="doc-signature"><code>get_tp_world_size() -&gt; int</code></pre>
<p>Return world size for the tensor model parallel group.</p>
<h2 id="fastvideo.models.encoders.qwen3.SiluAndMul"><code>fastvideo.models.encoders.qwen3.SiluAndMul</code></h2>
<pre class="doc-signature"><code>SiluAndMul()</code></pre>
<p>An activation function for SwiGLU.</p>
<p>The function computes x -&gt; silu(x[:d]) * x[d:] where d = x.shape[-1] // 2.</p>
<h3>Shapes</h3>
<p>x: (num_tokens, 2 * d) or (batch_size, seq_len, 2 * d)
return: (num_tokens, d) or (batch_size, seq_len, d)</p>

<h3 id="fastvideo.models.encoders.qwen3.SiluAndMul.forward_native"><code>fastvideo.models.encoders.qwen3.SiluAndMul.forward_native</code></h3>
<pre class="doc-signature"><code>forward_native(x: torch.Tensor) -&gt; torch.Tensor</code></pre>
<p>PyTorch-native implementation equivalent to forward().</p>
<h2 id="fastvideo.models.encoders.qwen3.RMSNorm"><code>fastvideo.models.encoders.qwen3.RMSNorm</code></h2>
<pre class="doc-signature"><code>RMSNorm(hidden_size: int, eps: float = 1e-06, dtype: torch.dtype = torch.float32, var_hidden_size: int | None = None, has_weight: bool = True)</code></pre>
<p>Root mean square normalization.</p>
<p>Computes x -&gt; w * x / sqrt(E[x^2] + eps) where w is the learned weight.
Refer to https://arxiv.org/abs/1910.07467</p>

<h3 id="fastvideo.models.encoders.qwen3.RMSNorm.forward_native"><code>fastvideo.models.encoders.qwen3.RMSNorm.forward_native</code></h3>
<pre class="doc-signature"><code>forward_native(x: torch.Tensor, residual: torch.Tensor | None = None) -&gt; torch.Tensor | tuple&#91;torch.Tensor, torch.Tensor&#93;</code></pre>
<p>PyTorch-native implementation equivalent to forward().</p>
<h3 id="fastvideo.models.encoders.qwen3.RMSNorm.extra_repr"><code>fastvideo.models.encoders.qwen3.RMSNorm.extra_repr</code></h3>
<pre class="doc-signature"><code>extra_repr() -&gt; str</code></pre>

<h2 id="fastvideo.models.encoders.qwen3.MergedColumnParallelLinear"><code>fastvideo.models.encoders.qwen3.MergedColumnParallelLinear</code></h2>
<pre class="doc-signature"><code>MergedColumnParallelLinear(input_size: int, output_sizes: list&#91;int&#93;, bias: bool = True, gather_output: bool = False, skip_bias_add: bool = False, params_dtype: torch.dtype | None = None, quant_config: QuantizationConfig | None = None, prefix: str = &#x27;&#x27;)</code></pre>
<p>Packed linear layers with column parallelism.</p>
<p>Similar to ColumnParallelLinear, but the weight matrix is concatenated
along the output dimension. When the weight matrix is loaded, the
different partitions are sharded separately.</p>
<h3>Parameters</h3>
<dl>
<dt><code>input_size: int</code></dt><dd><p>input dimension of the linear layer.</p></dd>
<dt><code>output_sizes: list[int]</code></dt><dd><p>list of output dimensions of the linear layer.</p></dd>
<dt><code>bias: bool</code></dt><dd><p>If true, add bias.</p></dd>
<dt><code>gather_output: bool</code></dt><dd><p>If true, call all-gather on output and make the output
           available to all GPUs, otherwise, every GPU will have
           its own output.</p></dd>
<dt><code>skip_bias_add: bool</code></dt><dd><p>This was added to enable performance optimizations where
           bias can be fused with other element-wise operations. we
           skip adding bias but instead return it.</p></dd>
<dt><code>params_dtype: torch.dtype | None</code></dt><dd><p>Data type for the parameters.</p></dd>
<dt><code>quant_config: QuantizationConfig | None</code></dt><dd><p>Quantization configure.</p></dd>
<dt><code>prefix: str</code></dt><dd><p>The name of the layer in the state dict, including all parents
            (e.g. model.layers.0.qkv_proj)</p></dd>
</dl>

<h3 id="fastvideo.models.encoders.qwen3.MergedColumnParallelLinear.weight_loader"><code>fastvideo.models.encoders.qwen3.MergedColumnParallelLinear.weight_loader</code></h3>
<pre class="doc-signature"><code>weight_loader(param: Parameter, loaded_weight: torch.Tensor, loaded_shard_id: int | None = None) -&gt; None</code></pre>

<h3 id="fastvideo.models.encoders.qwen3.MergedColumnParallelLinear.weight_loader_v2"><code>fastvideo.models.encoders.qwen3.MergedColumnParallelLinear.weight_loader_v2</code></h3>
<pre class="doc-signature"><code>weight_loader_v2(param: BasevLLMParameter, loaded_weight: torch.Tensor, loaded_shard_id: int | None = None) -&gt; None</code></pre>

<h2 id="fastvideo.models.encoders.qwen3.QKVParallelLinear"><code>fastvideo.models.encoders.qwen3.QKVParallelLinear</code></h2>
<pre class="doc-signature"><code>QKVParallelLinear(hidden_size: int, head_size: int, total_num_heads: int, total_num_kv_heads: int | None = None, bias: bool = True, skip_bias_add: bool = False, params_dtype: torch.dtype | None = None, quant_config: QuantizationConfig | None = None, prefix: str = &#x27;&#x27;)</code></pre>
<p>Linear layers for the attention's QKV transformation.</p>
<p>Linear layers for the linear transformation of the query, key, and value
vectors in the attention layer. The weight matrix is concatenated along
the output dimension. The layer is parallelized along the head dimension.
When the number of key/value heads is smaller than the number of query
heads (e.g., multi-query/grouped-query attention), the key/value head may
be replicated while the query heads are partitioned.</p>
<h3>Parameters</h3>
<dl>
<dt><code>hidden_size: int</code></dt><dd><p>input hidden state size of the transformer.</p></dd>
<dt><code>head_size: int</code></dt><dd><p>size of each attention head.</p></dd>
<dt><code>total_num_heads: int</code></dt><dd><p>total number of attention query heads.</p></dd>
<dt><code>total_num_kv_heads: int | None</code></dt><dd><p>total number of attention key/value heads. If
                None, assume total_num_kv_heads = total_num_heads.</p></dd>
<dt><code>bias: bool</code></dt><dd><p>If true, add bias.</p></dd>
<dt><code>skip_bias_add: bool</code></dt><dd><p>This was added to enable performance optimizations where
           bias can be fused with other element-wise operations. we
           skip adding bias but instead return it.</p></dd>
<dt><code>params_dtype: torch.dtype | None</code></dt><dd><p>Data type for the parameters.</p></dd>
<dt><code>quant_config: QuantizationConfig | None</code></dt><dd><p>Quantization configure.</p></dd>
<dt><code>prefix: str</code></dt><dd><p>The name of the layer in the state dict, including all parents
            (e.g. model.layers.0.qkv_proj)</p></dd>
</dl>

<h3 id="fastvideo.models.encoders.qwen3.QKVParallelLinear.weight_loader_v2"><code>fastvideo.models.encoders.qwen3.QKVParallelLinear.weight_loader_v2</code></h3>
<pre class="doc-signature"><code>weight_loader_v2(param: BasevLLMParameter, loaded_weight: torch.Tensor, loaded_shard_id: str | None = None)</code></pre>

<h3 id="fastvideo.models.encoders.qwen3.QKVParallelLinear.weight_loader"><code>fastvideo.models.encoders.qwen3.QKVParallelLinear.weight_loader</code></h3>
<pre class="doc-signature"><code>weight_loader(param: Parameter, loaded_weight: torch.Tensor, loaded_shard_id: str | None = None)</code></pre>

<h2 id="fastvideo.models.encoders.qwen3.RowParallelLinear"><code>fastvideo.models.encoders.qwen3.RowParallelLinear</code></h2>
<pre class="doc-signature"><code>RowParallelLinear(input_size: int, output_size: int, bias: bool = True, input_is_parallel: bool = True, skip_bias_add: bool = False, params_dtype: torch.dtype | None = None, reduce_results: bool = True, quant_config: QuantizationConfig | None = None, prefix: str = &#x27;&#x27;)</code></pre>
<p>Linear layer with row parallelism.</p>
<p>The linear layer is defined as Y = XA + b. A is parallelized along
its first dimension and X along its second dimension as:
           -   -
          | A_1 |
          | .   |
      A = | .   |        X = [X_1, ..., X_p]
          | .   |
          | A_p |
           -   -
Arguments:
    input_size: first dimension of matrix A.
    output_size: second dimension of matrix A.
    bias: If true, add bias. Note that bias is not parallelized.
    input_is_parallel: If true, we assume that the input is already
                       split across the GPUs and we do not split
                       again.
    skip_bias_add: This was added to enable performance optimization where
                   bias can be fused with other element-wise operations.
                   We skip adding bias but instead return it.
    params_dtype: Data type for the parameters.
    quant_config: Quantization configure.</p>

<h3 id="fastvideo.models.encoders.qwen3.RowParallelLinear.weight_loader"><code>fastvideo.models.encoders.qwen3.RowParallelLinear.weight_loader</code></h3>
<pre class="doc-signature"><code>weight_loader(param: Parameter, loaded_weight: torch.Tensor)</code></pre>

<h3 id="fastvideo.models.encoders.qwen3.RowParallelLinear.weight_loader_v2"><code>fastvideo.models.encoders.qwen3.RowParallelLinear.weight_loader_v2</code></h3>
<pre class="doc-signature"><code>weight_loader_v2(param: BasevLLMParameter, loaded_weight: torch.Tensor)</code></pre>

<h3 id="fastvideo.models.encoders.qwen3.RowParallelLinear.forward"><code>fastvideo.models.encoders.qwen3.RowParallelLinear.forward</code></h3>
<pre class="doc-signature"><code>forward(input_) -&gt; tuple&#91;torch.Tensor, Parameter | None&#93;</code></pre>

<h3 id="fastvideo.models.encoders.qwen3.RowParallelLinear.extra_repr"><code>fastvideo.models.encoders.qwen3.RowParallelLinear.extra_repr</code></h3>
<pre class="doc-signature"><code>extra_repr() -&gt; str</code></pre>

<h2 id="fastvideo.models.encoders.qwen3.QuantizationConfig"><code>fastvideo.models.encoders.qwen3.QuantizationConfig</code></h2>
<pre class="doc-signature"><code>QuantizationConfig()</code></pre>
<p>Base class for quantization configs.</p>

<h3 id="fastvideo.models.encoders.qwen3.QuantizationConfig.get_name"><code>fastvideo.models.encoders.qwen3.QuantizationConfig.get_name</code></h3>
<pre class="doc-signature"><code>get_name() -&gt; QuantizationMethods</code></pre>
<p>Name of the quantization method.</p>
<h3 id="fastvideo.models.encoders.qwen3.QuantizationConfig.get_supported_act_dtypes"><code>fastvideo.models.encoders.qwen3.QuantizationConfig.get_supported_act_dtypes</code></h3>
<pre class="doc-signature"><code>get_supported_act_dtypes() -&gt; list&#91;torch.dtype&#93;</code></pre>
<p>List of supported activation dtypes.</p>
<h3 id="fastvideo.models.encoders.qwen3.QuantizationConfig.get_min_capability"><code>fastvideo.models.encoders.qwen3.QuantizationConfig.get_min_capability</code></h3>
<pre class="doc-signature"><code>get_min_capability() -&gt; int</code></pre>
<p>Minimum GPU capability to support the quantization method.</p>
<p>E.g., 70 for Volta, 75 for Turing, 80 for Ampere.
This requirement is due to the custom CUDA kernels used by the
quantization method.</p>
<h3 id="fastvideo.models.encoders.qwen3.QuantizationConfig.get_config_filenames"><code>fastvideo.models.encoders.qwen3.QuantizationConfig.get_config_filenames</code></h3>
<pre class="doc-signature"><code>get_config_filenames() -&gt; list&#91;str&#93;</code></pre>
<p>List of filenames to search for in the model directory.</p>
<h3 id="fastvideo.models.encoders.qwen3.QuantizationConfig.from_config"><code>fastvideo.models.encoders.qwen3.QuantizationConfig.from_config</code></h3>
<pre class="doc-signature"><code>from_config(config: dict&#91;str, Any&#93;) -&gt; QuantizationConfig</code></pre>
<p>Create a config class from the model's quantization config.</p>
<h3 id="fastvideo.models.encoders.qwen3.QuantizationConfig.override_quantization_method"><code>fastvideo.models.encoders.qwen3.QuantizationConfig.override_quantization_method</code></h3>
<pre class="doc-signature"><code>override_quantization_method(hf_quant_cfg, user_quant) -&gt; QuantizationMethods | None</code></pre>
<p>Detects if this quantization method can support a given checkpoint
format by overriding the user specified quantization method -- 
this method should only be overwritten by subclasses in exceptional 
circumstances</p>
<h3 id="fastvideo.models.encoders.qwen3.QuantizationConfig.get_from_keys"><code>fastvideo.models.encoders.qwen3.QuantizationConfig.get_from_keys</code></h3>
<pre class="doc-signature"><code>get_from_keys(config: dict&#91;str, Any&#93;, keys: list&#91;str&#93;) -&gt; Any</code></pre>
<p>Get a value from the model's quantization config.</p>
<h3 id="fastvideo.models.encoders.qwen3.QuantizationConfig.get_from_keys_or"><code>fastvideo.models.encoders.qwen3.QuantizationConfig.get_from_keys_or</code></h3>
<pre class="doc-signature"><code>get_from_keys_or(config: dict&#91;str, Any&#93;, keys: list&#91;str&#93;, default: Any) -&gt; Any</code></pre>
<p>Get a optional value from the model's quantization config.</p>
<h3 id="fastvideo.models.encoders.qwen3.QuantizationConfig.get_quant_method"><code>fastvideo.models.encoders.qwen3.QuantizationConfig.get_quant_method</code></h3>
<pre class="doc-signature"><code>get_quant_method(layer: torch.nn.Module, prefix: str) -&gt; QuantizeMethodBase | None</code></pre>
<p>Get the quantize method to use for the quantized layer.</p>
<h4>Parameters</h4>
<dl>
<dt><code>layer: torch.nn.Module</code></dt><dd><p>The layer for the quant method.</p></dd>
<dt><code>prefix: str</code></dt><dd><p>The full name of the layer in the state dict</p></dd>
</dl>
<p>Returns:
    The quantize method. None if the given layer doesn't support quant
    method.</p>
<h3 id="fastvideo.models.encoders.qwen3.QuantizationConfig.validate_runtime"><code>fastvideo.models.encoders.qwen3.QuantizationConfig.validate_runtime</code></h3>
<pre class="doc-signature"><code>validate_runtime(device: torch.device) -&gt; None</code></pre>
<p>Fail fast on a device the scheme cannot execute on.</p>
<p>Called once by loaders that select a serialized checkpoint scheme,
before any weight is read. The default accepts every device; schemes
with kernel or capability requirements override it.</p>
<h3 id="fastvideo.models.encoders.qwen3.QuantizationConfig.get_cache_scale"><code>fastvideo.models.encoders.qwen3.QuantizationConfig.get_cache_scale</code></h3>
<pre class="doc-signature"><code>get_cache_scale(name: str) -&gt; str | None</code></pre>

<h2 id="fastvideo.models.encoders.qwen3.get_rope"><code>fastvideo.models.encoders.qwen3.get_rope</code></h2>
<pre class="doc-signature"><code>get_rope(head_size: int, rotary_dim: int, max_position: int, base: int | float, is_neox_style: bool = True, rope_scaling: dict&#91;str, Any&#93; | None = None, dtype: torch.dtype | None = None, partial_rotary_factor: float = 1.0) -&gt; RotaryEmbedding</code></pre>

<h2 id="fastvideo.models.encoders.qwen3.VocabParallelEmbedding"><code>fastvideo.models.encoders.qwen3.VocabParallelEmbedding</code></h2>
<pre class="doc-signature"><code>VocabParallelEmbedding(num_embeddings: int, embedding_dim: int, params_dtype: torch.dtype | None = None, org_num_embeddings: int | None = None, padding_size: int = DEFAULT_VOCAB_PADDING_SIZE, quant_config: QuantizationConfig | None = None, prefix: str = &#x27;&#x27;)</code></pre>
<p>Embedding parallelized in the vocabulary dimension.</p>
<p>Adapted from torch.nn.Embedding, note that we pad the vocabulary size to
make sure it is divisible by the number of model parallel GPUs.</p>
<p>In order to support various loading methods, we ensure that LoRA-added
embeddings are always at the end of TP-sharded tensors. In other words,
we shard base embeddings and LoRA embeddings separately (both padded),
and place them in the same tensor.
In this example, we will have the original vocab size = 1010,
added vocab size = 16 and padding to 64. Therefore, the total
vocab size with padding will be 1088 (because we first pad 1010 to
1024, add 16, and then pad to 1088).
Therefore, the tensor format looks like the following:
TP1, rank 0 (no sharding):
                        |&lt; --------BASE-------- &gt;|&lt; -BASE PADDING-- &gt;|&lt; -----LORA------ &gt;|&lt; -LORA PADDING-- &gt;|
corresponding token_id: |  0  |  1  | ... | 1009 |  -1  | ... |  -1  | 1010 | ... | 1015 |  -1  | ... |  -1  |
                 index: |  0  |  1  | ... | 1009 | 1010 | ... | 1023 | 1024 | ... | 1039 | 1040 | ... | 1087 |</p>
<p>TP2, rank 0:
                        |&lt; --------------------BASE--------------------- &gt;|&lt; -----LORA------ &gt;|&lt; -LORA PADDING- &gt;|
corresponding token_id: |  0  |  1  |  2  | ... | 497  | 498 | ...  | 511 | 1000 | ... | 1015 |  -1  | ... |  -1 |
                 index: |  0  |  1  |  2  | ... | 497  | 498 | ...  | 511 | 512  | ... | 527  |  520 | ... | 543 |
TP2, rank 1:
                        |&lt; -----------BASE----------- &gt;|&lt; -BASE PADDING- &gt;|&lt; -----------LORA PADDING----------- &gt;|
corresponding token_id: | 512 | 513 | 514 | ... | 1009 | -1  | ...  | -1  |  -1  | ... |  -1  | -1  | ... |   -1 |
                 index: |  0  |  1  |  2  | ... | 497  | 498 | ...  | 511 | 512  | ... | 519  | 520 | ... |  543 |</p>
<h3>Parameters</h3>
<dl>
<dt><code>num_embeddings: int</code></dt><dd><p>vocabulary size.</p></dd>
<dt><code>embedding_dim: int</code></dt><dd><p>size of hidden state.</p></dd>
<dt><code>params_dtype: torch.dtype | None</code></dt><dd><p>type of the parameters.</p></dd>
<dt><code>org_num_embeddings: int | None</code></dt><dd><p>original vocabulary size (without LoRA).</p></dd>
<dt><code>padding_size: int</code></dt><dd><p>padding size for the vocabulary.</p></dd>
<dt><code>quant_config: QuantizationConfig | None</code></dt><dd><p>quant config for the layer</p></dd>
<dt><code>prefix: str</code></dt><dd><p>full name of the layer in the state dict</p></dd>
</dl>

<h3 id="fastvideo.models.encoders.qwen3.VocabParallelEmbedding.get_sharded_to_full_mapping"><code>fastvideo.models.encoders.qwen3.VocabParallelEmbedding.get_sharded_to_full_mapping</code></h3>
<pre class="doc-signature"><code>get_sharded_to_full_mapping() -&gt; list&#91;int&#93; | None</code></pre>
<p>Get a mapping that can be used to reindex the gathered
logits for sampling.</p>
<p>During sampling, we gather logits from all ranks. The relationship
of index-&gt;token_id will follow the same format as outlined in the class
docstring. However, after the gather, we want to reindex the final
logits tensor to map index-&gt;token_id one-to-one (the index is always
equal the token_id it corresponds to). The indices returned by this
method allow us to do that.</p>
<h3 id="fastvideo.models.encoders.qwen3.VocabParallelEmbedding.weight_loader"><code>fastvideo.models.encoders.qwen3.VocabParallelEmbedding.weight_loader</code></h3>
<pre class="doc-signature"><code>weight_loader(param: Parameter, loaded_weight: torch.Tensor)</code></pre>

<h3 id="fastvideo.models.encoders.qwen3.VocabParallelEmbedding.forward"><code>fastvideo.models.encoders.qwen3.VocabParallelEmbedding.forward</code></h3>
<pre class="doc-signature"><code>forward(input_)</code></pre>

<h3 id="fastvideo.models.encoders.qwen3.VocabParallelEmbedding.extra_repr"><code>fastvideo.models.encoders.qwen3.VocabParallelEmbedding.extra_repr</code></h3>
<pre class="doc-signature"><code>extra_repr() -&gt; str</code></pre>

<h2 id="fastvideo.models.encoders.qwen3.TextEncoder"><code>fastvideo.models.encoders.qwen3.TextEncoder</code></h2>
<pre class="doc-signature"><code>TextEncoder(config: TextEncoderConfig)</code></pre>
<p>Base for native encoders with a model-specific forward output contract.</p>

<h3 id="fastvideo.models.encoders.qwen3.TextEncoder.forward"><code>fastvideo.models.encoders.qwen3.TextEncoder.forward</code></h3>
<pre class="doc-signature"><code>forward(*args: Any, **kwargs: Any) -&gt; TextEncoderOutputT</code></pre>

<h2 id="fastvideo.models.encoders.qwen3.default_weight_loader"><code>fastvideo.models.encoders.qwen3.default_weight_loader</code></h2>
<pre class="doc-signature"><code>default_weight_loader(param: torch.Tensor, loaded_weight: torch.Tensor) -&gt; None</code></pre>
<p>Default weight loader.</p>
<h2 id="fastvideo.models.encoders.qwen3.maybe_remap_kv_scale_name"><code>fastvideo.models.encoders.qwen3.maybe_remap_kv_scale_name</code></h2>
<pre class="doc-signature"><code>maybe_remap_kv_scale_name(name: str, params_dict: dict) -&gt; str | None</code></pre>
<p>Remap the name of FP8 k/v_scale parameters.</p>
<p>This function handles the remapping of FP8 k/v_scale parameter names.
It detects if the given name ends with a suffix and attempts to remap
it to the expected name format in the model. If the remapped name is not
found in the params_dict, a warning is printed and None is returned.</p>
<h3>Parameters</h3>
<dl>
<dt><code>name: str</code></dt><dd><p>The original loaded checkpoint parameter name.</p></dd>
<dt><code>params_dict: dict</code></dt><dd><p>Dictionary containing the model's named parameters.</p></dd>
</dl>
<h3>Returns</h3>
<dl>
<dt><code>str: str | None</code></dt><dd><p>The remapped parameter name if successful, or the original name
 if no remapping is needed.</p></dd>
<dt><code>None: str | None</code></dt><dd><p>If the remapped name is not found in params_dict.</p></dd>
</dl>
<h2 id="fastvideo.models.encoders.qwen3.Qwen3MLP"><code>fastvideo.models.encoders.qwen3.Qwen3MLP</code></h2>
<pre class="doc-signature"><code>Qwen3MLP(hidden_size: int, intermediate_size: int, hidden_act: str, quant_config: QuantizationConfig | None = None, bias: bool = False, prefix: str = &#x27;&#x27;)</code></pre>
<p>Qwen3 MLP with SwiGLU activation and tensor parallelism.</p>

<details><summary>Source</summary><pre><code>class Qwen3MLP(nn.Module):
    &quot;&quot;&quot;Qwen3 MLP with SwiGLU activation and tensor parallelism.&quot;&quot;&quot;

    def __init__(
        self,
        hidden_size: int,
        intermediate_size: int,
        hidden_act: str,
        quant_config: QuantizationConfig | None = None,
        bias: bool = False,
        prefix: str = &quot;&quot;,
    ) -&gt; None:
        super().__init__()
        self.gate_up_proj = MergedColumnParallelLinear(
            input_size=hidden_size,
            output_sizes=&#91;intermediate_size&#93; * 2,
            bias=bias,
            quant_config=quant_config,
            prefix=f&quot;&#123;prefix&#125;.gate_up_proj&quot;,
        )
        self.down_proj = RowParallelLinear(
            input_size=intermediate_size,
            output_size=hidden_size,
            bias=bias,
            quant_config=quant_config,
            prefix=f&quot;&#123;prefix&#125;.down_proj&quot;,
        )
        if hidden_act != &quot;silu&quot;:
            raise ValueError(f&quot;Unsupported activation: &#123;hidden_act&#125;. Only silu is supported.&quot;)
        self.act_fn = SiluAndMul()

    def forward(self, x: torch.Tensor) -&gt; torch.Tensor:
        x, _ = self.gate_up_proj(x)
        x = self.act_fn(x)
        x, _ = self.down_proj(x)
        return x</code></pre></details>
<h3 id="fastvideo.models.encoders.qwen3.Qwen3MLP.forward"><code>fastvideo.models.encoders.qwen3.Qwen3MLP.forward</code></h3>
<pre class="doc-signature"><code>forward(x: torch.Tensor) -&gt; torch.Tensor</code></pre>

<details><summary>Source</summary><pre><code>def forward(self, x: torch.Tensor) -&gt; torch.Tensor:
    x, _ = self.gate_up_proj(x)
    x = self.act_fn(x)
    x, _ = self.down_proj(x)
    return x</code></pre></details>
<h2 id="fastvideo.models.encoders.qwen3.Qwen3Attention"><code>fastvideo.models.encoders.qwen3.Qwen3Attention</code></h2>
<pre class="doc-signature"><code>Qwen3Attention(config: Qwen3TextConfig, hidden_size: int, num_heads: int, num_kv_heads: int, rope_theta: float = 1000000.0, rope_scaling: dict&#91;str, Any&#93; | None = None, max_position_embeddings: int = 40960, quant_config: QuantizationConfig | None = None, bias: bool = False, prefix: str = &#x27;&#x27;)</code></pre>
<p>Qwen3 attention with QK-Norm and tensor parallelism.</p>
<p>Key difference from LLaMA: RMSNorm is applied to Q and K before attention.</p>

<details><summary>Source</summary><pre><code>class Qwen3Attention(nn.Module):
    &quot;&quot;&quot;Qwen3 attention with QK-Norm and tensor parallelism.

    Key difference from LLaMA: RMSNorm is applied to Q and K before attention.
    &quot;&quot;&quot;

    def __init__(
        self,
        config: Qwen3TextConfig,
        hidden_size: int,
        num_heads: int,
        num_kv_heads: int,
        rope_theta: float = 1000000.0,
        rope_scaling: dict&#91;str, Any&#93; | None = None,
        max_position_embeddings: int = 40960,
        quant_config: QuantizationConfig | None = None,
        bias: bool = False,
        prefix: str = &quot;&quot;,
    ) -&gt; None:
        super().__init__()
        self.hidden_size = hidden_size
        tp_size = get_tp_world_size()
        self.total_num_heads = num_heads
        assert self.total_num_heads % tp_size == 0
        self.num_heads = self.total_num_heads // tp_size
        self.total_num_kv_heads = num_kv_heads
        if self.total_num_kv_heads &gt;= tp_size:
            assert self.total_num_kv_heads % tp_size == 0
        else:
            assert tp_size % self.total_num_kv_heads == 0
        self.num_kv_heads = max(1, self.total_num_kv_heads // tp_size)

        self.head_dim = getattr(config, &quot;head_dim&quot;, self.hidden_size // self.total_num_heads)
        self.rotary_dim = self.head_dim
        self.q_size = self.num_heads * self.head_dim
        self.kv_size = self.num_kv_heads * self.head_dim
        self.scaling = self.head_dim**-0.5
        self.rope_theta = rope_theta
        self.max_position_embeddings = max_position_embeddings

        self.qkv_proj = QKVParallelLinear(
            hidden_size=hidden_size,
            head_size=self.head_dim,
            total_num_heads=self.total_num_heads,
            total_num_kv_heads=self.total_num_kv_heads,
            bias=bias,
            quant_config=quant_config,
            prefix=f&quot;&#123;prefix&#125;.qkv_proj&quot;,
        )
        self.o_proj = RowParallelLinear(
            input_size=self.total_num_heads * self.head_dim,
            output_size=hidden_size,
            bias=bias,
            quant_config=quant_config,
            prefix=f&quot;&#123;prefix&#125;.o_proj&quot;,
        )

        rms_norm_eps = getattr(config, &quot;rms_norm_eps&quot;, 1e-6)
        self.q_norm = RMSNorm(self.head_dim, eps=rms_norm_eps)
        self.k_norm = RMSNorm(self.head_dim, eps=rms_norm_eps)

        self.rotary_emb = get_rope(
            self.head_dim,
            rotary_dim=self.rotary_dim,
            max_position=max_position_embeddings,
            base=int(rope_theta),
            rope_scaling=rope_scaling,
            is_neox_style=True,
        )

        self.attn = LocalAttention(
            self.num_heads,
            self.head_dim,
            self.num_kv_heads,
            softmax_scale=self.scaling,
            causal=True,
            supported_attention_backends=config._supported_attention_backends,
        )

    def forward(
        self,
        positions: torch.Tensor,
        hidden_states: torch.Tensor,
        attention_mask: torch.Tensor | None = None,
    ) -&gt; torch.Tensor:
        qkv, _ = self.qkv_proj(hidden_states)
        q, k, v = qkv.split(&#91;self.q_size, self.kv_size, self.kv_size&#93;, dim=-1)

        batch_size, seq_len = q.shape&#91;0&#93;, q.shape&#91;1&#93;
        q = q.reshape(batch_size, seq_len, self.num_heads, self.head_dim)
        k = k.reshape(batch_size, seq_len, self.num_kv_heads, self.head_dim)
        v = v.reshape(batch_size, seq_len, self.num_kv_heads, self.head_dim)

        q = self.q_norm(q)
        k = self.k_norm(k)

        q = q.reshape(batch_size, seq_len, -1)
        k = k.reshape(batch_size, seq_len, -1)

        q, k = self.rotary_emb(positions, q, k)

        q = q.reshape(batch_size, seq_len, self.num_heads, self.head_dim)
        k = k.reshape(batch_size, seq_len, self.num_kv_heads, self.head_dim)

        if attention_mask is None:
            attn_output = self.attn(q, k, v)
        else:
            q_sdpa = q.transpose(1, 2)
            k_sdpa = k.transpose(1, 2)
            v_sdpa = v.transpose(1, 2)
            causal_mask = torch.ones(
                seq_len,
                seq_len,
                device=q.device,
                dtype=torch.bool,
            ).tril()
            key_mask = attention_mask.to(device=q.device, dtype=torch.bool)
            attn_mask = causal_mask&#91;None, None, :, :&#93; &amp; key_mask&#91;:, None, None, :&#93;
            attn_output = torch.nn.functional.scaled_dot_product_attention(
                q_sdpa,
                k_sdpa,
                v_sdpa,
                attn_mask=attn_mask,
                dropout_p=0.0,
                is_causal=False,
                scale=self.scaling,
                enable_gqa=self.num_heads != self.num_kv_heads,
            ).transpose(1, 2)

        attn_output = attn_output.reshape(batch_size, seq_len, -1)

        output, _ = self.o_proj(attn_output)
        return output</code></pre></details>
<h3 id="fastvideo.models.encoders.qwen3.Qwen3Attention.forward"><code>fastvideo.models.encoders.qwen3.Qwen3Attention.forward</code></h3>
<pre class="doc-signature"><code>forward(positions: torch.Tensor, hidden_states: torch.Tensor, attention_mask: torch.Tensor | None = None) -&gt; torch.Tensor</code></pre>

<details><summary>Source</summary><pre><code>def forward(
    self,
    positions: torch.Tensor,
    hidden_states: torch.Tensor,
    attention_mask: torch.Tensor | None = None,
) -&gt; torch.Tensor:
    qkv, _ = self.qkv_proj(hidden_states)
    q, k, v = qkv.split(&#91;self.q_size, self.kv_size, self.kv_size&#93;, dim=-1)

    batch_size, seq_len = q.shape&#91;0&#93;, q.shape&#91;1&#93;
    q = q.reshape(batch_size, seq_len, self.num_heads, self.head_dim)
    k = k.reshape(batch_size, seq_len, self.num_kv_heads, self.head_dim)
    v = v.reshape(batch_size, seq_len, self.num_kv_heads, self.head_dim)

    q = self.q_norm(q)
    k = self.k_norm(k)

    q = q.reshape(batch_size, seq_len, -1)
    k = k.reshape(batch_size, seq_len, -1)

    q, k = self.rotary_emb(positions, q, k)

    q = q.reshape(batch_size, seq_len, self.num_heads, self.head_dim)
    k = k.reshape(batch_size, seq_len, self.num_kv_heads, self.head_dim)

    if attention_mask is None:
        attn_output = self.attn(q, k, v)
    else:
        q_sdpa = q.transpose(1, 2)
        k_sdpa = k.transpose(1, 2)
        v_sdpa = v.transpose(1, 2)
        causal_mask = torch.ones(
            seq_len,
            seq_len,
            device=q.device,
            dtype=torch.bool,
        ).tril()
        key_mask = attention_mask.to(device=q.device, dtype=torch.bool)
        attn_mask = causal_mask&#91;None, None, :, :&#93; &amp; key_mask&#91;:, None, None, :&#93;
        attn_output = torch.nn.functional.scaled_dot_product_attention(
            q_sdpa,
            k_sdpa,
            v_sdpa,
            attn_mask=attn_mask,
            dropout_p=0.0,
            is_causal=False,
            scale=self.scaling,
            enable_gqa=self.num_heads != self.num_kv_heads,
        ).transpose(1, 2)

    attn_output = attn_output.reshape(batch_size, seq_len, -1)

    output, _ = self.o_proj(attn_output)
    return output</code></pre></details>
<h2 id="fastvideo.models.encoders.qwen3.Qwen3DecoderLayer"><code>fastvideo.models.encoders.qwen3.Qwen3DecoderLayer</code></h2>
<pre class="doc-signature"><code>Qwen3DecoderLayer(config: Qwen3TextConfig, quant_config: QuantizationConfig | None = None, prefix: str = &#x27;&#x27;)</code></pre>
<p>Qwen3 transformer decoder layer.</p>

<details><summary>Source</summary><pre><code>class Qwen3DecoderLayer(nn.Module):
    &quot;&quot;&quot;Qwen3 transformer decoder layer.&quot;&quot;&quot;

    def __init__(
        self,
        config: Qwen3TextConfig,
        quant_config: QuantizationConfig | None = None,
        prefix: str = &quot;&quot;,
    ) -&gt; None:
        super().__init__()
        self.hidden_size = config.hidden_size
        rope_theta = getattr(config, &quot;rope_theta&quot;, 1000000.0)
        rope_scaling = getattr(config, &quot;rope_scaling&quot;, None)
        max_position_embeddings = getattr(config, &quot;max_position_embeddings&quot;, 40960)
        attention_bias = getattr(config, &quot;attention_bias&quot;, False)

        self.self_attn = Qwen3Attention(
            config=config,
            hidden_size=self.hidden_size,
            num_heads=config.num_attention_heads,
            num_kv_heads=getattr(config, &quot;num_key_value_heads&quot;, config.num_attention_heads),
            rope_theta=rope_theta,
            rope_scaling=rope_scaling,
            max_position_embeddings=max_position_embeddings,
            quant_config=quant_config,
            bias=attention_bias,
            prefix=f&quot;&#123;prefix&#125;.self_attn&quot;,
        )
        self.mlp = Qwen3MLP(
            hidden_size=self.hidden_size,
            intermediate_size=config.intermediate_size,
            hidden_act=config.hidden_act,
            quant_config=quant_config,
            bias=getattr(config, &quot;mlp_bias&quot;, False),
            prefix=f&quot;&#123;prefix&#125;.mlp&quot;,
        )
        self.input_layernorm = RMSNorm(config.hidden_size, eps=config.rms_norm_eps)
        self.post_attention_layernorm = RMSNorm(config.hidden_size, eps=config.rms_norm_eps)

    def forward(
        self,
        positions: torch.Tensor,
        hidden_states: torch.Tensor,
        residual: torch.Tensor | None,
        attention_mask: torch.Tensor | None = None,
    ) -&gt; tuple&#91;torch.Tensor, torch.Tensor&#93;:
        if residual is None:
            residual = hidden_states
            hidden_states = self.input_layernorm(hidden_states)
        else:
            hidden_states, residual = self.input_layernorm(hidden_states, residual)

        hidden_states = self.self_attn(
            positions=positions,
            hidden_states=hidden_states,
            attention_mask=attention_mask,
        )

        hidden_states, residual = self.post_attention_layernorm(hidden_states, residual)
        hidden_states = self.mlp(hidden_states)
        return hidden_states, residual</code></pre></details>
<h3 id="fastvideo.models.encoders.qwen3.Qwen3DecoderLayer.forward"><code>fastvideo.models.encoders.qwen3.Qwen3DecoderLayer.forward</code></h3>
<pre class="doc-signature"><code>forward(positions: torch.Tensor, hidden_states: torch.Tensor, residual: torch.Tensor | None, attention_mask: torch.Tensor | None = None) -&gt; tuple&#91;torch.Tensor, torch.Tensor&#93;</code></pre>

<details><summary>Source</summary><pre><code>def forward(
    self,
    positions: torch.Tensor,
    hidden_states: torch.Tensor,
    residual: torch.Tensor | None,
    attention_mask: torch.Tensor | None = None,
) -&gt; tuple&#91;torch.Tensor, torch.Tensor&#93;:
    if residual is None:
        residual = hidden_states
        hidden_states = self.input_layernorm(hidden_states)
    else:
        hidden_states, residual = self.input_layernorm(hidden_states, residual)

    hidden_states = self.self_attn(
        positions=positions,
        hidden_states=hidden_states,
        attention_mask=attention_mask,
    )

    hidden_states, residual = self.post_attention_layernorm(hidden_states, residual)
    hidden_states = self.mlp(hidden_states)
    return hidden_states, residual</code></pre></details>
<h2 id="fastvideo.models.encoders.qwen3.Qwen3ForCausalLM"><code>fastvideo.models.encoders.qwen3.Qwen3ForCausalLM</code></h2>
<pre class="doc-signature"><code>Qwen3ForCausalLM(config: Qwen3TextConfig)</code></pre>
<p>Qwen3 causal language model for text encoding in diffusion models (e.g. Flux2 Klein).</p>
<p>Features:
- Tensor parallelism support
- FlashAttention/SDPA support via LocalAttention
- QK-Norm for better training stability
- output_hidden_states for Klein (layers 9, 18, 27)</p>

<details><summary>Source</summary><pre><code>class Qwen3ForCausalLM(TextEncoder):
    &quot;&quot;&quot;Qwen3 causal language model for text encoding in diffusion models (e.g. Flux2 Klein).

    Features:
    - Tensor parallelism support
    - FlashAttention/SDPA support via LocalAttention
    - QK-Norm for better training stability
    - output_hidden_states for Klein (layers 9, 18, 27)
    &quot;&quot;&quot;

    supports_hf_from_pretrained = True

    def __init__(self, config: Qwen3TextConfig) -&gt; None:
        super().__init__(config)

        self.config = config
        self.quant_config = getattr(config, &quot;quant_config&quot;, None)

        if getattr(config, &quot;lora_config&quot;, None) is not None:
            max_loras = getattr(config.lora_config, &quot;max_loras&quot;, 1)
            lora_vocab_size = getattr(config.lora_config, &quot;lora_extra_vocab_size&quot;, 1)
            lora_vocab = lora_vocab_size * max_loras
        else:
            lora_vocab = 0
        self.vocab_size = config.vocab_size + lora_vocab
        self.org_vocab_size = config.vocab_size

        self.embed_tokens = VocabParallelEmbedding(
            self.vocab_size,
            config.hidden_size,
            org_num_embeddings=config.vocab_size,
            quant_config=self.quant_config,
        )

        self.layers = nn.ModuleList(&#91;
            Qwen3DecoderLayer(
                config=config,
                quant_config=self.quant_config,
                prefix=f&quot;&#123;config.prefix&#125;.layers.&#123;i&#125;&quot;,
            ) for i in range(config.num_hidden_layers)
        &#93;)

        self.norm = RMSNorm(config.hidden_size, eps=config.rms_norm_eps)

    @classmethod
    def from_pretrained_local(
        cls,
        model_path: str,
        model_config: Qwen3TextConfig,
        dtype: torch.dtype,
        device: torch.device,
    ) -&gt; nn.Module:
        from transformers import AutoModel

        # FastVideo uses Qwen3 only as a text encoder. Loading the body avoids
        # materializing an unused LM head and full-vocabulary logits, including
        # for checkpoints whose metadata names Qwen3ForCausalLM.
        return AutoModel.from_pretrained(
            model_path,
            local_files_only=True,
            dtype=dtype,
            low_cpu_mem_usage=True,
        ).eval().to(device)

    def get_input_embeddings(self, input_ids: torch.Tensor) -&gt; torch.Tensor:
        return self.embed_tokens(input_ids)

    def forward(
        self,
        input_ids: torch.Tensor | None = None,
        position_ids: torch.Tensor | None = None,
        attention_mask: torch.Tensor | None = None,
        inputs_embeds: torch.Tensor | None = None,
        output_hidden_states: bool | None = None,
        **kwargs: Any,
    ) -&gt; BaseEncoderOutput:
        output_hidden_states = (output_hidden_states
                                if output_hidden_states is not None else self.config.output_hidden_states)

        if inputs_embeds is not None:
            hidden_states = inputs_embeds
        else:
            assert input_ids is not None
            hidden_states = self.get_input_embeddings(input_ids)

        residual = None

        if position_ids is None:
            # Expand to &#91;batch_size, seq_len&#93;: the rotary layer flattens
            # positions to ``num_tokens`` and reshapes q/k to
            # ``(num_tokens, -1, head_dim)``. A bare &#91;1, seq_len&#93; only matches
            # ``num_tokens`` when batch_size == 1; for batched inputs it folds
            # the batch dim into the head dim and misaligns RoPE. Expanding to
            # ``batch_size * seq_len`` tokens keeps the layout correct.
            position_ids = torch.arange(
                0,
                hidden_states.shape&#91;1&#93;,
                device=hidden_states.device,
                dtype=torch.long,
            ).unsqueeze(0).expand(hidden_states.shape&#91;0&#93;, -1)

        all_hidden_states: tuple&#91;Any, ...&#93; | None = (() if output_hidden_states else None)

        for layer in self.layers:
            if all_hidden_states is not None:
                all_hidden_states += ((hidden_states, ) if residual is None else (hidden_states + residual, ))
            hidden_states, residual = layer(
                position_ids,
                hidden_states,
                residual,
                attention_mask=attention_mask,
            )

        hidden_states, _ = self.norm(hidden_states, residual)

        if all_hidden_states is not None:
            all_hidden_states += (hidden_states, )

        return BaseEncoderOutput(
            last_hidden_state=hidden_states,
            hidden_states=all_hidden_states,
        )

    def load_weights(self, weights: Iterable&#91;tuple&#91;str, torch.Tensor&#93;&#93;) -&gt; set&#91;str&#93;:
        params_dict = dict(self.named_parameters())
        loaded_params: set&#91;str&#93; = set()
        stacked_params_mapping = self.config.arch_config.stacked_params_mapping
        # A fused destination is initialized either by one already-fused tensor
        # or after every split source projection has been loaded. Include
        # auxiliary quantization parameters (for example scale_weight) rather
        # than limiting completeness checks to weight/bias tensors.
        expected_stacked_shards = &#123;(name, shard_id)
                                   for name in params_dict
                                   for param_name, _, shard_id in stacked_params_mapping if param_name in name&#125;
        fused_param_names = &#123;name for name, _ in expected_stacked_shards&#125;
        loaded_stacked_shards: set&#91;tuple&#91;str, str | int&#93;&#93; = set()
        loaded_fused_params: set&#91;str&#93; = set()

        for name, loaded_weight in weights:
            if name.startswith(&quot;model.&quot;):
                name = name&#91;6:&#93;

            if &quot;rotary_emb.inv_freq&quot; in name:
                continue
            if &quot;rotary_emb.cos_cached&quot; in name or &quot;rotary_emb.sin_cached&quot; in name:
                continue

            if &quot;scale&quot; in name:
                kv_scale_name: str | None = maybe_remap_kv_scale_name(name, params_dict)
                if kv_scale_name is None:
                    continue
                name = kv_scale_name

            matched_stacked_param = False
            for param_name, weight_name, shard_id in stacked_params_mapping:
                if weight_name not in name:
                    continue
                matched_stacked_param = True
                target_name = name.replace(weight_name, param_name)

                if target_name.endswith(&quot;.bias&quot;) and target_name not in params_dict:
                    break

                if target_name not in params_dict:
                    break

                param = params_dict&#91;target_name&#93;
                weight_loader = param.weight_loader
                weight_loader(param, loaded_weight, shard_id)
                loaded_params.add(target_name)
                loaded_stacked_shards.add((target_name, shard_id))
                break

            if matched_stacked_param:
                continue

            if name.endswith(&quot;.bias&quot;) and name not in params_dict:
                continue

            if name not in params_dict:
                continue

            param = params_dict&#91;name&#93;
            if name in fused_param_names and name.endswith(&quot;.scale_weight&quot;):
                # Merged scale loaders interpret a missing shard id as shard 0.
                # An exact fused key is already a complete vector, so copy it
                # atomically and retain the default loader&#x27;s shape validation.
                default_weight_loader(param, loaded_weight)
            else:
                weight_loader = getattr(param, &quot;weight_loader&quot;, default_weight_loader)
                weight_loader(param, loaded_weight)
            loaded_params.add(name)
            if name in fused_param_names:
                loaded_fused_params.add(name)

        required_split_shards = &#123;(name, shard_id)
                                 for name, shard_id in expected_stacked_shards if name not in loaded_fused_params&#125;
        missing_stacked_shards = required_split_shards - loaded_stacked_shards
        if missing_stacked_shards:
            formatted_missing = &quot;, &quot;.join(f&quot;&#123;name&#125;&#91;&#123;shard_id&#125;&#93;&quot; for name, shard_id in sorted(
                missing_stacked_shards,
                key=lambda item: (item&#91;0&#93;, str(item&#91;1&#93;)),
            ))
            raise ValueError(&quot;Missing required stacked checkpoint shards: &quot;
                             f&quot;&#123;formatted_missing&#125;&quot;)

        return loaded_params</code></pre></details>
<h3 id="fastvideo.models.encoders.qwen3.Qwen3ForCausalLM.from_pretrained_local"><code>fastvideo.models.encoders.qwen3.Qwen3ForCausalLM.from_pretrained_local</code></h3>
<pre class="doc-signature"><code>from_pretrained_local(model_path: str, model_config: Qwen3TextConfig, dtype: torch.dtype, device: torch.device) -&gt; nn.Module</code></pre>

<details><summary>Source</summary><pre><code>@classmethod
def from_pretrained_local(
    cls,
    model_path: str,
    model_config: Qwen3TextConfig,
    dtype: torch.dtype,
    device: torch.device,
) -&gt; nn.Module:
    from transformers import AutoModel

    # FastVideo uses Qwen3 only as a text encoder. Loading the body avoids
    # materializing an unused LM head and full-vocabulary logits, including
    # for checkpoints whose metadata names Qwen3ForCausalLM.
    return AutoModel.from_pretrained(
        model_path,
        local_files_only=True,
        dtype=dtype,
        low_cpu_mem_usage=True,
    ).eval().to(device)</code></pre></details>
<h3 id="fastvideo.models.encoders.qwen3.Qwen3ForCausalLM.get_input_embeddings"><code>fastvideo.models.encoders.qwen3.Qwen3ForCausalLM.get_input_embeddings</code></h3>
<pre class="doc-signature"><code>get_input_embeddings(input_ids: torch.Tensor) -&gt; torch.Tensor</code></pre>

<details><summary>Source</summary><pre><code>def get_input_embeddings(self, input_ids: torch.Tensor) -&gt; torch.Tensor:
    return self.embed_tokens(input_ids)</code></pre></details>
<h3 id="fastvideo.models.encoders.qwen3.Qwen3ForCausalLM.forward"><code>fastvideo.models.encoders.qwen3.Qwen3ForCausalLM.forward</code></h3>
<pre class="doc-signature"><code>forward(input_ids: torch.Tensor | None = None, position_ids: torch.Tensor | None = None, attention_mask: torch.Tensor | None = None, inputs_embeds: torch.Tensor | None = None, output_hidden_states: bool | None = None, **kwargs: Any) -&gt; BaseEncoderOutput</code></pre>

<details><summary>Source</summary><pre><code>def forward(
    self,
    input_ids: torch.Tensor | None = None,
    position_ids: torch.Tensor | None = None,
    attention_mask: torch.Tensor | None = None,
    inputs_embeds: torch.Tensor | None = None,
    output_hidden_states: bool | None = None,
    **kwargs: Any,
) -&gt; BaseEncoderOutput:
    output_hidden_states = (output_hidden_states
                            if output_hidden_states is not None else self.config.output_hidden_states)

    if inputs_embeds is not None:
        hidden_states = inputs_embeds
    else:
        assert input_ids is not None
        hidden_states = self.get_input_embeddings(input_ids)

    residual = None

    if position_ids is None:
        # Expand to &#91;batch_size, seq_len&#93;: the rotary layer flattens
        # positions to ``num_tokens`` and reshapes q/k to
        # ``(num_tokens, -1, head_dim)``. A bare &#91;1, seq_len&#93; only matches
        # ``num_tokens`` when batch_size == 1; for batched inputs it folds
        # the batch dim into the head dim and misaligns RoPE. Expanding to
        # ``batch_size * seq_len`` tokens keeps the layout correct.
        position_ids = torch.arange(
            0,
            hidden_states.shape&#91;1&#93;,
            device=hidden_states.device,
            dtype=torch.long,
        ).unsqueeze(0).expand(hidden_states.shape&#91;0&#93;, -1)

    all_hidden_states: tuple&#91;Any, ...&#93; | None = (() if output_hidden_states else None)

    for layer in self.layers:
        if all_hidden_states is not None:
            all_hidden_states += ((hidden_states, ) if residual is None else (hidden_states + residual, ))
        hidden_states, residual = layer(
            position_ids,
            hidden_states,
            residual,
            attention_mask=attention_mask,
        )

    hidden_states, _ = self.norm(hidden_states, residual)

    if all_hidden_states is not None:
        all_hidden_states += (hidden_states, )

    return BaseEncoderOutput(
        last_hidden_state=hidden_states,
        hidden_states=all_hidden_states,
    )</code></pre></details>
<h3 id="fastvideo.models.encoders.qwen3.Qwen3ForCausalLM.load_weights"><code>fastvideo.models.encoders.qwen3.Qwen3ForCausalLM.load_weights</code></h3>
<pre class="doc-signature"><code>load_weights(weights: Iterable&#91;tuple&#91;str, torch.Tensor&#93;&#93;) -&gt; set&#91;str&#93;</code></pre>

<details><summary>Source</summary><pre><code>def load_weights(self, weights: Iterable&#91;tuple&#91;str, torch.Tensor&#93;&#93;) -&gt; set&#91;str&#93;:
    params_dict = dict(self.named_parameters())
    loaded_params: set&#91;str&#93; = set()
    stacked_params_mapping = self.config.arch_config.stacked_params_mapping
    # A fused destination is initialized either by one already-fused tensor
    # or after every split source projection has been loaded. Include
    # auxiliary quantization parameters (for example scale_weight) rather
    # than limiting completeness checks to weight/bias tensors.
    expected_stacked_shards = &#123;(name, shard_id)
                               for name in params_dict
                               for param_name, _, shard_id in stacked_params_mapping if param_name in name&#125;
    fused_param_names = &#123;name for name, _ in expected_stacked_shards&#125;
    loaded_stacked_shards: set&#91;tuple&#91;str, str | int&#93;&#93; = set()
    loaded_fused_params: set&#91;str&#93; = set()

    for name, loaded_weight in weights:
        if name.startswith(&quot;model.&quot;):
            name = name&#91;6:&#93;

        if &quot;rotary_emb.inv_freq&quot; in name:
            continue
        if &quot;rotary_emb.cos_cached&quot; in name or &quot;rotary_emb.sin_cached&quot; in name:
            continue

        if &quot;scale&quot; in name:
            kv_scale_name: str | None = maybe_remap_kv_scale_name(name, params_dict)
            if kv_scale_name is None:
                continue
            name = kv_scale_name

        matched_stacked_param = False
        for param_name, weight_name, shard_id in stacked_params_mapping:
            if weight_name not in name:
                continue
            matched_stacked_param = True
            target_name = name.replace(weight_name, param_name)

            if target_name.endswith(&quot;.bias&quot;) and target_name not in params_dict:
                break

            if target_name not in params_dict:
                break

            param = params_dict&#91;target_name&#93;
            weight_loader = param.weight_loader
            weight_loader(param, loaded_weight, shard_id)
            loaded_params.add(target_name)
            loaded_stacked_shards.add((target_name, shard_id))
            break

        if matched_stacked_param:
            continue

        if name.endswith(&quot;.bias&quot;) and name not in params_dict:
            continue

        if name not in params_dict:
            continue

        param = params_dict&#91;name&#93;
        if name in fused_param_names and name.endswith(&quot;.scale_weight&quot;):
            # Merged scale loaders interpret a missing shard id as shard 0.
            # An exact fused key is already a complete vector, so copy it
            # atomically and retain the default loader&#x27;s shape validation.
            default_weight_loader(param, loaded_weight)
        else:
            weight_loader = getattr(param, &quot;weight_loader&quot;, default_weight_loader)
            weight_loader(param, loaded_weight)
        loaded_params.add(name)
        if name in fused_param_names:
            loaded_fused_params.add(name)

    required_split_shards = &#123;(name, shard_id)
                             for name, shard_id in expected_stacked_shards if name not in loaded_fused_params&#125;
    missing_stacked_shards = required_split_shards - loaded_stacked_shards
    if missing_stacked_shards:
        formatted_missing = &quot;, &quot;.join(f&quot;&#123;name&#125;&#91;&#123;shard_id&#125;&#93;&quot; for name, shard_id in sorted(
            missing_stacked_shards,
            key=lambda item: (item&#91;0&#93;, str(item&#91;1&#93;)),
        ))
        raise ValueError(&quot;Missing required stacked checkpoint shards: &quot;
                         f&quot;&#123;formatted_missing&#125;&quot;)

    return loaded_params</code></pre></details>
</div>
