Nodes/ComfyUI-PolyhedronLoRAStack/⬡ Polyhedron Attention
ComfyUI Node

⬡ Polyhedron Attention

The attention-backend switcher that only offers what your machine can actually run

By PolyhedronAI·Created 3 months ago·Updated a day ago· 2
⬡ Polyhedron Attention
  • model
  • latent
  • model
attentiondefault (leave the model alone)
fallbacktrue
attention_firstsame as main
first_steps0
attention_lastsame as main
last_steps0
sparse_time_window3
sparse_sinktrue
live_checktrue

⬡ Polyhedron Attention swaps the attention kernel your diffusion model runs on - and, the part that's easy to miss, it can swap it per step range: a different backend for the opening steps where composition is decided, a different one for the closing steps where fine detail lands, and the fast quantized kernel in between.

The dropdown is the polite part. It only ever lists backends this installation can actually load and run - a mode whose kernel imports but fails at scale isn't offered, because "an option you can pick and then watch fail" is worse than one that was never there. The chosen backend is launched once before patching; if the launch fails, the console names it and the model is left on its own backend, no crash.

Why the step-split exists

The fast quantized kernels aren't lossless on every model. The README's framing is honest about it: running the exact backend for the first and last few steps and the fast one in between is usually indistinguishable from full precision while still buying most of the time. Set attention_first / first_steps for the opening window, attention_last / last_steps for the closing one, and attention for the middle - first_steps and last_steps default to 0 (window off), and if both windows overlap on a short schedule, the first one wins. Step counts are per sampler call, so in a MoE run each expert gets its own opening steps.

The backends

attention offers nine choices: default (leave the model alone), four PyTorch SDPA flavours (plain, cudnn, flash, mem-efficient), sage auto (the SageAttention family), xformers, comfy kitchen int8, and sparse local (video). The tooltip's caveat is worth taking literally: which quantized mode is both fastest and most accurate depends on the model's geometry - on video shape one mode can win on both axes while the order reverses on image shape. Don't pick one for your whole model tree; measure per model. That's literally what live_check is for: it measures the chosen kernel once against the model's default backend on the first real attention call and prints both times plus how far their answers differ (peak and RMS, relative to signal size). It costs about four extra attention calls per run and is worth leaving on when you meet a new model.

The sparse mode

sparse local (video) is the specialist: it limits how many latent frames each token can attend to in each direction (sparse_time_window, default 3), which at 17 latent frames keeps about 41% of the frame pairs - and roughly that fraction of the attention cost. The risk is spelled out in the tooltip: motion spanning more frames than the window can no longer be attended directly. sparse_sink lets every token also see frame 0 as a common anchor - the cheapest guard against drift on a long shot. Sparse runs in bf16, so it only beats an unquantized backend; against an int8 sage kernel it's roughly a tie, and live_check tells you which side you're on. Sparse requires the latent input - the mask has to know how the token sequence splits into frames - and refuses out loud without it rather than guessing.

fallback (default on) means a kernel error mid-run quietly continues on the model's own backend, with the error named once in the console. Turn it off when you're measuring and a silent fallback would move your numbers without telling you.

Installing it

Part of the ⬡ Polyhedron Suite pack. ComfyUI Manager → "Polyhedron Suite", or:

cd ComfyUI/custom_nodes
git clone https://github.com/PolyhedronAI/ComfyUI-PolyhedronLoRAStack.git
# restart ComfyUI

The node itself has no dependencies, but the fancier kernels - SageAttention, xformers, the int8 kitchen - are things you install separately, and the node correctly won't offer them until they're importable. If you hit the known "Sage corrupts this specific model" family of bugs (documented on Z-Image Base, for one), that's exactly the case where this node's per-step split or per-model choice earns its keep.

Gotchas

Wire the same latent the sampler gets into latent whenever you use sparse mode. And remember the patch only touches the diffusion model - text encoder and VAE keep whatever backend ComfyUI chose at startup, so don't expect this node to speed up encoding. Blank node under Nodes 2.0? Disable Modern Node Design in Settings.

CategoryPolyhedron/Sampling

Inputs (11)

NameTypeDefaultDescription
modelMODELThe diffusion model to patch. Text encoder and VAE are NOT affected -- they do not read transformer_options and keep whatever backend ComfyUI chose at start-up.
attentionCOMBOdefault (leave the model alone)Only backends this installation can actually load are listed. The chosen one is launched once before patching; if the launch fails, the console says so by name and the model is left on its own backend. Quantised modes (sage) buy speed with accuracy -- which of them is the most accurate depends on the model geometry, so measure per model rather than picking one for the whole tree.
fallbackBOOLEANtrueOn a kernel error mid-run, quietly continue on the model's own backend (the console names the error once). Turn this off to let the run fail instead -- useful when you are measuring and a silent fallback would move the numbers without telling you.
attention_firstCOMBOsame as mainBackend for the opening steps. The first step sets the composition out of pure noise, which is where a quantised kernel costs the most and saves the least. Leave on 'same as main' to switch nothing.
first_stepsINT00–1000How many steps at the START of THIS sampler call use attention_first. Counted per call, so in a MoE run each expert gets its own opening steps. 0 disables the window. Multi-stage samplers evaluate the model between schedule points, so the window edge can be fuzzy by one stage there.
attention_lastCOMBOsame as mainBackend for the closing steps, where fine detail is settled. Leave on 'same as main' to switch nothing.
last_stepsINT00–1000How many steps at the END of THIS sampler call use attention_last. 0 disables the window. If both windows overlap on a short schedule, the first one wins.
sparse_time_windowINT30–64Only for the sparse mode: how many latent frames each token may reach in each direction. At 17 latent frames a window of 3 keeps about 41% of the frame pairs, and roughly that fraction of the attention cost. Motion spanning more frames than this can no longer be attended directly -- that is the risk. Sparse runs in bf16, so it only pays off against an UNQUANTISED backend; against an int8 sage kernel it is roughly a tie. Leave live_check on and the node will tell you which side you are on. 0 means dense.
sparse_sinkBOOLEANtrueOnly for the sparse mode: let every token also see all of latent frame 0. Costs one extra frame of attention and gives the whole clip a common anchor -- the cheapest guard against drift over a long shot.
live_checkBOOLEANtrueMeasure the chosen kernel ONCE against the backend the model would otherwise use, on the first real attention call, and print both times plus how far their answers differ -- the difference is given against the signal's own size (peak and rms), because an absolute number alone cannot tell you whether it matters. Nothing is switched -- the number is for you, the decision stays in the workflow. Costs about four extra attention calls per run (two are warm-ups). Worth leaving on when you meet a new model, since the right kernel depends on the geometry: on video shape one mode can be both fastest and most accurate while the order reverses on image shape.
latentoptLATENTREQUIRED by the sparse mode, ignored by every other one: the mask has to know how the token sequence splits into frames, and only the latent knows that. Wire the same latent the sampler gets. Without it the sparse mode refuses out loud rather than guessing.

Outputs (1)

NameTypeDescription
modelMODEL