Download ComfyUI-MiniMaxH3-Context-Loop/ComfyUI-MAINodes/tests/test_latent_upscale.py from dzmdd/Fast_deploy: direct link, hf CLI and curl.
- Browser
- Download file 7.01 kB
-
https://huggingface.co/dzmdd/Fast_deploy/resolve/main/ComfyUI-MiniMaxH3-Context-Loop/ComfyUI-MAINodes/tests/test_latent_upscale.py
- Command line
-
hf download hf://dzmdd/Fast_deploy/ComfyUI-MiniMaxH3-Context-Loop/ComfyUI-MAINodes/tests/test_latent_upscale.py
-
curl -L -o test_latent_upscale.py https://huggingface.co/dzmdd/Fast_deploy/resolve/main/ComfyUI-MiniMaxH3-Context-Loop/ComfyUI-MAINodes/tests/test_latent_upscale.py
7.01 kB
| #!/usr/bin/env python3 | |
| """Unit test for H3 Latent Upscale, the node that resizes the VIDEO half of | |
| an H3 nested AV latent and leaves the audio alone. | |
| python tests/test_latent_upscale.py | |
| Synthetic, no GPU, no comfy, no models. | |
| What it checks: | |
| 1. SHAPES. The video's h/w become the requested size; batch, channels and | |
| the TIME axis are untouched (the token clock is not this node's | |
| business). | |
| 2. AUDIO PASSTHROUGH is bit-exact and the nested container survives. | |
| 3. BOTH MODES run and differ: nearest-exact replicates cell values | |
| verbatim (a 2x nearest upscale is a 2x2 block copy), bilinear does not. | |
| 4. GRID SNAPPING. Targets land on the legal /32-pixel = /2-cell grid, from | |
| scale factors AND from explicit width/height, and an odd request is | |
| snapped rather than accepted. | |
| 5. PLAIN LATENTS. A bare VAEEncode video latent (no audio) works, because | |
| that is where the node sits in the latent-resident graph. | |
| 6. NO-OP. scale 1.0 changes nothing and returns the video by identity. | |
| 7. NOISE MASK, if present, follows the video (nearest) so a freeze mask | |
| does not silently apply at the wrong resolution. | |
| Exit code 0 = pass. | |
| """ | |
| import importlib.util | |
| import os | |
| import sys | |
| import torch | |
| HERE = os.path.dirname(os.path.abspath(__file__)) | |
| spec = importlib.util.spec_from_file_location( | |
| "mainodes_motion", os.path.join(os.path.dirname(HERE), "motion.py")) | |
| motion = importlib.util.module_from_spec(spec) | |
| spec.loader.exec_module(motion) | |
| FAILS = [] | |
| def check(name, ok, detail=""): | |
| print((" PASS " if ok else " FAIL ") + name + (" " + detail if detail else "")) | |
| if not ok: | |
| FAILS.append(name) | |
| class FakeNested: | |
| """Stands in for comfy.nested_tensor.NestedTensor: same duck type.""" | |
| def __init__(self, tensors): | |
| self.tensors = list(tensors) | |
| self.is_nested = True | |
| def unbind(self): | |
| return self.tensors | |
| def av_latent(h=30, w=54, t=32): | |
| torch.manual_seed(3) | |
| return {"samples": FakeNested([torch.randn(1, 24, t, h, w), | |
| torch.randn(1, 32, 2, 178)])} | |
| def main(): | |
| node = motion.H3LatentUpscale() | |
| # 1 + 2. nested AV latent, 2x | |
| lat = av_latent() | |
| audio_in = lat["samples"].unbind()[1] | |
| audio_ref = audio_in.clone() | |
| out, rep = node.upscale(samples=lat, scale=2.0, mode="bilinear") | |
| v, a = out["samples"].unbind() | |
| check("2x resizes only h/w of the video", | |
| tuple(v.shape) == (1, 24, 32, 60, 108), str(tuple(v.shape))) | |
| check("the time axis is untouched", v.shape[2] == 32, str(v.shape[2])) | |
| check("the container is still nested", getattr(out["samples"], "is_nested", False)) | |
| check("audio comes out bit-exact", a.shape == audio_ref.shape and | |
| torch.equal(a, audio_ref), str(tuple(a.shape))) | |
| check("audio is passed by reference (not copied)", a is audio_in) | |
| check("the input latent's video is not mutated", | |
| tuple(lat["samples"].unbind()[0].shape) == (1, 24, 32, 30, 54)) | |
| check("the report names both halves", | |
| "30x54 cells -> 60x108 cells" in rep.replace(" -> ", " -> ") or | |
| "video 30x54 -> 60x108 cells" in rep, rep.splitlines()[0]) | |
| check("the report says the audio was untouched", | |
| "audio passed through untouched" in rep, rep.splitlines()[-1]) | |
| # 3. both modes; nearest-exact = 2x2 block copy of the source cells | |
| src = av_latent() | |
| v0 = src["samples"].unbind()[0] | |
| near, _ = node.upscale(samples=av_latent(), scale=2.0, mode="nearest-exact") | |
| vn = near["samples"].unbind()[0] | |
| check("nearest-exact 2x is a verbatim 2x2 block copy", | |
| torch.equal(vn[:, :, :, ::2, ::2], v0) and | |
| torch.equal(vn[:, :, :, 1::2, 1::2], v0), | |
| f"max|diff| {float((vn[:, :, :, ::2, ::2] - v0).abs().max()):.3e}") | |
| bil, _ = node.upscale(samples=av_latent(), scale=2.0, mode="bilinear") | |
| vb = bil["samples"].unbind()[0] | |
| check("bilinear differs from nearest", not torch.equal(vb, vn), | |
| f"mean|diff| {float((vb - vn).abs().mean()):.4f}") | |
| check("bilinear stays in range of the source", | |
| float(vb.min()) >= float(v0.min()) - 1e-5 and | |
| float(vb.max()) <= float(v0.max()) + 1e-5, | |
| f"[{float(vb.min()):.3f}, {float(vb.max()):.3f}] vs " | |
| f"[{float(v0.min()):.3f}, {float(v0.max()):.3f}]") | |
| # 4. grid snapping | |
| check("cells snap to the /2 grid (=/32 px)", | |
| [motion._snap_cells(px) for px in (864, 1728, 1000, 900, 33, 8)] | |
| == [54, 108, 62, 56, 2, 2], | |
| str([motion._snap_cells(px) for px in (864, 1728, 1000, 900, 33, 8)])) | |
| odd, rep_odd = node.upscale(samples=av_latent(), scale=1.5, mode="bilinear") | |
| vo = odd["samples"].unbind()[0] | |
| check("a scale landing off-grid is snapped, not accepted", | |
| tuple(vo.shape[3:]) == (46, 82), # 45->46, 81->82 cells | |
| f"{tuple(vo.shape[3:])} cells = {vo.shape[3] * 16}x{vo.shape[4] * 16} px") | |
| wh, _ = node.upscale(samples=av_latent(), scale=2.0, width=1728, height=960, | |
| mode="bilinear") | |
| vw = wh["samples"].unbind()[0] | |
| check("explicit width/height override scale", | |
| tuple(vw.shape[3:]) == (60, 108), str(tuple(vw.shape[3:]))) | |
| wh2, _ = node.upscale(samples=av_latent(), scale=2.0, width=1000, | |
| mode="bilinear") | |
| vw2 = wh2["samples"].unbind()[0] | |
| check("a nonzero axis snaps and the zero axis still uses scale", | |
| tuple(vw2.shape[3:]) == (60, 62), str(tuple(vw2.shape[3:]))) | |
| # 5. plain video latent (VAEEncode output, no audio) | |
| plain = {"samples": torch.randn(1, 24, 32, 30, 54)} | |
| pout, prep = node.upscale(samples=plain, scale=2.0, mode="bilinear") | |
| check("a plain video latent upscales and stays plain", | |
| isinstance(pout["samples"], torch.Tensor) and | |
| tuple(pout["samples"].shape) == (1, 24, 32, 60, 108), | |
| str(tuple(pout["samples"].shape))) | |
| check("...and the report says there is no audio", | |
| "no audio component" in prep, prep.splitlines()[-1]) | |
| # 6. no-op | |
| same = av_latent() | |
| sout, srep = node.upscale(samples=same, scale=1.0, mode="bilinear") | |
| check("scale 1.0 is a no-op (video by identity)", | |
| sout["samples"] is same["samples"], srep.splitlines()[0]) | |
| # 7. noise mask follows the video | |
| masked = av_latent() | |
| masked["noise_mask"] = FakeNested([torch.ones(1, 1, 32, 30, 54), | |
| torch.ones(1, 32, 2, 178)]) | |
| mout, _ = node.upscale(samples=masked, scale=2.0, mode="bilinear") | |
| mv, ma = mout["noise_mask"].unbind() | |
| check("a nested noise_mask is resized with the video", | |
| tuple(mv.shape) == (1, 1, 32, 60, 108), str(tuple(mv.shape))) | |
| check("the audio mask is left alone", tuple(ma.shape) == (1, 32, 2, 178), | |
| str(tuple(ma.shape))) | |
| print() | |
| if FAILS: | |
| print(f"FAILED: {len(FAILS)} check(s): " + ", ".join(FAILS)) | |
| return 1 | |
| print("all checks passed") | |
| return 0 | |
| if __name__ == "__main__": | |
| sys.exit(main()) | |