---
title: siglip
---

<div class="python-reference">
<a id="fastvideo.models.encoders.siglip-classes"></a>
<a id="fastvideo.models.encoders.siglip-functions"></a>
<a id="fastvideo.models.encoders.siglip.SiglipAttention-functions"></a>
<a id="fastvideo.models.encoders.siglip"></a>
<p>SigLIP Vision Encoder for FastVideo.</p>
<p>SigLIP (Sigmoid Loss for Language-Image Pre-training) is similar to CLIP
but uses sigmoid loss instead of contrastive loss, and doesn't use a CLS token.</p>
<h2 id="fastvideo.models.encoders.siglip.LocalAttention"><code>fastvideo.models.encoders.siglip.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.siglip.LocalAttention.forward"><code>fastvideo.models.encoders.siglip.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.siglip.BaseEncoderOutput"><code>fastvideo.models.encoders.siglip.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.siglip.SiglipVisionArchConfig"><code>fastvideo.models.encoders.siglip.SiglipVisionArchConfig</code></h2>
<pre class="doc-signature"><code>SiglipVisionArchConfig(stacked_params_mapping: list = (lambda: &#91;(&#x27;qkv_proj&#x27;, &#x27;q_proj&#x27;, &#x27;q&#x27;), (&#x27;qkv_proj&#x27;, &#x27;k_proj&#x27;, &#x27;k&#x27;), (&#x27;qkv_proj&#x27;, &#x27;v_proj&#x27;, &#x27;v&#x27;)&#93;)(), architectures: list&#91;str&#93; = (lambda: &#91;&#x27;SiglipVisionModel&#x27;&#93;)(), _supported_attention_backends: tuple&#91;AttentionBackendEnum, ...&#93; = (AttentionBackendEnum.FLASH_ATTN, AttentionBackendEnum.TORCH_SDPA), output_hidden_states: bool = False, use_return_dict: bool = True, attention_dropout: float = 0.0, dtype: str | None = None, hidden_act: str = &#x27;gelu_pytorch_tanh&#x27;, hidden_size: int = 1152, image_size: int = 384, intermediate_size: int = 4304, layer_norm_eps: float = 1e-06, model_type: str = &#x27;siglip_vision_model&#x27;, num_attention_heads: int = 16, num_channels: int = 3, num_hidden_layers: int = 27, patch_size: int = 14)</code></pre>
<p>Architecture configuration for SigLIP vision encoder.</p>
<p>Fields match the config.json from HuggingFace SigLIP checkpoints.</p>

<h2 id="fastvideo.models.encoders.siglip.SiglipVisionConfig"><code>fastvideo.models.encoders.siglip.SiglipVisionConfig</code></h2>
<pre class="doc-signature"><code>SiglipVisionConfig(arch_config: ImageEncoderArchConfig = SiglipVisionArchConfig(), prefix: str = &#x27;siglip&#x27;, quant_config: QuantizationConfig | None = None, lora_config: Any | None = None, num_hidden_layers_override: int | None = None, require_post_norm: bool | None = None, enable_scale: bool = True, is_causal: bool = False, *, _resolved_attention_backend: AttentionBackendEnum | None = None)</code></pre>
<p>Configuration for SigLIP vision encoder.</p>

<h2 id="fastvideo.models.encoders.siglip.divide"><code>fastvideo.models.encoders.siglip.divide</code></h2>
<pre class="doc-signature"><code>divide(numerator: int, denominator: int) -&gt; int</code></pre>
<p>Ensure that numerator is divisible by the denominator and return
the division value.</p>
<h2 id="fastvideo.models.encoders.siglip.get_tp_world_size"><code>fastvideo.models.encoders.siglip.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.siglip.get_act_fn"><code>fastvideo.models.encoders.siglip.get_act_fn</code></h2>
<pre class="doc-signature"><code>get_act_fn(act_fn_name: str) -&gt; nn.Module</code></pre>
<p>Get an activation function by name.</p>
<h2 id="fastvideo.models.encoders.siglip.ColumnParallelLinear"><code>fastvideo.models.encoders.siglip.ColumnParallelLinear</code></h2>
<pre class="doc-signature"><code>ColumnParallelLinear(input_size: int, output_size: int, bias: bool = True, gather_output: bool = False, skip_bias_add: bool = False, params_dtype: torch.dtype | None = None, quant_config: QuantizationConfig | None = None, output_sizes: list&#91;int&#93; | None = None, prefix: str = &#x27;&#x27;)</code></pre>
<p>Linear layer with column parallelism.</p>
<p>The linear layer is defined as Y = XA + b. A is parallelized along
its second dimension as A = [A_1, ..., A_p].</p>
<h3>Parameters</h3>
<dl>
<dt><code>input_size: int</code></dt><dd><p>first dimension of matrix A.</p></dd>
<dt><code>output_size: int</code></dt><dd><p>second dimension of matrix A.</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 Y available
           to all GPUs, otherwise, every GPU will have its output
           which is Y_i = XA_i</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>output_sizes: list[int] | None</code></dt><dd><p>list of output sizes packed into one output, like for QKV
           the list would be size 3.</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.siglip.ColumnParallelLinear.weight_loader"><code>fastvideo.models.encoders.siglip.ColumnParallelLinear.weight_loader</code></h3>
<pre class="doc-signature"><code>weight_loader(param: Parameter, loaded_weight: torch.Tensor) -&gt; None</code></pre>

<h3 id="fastvideo.models.encoders.siglip.ColumnParallelLinear.weight_loader_v2"><code>fastvideo.models.encoders.siglip.ColumnParallelLinear.weight_loader_v2</code></h3>
<pre class="doc-signature"><code>weight_loader_v2(param: Parameter, loaded_weight: torch.Tensor) -&gt; None</code></pre>

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

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

<h2 id="fastvideo.models.encoders.siglip.QKVParallelLinear"><code>fastvideo.models.encoders.siglip.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.siglip.QKVParallelLinear.weight_loader_v2"><code>fastvideo.models.encoders.siglip.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.siglip.QKVParallelLinear.weight_loader"><code>fastvideo.models.encoders.siglip.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.siglip.RowParallelLinear"><code>fastvideo.models.encoders.siglip.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.siglip.RowParallelLinear.weight_loader"><code>fastvideo.models.encoders.siglip.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.siglip.RowParallelLinear.weight_loader_v2"><code>fastvideo.models.encoders.siglip.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.siglip.RowParallelLinear.forward"><code>fastvideo.models.encoders.siglip.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.siglip.RowParallelLinear.extra_repr"><code>fastvideo.models.encoders.siglip.RowParallelLinear.extra_repr</code></h3>
<pre class="doc-signature"><code>extra_repr() -&gt; str</code></pre>

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

<h3 id="fastvideo.models.encoders.siglip.QuantizationConfig.get_name"><code>fastvideo.models.encoders.siglip.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.siglip.QuantizationConfig.get_supported_act_dtypes"><code>fastvideo.models.encoders.siglip.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.siglip.QuantizationConfig.get_min_capability"><code>fastvideo.models.encoders.siglip.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.siglip.QuantizationConfig.get_config_filenames"><code>fastvideo.models.encoders.siglip.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.siglip.QuantizationConfig.from_config"><code>fastvideo.models.encoders.siglip.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.siglip.QuantizationConfig.override_quantization_method"><code>fastvideo.models.encoders.siglip.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.siglip.QuantizationConfig.get_from_keys"><code>fastvideo.models.encoders.siglip.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.siglip.QuantizationConfig.get_from_keys_or"><code>fastvideo.models.encoders.siglip.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.siglip.QuantizationConfig.get_quant_method"><code>fastvideo.models.encoders.siglip.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.siglip.QuantizationConfig.validate_runtime"><code>fastvideo.models.encoders.siglip.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.siglip.QuantizationConfig.get_cache_scale"><code>fastvideo.models.encoders.siglip.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.siglip.init_logger"><code>fastvideo.models.encoders.siglip.init_logger</code></h2>
<pre class="doc-signature"><code>init_logger(name: str) -&gt; _FastvideoLogger</code></pre>
<p>The main purpose of this function is to ensure that loggers are
retrieved in such a way that we can be sure the root fastvideo logger has
already been configured.</p>
<h2 id="fastvideo.models.encoders.siglip.ImageEncoder"><code>fastvideo.models.encoders.siglip.ImageEncoder</code></h2>
<pre class="doc-signature"><code>ImageEncoder(config: ImageEncoderConfig)</code></pre>


<h3 id="fastvideo.models.encoders.siglip.ImageEncoder.forward"><code>fastvideo.models.encoders.siglip.ImageEncoder.forward</code></h3>
<pre class="doc-signature"><code>forward(pixel_values: torch.Tensor, **kwargs) -&gt; BaseEncoderOutput</code></pre>

<h2 id="fastvideo.models.encoders.siglip.default_weight_loader"><code>fastvideo.models.encoders.siglip.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.siglip.SiglipVisionEmbeddings"><code>fastvideo.models.encoders.siglip.SiglipVisionEmbeddings</code></h2>
<pre class="doc-signature"><code>SiglipVisionEmbeddings(arch_config: SiglipVisionArchConfig)</code></pre>
<p>SigLIP vision embeddings - similar to CLIP but without class embedding.</p>

<details><summary>Source</summary><pre><code>class SiglipVisionEmbeddings(nn.Module):
    &quot;&quot;&quot;
    SigLIP vision embeddings - similar to CLIP but without class embedding.
    &quot;&quot;&quot;

    def __init__(self, arch_config: SiglipVisionArchConfig):
        super().__init__()
        self.arch_config = arch_config
        self.embed_dim = arch_config.hidden_size
        self.image_size = arch_config.image_size
        self.patch_size = arch_config.patch_size
        # SigLIP uses valid padding, so non-divisible sizes work (edge pixels are ignored)

        self.patch_embedding = nn.Conv2d(
            in_channels=arch_config.num_channels,
            out_channels=self.embed_dim,
            kernel_size=self.patch_size,
            stride=self.patch_size,
            padding=&quot;valid&quot;,  # SigLIP uses valid padding
        )

        # Integer division - with valid padding, edge pixels are ignored
        self.num_patches = (self.image_size // self.patch_size)**2
        self.num_positions = self.num_patches
        self.position_embedding = nn.Embedding(self.num_positions, self.embed_dim)
        self.register_buffer(
            &quot;position_ids&quot;,
            torch.arange(self.num_positions).expand((1, -1)),
            persistent=False,
        )

    def forward(self, pixel_values: torch.Tensor) -&gt; torch.Tensor:
        target_dtype = self.patch_embedding.weight.dtype
        patch_embeds = self.patch_embedding(pixel_values.to(dtype=target_dtype))  # shape = &#91;*, embed_dim, grid, grid&#93;
        embeddings = patch_embeds.flatten(2).transpose(1, 2)
        embeddings = embeddings + self.position_embedding(self.position_ids)
        return embeddings</code></pre></details>
<h3 id="fastvideo.models.encoders.siglip.SiglipVisionEmbeddings.forward"><code>fastvideo.models.encoders.siglip.SiglipVisionEmbeddings.forward</code></h3>
<pre class="doc-signature"><code>forward(pixel_values: torch.Tensor) -&gt; torch.Tensor</code></pre>

<details><summary>Source</summary><pre><code>def forward(self, pixel_values: torch.Tensor) -&gt; torch.Tensor:
    target_dtype = self.patch_embedding.weight.dtype
    patch_embeds = self.patch_embedding(pixel_values.to(dtype=target_dtype))  # shape = &#91;*, embed_dim, grid, grid&#93;
    embeddings = patch_embeds.flatten(2).transpose(1, 2)
    embeddings = embeddings + self.position_embedding(self.position_ids)
    return embeddings</code></pre></details>
<h2 id="fastvideo.models.encoders.siglip.SiglipAttention"><code>fastvideo.models.encoders.siglip.SiglipAttention</code></h2>
<pre class="doc-signature"><code>SiglipAttention(arch_config: SiglipVisionArchConfig, enable_scale: bool = True, is_causal: bool = False, quant_config: QuantizationConfig | None = None, prefix: str = &#x27;&#x27;)</code></pre>
<p>Multi-headed attention for SigLIP.</p>

<details><summary>Source</summary><pre><code>class SiglipAttention(nn.Module):
    &quot;&quot;&quot;Multi-headed attention for SigLIP.&quot;&quot;&quot;

    def __init__(
        self,
        arch_config: SiglipVisionArchConfig,
        enable_scale: bool = True,
        is_causal: bool = False,
        quant_config: QuantizationConfig | None = None,
        prefix: str = &quot;&quot;,
    ):
        super().__init__()
        self.arch_config = arch_config
        self.embed_dim = arch_config.hidden_size
        self.num_heads = arch_config.num_attention_heads
        self.head_dim = self.embed_dim // self.num_heads

        if self.head_dim * self.num_heads != self.embed_dim:
            raise ValueError(f&quot;embed_dim must be divisible by num_heads &quot;
                             f&quot;(got `embed_dim`: &#123;self.embed_dim&#125; and `num_heads`: &#123;self.num_heads&#125;).&quot;)

        self.scale = self.head_dim**-0.5 if enable_scale else None
        self.dropout = arch_config.attention_dropout

        self.qkv_proj = QKVParallelLinear(
            hidden_size=self.embed_dim,
            head_size=self.head_dim,
            total_num_heads=self.num_heads,
            quant_config=quant_config,
            prefix=f&quot;&#123;prefix&#125;.qkv_proj&quot;,
        )

        self.out_proj = RowParallelLinear(
            input_size=self.embed_dim,
            output_size=self.embed_dim,
            quant_config=quant_config,
            prefix=f&quot;&#123;prefix&#125;.out_proj&quot;,
        )

        self.tp_size = get_tp_world_size()
        self.num_heads_per_partition = divide(self.num_heads, self.tp_size)

        self.attn = LocalAttention(
            self.num_heads_per_partition,
            self.head_dim,
            self.num_heads_per_partition,
            softmax_scale=self.scale,
            causal=is_causal,
            supported_attention_backends=arch_config._supported_attention_backends,
        )

    def forward(self, hidden_states: torch.Tensor):
        &quot;&quot;&quot;Input shape: Batch x Time x Channel&quot;&quot;&quot;
        qkv_states, _ = self.qkv_proj(hidden_states)
        query_states, key_states, value_states = qkv_states.chunk(3, dim=-1)

        query_states = query_states.reshape(query_states.shape&#91;0&#93;, query_states.shape&#91;1&#93;, self.num_heads_per_partition,
                                            self.head_dim)
        key_states = key_states.reshape(key_states.shape&#91;0&#93;, key_states.shape&#91;1&#93;, self.num_heads_per_partition,
                                        self.head_dim)
        value_states = value_states.reshape(value_states.shape&#91;0&#93;, value_states.shape&#91;1&#93;, self.num_heads_per_partition,
                                            self.head_dim)

        attn_output = self.attn(query_states, key_states, value_states)
        attn_output = attn_output.reshape(attn_output.shape&#91;0&#93;, attn_output.shape&#91;1&#93;,
                                          self.num_heads_per_partition * self.head_dim)
        attn_output, _ = self.out_proj(attn_output)
        return attn_output, None</code></pre></details>
<h3 id="fastvideo.models.encoders.siglip.SiglipAttention.forward"><code>fastvideo.models.encoders.siglip.SiglipAttention.forward</code></h3>
<pre class="doc-signature"><code>forward(hidden_states: torch.Tensor)</code></pre>
<p>Input shape: Batch x Time x Channel</p>
<details><summary>Source</summary><pre><code>def forward(self, hidden_states: torch.Tensor):
    &quot;&quot;&quot;Input shape: Batch x Time x Channel&quot;&quot;&quot;
    qkv_states, _ = self.qkv_proj(hidden_states)
    query_states, key_states, value_states = qkv_states.chunk(3, dim=-1)

    query_states = query_states.reshape(query_states.shape&#91;0&#93;, query_states.shape&#91;1&#93;, self.num_heads_per_partition,
                                        self.head_dim)
    key_states = key_states.reshape(key_states.shape&#91;0&#93;, key_states.shape&#91;1&#93;, self.num_heads_per_partition,
                                    self.head_dim)
    value_states = value_states.reshape(value_states.shape&#91;0&#93;, value_states.shape&#91;1&#93;, self.num_heads_per_partition,
                                        self.head_dim)

    attn_output = self.attn(query_states, key_states, value_states)
    attn_output = attn_output.reshape(attn_output.shape&#91;0&#93;, attn_output.shape&#91;1&#93;,
                                      self.num_heads_per_partition * self.head_dim)
    attn_output, _ = self.out_proj(attn_output)
    return attn_output, None</code></pre></details>
<h2 id="fastvideo.models.encoders.siglip.SiglipMLP"><code>fastvideo.models.encoders.siglip.SiglipMLP</code></h2>
<pre class="doc-signature"><code>SiglipMLP(arch_config: SiglipVisionArchConfig, quant_config: QuantizationConfig | None = None, prefix: str = &#x27;&#x27;)</code></pre>


<details><summary>Source</summary><pre><code>class SiglipMLP(nn.Module):

    def __init__(
        self,
        arch_config: SiglipVisionArchConfig,
        quant_config: QuantizationConfig | None = None,
        prefix: str = &quot;&quot;,
    ) -&gt; None:
        super().__init__()
        self.arch_config = arch_config
        self.activation_fn = get_act_fn(arch_config.hidden_act)
        self.fc1 = ColumnParallelLinear(
            arch_config.hidden_size,
            arch_config.intermediate_size,
            bias=True,
            quant_config=quant_config,
            prefix=f&quot;&#123;prefix&#125;.fc1&quot;,
        )
        self.fc2 = RowParallelLinear(
            arch_config.intermediate_size,
            arch_config.hidden_size,
            bias=True,
            quant_config=quant_config,
            prefix=f&quot;&#123;prefix&#125;.fc2&quot;,
        )

    def forward(self, hidden_states: torch.Tensor) -&gt; torch.Tensor:
        hidden_states, _ = self.fc1(hidden_states)
        hidden_states = self.activation_fn(hidden_states)
        hidden_states, _ = self.fc2(hidden_states)
        return hidden_states</code></pre></details>
<h3 id="fastvideo.models.encoders.siglip.SiglipMLP.forward"><code>fastvideo.models.encoders.siglip.SiglipMLP.forward</code></h3>
<pre class="doc-signature"><code>forward(hidden_states: torch.Tensor) -&gt; torch.Tensor</code></pre>

<details><summary>Source</summary><pre><code>def forward(self, hidden_states: torch.Tensor) -&gt; torch.Tensor:
    hidden_states, _ = self.fc1(hidden_states)
    hidden_states = self.activation_fn(hidden_states)
    hidden_states, _ = self.fc2(hidden_states)
    return hidden_states</code></pre></details>
<h2 id="fastvideo.models.encoders.siglip.SiglipEncoderLayer"><code>fastvideo.models.encoders.siglip.SiglipEncoderLayer</code></h2>
<pre class="doc-signature"><code>SiglipEncoderLayer(arch_config: SiglipVisionArchConfig, enable_scale: bool = True, is_causal: bool = False, quant_config: QuantizationConfig | None = None, prefix: str = &#x27;&#x27;)</code></pre>


<details><summary>Source</summary><pre><code>class SiglipEncoderLayer(nn.Module):

    def __init__(
        self,
        arch_config: SiglipVisionArchConfig,
        enable_scale: bool = True,
        is_causal: bool = False,
        quant_config: QuantizationConfig | None = None,
        prefix: str = &quot;&quot;,
    ) -&gt; None:
        super().__init__()
        self.self_attn = SiglipAttention(
            arch_config,
            enable_scale=enable_scale,
            is_causal=is_causal,
            quant_config=quant_config,
            prefix=f&quot;&#123;prefix&#125;.self_attn&quot;,
        )
        self.layer_norm1 = nn.LayerNorm(arch_config.hidden_size, eps=arch_config.layer_norm_eps)
        self.mlp = SiglipMLP(
            arch_config,
            quant_config=quant_config,
            prefix=f&quot;&#123;prefix&#125;.mlp&quot;,
        )
        self.layer_norm2 = nn.LayerNorm(arch_config.hidden_size, eps=arch_config.layer_norm_eps)

    def forward(self, hidden_states: torch.Tensor) -&gt; torch.Tensor:
        # SigLIP uses post-norm (like original ViT)
        residual = hidden_states
        hidden_states = self.layer_norm1(hidden_states)
        hidden_states, _ = self.self_attn(hidden_states=hidden_states)
        hidden_states = residual + hidden_states

        residual = hidden_states
        hidden_states = self.layer_norm2(hidden_states)
        hidden_states = self.mlp(hidden_states)
        hidden_states = residual + hidden_states

        return hidden_states</code></pre></details>
<h3 id="fastvideo.models.encoders.siglip.SiglipEncoderLayer.forward"><code>fastvideo.models.encoders.siglip.SiglipEncoderLayer.forward</code></h3>
<pre class="doc-signature"><code>forward(hidden_states: torch.Tensor) -&gt; torch.Tensor</code></pre>

<details><summary>Source</summary><pre><code>def forward(self, hidden_states: torch.Tensor) -&gt; torch.Tensor:
    # SigLIP uses post-norm (like original ViT)
    residual = hidden_states
    hidden_states = self.layer_norm1(hidden_states)
    hidden_states, _ = self.self_attn(hidden_states=hidden_states)
    hidden_states = residual + hidden_states

    residual = hidden_states
    hidden_states = self.layer_norm2(hidden_states)
    hidden_states = self.mlp(hidden_states)
    hidden_states = residual + hidden_states

    return hidden_states</code></pre></details>
<h2 id="fastvideo.models.encoders.siglip.SiglipEncoder"><code>fastvideo.models.encoders.siglip.SiglipEncoder</code></h2>
<pre class="doc-signature"><code>SiglipEncoder(arch_config: SiglipVisionArchConfig, enable_scale: bool = True, is_causal: bool = False, quant_config: QuantizationConfig | None = None, num_hidden_layers_override: int | None = None, prefix: str = &#x27;&#x27;)</code></pre>
<p>SigLIP encoder consisting of transformer layers.</p>

<details><summary>Source</summary><pre><code>class SiglipEncoder(nn.Module):
    &quot;&quot;&quot;SigLIP encoder consisting of transformer layers.&quot;&quot;&quot;

    def __init__(
        self,
        arch_config: SiglipVisionArchConfig,
        enable_scale: bool = True,
        is_causal: bool = False,
        quant_config: QuantizationConfig | None = None,
        num_hidden_layers_override: int | None = None,
        prefix: str = &quot;&quot;,
    ) -&gt; None:
        super().__init__()
        self.arch_config = arch_config

        if num_hidden_layers_override is None:
            num_hidden_layers = arch_config.num_hidden_layers
        else:
            num_hidden_layers = num_hidden_layers_override

        self.layers = nn.ModuleList(&#91;
            SiglipEncoderLayer(
                arch_config=arch_config,
                enable_scale=enable_scale,
                is_causal=is_causal,
                quant_config=quant_config,
                prefix=f&quot;&#123;prefix&#125;.layers.&#123;layer_idx&#125;&quot;,
            ) for layer_idx in range(num_hidden_layers)
        &#93;)

    def forward(
        self,
        inputs_embeds: torch.Tensor,
        return_all_hidden_states: bool,
    ) -&gt; torch.Tensor | list&#91;torch.Tensor&#93;:
        hidden_states_pool = &#91;inputs_embeds&#93;
        hidden_states = inputs_embeds

        for encoder_layer in self.layers:
            hidden_states = encoder_layer(hidden_states)
            if return_all_hidden_states:
                hidden_states_pool.append(hidden_states)

        if return_all_hidden_states:
            return hidden_states_pool
        return &#91;hidden_states&#93;</code></pre></details>
<h3 id="fastvideo.models.encoders.siglip.SiglipEncoder.forward"><code>fastvideo.models.encoders.siglip.SiglipEncoder.forward</code></h3>
<pre class="doc-signature"><code>forward(inputs_embeds: torch.Tensor, return_all_hidden_states: bool) -&gt; torch.Tensor | list&#91;torch.Tensor&#93;</code></pre>

<details><summary>Source</summary><pre><code>def forward(
    self,
    inputs_embeds: torch.Tensor,
    return_all_hidden_states: bool,
) -&gt; torch.Tensor | list&#91;torch.Tensor&#93;:
    hidden_states_pool = &#91;inputs_embeds&#93;
    hidden_states = inputs_embeds

    for encoder_layer in self.layers:
        hidden_states = encoder_layer(hidden_states)
        if return_all_hidden_states:
            hidden_states_pool.append(hidden_states)

    if return_all_hidden_states:
        return hidden_states_pool
    return &#91;hidden_states&#93;</code></pre></details>
<h2 id="fastvideo.models.encoders.siglip.SiglipVisionTransformer"><code>fastvideo.models.encoders.siglip.SiglipVisionTransformer</code></h2>
<pre class="doc-signature"><code>SiglipVisionTransformer(config: SiglipVisionConfig, quant_config: QuantizationConfig | None = None, num_hidden_layers_override: int | None = None, require_post_norm: bool | None = None, prefix: str = &#x27;&#x27;)</code></pre>


<details><summary>Source</summary><pre><code>class SiglipVisionTransformer(nn.Module):

    def __init__(
        self,
        config: SiglipVisionConfig,
        quant_config: QuantizationConfig | None = None,
        num_hidden_layers_override: int | None = None,
        require_post_norm: bool | None = None,
        prefix: str = &quot;&quot;,
    ) -&gt; None:
        super().__init__()
        self.config = config
        arch_config = config.arch_config
        embed_dim = arch_config.hidden_size

        self.embeddings = SiglipVisionEmbeddings(arch_config)

        self.encoder = SiglipEncoder(
            arch_config=arch_config,
            enable_scale=config.enable_scale,
            is_causal=config.is_causal,
            quant_config=quant_config,
            num_hidden_layers_override=num_hidden_layers_override,
            prefix=f&quot;&#123;prefix&#125;.encoder&quot;,
        )

        num_hidden_layers = arch_config.num_hidden_layers
        if len(self.encoder.layers) &gt; arch_config.num_hidden_layers:
            raise ValueError(f&quot;The original encoder only has &#123;num_hidden_layers&#125; &quot;
                             f&quot;layers, but you requested &#123;len(self.encoder.layers)&#125; layers.&quot;)

        # Post layer norm (applied to output)
        if require_post_norm is None:
            require_post_norm = len(self.encoder.layers) == num_hidden_layers

        if require_post_norm:
            self.post_layernorm = nn.LayerNorm(embed_dim, eps=arch_config.layer_norm_eps)
        else:
            self.post_layernorm = None

    def forward(
        self,
        pixel_values: torch.Tensor,
        feature_sample_layers: list&#91;int&#93; | None = None,
    ) -&gt; torch.Tensor:
        hidden_states = self.embeddings(pixel_values)

        return_all_hidden_states = feature_sample_layers is not None
        encoder_outputs = self.encoder(
            inputs_embeds=hidden_states,
            return_all_hidden_states=return_all_hidden_states,
        )

        if not return_all_hidden_states:
            encoder_outputs = encoder_outputs&#91;0&#93;

        # Apply post-layernorm
        if self.post_layernorm is not None:
            if isinstance(encoder_outputs, list):
                encoder_outputs&#91;-1&#93; = self.post_layernorm(encoder_outputs&#91;-1&#93;)
            else:
                encoder_outputs = self.post_layernorm(encoder_outputs)

        return encoder_outputs</code></pre></details>
<h3 id="fastvideo.models.encoders.siglip.SiglipVisionTransformer.forward"><code>fastvideo.models.encoders.siglip.SiglipVisionTransformer.forward</code></h3>
<pre class="doc-signature"><code>forward(pixel_values: torch.Tensor, feature_sample_layers: list&#91;int&#93; | None = None) -&gt; torch.Tensor</code></pre>

<details><summary>Source</summary><pre><code>def forward(
    self,
    pixel_values: torch.Tensor,
    feature_sample_layers: list&#91;int&#93; | None = None,
) -&gt; torch.Tensor:
    hidden_states = self.embeddings(pixel_values)

    return_all_hidden_states = feature_sample_layers is not None
    encoder_outputs = self.encoder(
        inputs_embeds=hidden_states,
        return_all_hidden_states=return_all_hidden_states,
    )

    if not return_all_hidden_states:
        encoder_outputs = encoder_outputs&#91;0&#93;

    # Apply post-layernorm
    if self.post_layernorm is not None:
        if isinstance(encoder_outputs, list):
            encoder_outputs&#91;-1&#93; = self.post_layernorm(encoder_outputs&#91;-1&#93;)
        else:
            encoder_outputs = self.post_layernorm(encoder_outputs)

    return encoder_outputs</code></pre></details>
<h2 id="fastvideo.models.encoders.siglip.SiglipVisionModel"><code>fastvideo.models.encoders.siglip.SiglipVisionModel</code></h2>
<pre class="doc-signature"><code>SiglipVisionModel(config: SiglipVisionConfig)</code></pre>
<p>SigLIP Vision Model for FastVideo.</p>

<details><summary>Source</summary><pre><code>class SiglipVisionModel(ImageEncoder):
    &quot;&quot;&quot;SigLIP Vision Model for FastVideo.&quot;&quot;&quot;

    config_class = SiglipVisionConfig
    main_input_name = &quot;pixel_values&quot;
    packed_modules_mapping = &#123;&quot;qkv_proj&quot;: &#91;&quot;q_proj&quot;, &quot;k_proj&quot;, &quot;v_proj&quot;&#93;&#125;

    def __init__(self, config: SiglipVisionConfig) -&gt; None:
        super().__init__(config)
        self.config = config
        self.vision_model = SiglipVisionTransformer(
            config=config,
            quant_config=config.quant_config,
            num_hidden_layers_override=config.num_hidden_layers_override,
            require_post_norm=config.require_post_norm,
            prefix=f&quot;&#123;config.prefix&#125;.vision_model&quot;,
        )

    def forward(
        self,
        pixel_values: torch.Tensor,
        feature_sample_layers: list&#91;int&#93; | None = None,
        **kwargs,
    ) -&gt; BaseEncoderOutput:
        last_hidden_state = self.vision_model(pixel_values, feature_sample_layers)
        return BaseEncoderOutput(last_hidden_state=last_hidden_state)

    @property
    def device(self):
        return next(self.parameters()).device

    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()
        layer_count = len(self.vision_model.encoder.layers)

        for name, loaded_weight in weights:
            # Skip projection layers if any
            if name.startswith(&quot;visual_projection&quot;):
                continue

            # Skip head if any
            if &quot;head&quot; in name:
                continue

            # Post layernorm handling
            if (name.startswith(&quot;vision_model.post_layernorm&quot;) and self.vision_model.post_layernorm is None):
                continue

            # Omit layers when num_hidden_layers_override is set
            if name.startswith(&quot;vision_model.encoder.layers&quot;):
                layer_idx = int(name.split(&quot;.&quot;)&#91;3&#93;)
                if layer_idx &gt;= layer_count:
                    continue

            # Handle QKV projection weight mapping
            for (param_name, weight_name, shard_id) in self.config.arch_config.stacked_params_mapping:
                if weight_name not in name:
                    continue
                name = name.replace(weight_name, param_name)

                if name in params_dict:
                    param = params_dict&#91;name&#93;
                    weight_loader = param.weight_loader
                    weight_loader(param, loaded_weight, shard_id)
                break
            else:
                if name in params_dict:
                    param = params_dict&#91;name&#93;
                    weight_loader = getattr(param, &quot;weight_loader&quot;, default_weight_loader)
                    weight_loader(param, loaded_weight)
            loaded_params.add(name)

        return loaded_params</code></pre></details>
<h3 id="fastvideo.models.encoders.siglip.SiglipVisionModel.forward"><code>fastvideo.models.encoders.siglip.SiglipVisionModel.forward</code></h3>
<pre class="doc-signature"><code>forward(pixel_values: torch.Tensor, feature_sample_layers: list&#91;int&#93; | None = None, **kwargs) -&gt; BaseEncoderOutput</code></pre>

<details><summary>Source</summary><pre><code>def forward(
    self,
    pixel_values: torch.Tensor,
    feature_sample_layers: list&#91;int&#93; | None = None,
    **kwargs,
) -&gt; BaseEncoderOutput:
    last_hidden_state = self.vision_model(pixel_values, feature_sample_layers)
    return BaseEncoderOutput(last_hidden_state=last_hidden_state)</code></pre></details>
<h3 id="fastvideo.models.encoders.siglip.SiglipVisionModel.load_weights"><code>fastvideo.models.encoders.siglip.SiglipVisionModel.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()
    layer_count = len(self.vision_model.encoder.layers)

    for name, loaded_weight in weights:
        # Skip projection layers if any
        if name.startswith(&quot;visual_projection&quot;):
            continue

        # Skip head if any
        if &quot;head&quot; in name:
            continue

        # Post layernorm handling
        if (name.startswith(&quot;vision_model.post_layernorm&quot;) and self.vision_model.post_layernorm is None):
            continue

        # Omit layers when num_hidden_layers_override is set
        if name.startswith(&quot;vision_model.encoder.layers&quot;):
            layer_idx = int(name.split(&quot;.&quot;)&#91;3&#93;)
            if layer_idx &gt;= layer_count:
                continue

        # Handle QKV projection weight mapping
        for (param_name, weight_name, shard_id) in self.config.arch_config.stacked_params_mapping:
            if weight_name not in name:
                continue
            name = name.replace(weight_name, param_name)

            if name in params_dict:
                param = params_dict&#91;name&#93;
                weight_loader = param.weight_loader
                weight_loader(param, loaded_weight, shard_id)
            break
        else:
            if name in params_dict:
                param = params_dict&#91;name&#93;
                weight_loader = getattr(param, &quot;weight_loader&quot;, default_weight_loader)
                weight_loader(param, loaded_weight)
        loaded_params.add(name)

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