---
title: stable_audio_conditioner
---

<div class="python-reference">
<a id="fastvideo.models.encoders.stable_audio_conditioner-classes"></a>
<a id="fastvideo.models.encoders.stable_audio_conditioner.StableAudioMultiConditioner-functions"></a>
<a id="fastvideo.models.encoders.stable_audio_conditioner"></a>
<p>Stable Audio Open 1.0 conditioner.</p>
<p>T5-base text encoder + two NumberConditioners (<code>seconds_start</code>,
<code>seconds_total</code>), wrapped by <code>StableAudioMultiConditioner</code> which
produces the cross-attention and global-conditioning tensors the DiT
expects.</p>
<h2 id="fastvideo.models.encoders.stable_audio_conditioner.StableAudioConditionerConfig"><code>fastvideo.models.encoders.stable_audio_conditioner.StableAudioConditionerConfig</code></h2>
<pre class="doc-signature"><code>StableAudioConditionerConfig(arch_config: ArchConfig = StableAudioConditionerArchConfig(), prefix: str = &#x27;stable_audio_conditioner&#x27;, quant_config: QuantizationConfig | None = None, lora_config: Any | None = None, *, _resolved_attention_backend: AttentionBackendEnum | None = None)</code></pre>


<h2 id="fastvideo.models.encoders.stable_audio_conditioner.NumberEmbedder"><code>fastvideo.models.encoders.stable_audio_conditioner.NumberEmbedder</code></h2>
<pre class="doc-signature"><code>NumberEmbedder(features: int, dim: int = 256)</code></pre>


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

    def __init__(self, features: int, dim: int = 256) -&gt; None:
        super().__init__()
        self.features = features
        self.embedding = _time_positional_embedding(dim=dim, out_features=features)

    def forward(self, x: torch.Tensor | list&#91;float&#93;) -&gt; torch.Tensor:
        if not torch.is_tensor(x):
            device = next(self.embedding.parameters()).device
            x = torch.tensor(x, device=device)
        shape = x.shape
        x = rearrange(x, &quot;... -&gt; (...)&quot;)
        out = self.embedding(x)
        return out.view(*shape, self.features)</code></pre></details>
<h3 id="fastvideo.models.encoders.stable_audio_conditioner.NumberEmbedder.forward"><code>fastvideo.models.encoders.stable_audio_conditioner.NumberEmbedder.forward</code></h3>
<pre class="doc-signature"><code>forward(x: torch.Tensor | list&#91;float&#93;) -&gt; torch.Tensor</code></pre>

<details><summary>Source</summary><pre><code>def forward(self, x: torch.Tensor | list&#91;float&#93;) -&gt; torch.Tensor:
    if not torch.is_tensor(x):
        device = next(self.embedding.parameters()).device
        x = torch.tensor(x, device=device)
    shape = x.shape
    x = rearrange(x, &quot;... -&gt; (...)&quot;)
    out = self.embedding(x)
    return out.view(*shape, self.features)</code></pre></details>
<h2 id="fastvideo.models.encoders.stable_audio_conditioner.T5Conditioner"><code>fastvideo.models.encoders.stable_audio_conditioner.T5Conditioner</code></h2>
<pre class="doc-signature"><code>T5Conditioner(output_dim: int, t5_model_name: str = &#x27;t5-base&#x27;, max_length: int = 128, dtype: str = &#x27;float16&#x27;)</code></pre>
<p>T5 text conditioner. Pads to <code>model_max_length</code> (=128 for the SA
repo's tokenizer, NOT the standard 512) and emits a masked
last-hidden-state.</p>

<details><summary>Source</summary><pre><code>class T5Conditioner(_Conditioner):
    &quot;&quot;&quot;T5 text conditioner. Pads to `model_max_length` (=128 for the SA
    repo&#x27;s tokenizer, NOT the standard 512) and emits a masked
    last-hidden-state.
    &quot;&quot;&quot;

    T5_MODEL_DIMS = &#123;&quot;t5-base&quot;: 768&#125;

    def __init__(self,
                 output_dim: int,
                 t5_model_name: str = &quot;t5-base&quot;,
                 max_length: int = 128,
                 dtype: str = &quot;float16&quot;) -&gt; None:
        super().__init__(self.T5_MODEL_DIMS&#91;t5_model_name&#93;, output_dim, project_out=False)
        from transformers import AutoTokenizer, T5EncoderModel
        self.max_length = max_length
        self.tokenizer = AutoTokenizer.from_pretrained(t5_model_name)
        # T5 loaded directly in fp16 (config-driven) to match official
        # `stable_audio_tools/models/conditioners.py:334`. Registered as
        # a normal submodule so `.to(device)` / `torch.compile` track it;
        # `from_official_state_dict` filters `conditioners.prompt.*` from
        # the missing-key check (T5 weights are absent from the SA
        # checkpoint by design).
        # Explicit lookup so a typo (e.g. &quot;fp16&quot; instead of &quot;float16&quot;) errors
        # at load time rather than silently falling back to a wrong dtype.
        torch_dtype = getattr(torch, dtype)
        if not isinstance(torch_dtype, torch.dtype):
            raise ValueError(f&quot;T5Conditioner dtype=&#123;dtype!r&#125; is not a torch.dtype.&quot;)
        self._t5_dtype = torch_dtype
        self.model = (T5EncoderModel.from_pretrained(t5_model_name).eval().requires_grad_(False).to(torch_dtype))

    def forward(self, texts: list&#91;str&#93;, device: torch.device | str) -&gt; tuple&#91;torch.Tensor, torch.Tensor&#93;:
        encoded = self.tokenizer(texts,
                                 truncation=True,
                                 max_length=self.max_length,
                                 padding=&quot;max_length&quot;,
                                 return_tensors=&quot;pt&quot;)
        input_ids = encoded&#91;&quot;input_ids&quot;&#93;.to(device)
        attention_mask = encoded&#91;&quot;attention_mask&quot;&#93;.to(device).to(torch.bool)
        # Mirror official&#x27;s `autocast(fp16)` wrap on T5 forward.
        with torch.no_grad(), torch.autocast(device_type=&quot;cuda&quot;, dtype=self._t5_dtype):
            embeddings = self.model(input_ids=input_ids, attention_mask=attention_mask)&#91;&quot;last_hidden_state&quot;&#93;
        embeddings = self.proj_out(embeddings) * attention_mask.unsqueeze(-1).float()
        return embeddings, attention_mask</code></pre></details>
<h3 id="fastvideo.models.encoders.stable_audio_conditioner.T5Conditioner.forward"><code>fastvideo.models.encoders.stable_audio_conditioner.T5Conditioner.forward</code></h3>
<pre class="doc-signature"><code>forward(texts: list&#91;str&#93;, device: torch.device | str) -&gt; tuple&#91;torch.Tensor, torch.Tensor&#93;</code></pre>

<details><summary>Source</summary><pre><code>def forward(self, texts: list&#91;str&#93;, device: torch.device | str) -&gt; tuple&#91;torch.Tensor, torch.Tensor&#93;:
    encoded = self.tokenizer(texts,
                             truncation=True,
                             max_length=self.max_length,
                             padding=&quot;max_length&quot;,
                             return_tensors=&quot;pt&quot;)
    input_ids = encoded&#91;&quot;input_ids&quot;&#93;.to(device)
    attention_mask = encoded&#91;&quot;attention_mask&quot;&#93;.to(device).to(torch.bool)
    # Mirror official&#x27;s `autocast(fp16)` wrap on T5 forward.
    with torch.no_grad(), torch.autocast(device_type=&quot;cuda&quot;, dtype=self._t5_dtype):
        embeddings = self.model(input_ids=input_ids, attention_mask=attention_mask)&#91;&quot;last_hidden_state&quot;&#93;
    embeddings = self.proj_out(embeddings) * attention_mask.unsqueeze(-1).float()
    return embeddings, attention_mask</code></pre></details>
<h2 id="fastvideo.models.encoders.stable_audio_conditioner.NumberConditioner"><code>fastvideo.models.encoders.stable_audio_conditioner.NumberConditioner</code></h2>
<pre class="doc-signature"><code>NumberConditioner(output_dim: int, min_val: float = 0, max_val: float = 1)</code></pre>
<p>Float-valued conditioner with min/max clamping + NumberEmbedder.</p>

<details><summary>Source</summary><pre><code>class NumberConditioner(_Conditioner):
    &quot;&quot;&quot;Float-valued conditioner with min/max clamping + NumberEmbedder.&quot;&quot;&quot;

    def __init__(self, output_dim: int, min_val: float = 0, max_val: float = 1) -&gt; None:
        super().__init__(output_dim, output_dim)
        self.min_val = min_val
        self.max_val = max_val
        self.embedder = NumberEmbedder(features=output_dim)

    def forward(self, floats: list&#91;float&#93;, device: torch.device | str) -&gt; tuple&#91;torch.Tensor, torch.Tensor&#93;:
        floats = &#91;float(x) for x in floats&#93;
        floats_t = torch.tensor(floats, device=device).clamp(self.min_val, self.max_val)
        normalized = (floats_t - self.min_val) / (self.max_val - self.min_val)
        emb_dtype = next(self.embedder.parameters()).dtype
        normalized = normalized.to(emb_dtype)
        float_embeds = self.embedder(normalized).unsqueeze(1)
        return float_embeds, torch.ones(float_embeds.shape&#91;0&#93;, 1, device=device)</code></pre></details>
<h3 id="fastvideo.models.encoders.stable_audio_conditioner.NumberConditioner.forward"><code>fastvideo.models.encoders.stable_audio_conditioner.NumberConditioner.forward</code></h3>
<pre class="doc-signature"><code>forward(floats: list&#91;float&#93;, device: torch.device | str) -&gt; tuple&#91;torch.Tensor, torch.Tensor&#93;</code></pre>

<details><summary>Source</summary><pre><code>def forward(self, floats: list&#91;float&#93;, device: torch.device | str) -&gt; tuple&#91;torch.Tensor, torch.Tensor&#93;:
    floats = &#91;float(x) for x in floats&#93;
    floats_t = torch.tensor(floats, device=device).clamp(self.min_val, self.max_val)
    normalized = (floats_t - self.min_val) / (self.max_val - self.min_val)
    emb_dtype = next(self.embedder.parameters()).dtype
    normalized = normalized.to(emb_dtype)
    float_embeds = self.embedder(normalized).unsqueeze(1)
    return float_embeds, torch.ones(float_embeds.shape&#91;0&#93;, 1, device=device)</code></pre></details>
<h2 id="fastvideo.models.encoders.stable_audio_conditioner.StableAudioMultiConditioner"><code>fastvideo.models.encoders.stable_audio_conditioner.StableAudioMultiConditioner</code></h2>
<pre class="doc-signature"><code>StableAudioMultiConditioner(config: StableAudioConditionerConfig | None = None)</code></pre>
<p>SA-Open-1.0 conditioner: T5 prompt + duration NumberConditioners.</p>
<p>All hardcoded constants (cond_dim, sub-conditioner ids, T5 model
name + max_length, NumberConditioner ranges) live on
<code>StableAudioConditionerConfig</code> — see
<code>fastvideo/configs/models/encoders/stable_audio_conditioner.py</code>.</p>

<details><summary>Source</summary><pre><code>class StableAudioMultiConditioner(nn.Module):
    &quot;&quot;&quot;SA-Open-1.0 conditioner: T5 prompt + duration NumberConditioners.

    All hardcoded constants (cond_dim, sub-conditioner ids, T5 model
    name + max_length, NumberConditioner ranges) live on
    `StableAudioConditionerConfig` — see
    `fastvideo/configs/models/encoders/stable_audio_conditioner.py`.
    &quot;&quot;&quot;

    def __init__(self, config: StableAudioConditionerConfig | None = None) -&gt; None:
        super().__init__()
        self.config = config or StableAudioConditionerConfig()
        arch = self.config.arch_config
        # Build sub-conditioners from the `configs` list (mirrors
        # upstream&#x27;s `MultiConditioner` factory).
        sub: dict&#91;str, nn.Module&#93; = &#123;&#125;
        for spec in arch.configs:
            sid = spec&#91;&quot;id&quot;&#93;
            stype = spec&#91;&quot;type&quot;&#93;
            scfg = spec&#91;&quot;config&quot;&#93;
            if stype == &quot;t5&quot;:
                sub&#91;sid&#93; = T5Conditioner(output_dim=arch.cond_dim,
                                         t5_model_name=scfg&#91;&quot;t5_model_name&quot;&#93;,
                                         max_length=scfg&#91;&quot;max_length&quot;&#93;,
                                         dtype=arch.t5_dtype)
            elif stype == &quot;number&quot;:
                sub&#91;sid&#93; = NumberConditioner(output_dim=arch.cond_dim, min_val=scfg&#91;&quot;min_val&quot;&#93;, max_val=scfg&#91;&quot;max_val&quot;&#93;)
            else:
                raise ValueError(f&quot;Unknown sub-conditioner type &#123;stype!r&#125; for id &#123;sid!r&#125;.&quot;)
        self.conditioners = nn.ModuleDict(sub)
        self.cross_attention_cond_ids = tuple(arch.cross_attention_cond_ids)
        self.global_cond_ids = tuple(arch.global_cond_ids)

    def forward(self, batch_metadata: list&#91;dict&#93;,
                device: torch.device | str) -&gt; dict&#91;str, tuple&#91;torch.Tensor, torch.Tensor&#93;&#93;:
        out: dict&#91;str, tuple&#91;torch.Tensor, torch.Tensor&#93;&#93; = &#123;&#125;
        for key, conditioner in self.conditioners.items():
            inputs = &#91;x&#91;key&#93; for x in batch_metadata&#93;
            out&#91;key&#93; = conditioner(inputs, device)
        return out

    def get_conditioning_inputs(
            self, cond: dict&#91;str, tuple&#91;torch.Tensor,
                                        torch.Tensor&#93;&#93;) -&gt; tuple&#91;torch.Tensor, torch.Tensor, torch.Tensor&#93;:
        &quot;&quot;&quot;Pack conditioner outputs into the (cross_attn_cond,
        cross_attn_mask, global_embed) triple the DiT consumes. Order
        is driven by `cross_attention_cond_ids` / `global_cond_ids`
        from the config — SA-1.0 uses three sub-conditioners
        (prompt + seconds_start + seconds_total); SA-small uses two
        (prompt + seconds_total).
        &quot;&quot;&quot;
        x_embs = &#91;cond&#91;i&#93;&#91;0&#93; for i in self.cross_attention_cond_ids&#93;
        x_masks = &#91;cond&#91;i&#93;&#91;1&#93; for i in self.cross_attention_cond_ids&#93;
        cross_attn_cond = torch.cat(x_embs, dim=1)
        cross_attn_mask = torch.cat(x_masks, dim=1)
        global_embed = torch.cat(&#91;cond&#91;i&#93;&#91;0&#93;&#91;:, 0&#93; for i in self.global_cond_ids&#93;, dim=-1)
        return cross_attn_cond, cross_attn_mask, global_embed

    @classmethod
    def from_official_state_dict(cls,
                                 state_dict: dict&#91;str, torch.Tensor&#93;,
                                 prefix: str = &quot;conditioner.&quot;) -&gt; &quot;StableAudioMultiConditioner&quot;:
        &quot;&quot;&quot;Load NumberConditioner weights from a raw `stable_audio_tools`
        monolithic state dict. Kept for tests / older checkpoints;
        production loads go through the standard `ConditionerLoader`
        against the converted Diffusers repo.
        &quot;&quot;&quot;
        mc = cls()
        own_state = mc.state_dict()
        loaded: dict&#91;str, torch.Tensor&#93; = &#123;&#125;
        for k, v in state_dict.items():
            if not k.startswith(prefix):
                continue
            stripped = k&#91;len(prefix):&#93;
            if stripped in own_state:
                loaded&#91;stripped&#93; = v
        # T5 keys are intentionally absent from the checkpoint.
        missing = &#91;k for k in own_state.keys() if k not in loaded and not k.startswith(&quot;conditioners.prompt.&quot;)&#93;
        unexpected = &#91;k for k in loaded.keys() if k not in own_state&#93;
        if missing or unexpected:
            raise RuntimeError(
                f&quot;StableAudioMultiConditioner load mismatch — missing=&#123;missing&#91;:5&#93;&#125; unexpected=&#123;unexpected&#91;:5&#93;&#125;&quot;)
        mc.load_state_dict(loaded, strict=False)
        return mc</code></pre></details>
<h3 id="fastvideo.models.encoders.stable_audio_conditioner.StableAudioMultiConditioner.forward"><code>fastvideo.models.encoders.stable_audio_conditioner.StableAudioMultiConditioner.forward</code></h3>
<pre class="doc-signature"><code>forward(batch_metadata: list&#91;dict&#93;, device: torch.device | str) -&gt; dict&#91;str, tuple&#91;torch.Tensor, torch.Tensor&#93;&#93;</code></pre>

<details><summary>Source</summary><pre><code>def forward(self, batch_metadata: list&#91;dict&#93;,
            device: torch.device | str) -&gt; dict&#91;str, tuple&#91;torch.Tensor, torch.Tensor&#93;&#93;:
    out: dict&#91;str, tuple&#91;torch.Tensor, torch.Tensor&#93;&#93; = &#123;&#125;
    for key, conditioner in self.conditioners.items():
        inputs = &#91;x&#91;key&#93; for x in batch_metadata&#93;
        out&#91;key&#93; = conditioner(inputs, device)
    return out</code></pre></details>
<h3 id="fastvideo.models.encoders.stable_audio_conditioner.StableAudioMultiConditioner.get_conditioning_inputs"><code>fastvideo.models.encoders.stable_audio_conditioner.StableAudioMultiConditioner.get_conditioning_inputs</code></h3>
<pre class="doc-signature"><code>get_conditioning_inputs(cond: dict&#91;str, tuple&#91;torch.Tensor, torch.Tensor&#93;&#93;) -&gt; tuple&#91;torch.Tensor, torch.Tensor, torch.Tensor&#93;</code></pre>
<p>Pack conditioner outputs into the (cross_attn_cond,
cross_attn_mask, global_embed) triple the DiT consumes. Order
is driven by <code>cross_attention_cond_ids</code> / <code>global_cond_ids</code>
from the config — SA-1.0 uses three sub-conditioners
(prompt + seconds_start + seconds_total); SA-small uses two
(prompt + seconds_total).</p>
<details><summary>Source</summary><pre><code>def get_conditioning_inputs(
        self, cond: dict&#91;str, tuple&#91;torch.Tensor,
                                    torch.Tensor&#93;&#93;) -&gt; tuple&#91;torch.Tensor, torch.Tensor, torch.Tensor&#93;:
    &quot;&quot;&quot;Pack conditioner outputs into the (cross_attn_cond,
    cross_attn_mask, global_embed) triple the DiT consumes. Order
    is driven by `cross_attention_cond_ids` / `global_cond_ids`
    from the config — SA-1.0 uses three sub-conditioners
    (prompt + seconds_start + seconds_total); SA-small uses two
    (prompt + seconds_total).
    &quot;&quot;&quot;
    x_embs = &#91;cond&#91;i&#93;&#91;0&#93; for i in self.cross_attention_cond_ids&#93;
    x_masks = &#91;cond&#91;i&#93;&#91;1&#93; for i in self.cross_attention_cond_ids&#93;
    cross_attn_cond = torch.cat(x_embs, dim=1)
    cross_attn_mask = torch.cat(x_masks, dim=1)
    global_embed = torch.cat(&#91;cond&#91;i&#93;&#91;0&#93;&#91;:, 0&#93; for i in self.global_cond_ids&#93;, dim=-1)
    return cross_attn_cond, cross_attn_mask, global_embed</code></pre></details>
<h3 id="fastvideo.models.encoders.stable_audio_conditioner.StableAudioMultiConditioner.from_official_state_dict"><code>fastvideo.models.encoders.stable_audio_conditioner.StableAudioMultiConditioner.from_official_state_dict</code></h3>
<pre class="doc-signature"><code>from_official_state_dict(state_dict: dict&#91;str, torch.Tensor&#93;, prefix: str = &#x27;conditioner.&#x27;) -&gt; &#x27;StableAudioMultiConditioner&#x27;</code></pre>
<p>Load NumberConditioner weights from a raw <code>stable_audio_tools</code>
monolithic state dict. Kept for tests / older checkpoints;
production loads go through the standard <code>ConditionerLoader</code>
against the converted Diffusers repo.</p>
<details><summary>Source</summary><pre><code>@classmethod
def from_official_state_dict(cls,
                             state_dict: dict&#91;str, torch.Tensor&#93;,
                             prefix: str = &quot;conditioner.&quot;) -&gt; &quot;StableAudioMultiConditioner&quot;:
    &quot;&quot;&quot;Load NumberConditioner weights from a raw `stable_audio_tools`
    monolithic state dict. Kept for tests / older checkpoints;
    production loads go through the standard `ConditionerLoader`
    against the converted Diffusers repo.
    &quot;&quot;&quot;
    mc = cls()
    own_state = mc.state_dict()
    loaded: dict&#91;str, torch.Tensor&#93; = &#123;&#125;
    for k, v in state_dict.items():
        if not k.startswith(prefix):
            continue
        stripped = k&#91;len(prefix):&#93;
        if stripped in own_state:
            loaded&#91;stripped&#93; = v
    # T5 keys are intentionally absent from the checkpoint.
    missing = &#91;k for k in own_state.keys() if k not in loaded and not k.startswith(&quot;conditioners.prompt.&quot;)&#93;
    unexpected = &#91;k for k in loaded.keys() if k not in own_state&#93;
    if missing or unexpected:
        raise RuntimeError(
            f&quot;StableAudioMultiConditioner load mismatch — missing=&#123;missing&#91;:5&#93;&#125; unexpected=&#123;unexpected&#91;:5&#93;&#125;&quot;)
    mc.load_state_dict(loaded, strict=False)
    return mc</code></pre></details>
</div>
