---
title: negative_prompt
---

<div class="python-reference">
<a id="fastvideo.train.utils.negative_prompt-classes"></a>
<a id="fastvideo.train.utils.negative_prompt-functions"></a>
<a id="fastvideo.train.utils.negative_prompt"></a>
<p>Per-rank negative-prompt encoding shared by training model plugins.</p>
<p>Encoding the negative prompt only on rank 0 and broadcasting (the
previous Wan path) ran <code>Pipeline.from_pretrained</code> asymmetrically across
ranks, which deadlocked on any collective fired during text-encoder load
(FSDP device-mesh init, weight broadcast, etc.). The text encoder is
small and only loaded once at startup, so loading it on every rank
sidesteps the deadlock entirely.</p>
<h2 id="fastvideo.train.utils.negative_prompt.set_forward_context"><code>fastvideo.train.utils.negative_prompt.set_forward_context</code></h2>
<pre class="doc-signature"><code>set_forward_context(current_timestep, attn_metadata, forward_batch: Optional&#91;ForwardBatch&#93; = None)</code></pre>
<p>A context manager that stores the current forward context,
can be attention metadata, etc.
Here we can inject common logic for every model forward pass.</p>
<h2 id="fastvideo.train.utils.negative_prompt.TextEncoderLoader"><code>fastvideo.train.utils.negative_prompt.TextEncoderLoader</code></h2>
<pre class="doc-signature"><code>TextEncoderLoader(device = None)</code></pre>
<p>Loader for text encoders.</p>
<h3 id="fastvideo.train.utils.negative_prompt.TextEncoderLoader.Source"><code>fastvideo.train.utils.negative_prompt.TextEncoderLoader.Source</code></h3>
<pre class="doc-signature"><code>Source(model_or_path: str, prefix: str = &#x27;&#x27;, fall_back_to_pt: bool = True, allow_patterns_overrides: list&#91;str&#93; | None = None)</code></pre>
<p>A source for weights.</p>

<h4 id="fastvideo.train.utils.negative_prompt.TextEncoderLoader.Source.model_or_path"><code>fastvideo.train.utils.negative_prompt.TextEncoderLoader.Source.model_or_path</code></h4>
<pre class="doc-signature"><code>model_or_path: str</code></pre>
<p>The model ID or path.</p>
<h4 id="fastvideo.train.utils.negative_prompt.TextEncoderLoader.Source.prefix"><code>fastvideo.train.utils.negative_prompt.TextEncoderLoader.Source.prefix</code></h4>
<pre class="doc-signature"><code>prefix: str = &#x27;&#x27;</code></pre>
<p>A prefix to prepend to all weights.</p>
<h4 id="fastvideo.train.utils.negative_prompt.TextEncoderLoader.Source.fall_back_to_pt"><code>fastvideo.train.utils.negative_prompt.TextEncoderLoader.Source.fall_back_to_pt</code></h4>
<pre class="doc-signature"><code>fall_back_to_pt: bool = True</code></pre>
<p>Whether .pt weights can be used.</p>
<h4 id="fastvideo.train.utils.negative_prompt.TextEncoderLoader.Source.allow_patterns_overrides"><code>fastvideo.train.utils.negative_prompt.TextEncoderLoader.Source.allow_patterns_overrides</code></h4>
<pre class="doc-signature"><code>allow_patterns_overrides: list&#91;str&#93; | None = None</code></pre>
<p>If defined, weights will load exclusively using these patterns.</p>
<h3 id="fastvideo.train.utils.negative_prompt.TextEncoderLoader.load"><code>fastvideo.train.utils.negative_prompt.TextEncoderLoader.load</code></h3>
<pre class="doc-signature"><code>load(model_path: str, fastvideo_args: FastVideoArgs)</code></pre>
<p>Load the text encoders based on the model path, and inference args.</p>
<h3 id="fastvideo.train.utils.negative_prompt.TextEncoderLoader.load_model"><code>fastvideo.train.utils.negative_prompt.TextEncoderLoader.load_model</code></h3>
<pre class="doc-signature"><code>load_model(model_path: str, model_config: EncoderConfig, target_device: torch.device, fastvideo_args: FastVideoArgs, dtype: str = &#x27;fp16&#x27;, use_text_encoder_override: bool = False, cpu_offload: bool | None = None, offload_flag: str = &#x27;text_encoder_cpu_offload&#x27;)</code></pre>

<h2 id="fastvideo.train.utils.negative_prompt.make_inference_args"><code>fastvideo.train.utils.negative_prompt.make_inference_args</code></h2>
<pre class="doc-signature"><code>make_inference_args(tc: TrainingConfig, *, model_path: str) -&gt; TrainingArgs</code></pre>
<p>Build a TrainingArgs for inference (validation / pipelines).</p>
<h2 id="fastvideo.train.utils.negative_prompt.maybe_download_model"><code>fastvideo.train.utils.negative_prompt.maybe_download_model</code></h2>
<pre class="doc-signature"><code>maybe_download_model(model_name_or_path: str, local_dir: str | None = None, download: bool = True, revision: str | None = None, allow_patterns: list&#91;str&#93; | None = None) -&gt; str</code></pre>
<p>Check if the model path is a Hugging Face Hub model ID and download it if needed.</p>
<p>Supports an "umbrella" repo layout where a single HF repo holds multiple
pipeline variants under sibling subfolders. If the input is shaped as
<code>org/repo/subfolder</code> (i.e. a non-existent local path with 3+ slash-
separated components and at least one segment that does not look like a
posix-absolute path), treat the first two components as the HF repo id
and the remainder as a subfolder; only the subfolder's blobs are
downloaded, and the returned local path points inside that subfolder.</p>
<h3>Parameters</h3>
<dl>
<dt><code>model_name_or_path: str</code></dt><dd><p>Local path, Hugging Face Hub model ID, or
<code>org/repo/subfolder</code> umbrella-repo reference.</p></dd>
<dt><code>local_dir: str | None</code></dt><dd><p>Local directory to save the model</p></dd>
<dt><code>download: bool</code></dt><dd><p>Whether to download the model from Hugging Face Hub</p></dd>
<dt><code>revision: str | None</code></dt><dd><p>Optional immutable Hub revision.</p></dd>
<dt><code>allow_patterns: list[str] | None</code></dt><dd><p>Optional Hub glob patterns limiting downloaded files.
Local paths are returned unchanged. For umbrella references, the
patterns are interpreted relative to the selected subfolder.</p></dd>
</dl>
<h3>Returns</h3>
<dl>
<dt><code>str</code></dt><dd><p>Local path to the model (or to the subfolder inside the snapshot).</p></dd>
</dl>
<h2 id="fastvideo.train.utils.negative_prompt.TrainingConfig"><code>fastvideo.train.utils.negative_prompt.TrainingConfig</code></h2>
<pre class="doc-signature"><code>TrainingConfig(distributed: DistributedConfig = DistributedConfig(), data: DataConfig = DataConfig(), optimizer: OptimizerConfig = OptimizerConfig(), loop: TrainingLoopConfig = TrainingLoopConfig(), checkpoint: CheckpointConfig = CheckpointConfig(), tracker: TrackerConfig = TrackerConfig(), performance: PerformanceConfig = PerformanceConfig(), vsa_sparsity: float = 0.0, vsa_cache_tile_buf: bool = False, model: ModelTrainingConfig = ModelTrainingConfig(), pipeline_config: PipelineConfig | None = None, model_path: str = &#x27;&#x27;, dit_precision: str = &#x27;fp32&#x27;, vsa_ref_keep_rate: float | None = None, vsa_tile_size: int = 256)</code></pre>


<h2 id="fastvideo.train.utils.negative_prompt.encode_negative_prompt"><code>fastvideo.train.utils.negative_prompt.encode_negative_prompt</code></h2>
<pre class="doc-signature"><code>encode_negative_prompt(training_config: TrainingConfig, *, prompt: str, device: torch.device, dtype: torch.dtype, encoder_index: int = 0) -&gt; tuple&#91;torch.Tensor, torch.Tensor&#93;</code></pre>
<p>Per-rank encode of <code>prompt</code> using encoder <code>encoder_index</code>.</p>
<p>Reads <code>pipeline_config.text_encoder_configs[encoder_index]</code> so the
encoder class (e.g. UMT5 for Wan) and tokenizer kwargs match the
inference path, and applies the matching <code>postprocess_text_funcs</code>
entry. Returns <code>(embeds, mask)</code> on <code>device</code> cast to <code>dtype</code>.</p>
<details><summary>Source</summary><pre><code>def encode_negative_prompt(
    training_config: TrainingConfig,
    *,
    prompt: str,
    device: torch.device,
    dtype: torch.dtype,
    encoder_index: int = 0,
) -&gt; tuple&#91;torch.Tensor, torch.Tensor&#93;:
    &quot;&quot;&quot;Per-rank encode of ``prompt`` using encoder ``encoder_index``.

    Reads ``pipeline_config.text_encoder_configs&#91;encoder_index&#93;`` so the
    encoder class (e.g. UMT5 for Wan) and tokenizer kwargs match the
    inference path, and applies the matching ``postprocess_text_funcs``
    entry. Returns ``(embeds, mask)`` on ``device`` cast to ``dtype``.
    &quot;&quot;&quot;
    tc = training_config
    pipeline_config = tc.pipeline_config
    if pipeline_config is None:
        raise ValueError(&quot;training_config.pipeline_config is required for negative &quot;
                         &quot;prompt encoding&quot;)

    encoder_configs = pipeline_config.text_encoder_configs
    postprocess_funcs = pipeline_config.postprocess_text_funcs
    preprocess_funcs = getattr(pipeline_config, &quot;preprocess_text_funcs&quot;, None)

    if encoder_index &lt; 0 or encoder_index &gt;= len(encoder_configs):
        raise IndexError(f&quot;encoder_index &#123;encoder_index&#125; out of range for &quot;
                         f&quot;text_encoder_configs (len=&#123;len(encoder_configs)&#125;)&quot;)
    encoder_config = encoder_configs&#91;encoder_index&#93;
    postprocess_text = postprocess_funcs&#91;encoder_index&#93;
    preprocess_text = (preprocess_funcs&#91;encoder_index&#93; if preprocess_funcs is not None else None)

    # HF convention: text_encoder / tokenizer for index 0,
    # text_encoder_2 / tokenizer_2 for index 1, etc.
    suffix = &quot;&quot; if encoder_index == 0 else f&quot;_&#123;encoder_index + 1&#125;&quot;
    encoder_subdir = f&quot;text_encoder&#123;suffix&#125;&quot;
    tokenizer_subdir = f&quot;tokenizer&#123;suffix&#125;&quot;

    model_path = maybe_download_model(tc.model_path)
    inference_args = make_inference_args(tc, model_path=model_path)
    # Keep the encoder on-device; CPU offload would init an FSDP device
    # mesh and reintroduce the collective at load time.
    inference_args.text_encoder_cpu_offload = False

    loader = TextEncoderLoader()
    text_encoder = loader.load(
        os.path.join(model_path, encoder_subdir),
        inference_args,
    ).to(device).eval()
    tokenizer = AutoTokenizer.from_pretrained(os.path.join(model_path, tokenizer_subdir))

    tok_kwargs = dict(encoder_config.tokenizer_kwargs)
    text = preprocess_text(prompt) if preprocess_text is not None else prompt

    with torch.no_grad(), set_forward_context(
            current_timestep=0,
            attn_metadata=None,
    ):
        text_inputs = tokenizer(text, **tok_kwargs).to(device)
        outputs = text_encoder(
            input_ids=text_inputs.input_ids,
            attention_mask=text_inputs.attention_mask,
        )
        # Mirror TextEncodingStage: postprocess reads outputs.attention_mask.
        outputs.attention_mask = text_inputs&#91;&quot;attention_mask&quot;&#93;
        embeds = postprocess_text(outputs).to(device=device, dtype=dtype)
        mask = text_inputs&#91;&quot;attention_mask&quot;&#93;.to(device=device, dtype=dtype)

    del text_encoder, tokenizer

    return embeds, mask</code></pre></details>
</div>
