Comfy-Org / Comfy-Org/ComfyUI

LTXAV memory estimate differs by ~128x between video-only and nested AV latents, causing PCIe thrashing

Open
#15,356 1 comment 1 reaction 1 assignee Claimed by @rattus128 View on GitHub
Dominant language
Python
Stars
133k
Forks
15.7k
Avg merge
1d 7h
Merged PRs (30d)
158

Description

## Summary: what the bug is

LTXAV behaves incorrectly when sampling **video without an audio latent**.

The video itself is the same, but ComfyUI represents and estimates it differently:

- Video-only input stays a normal 5D tensor: `(B, 128, T, H, W)`.
- Video+audio input is a nested latent. Before sampling, ComfyUI flattens it to `(B, 1, N)`.

The generic memory estimator multiplies the dimensions beginning at index 2. As a result, for video-only input it excludes the `128` video-latent channels, while for packed nested input those same channels are already included in `N`.

For the post-upscale latent used in this test, ComfyUI therefore estimates approximately:

- `129.6 MiB` for plain video-only `(1, 128, 61, 30, 46)`;
- `16,593.6 MiB` for the exact same video values when flattened as part of a nested latent;
- a difference of exactly `128x`, before audio values are even added.

This confirmed shape-dependent discrepancy makes Dynamic VRAM choose a radically different model placement/offload plan. In the failing video-only run, the second sampler loads only part of the 22.4 GB LTXAV model into 16 GB VRAM, then spends minutes transferring data over PCIe without ever reaching sampler step 0.

The memory-estimation discrepancy is confirmed directly from the current ComfyUI code and the tensor shapes recorded by the linked minimal reproduction. In that reproduction, the low-resolution 8-step video-only pass works, but immediately after native latent upscaling the 4-step pass does not reach step 0 in more than 5 minutes and produces sustained PCIe traffic.

The issue therefore does not depend on a larger multi-stage workflow. It reproduces with the linked native-only graph containing two samplers and one native LTX latent upscaler.

## Custom Node Testing

- [ ] I have tried disabling custom nodes and the issue persists

The linked reproduction workflow uses native ComfyUI nodes only. Custom node packages were installed and loaded by ComfyUI during this test, but none are referenced by the workflow. I have not yet repeated the test with `--disable-all-custom-nodes`.

## Expected Behavior

LTXAV sampling should use a consistent and appropriate activation-memory estimate regardless of whether the same video latent is supplied alone or wrapped in a nested video+audio latent. Disabling audio generation should not make the video sampler dramatically slower or prevent it from reaching step 0.

## Actual Behavior

With a plain video-only latent, the first sampling pass starts and completes normally. After `LTXVLatentUpsampler`, the second sampler receives the upscaled video latent but never reaches its first sampling step. The GPU spends this time at high compute utilization with sustained PCIe transfers instead of making sampling progress.

In the minimal reproduction:

- First sampler latent shape: `(1, 128, 61, 15, 23)`
- First sampler reached step 0 after about 22.8 seconds
- Upscaled latent shape passed to the second sampler: `(1, 128, 61, 30, 46)`
- The second sampler did not reach step 0 after more than 5 minutes
- During the stall, GPU SM utilization reported 100%, memory-controller utilization was around 1%, and sustained PCIe transfers were observed
- An interrupt was requested, but execution remained inside the stalled operation for several more minutes before the prompt was cancelled

There is no audio latent in the minimal workflow. Source inspection shows that adding an audio latent would change the sampler input from a plain 5D video tensor to a packed nested tensor and would therefore send a radically different shape into the generic memory estimator. This representation-dependent calculation is the suspected reason that the video-only path selects a pathological Dynamic VRAM/offload plan.

### Suspected cause: representation-dependent memory estimation

The current native sampling path appears to estimate radically different memory requirements for the same video tensor depending on whether it is nested:

1. In `comfy.samplers.KSampler.sample`, a nested AV latent is flattened by `comfy.utils.pack_latents()` to a shape like `(B, 1, N)`. A non-nested video latent remains `(B, C, T, H, W)`.
2. `comfy.sampler_helpers.estimate_memory()` passes that resulting shape to `BaseModel.memory_required()`.
3. `BaseModel.memory_required()` calculates its area using `batch * product(input_shape[2:])`.

Consequently:

- Plain video `(1, 128, 61, 30, 46)` is estimated from `61 * 30 * 46`; its 128 latent channels are excluded.
- The same video packed as part of a nested latent becomes `(1, 1, N)`, so all flattened video values, including the 128 channels, are included in `N`.

Using the current LTXAV `memory_usage_factor = 0.077` and BF16, the minimum estimate for the post-upscale video in this reproduction is approximately:

- Plain video-only latent: `129.6 MiB`
- The same video values in packed form, before even adding audio: `16,593.6 MiB`
- Difference: exactly `128x`

It is not clear whether the video-only estimate is too low, the packed nested estimate is too high, or both need a modality-aware calculation. However, this representation-dependent difference changes Dynamic VRAM placement/offloading by orders of magnitude. In the failing video-only second pass, the log reports `ram_mb=22404.4` and `vram_mb=5091.2`, followed by sustained PCIe activity and no first sampler step.

## Steps to Reproduce

1. Download and load [`LTX_TEST_001.json`](https://gist.github.com/Kinasa0096/a2dacea6770c68bc1690ff52801ecb2e).
2. Select an LTX 2.3 diffusion model, the matching LTX text encoders, LTX video VAE, and the native LTX spatial latent upscaler.
3. Keep the workflow video-only; do not supply an audio latent.
4. Queue the workflow.
5. Observe that the first 8-step sampler completes and `LTXVLatentUpsampler` produces the larger latent.
6. Observe that the second 4-step sampler logs its input latent shape and model-loading state, but does not log `First sampler step` or make normal sampling progress.

The linked reproduction uses:

- 736x480
- 481 frames at 24 fps
- `euler_cfg_pp`
- `linear_quadratic`
- First pass: 8 steps, denoise 1.0
- Native LTX latent spatial upscaler x2
- Second pass: 4 steps, denoise 0.4
- No VAE decode and no video output node; the result is connected only to native `SaveLatent`
- The graph contains only native ComfyUI nodes

## Debug Logs

```powershell
[2026-08-06 20:33:36,996] [INFO] got prompt
[2026-08-06 20:33:46,652] [DETAIL] Sampler: model=LTXAV latent_shapes=[(1, 128, 61, 15, 23)]
[2026-08-06 20:33:46,653] [INFO] Requested to load LTXAV
[2026-08-06 20:33:46,968] [INFO] Model LTXAV prepared for dynamic VRAM loading. 22404MB Staged. 0 patches attached. Force pre-loaded 608 weights: 3303 KB.
[2026-08-06 20:33:46,969] [DETAIL] Model loaded: patcher=ModelPatcherDynamic model=LTXAV ram_mb=0.0 vram_mb=3.2
[2026-08-06 20:34:09,436] [DETAIL] First sampler step: model=LTXAV sampler=sample_euler_cfg_pp step=0 total_steps=8 cfg=1.0 seed=1069963453138007 sigma=tensor(1.0000, device='cuda:0') sigma_hat=tensor(1.0000, device='cuda:0') latent_shape=(1, 128, 61, 15, 23) denoised_shape=(1, 128, 61, 15, 23)
[2026-08-06 20:35:22,688] [INFO] Requested to load LatentUpsampler
[2026-08-06 20:35:22,700] [INFO] Model LatentUpsampler prepared for dynamic VRAM loading. 949MB Staged. 0 patches attached. Force pre-loaded 34 weights: 68 KB.
[2026-08-06 20:35:22,700] [DETAIL] Model loaded: patcher=ModelPatcherDynamic model=LatentUpsampler ram_mb=0.0 vram_mb=0.1
[2026-08-06 20:35:23,623] [DETAIL] Sampler: model=LTXAV latent_shapes=[(1, 128, 61, 30, 46)]
[2026-08-06 20:35:23,840] [INFO] Model LTXAV prepared for dynamic VRAM loading. 22404MB Staged. 0 patches attached. Force pre-loaded 608 weights: 3303 KB.
[2026-08-06 20:35:23,841] [DETAIL] Model loaded: patcher=ModelPatcherDynamic model=LTXAV ram_mb=22404.4 vram_mb=5091.2
[2026-08-06 20:40:33,254] [INFO] Global interrupt (no prompt_id specified)
[2026-08-06 20:43:45,368] [INFO] Cancelling running prompt 97e3dd13-ea1c-4c30-a730-470c9d9c1b0e
```

## Other

- ComfyUI commit: `2eb609766a749e3104485979615e062e401bab97`
- Version: `v0.30.0-17-g2eb60976`
- OS: Windows 10 Pro 22H2, build 19045
- GPU: NVIDIA GeForce RTX 5080, 16 GB VRAM
- NVIDIA driver: 610.62
- System RAM: 64 GB
- Python: 3.12.10
- PyTorch: 2.10.0+cu130
- CUDA reported by PyTorch: 13.0
- Diffusion model used for this reproduction: `DasiwaLTX23_dragonleapV4_INT8.safetensors`
- LTX video VAE: `LTX23_video_vae_bf16.safetensors`
- LTX spatial upscaler: `ltx-2.3-spatial-upscaler-x2-1.1.safetensors`

The minimal reproduction and this report were prepared with OpenAI Codex and reviewed by the reporter before submission.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.