MiniMax H3 PDD Acc Scheduler
The Second Pass Only Needs the Last Two Blocks — This Node Knows Which Ones
- SIGMAS
Here's the thing nobody tells you about refining an H3 clip: you can't pick a denoise strength off a slider and call it 0.3. The PDD acceleration LoRAs decode one trained head per block of four fine steps on a fixed shift-12 sigma grid. Land between blocks and the heads get trunk features they never trained on, and you get noise. So "re-denoise this latent by 30%" is not a well-defined request on this model.
This node turns it into one. You give it a step count and a denoise, it gives you back the actual trained block boundaries to hand your sampler.
What it emits
At denoise 1.0 it's the same schedule the Apply node's sigmas output produces: the nine knots of an 8-block partition on the shift-12 grid, starting at 1.0 and ending at exactly 0.0. Below 1.0 it slices - and it slices by whole blocks, not by sigma. keep = round(steps * denoise) blocks are retained from the tail, which is why the numbers look strange at first and then make complete sense:
0.125→ 1 block, resume sigma 0.632 - a subtle sharpen0.25→ 2 blocks, resume sigma 0.8 - the default in the pack's hi-res example0.375→ 3 blocks, resume sigma 0.878 - a strong repaint, and composition can drift
Between 0.125 and 0.25 is nothing. There's no partial block to land in, which is exactly the point.
There's a scar in the source worth mentioning because it explains why the schedule you get back is trustworthy: the sigma tensor builder used to unconditionally snap its first element to 1.0. On a denoise-sliced schedule that turned [0.8, 0.632, 0.0] into [1.0, 0.632, 0.0] - discarding your resume latent at full noise and integrating block 0's head across a 37% sigma span, which renders as structured water-droplet garbage. It now only snaps endpoints that are already endpoints. If you've ever seen a latent-upscale pass produce that specific artefact on an older build, that was it.
Inputs and output
nfe (8, 4, 6) has to match the Apply node. Not "roughly" - the heads are armed per block, so a scheduler telling the sampler to resume at 0.8 while the model was armed for 4 blocks is an off-grid evaluation and the Apply node's guard will say so. denoise is the block slicer above. partition is the optional string escape hatch (8,8,4,4,4,4, 8,4,4,4,4,4,4), must sum to 32, only sizes 4 and 8 accepted, and again must mirror the Apply node's field.
One output: SIGMAS, into SamplerCustomAdvanced's sigma input.
Where it goes in a graph
The canonical use is the two-pass hi-res fix, and the KB's upscaling notes describe the shape of the thing in general terms - render at a sane resolution, then do a second pass that adds coherent detail rather than inventing a new image. Same idea here, except the second pass is a partial denoise on the distilled grid. Pass one samples 8 steps at 896x512; MiniMax H3 AV Latent Upscale By at scale_by 1.5 lands you on 1344x768; pass two takes the upscaled latent, a fresh RandomNoise, and this node's sigmas at denoise 0.25, with the same PDD model and guider as pass one.
Both passes run the same patched model. Only sigmas, noise and latent differ - that trips people up who expect a "refiner model" to swap in.
Install
cd ComfyUI/custom_nodes
git clone https://github.com/xm6018924/BSAI-ComfyUI-MiniMax-H3-PDD-Acc
Restart, then find it under sampling/custom_sampling/schedulers. No models beyond the PDD file in models/pdd_acc/, no extra Python deps (torch, safetensors, numpy, all present in any ComfyUI install). It does need a core with H3's nested carried-audio latent, which the pack puts at v0.33.0+.
Troubleshooting the boring stuff
If the sampler errors with a message about evaluating off a trained block boundary, the usual cause is a mismatch, not a bug: this node and the Apply node disagreeing on nfe or partition. The other classic is sampler choice - euler only. Multi-stage samplers (er_sde, the dpmpp family, the res* samplers) evaluate between the boundaries you just carefully produced, and the whole schedule becomes decoration.
And if you're wiring this into a graph with an un-distilled H3 model for some reason, stop and use a BasicScheduler instead. This node's entire output is PDD block boundaries; on a model with no heads attached they're just an odd-looking custom schedule, and you'll also need CFG back on, which is a different workflow.
Inputs (3)
| Name | Type | Default | Description |
|---|---|---|---|
| nfe | COMBO | 8 | 3 options: 8, 4, 6 |
| denoise | FLOAT | 1.000–1 | Keep only the last round(steps*denoise) blocks (v2v-style partial denoise on the trained grid). |
| partitionopt | STRING | Custom block sizes summing to 32, overrides nfe — must match the Apply node's partition. |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| SIGMAS | SIGMAS | — |