HAP Calibrate (HRDiT)
Make HAP's speed trick work on your model, once
- model
- positive
- negative
- reference_latent
- scope_plan
- plan_path
- summary
HAP's whole trick is "each attention head only attends to what it needs" - but what it needs depends on the model and the resolution. The pack ships a scope plan for FLUX, and if that's what you run, you can stop reading. If you run Qwen, Z-Image, Anima, a fine-tune that behaves differently, or just want a tighter speed budget than the shipped plan, you need your own plan - and that's exactly what HAP Calibrate does, in-graph, without ever leaving ComfyUI.
Calibration is a one-time job per model + resolution, and the tooltip is explicit that the payoff is reuse: "Calibrate once per model+resolution; reuse the plan for all subsequent generations." The node runs one denoising step per calibration prompt at a chosen sigma, collects attention-gradient scores from every head, then solves a scope-selection knapsack to pick the per-head scopes that keep the most useful attention within your compute budget. The result is a SCOPE_PLAN you link straight into the HAP node - no file round-trip - plus a copy written to disk and a human-readable summary.
The inputs that matter
The one rule that will save you an hour: connect the same model you'll run HAP on, unpruned. The tooltip warns directly - "Do NOT connect a HAP-patched model (calibrate unpruned)." Then positive/negative from a CLIP Text Encode (keep them representative of your real prompts), and these:
width/height- calibration resolution. Calibrate at ≤ 2K to fit memory; the plan then reuses at higher resolutions.num_prompts(default 5) - prompts actually run; the paper used 30. More prompts = better averaging, longer calibration.budget_ratio(default 0.1) - fraction of full attention compute retained. Lower = faster sampling but more aggressive pruning.num_scopes(default 50) andbins(default 4000) - solver granularity. Leave them alone unless you're chasing the last few percent.chunk(default 256) - memory knob: fewer query rows per calibration chunk = less VRAM, slower.loss_type-output_norm(default) needs no external data (MSE of the denoised prediction vs zero);reference_msecompares against areference_latentyou connect.run- the master switch.falsereturns an empty plan so you can wire the graph safely before committing GPU time.
The three outputs: scope_plan (link into HAP), plan_path (absolute path of the written JSON, also usable in HAP's scope_plan_path), and summary (the calibration report - worth a glance to see per-head pruning).
Installing and running it
HAP Calibrate ships inside ComfyUI-DyPE, so install the pack: ComfyUI Manager → search "ComfyUI-DyPE" → install, or:
cd ComfyUI/custom_nodes
git clone https://github.com/wildminder/ComfyUI-DyPE.git
Restart. No extra dependencies and nothing to download. If you'd rather calibrate headlessly, the pack also ships calibration/calibrate_hap.py - with a --dry_run flag that exercises the whole pipeline on a toy model with no GPU, and a real-model mode that loads a checkpoint through ComfyUI:
python calibration/calibrate_hap.py --dry_run --out tmp/scope_plan_toy.json
Honest positioning
This is the fiddliest node in the pack, and that's by design - it exists because scope plans are model-specific and there's no way around measuring your model's attention. Most people will never touch it (the FLUX default just works). But if you're on a non-FLUX model, this is the difference between HAP being a toy and HAP being real. Two things to expect: it's a real GPU run, not instant - pick your prompts, set num_prompts to 30 for quality, and let it cook; and on a low-VRAM card, enable purge_between_prompts and calibrate at 2K, not 4K. The plan you get is validated and directly loadable, which is more than most calibration tooling in this ecosystem bothers to guarantee.
Inputs (21)
| Name | Type | Default | Description |
|---|---|---|---|
| model | MODEL | The model to calibrate. Must be the SAME model + resolution you will run HAP on. Do NOT connect a HAP-patched model (calibrate unpruned). | |
| positive | CONDITIONING | Positive conditioning (from a CLIP Text Encode node). Keep it representative of your typical prompts. The same conditioning is used for every calibration prompt; each prompt index varies the noise seed. | |
| negative | CONDITIONING | Negative conditioning (from a CLIP Text Encode node). | |
| width | INT | 1024256–8192 | Calibration resolution width. Calibrate at <= 2K (memory); reuse the plan at higher resolutions. |
| height | INT | 1024256–8192 | Calibration resolution height. Calibrate at <= 2K (memory); reuse the plan at higher resolutions. |
| num_prompts | INT | 51–64 | Number of calibration prompts to actually run (first N of the list). Paper: 30. More prompts = better averaging but longer calibration. |
| num_scopes | INT | 502–200 | Candidate scopes N_scope. Paper: 50. More scopes = finer granularity but slower solver. |
| budget_ratio | FLOAT | 0.100.01–1 | Attention cost ratio r_c (fraction of full attention compute retained). Paper: 0.1. Lower = faster but more pruning. |
| bins | INT | 4000100–20000 | Knapsack discretization resolution. |
| chunk | INT | 2561–4096 | Query rows per calibration chunk (memory knob; result-invariant). Lower = less VRAM but slower. |
| text_len | INT | 5120–4096 | Number of leading text tokens (never pruned). 512 = FLUX convention. |
| anchor_stride | INT | 320–1024 | Global anchor blocks in the cost model. 32 = HRDiT default. 0 = off. |
| calib_sigma | FLOAT | 1.000–1 | Denoising sigma at which the single calibration step runs. 1.0 = first step (max noise). Lower values probe mid-trajectory behaviour. |
| seed | INT | 34070–2147483648 | Noise seed base (prompt i uses seed + i). |
| loss_type | COMBO | output_norm | Calibration loss. 'output_norm' = MSE of the denoised prediction vs zero (no external data needed). 'reference_mse' = MSE vs a reference latent (connect the reference_latent input). |
| run | BOOLEAN | true | Master switch. False = return empty plan without running (for safe graph wiring). |
| promptsopt | STRING | Calibration prompts, one per line. Empty = built-in default list (5 prompts). Paper uses 30. | |
| prompts_fileopt | STRING | Optional text file with one prompt per line (overrides the 'prompts' input). Relative paths resolve against the ComfyUI-DyPE folder. | |
| reference_latentopt | LATENT | Target latent for 'reference_mse' loss (e.g. an encoded real image). Only needed when loss_type='reference_mse'. | |
| output_nameopt | STRING | scope_plan_calibrated.json | JSON file name inside <output>/dype_hap/. The written file is also loadable by the HAP node's scope_plan_path. |
| purge_between_promptsopt | BOOLEAN | false | Run gc + VRAM cache purge between calibration prompts (low-VRAM cards). Slower; results identical. |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| scope_plan | SCOPE_PLAN | Validated scope plan dict — link into the HAP node's scope_plan input. |
| plan_path | STRING | Absolute path of the written JSON (also usable in HAP's scope_plan_path). |
| summary | STRING | Human-readable calibration report. |