MiniMax H3: MLP runs fc1 on all tokens at once (6.3 GB at 15 s 1344x768), OOM on 12 GB; token-chunked MLP gives identical output
Maintainers usually reply within 1 day
Nobody has claimed this yet.
Assessment
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Newbie friendliness
- 45/100
- Issue type
- Bug
- Clarity
- Clearly specified
- Activity status
- Active
- Domain
- machine-learning, performance
Research direction
Start with MLP.forward and DiTBlock.forward in comfy/ldm/minimax/model.py; the issue describes the full-token allocation and provides a chunked approach. Check how _run_blocks uses the block before changing the in-place residual update. Done when the 15-second T2V workflow at 1344×768 runs on a 12 GB GPU without the fc1 OOM.
Written by the indexing model from the issue text.
Description
MLP.forward (comfy/ldm/minimax/model.py) runs fc1 on every token at once: comfy.ops.linear_input_act(self.fc2, self.fc1(x), "swiglu"). fc1 outputs ffn * 2 = 28672 features, so a 15 s 1344x768 clip (about 109k tokens) needs a 6.3 GB bf16 buffer for that one matmul, and it fails on 12 GB:
File "comfy_kitchen/backends/cuda/__init__.py", line 2314, in int8_linear
out = torch.empty((m, n), dtype=out_dtype, device=x.device)
torch.OutOfMemoryError: Allocation on device 0 would exceed allowed memory. (out of memory)
DiTBlock.forward then also keeps the full-size MLP output and two normalized copies of the stream alive at the same time (h from norm1 stays referenced while norm2's h is built).
Environment: ComfyUI v0.45.0 (code also checked unchanged on master b2f6707443), comfy-aimdo 0.6.0, comfy-kitchen 0.2.41, PyTorch 2.15.0+cu132, RTX 3060 12 GB, Linux, Dynamic VRAM on (default). Workflow: the official video_fastvideo_fasth3_t2v / i2v / video_fasth3_ominiref_r2v templates with length 362 (15 s) at 1344x768, about 109k video tokens.
Fix direction. The MLP acts on each token independently. Running it over token chunks (16384 tokens) and adding each chunk's gated output straight into the residual stream gives the same result with about 0.9 GB peak. Locally, this replacement for DiTBlock.forward matched the original bit for bit (max diff 0.0) on test inputs:
def forward(self, x, t_emb, mod_segments, rope_freqs, transformer_options={}, attention=None):
attention = self.attn if attention is None else attention
shift_msa, scale_msa, gate_msa, shift_mlp, scale_mlp, gate_mlp = self.adaln_proj(t_emb)
h = _mod_scale_shift(self.norm1(x), shift_msa, scale_msa, mod_segments)
x = _mod_gate(x, gate_msa, attention(h, rope_freqs=rope_freqs, transformer_options=transformer_options), mod_segments)
del h
h = _mod_scale_shift(self.norm2(x), shift_mlp, scale_mlp, mod_segments)
for c0 in range(0, x.shape[0], CHUNK):
c1 = min(x.shape[0], c0 + CHUNK)
out = self.mlp(h[c0:c1])
for a, b, row in mod_segments: # gated add, restricted to this chunk
lo, hi = max(a, c0), min(b, c1)
if lo < hi:
r = row[lo - a:hi - a] if torch.is_tensor(row) and row.dim() > 0 else row
x[lo:hi].addcmul_(out[lo - c0:hi - c0], _mod_row(gate_mlp, r, x.dtype))
return x
The in-place addcmul_ assumes x is not needed elsewhere after the block, which holds in _run_blocks. Done when 15 s T2V at 1344x768 runs on 12 GB without the fc1 OOM.
Filed by Claude Opus 5.5 in Claude Code.
- Dominant language
- Python
- Stars
- 146k
- Forks
- 17.4k
- Avg merge
- 19h 44m
- Merged PRs (30d)
- 178
Getting set up
- No Dockerfile or Docker Compose file
- Has a pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from Comfy-Org/ComfyUI
-
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
Maintainers usually reply within 1 day
-
ROCm gfx1100: contiguous-k/v SDPA workaround is gfx1151-only, MiniMax H3 sampling 2.2x slower on RX 7900 XTXPossibly taken @TwelveNights claimed this 3 days ago. OpenPotential Bug
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
Maintainers usually reply within 1 day
-
Sub-quadratic attention is ~10x slower on long sequences on RDNA2 (gfx1030) because the key passed to bmm is non-contiguousPossibly taken @KornienkoDev claimed this 3 days ago. Open
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
Maintainers usually reply within 1 day
-
MoGe-3 output is nondeterministic on CUDA: sparse_pool3d_mean sums with float index_add_ (atomics)Possibly taken @potoior claimed this 10 days ago. Open
Difficulty 2/5 1-3 hours Newbie friendliness 85/100
Comfy-Org/ComfyUI#17498 · 1 comment ·
Maintainers usually reply within 1 day
-
TRELLIS.2 texture bake fails under --bf16-vae: BakeTextureFromVoxel 'Got unsupported ScalarType BFloat16'Possibly taken @Shubham-Padkonde claimed this 11 days ago. Open
Difficulty 2/5 1-3 hours Newbie friendliness 65/100
Maintainers usually reply within 1 day
All issues in Comfy-Org/ComfyUI
Similar issues
-
add entry to blockOpen
Difficulty 1/5 Under an hour Newbie friendliness 65/100
StevenBlack/hosts#3299 ·
-
`garak --report` overwrites the input report when its name has no ".report"Possibly taken @0z5a claimed this today. Openneeds-triage
Difficulty 2/5 Half a day Newbie friendliness 72/100
Maintainers usually reply within 2 days
-
plot_graph crashes when a mesh node has no m2m edgePossibly taken @tygvi claimed this today. Open
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
mllam/neural-lam#883 · 1 comment ·
Maintainers usually reply within 2 days
-
Difficulty 2/5 1-3 hours Newbie friendliness 62/100
future-agi/future-agi#4092 · 1 comment ·
Maintainers usually reply within 1 day
-
transcript analytics: a text whose only protected spans the prose pass redacts is withheld wholeOpen
Difficulty 1/5 Under an hour Newbie friendliness 82/100
WingedGuardian/GENesis-AGI#4641 ·
Maintainers usually reply within 1 day