TS NAG
At CFG 1 Your Negative Prompt Is Decoration — NAG Puts It Back
- model
- negative
- model
The thing you've probably already noticed
You typed a negative prompt, ran a distilled model at CFG 1, and nothing happened. That's not a bug and not something you're doing wrong. ComfyUI gates the unconditional pass on math.isclose(cond_scale, 1.0) and skips computing it entirely - substituting 1 into the guidance formula leaves you with the conditional prediction, so the second forward pass is pure waste. The box still renders. The text is discarded. People test this, don't believe it, then test it again and post about it.
The usual advice is to restate the constraint positively, which works and costs nothing. NAG is the other answer: it applies the negative inside every cross-attention block instead of through guidance, so it doesn't need a second pass of the model to exist.
How it works
In each cross-attention block, the same query meets the positive context and the negative context, and the two results are combined:
guidance = x_positive * scale - x_negative * (scale - 1) # extrapolate away
r = ||guidance||_1 / ||x_positive||_1 # per token
if r > tau: guidance *= (||x_positive||_1 * tau) / ||guidance||_1
out = guidance * alpha + x_positive * (1 - alpha)
That clamp by tau is the reason the word "normalized" is in the name. An extrapolation at nag_scale = 11 would otherwise tear the activations apart; capping how far the guided attention may stray, measured as a ratio of L1 norms, is what keeps a number that big usable.
The cost is the point: one extra cross-attention per block, not a second full pass. The query already comes from the picture and only meets a short text context, so it's cheap - nothing like the compute CFG burns.
Inputs and outputs
model- a Wan or LTX model.negative- a realCONDITIONINGfrom a text encode. Not a zeroed-out one; aConditioningZeroOutor an empty encoder sends nothing and the node politely does nothing.nag_scale- default 11, and0switches the node off entirely. This is the push.nag_alpha- 0.25 by default: how much of the guided attention reaches the result, the rest staying plain positive attention.nag_tau- 2.5: the ceiling on the deviation. Lower is safer and weaker.model_type- an advanced widget,autoby default. Auto recognises the family by the structure of the blocks, which is what you want; name one only to check something detection doesn't know.
One output, model - the same model with guided cross-attention. Wire it into your KSampler and leave the sampler at CFG 1; the sampler's own negative input stays irrelevant.
On the numbers: the defaults here (scale 11) come from kijai's WanVideoNAG, not from ChenDarYen's original standalone NAG node, where the community advice was to stay nearer 3. Those figures are not interchangeable between implementations. Start at the default with your existing negative prompt, and if nothing visibly changes, push scale rather than touching tau - tau is the seatbelt, not the accelerator.
What it supports, and what it refuses
- Wan -
blocks[i].cross_attn, both T2V and I2V. The maths is reproduced one-to-one and NAG lands before the output projection, matchingWanVideoNAGnumber for number, so settings shared for Wan transfer as they are. - LTX -
transformer_blocks[i].attn2. Here the original forward is called twice and the combination happens after the output projection, because duplicating LTX's internals (RoPE, guide masks, per-head gating) would break on every upstream update. - Krea 2, MiniMax H3 - refused, with the reason. Those models concatenate text and picture into one sequence before the stack, so a negative variant would have to be carried through every block - a full second forward, which is exactly what CFG already does. The error tells you to raise CFG on the sampler instead of pretending it saved you something.
Install
ComfyUI Manager → search Timesaver, or:
cd ComfyUI/custom_nodes
git clone https://github.com/AlexYez/comfyui-timesaver
cd comfyui-timesaver
python -m pip install -r requirements.txt
Restart ComfyUI - nothing is downloaded for this node and there's no optional extra to add. The pack flags it as experimental, which is fair: it patches every cross-attention block in the model, so test it on a short clip before it joins a 20-minute batch.
If it doesn't bite
The empty-negative mistake is the common one - you copied your old CFG-1 graph, where the negative text encode was a placeholder, and fed that in. Encode a real negative prompt with the same text encoder your Wan or LTX graph uses.
The other one is the wrong model: Could not find cross-attention blocks in this model means you're on something other than Wan or LTX (the supported families are listed in the message). Detection asks the blocks, not the filename, so a renamed checkpoint is not a problem - a different architecture is.
Inputs (6)
| Name | Type | Default | Description |
|---|---|---|---|
| model | MODEL | A Wan or LTX model. | |
| negative | CONDITIONING | What the picture should move away from. This is a real negative prompt, not the zeroed-out one a cfg-1 sampler ignores. | |
| nag_scale | FLOAT | 11.00–100 | How far to push away from the negative. 0 switches the node off entirely. The clamp below is what keeps a number this large usable. |
| nag_alpha | FLOAT | 0.250–1 | How much of the guided attention reaches the result; the rest stays the plain positive attention. |
| nag_tau | FLOAT | 2.500–10 | Ceiling on how far the guided attention may stray from the positive one, measured as a ratio of L1 norms. Lower is safer and weaker. |
| model_type | COMBO | auto | Which family to patch. 'auto' recognises it by the structure of the blocks, which is what you want; name one only to check a model the detection does not know yet. |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| model | MODEL | The same model with guided cross-attention. The original is untouched. |