Ultimate Affine KSampler
Ultimate Affine KSampler, no upscale
- image
- model
- positive
- negative
- vae
- external_mask
- options
- noise_options
- affine_schedule
- IMAGE
WASUltimateCustomAdvancedAffineNoUpscale - "Ultimate Affine KSampler" in the UI - is the pack's flagship image node, and the one behind the README's 720p → 2k demo. It takes an image, re-encodes it to latent, runs a tiled sampling pass with Affine's scale/bias enhancement baked into every few steps, and hands you back pixels. The "No Upscale" in the name is the key: unlike the sibling USDU node it doesn't scale the image up with a model first. It's a quality pass, not a size pass - low-denoise, tiled, and detail-targeted.
If you've ever done the hi-res-fix dance - upscale, re-sampler at low denoise, watch the seams - this is that idea collapsed into one node with the seams handled for you. The tiling is the Ultimate SD Upscale approach: split into overlapping tiles, sample each, blend, no VRAM ceiling on output size. The README's own "Things to take note of" on the 2k example - better rock, natural brush, preserved foreground, reduced contrast - is the Affine pitch in one screenshot: it tames the burned, over-contrasted output that speed LoRAs love to produce.
How it works
At its core it's a KSampler with three things bolted on:
Tiling. tile_width/tile_height (default 0) in image pixels. 0 disables tiling (one pass over the whole image); -1 auto-sizes tiles to ≤1024px; explicit values give you control. tile_overlap (default 64px) is how much tiles bleed into each other so the seams don't show. Tiling is what lets you process a 2K image on a card that can't touch a 2K image in one shot.
Affine, scheduled during sampling. Every affine_interval steps (default 1 = every step), the sampler applies z' = scale * z + bias through a mask generated from pattern (26 choices, default white_noise). max_scale (default 1.2) is the peak - the scale ramps as 1 + (max_scale-1)*t - and max_bias (default 0) adds a brightness offset that also scales with progress. The affine_seed controls the mask; toggle affine_seed_increment to vary it per application for temporal variety. Optionally drop a grayscale external_mask on it to gate the whole thing to specific regions, and layer the option dicts (options + pattern-specific noise_options) for finer control.
Standard sampler controls. sampler_name (default euler, 44 choices), scheduler (default simple), steps (20), cfg (8), denoise (default 0.2). That low default denoise is the whole trick - you're not regenerating, you're re-detailing. You can even pass a per-step list as cfg for schedule-shaped guidance.
The VRAM knobs are worth naming because they're why this node works on modest cards: tiled_decode (uses ComfyUI's VAE tiled decode for big outputs), batch_size (chunks the batch dimension), and merge_frames_in_batch (flattens 5D video decodes so batches concatenate safely). vae_encode_batch_mode mirrors the Wan encode node: images or frames, depending on whether your input batch is stills or video frames.
The output
One IMAGE, ready for a preview or save node - and that's the point, it's a complete replace-in-line upscale-and-refine stage.
Installing it
Part of WAS Affine (WASasquatch/was_affine). Manager: search "WAS Affine", install, restart. Or:
cd ComfyUI/custom_nodes
git clone https://github.com/WASasquatch/was_affine.git
No model downloads, deps are torch/numpy (plus matplotlib). Despite the name, it explicitly does not require UltimateSDUpscale nodes.
Where people get burned
- Start with the Affine dials low. The README hammers this: latent space is sensitive,
scale=0.95can be strong. The defaultmax_scaleof 1.2 is a big swing on some models - pull it toward 1.05 before blaming the sampler. - Model sensitivity varies wildly. The README flags that Flux/Krea-family models may want inverted (positive) scale behavior, and that Lightning LoRAs pair best with CFG 1–2. If your first run looks wrong, check these before anything else.
- Pattern choices are 26 but defaulting is fine. White noise works as a general mask; perlin/worley for organic content, velvet/ring for fine detail. Don't feel obligated to options-node every pattern.
- Tiling ≠ free. Very small tiles with heavy overlap multiply the sampling work;
-1auto-sizing is usually the best price/quality point.
Inputs (32)
| Name | Type | Default | Description |
|---|---|---|---|
| image | IMAGE | Input IMAGE or VIDEO tensor. Supports [B,H,W,C] or [B,F,H,W,C]. | |
| model | MODEL | Diffusion model to sample with. | |
| positive | CONDITIONING | Positive prompt conditioning. | |
| negative | CONDITIONING | Negative prompt conditioning. | |
| vae | VAE | VAE used to encode/decode latents during USDU. | |
| seed | INT | 00–18446744073709550000 | Seed for base sampler (noise). |
| steps | INT | 201–10000 | Number of denoising steps. |
| cfg | FLOAT | 8.00–100 | Classifier-free guidance scale. Can be a single float or a per-step list (short lists repeat last value). |
| sampler_name | COMBO | euler | Base sampler algorithm. |
| scheduler | COMBO | simple | Scheduler for sigma schedule. |
| denoise | FLOAT | 0.200–1 | Denoise fraction (<=1). |
| external_maskopt | IMAGE | Optional external mask to gate affine. | |
| optionsopt | DICT | Base options for Affine (common/full options). | |
| noise_optionsopt | DICT | Pattern-specific overrides layered onto 'options'. | |
| affine_intervalopt | INT | 11–100 | Apply affine every N steps (1 = every step). |
| max_scaleopt | FLOAT | 1.20000–2 | Scale at schedule peak: 1 + (max_scale-1)*t. |
| max_biasopt | FLOAT | 0.0000-2–2 | Bias at schedule peak: max_bias*t. |
| patternopt | COMBO | white_noise | Affine mask pattern. |
| affine_seedopt | INT | 00–18446744073709550000 | Seed for affine mask generation (separate from sampler seed). |
| affine_seed_incrementopt | BOOLEAN | false | Increment affine seed after each application (temporal). |
| affine_scheduleopt | DICT | WASAffineScheduleOptions dict; interpreted over total steps with repeat-last behavior. | |
| tile_widthopt | INT | 0-1–16384 | IMAGE-space sampling tile width in pixels. 0 disables IMAGE tiling (single pass). -1 auto-calculates proportional tile size ≤1024 pixels. |
| tile_heightopt | INT | 0-1–16384 | IMAGE-space sampling tile height in pixels. 0 disables IMAGE tiling (single pass). -1 auto-calculates proportional tile size ≤1024 pixels. |
| tile_overlapopt | INT | 640–2048 | IMAGE-space overlap between sampling tiles (pixels). |
| tiled_decodeopt | BOOLEAN | false | Use VAE tiled decode to reduce VRAM spikes for large outputs/video. |
| tiled_tile_sizeopt | INT | 51264–8192 | Target output tile size (pixels) for VAE tiled decode. |
| tiled_overlapopt | INT | 640–1024 | Output-space overlap (pixels) for tiled decode. |
| tiled_temporal_sizeopt | INT | 640–4096 | Temporal window size (frames) for video tiled decode. 0 disables temporal tiling. |
| tiled_temporal_overlapopt | INT | 80–512 | Temporal overlap (frames) for video tiled decode. |
| batch_sizeopt | INT | 00–4096 | Process the batch dimension in chunks of this size to reduce peak VRAM. 0 = process all at once. Applies to non-tiling path. |
| merge_frames_in_batchopt | BOOLEAN | true | If decoded IMAGE is 5D [B,F,H,W,C], merge F into batch for concat. |
| vae_encode_batch_modeopt | COMBO | images | images: treat batch dim as separate images [B,C,1,H,W]. frames: treat batch dim as video frames [1,C,B,H,W]. |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| IMAGE | IMAGE | — |