Skip to content

Untruncated text calibration produces a misleading 16 GiB CUDA OOM in mask expansion; warn or guard when max_seq_length is unset #3011

Description

@Rodder5

⚙️ Your current environment

  • llmcompressor 0.12.1.dev100+g170a2e19 (traceback below); the same 16.00 GiB OOM also killed earlier runs on released 0.12.0.1 (both pipeline="basic" and CPU-offload variants)
  • transformers 5.10.1, torch 2.11.0+cu130
  • 1x RTX 5090 32 GB (sm_120), driver 580.173.02, Ubuntu 24.04
  • Dataset: HuggingFaceH4/ultrachat_200k train_sft, 128 samples, rendered through the model chat template. Longest sample 3,994 tokens; only 10 of 128 exceed 2,048.

🐛 Describe the bug

Calling oneshot() with a text dataset and no max_seq_length reliably OOMs a 32 GB card during calibration of Qwen3-8B, with the allocation landing in transformers' attention-mask expansion:

File ".../transformers/masking_utils.py", line 52, in and_mask
    result = result & mask(batch_idx, head_idx, q_idx, kv_idx).to(result.device)
torch.OutOfMemoryError: CUDA out of memory. Tried to allocate 16.00 GiB.

Setting max_seq_length=2048 and changing nothing else makes the identical run complete with headroom. We have not pinned down which broadcast produces the 16.00 GiB request (calibration batch_size defaults to 1, so it is not simple cross-sample padding); full logs available on request.

What makes this worth an issue is how misleading the failure is. The error points at GPU capacity, not sample length, so the natural responses are pipeline="basic", CPU offload via device_map, or concluding the model does not fit the card. None of them help, and each failed attempt costs a full calibration cycle. It took us several such cycles to find the actual cause.

Related but distinct prior work: #2649 fixed truncation for pre-tokenized datasets, and #2917 fixed truncation state leaking into the saved tokenizer. This report is about the untruncated-text path and the quality of the failure when it bites.

Proposal, any of which would have saved the debugging time:

  1. Log a prominent warning when tokenizing calibration text with no max_seq_length set, including the longest sample length found.
  2. Or apply a documented default truncation for text datasets (matching what most recipes in examples/ opt into).
  3. Or catch OOM during calibration and re-raise with a hint naming max_seq_length when long samples are present.

Happy to submit a small PR for option 1, or whichever direction maintainers prefer.

🛠️ Steps to reproduce

from datasets import load_dataset
from transformers import AutoTokenizer
from llmcompressor import oneshot
from llmcompressor.modifiers.quantization import QuantizationModifier

MODEL = "Qwen/Qwen3-8B"
tok = AutoTokenizer.from_pretrained(MODEL)
ds = load_dataset("HuggingFaceH4/ultrachat_200k", split="train_sft") \
    .shuffle(seed=3407).select(range(128))
ds = ds.map(lambda ex: {"text": tok.apply_chat_template(ex["messages"], tokenize=False)},
            remove_columns=ds.column_names)
recipe = QuantizationModifier(targets="Linear", scheme="NVFP4", ignore=["lm_head"])
oneshot(model=MODEL, dataset=ds, recipe=recipe,
        num_calibration_samples=128, output_dir="out-nvfp4")   # no max_seq_length -> OOM on 32 GB

Add max_seq_length=2048 to the oneshot() call and it completes.

Hit while producing the quantization benchmark at https://github.com/Rodder5/sm120-quant-bench.

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions