H3 LBH Video Upscale + Continue
The actual trick behind the 20% speedup
- samples
- model
- noise
- sigmas
- LATENT
If you only understand one node in this pack, make it this one. Everything else is a supporting optimisation; H3 LBH Video Upscale + Continue is the move that turns four expensive steps at full resolution into three cheap ones plus one expensive one, and it's where the 20–25% saving on a 12GB card actually comes from.
The scheme, in the author's shorthand, is 3+1: sample three H3 steps at 384×672, upscale that half-finished latent, then run the fourth step at 544×960. The output stage then doubles to 1088×1920 with audio. Same seed, same prompt, measurably faster - 106.9 s down to 85.4 s for a 10-second clip, 154.8 s to 116.6 s for 14 seconds, on an RTX 4070.
How it works
Take a clean-ish low-resolution AV latent. Split it: H3 stores video and audio as a nested tensor, video first, audio second. Send only the video through a 3D latent upscaler (LBH, the FP16 3D conv model in models/latent_upscale_models) targeting your width/height, with chunking disabled so the full temporal context is available in one pass. Then bolt the untouched audio back on.
Then comes the part people miss: re-noising. The upscaled video isn't ready to sample - it's a magnified version of a partially denoised latent, and the remaining schedule expects a specific noise level. So the node builds a noise mask that is 1 for the video rows and 0 for the audio rows, generates noise through the supplied noise object, zeroes the audio half, and applies noise_scaling at sigmas[0]. The video comes out at exactly the noise level the next step wants; the audio stays exactly as sampled, which is why the voice doesn't fracture across the resolution change.
This is the image-world hi-res fix pattern - generate at native size, upscale the latent, finish at low denoise so the second pass adds coherent detail instead of new composition - applied to video, with a temporal-aware upscaler because a per-frame upscaler jitters fine texture into mush. Same idea, different medium.
The node also frees about 4 GiB before loading the upscaler and calls gc plus a soft cache empty on the way out. That's deliberate: the H3 model is still resident at that point and the 3D upscaler wants room.
Inputs and outputs
samples is the low sampler's latent. model is the patched model (same chain the first sampler used). noise wants a real RandomNoise - the node calls generate_noise on it, so a DisableNoise won't do. sigmas wants the remainder of the schedule: in the example, BasicScheduler(simple, 4 steps) → SplitSigmas(step 3) → here, and it must stay on the CPU. upscaler_name is your LBH file. width/height default to 544×960 and must land on H3's 32px grid.
One output: LATENT. Wire it into LTXVConcatAVLatent alongside the audio you pulled off the low sampler with LTXVSeparateAVLatent, then into the second SamplerCustomAdvanced with a DisableNoise and the same remaining sigmas. Decode at the end, not in the middle.
Install
Manager: search H3 LBH X2 Stream, install, restart - plus the sibling H3 X2 Stream for the INT8 X2 decoder and the async save node the examples use. Manual:
cd ComfyUI/custom_nodes
git clone https://github.com/sepiablue-ai/ComfyUI-H3-LBH-X2-Stream
then restart. Deps are einops and safetensors. The upscaler itself is a hand download and needs the latent_upscale_models folder - add it to extra_model_paths.yaml if your models live outside the ComfyUI tree. Prepare the X2 decoder once with examples/00_prepare_x2.json before expecting video out.
Common issues
"Connect the remaining original CPU sigma schedule from SplitSigmas." Two ways to earn this: passing the full schedule instead of the split remainder, or letting sigmas land on the GPU. Split it, keep it on CPU, done.
"LBH target dimensions must align to the H3 32px grid." The upscaler produced something whose latent shape isn't height//16 × width//16. Round both dimensions to multiples of 32, and keep them consistent with high_width/high_height on the conditioning node - a handoff at 576×960 over conditioning built for 544×960 is exactly the sort of "it runs but looks wrong" mismatch that costs you an hour.
Audio is mangled or silent. Nearly always the concat path: the low sampler's latent has to reach LTXVConcatAVLatent through LTXVSeparateAVLatent, not be re-encoded or replaced by a fresh latent. The handoff deliberately passes audio through untouched - if audio changed, your graph replaced it.
OOM right at the upscale. That's the peak of the workflow: model resident, high-res latent, upscaler loading. Lower the target resolution pair, or drop cache_mib on the QKV node to hand back some VRAM.
Tempted by 4+0 (upscale after all four steps)? The author tested it and rejected it for picture and audio quality. That's the useful part of this repo's framing: the configuration isn't arbitrary, it's the one that survived a quality check.
Inputs (7)
| Name | Type | Default | Description |
|---|---|---|---|
| samples | LATENT | — | |
| model | MODEL | — | |
| noise | NOISE | — | |
| sigmas | SIGMAS | — | |
| upscaler_name | COMBO | 0 options: | |
| width | INT | 54432–8192 | — |
| height | INT | 96032–8192 | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| LATENT | LATENT | — |