Zenaique

QLoRA OOMs at step 7000 after one clean epoch on a 24 GB GPU: which non-obvious causes deserve a look?

Multi-select·Medium·4.0 · 0·~1 min·Asked atLtimindtreeNVIDIATech Mahindra·Relevant atDatabricksMetaMicrosoft
Attempt it
TL;DR

A, B, and E are the real causes: rare packed-sequence spikes (A), eval without inference_mode (B), and undetached loss accumulation (E). C does not happen; D misdescribes AdamW.

Memory aid
Sign in to see the mnemonic that makes this stick.
Easy to grasp

Picture a backpack you can just barely close. Most days it holds the same kit of items and zips fine. Then one rare day a friend hands you a long umbrella that does not normally fit, and the backpack will not close. Or you start carrying a small souvenir from every day on top of the regular kit, and after enough days the backpack overflows. Or one afternoon you decide to also pack a duplicate of your bag inside it temporarily, and that is too much weight at once. Three of the listed problems are stories like these. The other two are not really problems at all; they describe things that never actually happen in the system.

Concept explanation~2 min read

Everything you need to truly understand this topic: intuition, mechanics, step by step explanation, code, formulas, and worked example. Click to expand.

Mid-run OOMs have a different debugging structure than first-step OOMs. A first-step OOM is constant: something is sized wrong from the start, and the fix is to resize. A mid-run OOM is either slow-growth (a leak that accumulates across steps) or a rare spike (input variability that eventually draws a worst-case sample). The arrival time at step 7000 rules out constant sizing and rules in growth or spike.

The question gives five candidate causes. Three of them are real failure modes (A: sequence-packing spike, B: eval without inference_mode, E: undetached loss accumulation). Two are not (C: silent re-download, D: AdamW growth). Knowing the difference requires a precise understanding of how each subsystem actually behaves.

This deep dive walks through the diagnostic framework, dissects each candidate cause, and closes with the instrumentation pattern that makes future mid-run OOMs much faster to diagnose.

The diagnostic framework: constant, growth, or spike

Every OOM in a training loop falls into one of three families based on its time signature.

Constant OOMs appear immediately, at step 1 or even at model initialization. The cause is sizing: the batch is too large, the model does not fit, sequence length is too long for the available memory. The fix is to resize (smaller batch, lower precision, gradient checkpointing, model sharding).

Growth OOMs appear at a step number that scales with how fast memory is leaking. The signature is monotonic growth in memory_allocated over steps. The cause is something in the training loop keeping references to tensors that should be freed: undetached loss tensors, accumulated metric tensors, a list that never gets cleared.

Spike OOMs appear at an unpredictable late step, after which the same recipe might run cleanly for hundreds of steps before spiking again. The signature is sudden peak memory at the OOM step that is much higher than recent average. The cause is input variability: a longer-than-average sequence, a larger-than-average batch, or a code path that runs rarely but allocates a lot.

The step-7000 OOM after a clean first epoch is either growth or spike. That immediately rules out the constant family. Among the five options in the question, A is a spike cause, B is a periodic spike cause (aligned with eval cadence), and E is a growth cause. C is impossible because Hugging Face does not re-download mid-run, and D is impossible because AdamW state is constant after step 1.

A: sequence-packing spike
B: eval without inference_mode
E: undetached loss accumulation
Why C and D are wrong
Instrumentation that catches all three
Sign in to unlock the full deep dive.

Situations where this technique stops working.

Sign in to see when this approach fails.

2–4 min · Everything important, quickly.

Sign in to see the quick scan of the deep dive.
Failure modeTime signatureDiagnostic signalFix
A: long-pack spikeRandom late stepPeak memory correlates with max seq lengthPre-allocate worst-case or cap pack length
B: eval graphOn eval step multiplesOOM aligns with eval cadenceWrap eval in torch.inference_mode()
E: undetached leakMonotonic growthmemory_allocated climbs steadilyCall .detach() or .item() on logged tensors
C: re-download (wrong)n/aDoes not happenn/a
D: optimizer growth (wrong)n/aConstant after step 1n/a

Real products, models, and research that use this idea.

  • Hugging Face TRL SFTTrainer documentation explicitly warns about sequence packing producing long-tail packs, which is the canonical setup for the A failure mode.
  • PyTorch documentation for torch.inference_mode covers the eval-time memory implications and recommends it over torch.no_grad for inference and eval loops.
Sign in to see more production examples.

What an interviewer would ask next. Try answering before peeking at the approach.

QHow would you instrument a training loop to distinguish A, B, and E in practice?
A

Log three signals every step: torch.cuda.memory_allocated, torch.cuda.max_memory_allocated since last log, and the input sequence length. Plot all three over steps. Monotonic memory_allocated growth points at E. Spikes in max_memory_allocated correlated with long sequences point at A. Spikes aligned with eval cadence point at B.

2 more follow-ups an interviewer would ask next. Sign in to reveal them.

Red flags & common mistakes

The phrases that signal junior thinking. Click to expand.

Most common mistake

Picking D because AdamW state sounds like a growth source, or picking C because re-downloads sound plausible. Neither describes actual framework behavior; the real culprits are spikes (A), eval-time graph builds (B), and undetached accumulation (E).

Sign in to see all red flags and common mistakes.

60 second bullets to scan on the way to the call.

  • Why peak memory under sequence packing is determined by the longest pack

  • How the absence of inference_mode doubles eval-time working memory

Sign in to unlock the revision sheet.

Primary sources. Browse if you want the original framing.

Similar questions

Same topic, related formats. Practice these next.

4 curated
Next question
What is RLHF, and why is it used after pretraining?
MCQ·Easy