Skip to content

Reject long untruncated calibration samples when max_seq_length is unset - #3012

Open
rishabhsinha17 wants to merge 1 commit into
vllm-project:mainfrom
rishabhsinha17:fix/calibration-untruncated-oom-guard
Open

Reject long untruncated calibration samples when max_seq_length is unset#3012
rishabhsinha17 wants to merge 1 commit into
vllm-project:mainfrom
rishabhsinha17:fix/calibration-untruncated-oom-guard

Conversation

@rishabhsinha17

@rishabhsinha17 rishabhsinha17 commented Aug 9, 2026

Copy link
Copy Markdown

SUMMARY:
Resolves #3011

When oneshot() runs with a text dataset and no max_seq_length, tokenization uses max_length=tokenizer.model_max_length, so long samples reach calibration untruncated. On a 32 GB card this OOMs inside transformers attention mask expansion with an error that points at GPU capacity, not sequence length, sending users toward pipeline="basic" or CPU offload, which do not help.

Reworked per the review discussion with @brian-dellabetta: format_calibration_data now raises a ValueError, instead of warning, when max_seq_length is unset and the tokenized calibration dataset contains samples longer than 2048 tokens. The error reports how many samples exceed the threshold and the longest sample length, and gives both remedies: set max_seq_length to truncate, or set it to at least the longest length to calibrate on the full-length samples intentionally (truncation to a bound no sample exceeds is a no-op, so that is the explicit opt-in). Checking the tokenized dataset also covers pre-tokenized datasets, which skip the tokenization path entirely. Sample lengths are measured on the arrow column to avoid materializing the tokenized dataset in Python memory.

This also carries over #3020's improvement so it can close in favor of this PR: the sequential pipeline's OOM message now also suggests reducing num_calibration_samples or max_seq_length (co-author credit in the commit).

TEST PLAN:
Unit tests in tests/llmcompressor/datasets/test_max_seq_length.py updated to assert the ValueError: trigger paths (input_ids, decoder_input_ids) check the measured numbers and both max_seq_length suggestions in the message; non-trigger paths (samples at or below threshold, max_seq_length set, dataset without input ids) complete without raising. pytest tests/llmcompressor/datasets/test_max_seq_length.py passes (10 tests). ruff check and ruff format --check are clean on the changed files with the repo-pinned ruff (0.4.10). Branch rebased onto latest main.

@coderabbitai

coderabbitai Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 13701f5a-db3f-42a3-9c45-1c313f6cb085

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@mergify mergify Bot added the two-reviews When a PR requires two reviews label Aug 9, 2026
@mergify

mergify Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Merge Protections

🔴 2 of 2 protections blocking · waiting on 👀 reviews

Protection Waiting on
🔴 Require one maintainer review 👀 reviews
🔴 Require two reviews 👀 reviews

🔴 Require one maintainer review

Waiting for any of

  • approved-reviews-by=HDCharles
  • approved-reviews-by=brian-dellabetta
  • approved-reviews-by=dsikka
  • approved-reviews-by=kylesayrs
  • approved-reviews-by=yiliu30
This rule is failing.

All PRs must have at least one approving review from a maintainer before merging.

  • any of:
    • approved-reviews-by=HDCharles
    • approved-reviews-by=brian-dellabetta
    • approved-reviews-by=dsikka
    • approved-reviews-by=kylesayrs
    • approved-reviews-by=yiliu30
  • #changes-requested-reviews-by = 0

🔴 Require two reviews

Waiting for

  • #approved-reviews-by >= 2
This rule is failing.

PRs labelled "two-reviews" must have at least two approving reviews before merging.

  • #approved-reviews-by >= 2
  • #changes-requested-reviews-by = 0

@github-actions

github-actions Bot commented Aug 9, 2026

Copy link
Copy Markdown

👋 Hi! Thank you for contributing to llm-compressor. Please add the ready label when the PR is ready for review.

Note: This is required to complete the testing suite, please only add the label once the PR is code complete and local testing has been performed.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a warning mechanism to alert users when max_seq_length is unset and the calibration dataset contains long untruncated sequences, which could lead to GPU out-of-memory errors. It also adds corresponding unit tests. The feedback suggests optimizing the sequence length calculation for large datasets using PyArrow to prevent potential CPU memory spikes or OOM errors.

Comment thread src/llmcompressor/datasets/utils.py Outdated
else:
return

lengths = [len(sample) for sample in dataset[feature_name]]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

For large datasets, loading the entire tokenized column into Python memory using dataset[feature_name] can be extremely slow and cause a massive CPU memory spike (or even OOM), as it instantiates Python list and integer objects for every single token in the dataset.

Since Hugging Face Dataset is backed by PyArrow, we can compute the sequence lengths extremely efficiently in C++ using pyarrow.compute.list_value_length without loading the nested lists into Python memory. This reduces memory usage from gigabytes to megabytes and speeds up the check from seconds/minutes to milliseconds.

We can fall back to the list comprehension if PyArrow is unavailable or if an exception occurs.

    try:
        import pyarrow.compute as pc
        column = dataset.data[feature_name]
        if hasattr(dataset, "_indices") and dataset._indices is not None:
            column = pc.take(column, dataset._indices.arrow_array)
        lengths = pc.list_value_length(column).to_pylist()
    except Exception:
        lengths = [len(sample) for sample in dataset[feature_name]]

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in the amended commit: lengths now come from pyarrow list_value_length on the arrow column, with the indices mapping applied for shuffled/selected datasets and the list comprehension kept as fallback. Verified the arrow path returns identical lengths to the fallback on an indexed dataset.

@rishabhsinha17
rishabhsinha17 force-pushed the fix/calibration-untruncated-oom-guard branch from e901a74 to 837e303 Compare August 9, 2026 17:20
@rishabhsinha17

Copy link
Copy Markdown
Author

@brian-dellabetta #3020 looks like the right fix for the failure path, and I agree the error site beats a warning for anyone who never hits this. Flagging where this PR sits relative to it so you can take one, both, or neither.

They fire at different points and in different places:

The part that is not duplicated: the warning reports the measured longest sample and how many exceed the threshold, so the user sees which lever applies to their data and by how much, rather than a list of levers to try. It also covers pre-tokenized datasets, which skip the tokenization path entirely.

If you would rather carry a single mechanism, say so and I will close this. If both are wanted I am happy to rebase on #3020 once it lands and trim anything the error message makes redundant.

@brian-dellabetta

Copy link
Copy Markdown
Collaborator

Hi @rishabhsinha17 , yes the error is favorable to the warning. logs are inevitably noisy with warnings from transformers and ourselves, and the error will display it at the proper location in logs. if you'd like to update your PR to look more like mine -- raising an error, fixing the merge conflict, and displaying max sequence length in error message -- we can close mine in favor of yours

@rishabhsinha17
rishabhsinha17 force-pushed the fix/calibration-untruncated-oom-guard branch from 837e303 to c446a9d Compare August 14, 2026 18:47
@rishabhsinha17
rishabhsinha17 requested a review from dsikka as a code owner August 14, 2026 18:47
@rishabhsinha17
rishabhsinha17 force-pushed the fix/calibration-untruncated-oom-guard branch from c446a9d to eda22e2 Compare August 14, 2026 18:47
@rishabhsinha17 rishabhsinha17 changed the title Warn on long untruncated calibration samples when max_seq_length is unset Reject long untruncated calibration samples when max_seq_length is unset Aug 14, 2026
@rishabhsinha17

Copy link
Copy Markdown
Author

@brian-dellabetta Done, reworked as you described. format_calibration_data now raises a ValueError when max_seq_length is unset and the tokenized dataset has samples over 2048 tokens. The message keeps the measured data (how many samples exceed the threshold, longest length) and shows max_seq_length both ways: set it to truncate, or set it to at least the longest length to keep full-length samples deliberately. Also carried your #3020 message addition into the sequential OOM re-raise, with co-author credit, so closing #3020 loses nothing. Branch is rebased on latest main and conflict-free; tests updated to assert the error.

When `max_seq_length` is unset and the tokenized calibration dataset
contains samples longer than SEQ_LEN_ERROR_THRESHOLD (2048) tokens,
format_calibration_data() now raises a ValueError instead of warning.
Calibrating with long untruncated samples runs out of GPU memory with
the OOM raised from attention or attention mask expansion, which is
easily mistaken for the model not fitting on the device, and a warning
for it is buried in noisy logs while an error surfaces at the failure
point (per review). The message reports how many samples exceed the
threshold and the longest length, and gives both remedies: set
`max_seq_length` to truncate, or set it to at least the longest length
to calibrate on full-length samples intentionally. Sample lengths are
measured on the arrow column to avoid materializing the tokenized
dataset in Python memory.

Also fold in vllm-project#3020's guidance so it can close in favor of this PR: the
sequential pipeline's OOM message now also suggests reducing
`num_calibration_samples` or `max_seq_length`.

Fixes vllm-project#3011

Co-authored-by: Brian Dellabetta <bdellabe@redhat.com>
Signed-off-by: Rishabh Sinha <rsinha17@terpmail.umd.edu>
@rishabhsinha17
rishabhsinha17 force-pushed the fix/calibration-untruncated-oom-guard branch from eda22e2 to 626173b Compare August 16, 2026 08:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

two-reviews When a PR requires two reviews

Projects

None yet

Development

Successfully merging this pull request may close these issues.

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

2 participants