-
Notifications
You must be signed in to change notification settings - Fork 242
Support VLM calibration with image-text data #755
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
|
Auto-sync is disabled for draft pull requests in this repository. Workflows must be run manually. Contributors can view more details about this message here. |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #755 +/- ##
==========================================
- Coverage 74.13% 73.08% -1.05%
==========================================
Files 192 193 +1
Lines 19263 19583 +320
==========================================
+ Hits 14280 14312 +32
- Misses 4983 5271 +288 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
|
So, we only support image quantization for just nemotron-vl? If yes, why? |
| # limitations under the License. | ||
|
|
||
| """Utility functions for getting samples and forward loop function for different vlm datasets.""" | ||
| """Utility functions for getting samples and dataloader for different VLM calibration datasets. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ajrasane could you review this change?
|
@Edwardf0t1 do you have experiments evaluating the accuracy impact of using the new dataset? |
At this time, only Nemotron VL has been tested. We can extend the logic to support other VLMs later. Note that different VLMs may have different forward functions—e.g., the way the vision encoder interacts with the language decoder can vary across models. Do you have a preferred VL model you’d like us to support next? For instance, Qwen3-VL? |
Tested on two benchmarks DocVQA and InfoVQA for Nemotron Nano VL v2 with vLLM backend:
Image-text calibration is only marginally better in these cases, but the calibration flow in this PR should be ready. The follow-up experiments can be
|
| # prompt = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True) | ||
| # inputs = processor(text=[prompt], images=[pil_image], ...) | ||
|
|
||
| def _collate_fn(examples: list[dict[str, Any]]) -> dict[str, torch.Tensor] | dict[str, Any]: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why do we need to introduce these while the original one does not?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Previously we don't use image-text data for calibration, and standard dataLoader collation doesn't work for VLMs. A few reasons:
- Dataset has inconsistent image formats
- We need to convert conversational format to model input format.
- Processor must process images and text together to align properly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we create a class for this collate function?
class VLMCollator:
def __init__(self, processor, dataset_name, require_image, max_length, device):
self.processor = processor
self.repo_id = (
SUPPORTED_VLM_DATASET_CONFIG[dataset_name]["config"]["path"]
if dataset_name == "nemotron_vlm_dataset_v2"
else None
)
self.image_root = getattr(processor, "_modelopt_vlm_image_root", None)
self.require_image = require_image
self.max_length = max_length
self.device = device
def __call__(self, examples):
# ... the collate logicThis would make it more readable and easier to test.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think a class is needed here. This _collate_fn is already tightly scoped to get_vlm_dataset_dataloader() and only depends on a small set of captured variables. Making it a class would add boilerplate without real benefit unless you need stateful caching, metrics, or config reuse across multiple dataloaders.
jingyu-ml
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. I only reviewed the dataset processing part, which behaves as expected, loading the dataset on demand rather than downloading the entire dataset.
| # prompt = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True) | ||
| # inputs = processor(text=[prompt], images=[pil_image], ...) | ||
|
|
||
| def _collate_fn(examples: list[dict[str, Any]]) -> dict[str, torch.Tensor] | dict[str, Any]: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we create a class for this collate function?
class VLMCollator:
def __init__(self, processor, dataset_name, require_image, max_length, device):
self.processor = processor
self.repo_id = (
SUPPORTED_VLM_DATASET_CONFIG[dataset_name]["config"]["path"]
if dataset_name == "nemotron_vlm_dataset_v2"
else None
)
self.image_root = getattr(processor, "_modelopt_vlm_image_root", None)
self.require_image = require_image
self.max_length = max_length
self.device = device
def __call__(self, examples):
# ... the collate logicThis would make it more readable and easier to test.
Signed-off-by: Zhiyu Cheng <zhiyuc@nvidia.com>
Signed-off-by: Zhiyu Cheng <zhiyuc@nvidia.com>
Signed-off-by: Zhiyu Cheng <zhiyuc@nvidia.com>
Signed-off-by: Zhiyu Cheng <zhiyuc@nvidia.com>
Signed-off-by: Zhiyu Cheng <zhiyuc@nvidia.com>
Signed-off-by: Zhiyu Cheng <zhiyuc@nvidia.com>
Signed-off-by: Zhiyu Cheng <zhiyuc@nvidia.com>
Signed-off-by: Zhiyu Cheng <zhiyuc@nvidia.com>
…for Nemotron-VLM-Dataset-v2 Signed-off-by: Zhiyu Cheng <zhiyuc@nvidia.com>
…for Nemotron-VLM-Dataset-v2 Signed-off-by: Zhiyu Cheng <zhiyuc@nvidia.com>
Signed-off-by: Zhiyu Cheng <zhiyuc@nvidia.com>
Signed-off-by: Zhiyu Cheng <zhiyuc@nvidia.com>
Signed-off-by: Zhiyu Cheng <zhiyuc@nvidia.com>
Signed-off-by: Zhiyu Cheng <zhiyuc@nvidia.com>
Signed-off-by: Zhiyu Cheng <zhiyuc@nvidia.com>
Signed-off-by: Zhiyu Cheng <zhiyuc@nvidia.com>
Signed-off-by: Zhiyu Cheng <zhiyuc@nvidia.com>
794fdfa to
b313f93
Compare
📝 WalkthroughWalkthroughThis pull request introduces Vision-Language Model (VLM) calibration support for post-training quantization. It adds new dataset utilities for streaming Nemotron VLM data, implements image-text pair calibration loops, extends the quantization pipeline to handle multimodal models, and includes documentation and helper functions for Nemotron VL model processing. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant hf_ptq
participant ModelLoader
participant VLMProcessor
participant DataLoader
participant CalibLoop
participant Quantizer
User->>hf_ptq: Execute with --calib_with_images
hf_ptq->>ModelLoader: load_model() with calib_with_images=True
ModelLoader->>ModelLoader: Detect Nemotron VL model
ModelLoader->>VLMProcessor: Create AutoProcessor
VLMProcessor->>VLMProcessor: Configure padding tokens & side
ModelLoader->>ModelLoader: extract_and_prepare_language_model_from_vl()
ModelLoader->>hf_ptq: Return LM + default_pad_token
hf_ptq->>DataLoader: Load nemotron_vlm_dataset_v2
DataLoader->>DataLoader: Stream tar shards + JSONL
DataLoader->>DataLoader: Match images to messages
DataLoader->>hf_ptq: Yield {id, messages, image}
hf_ptq->>CalibLoop: create_vlm_calibration_loop(model, dataloader)
CalibLoop->>CalibLoop: Inspect model.forward signature
loop Per batch
CalibLoop->>CalibLoop: Extract pixel_values, input_ids, attention_mask
CalibLoop->>CalibLoop: safe_nemotron_vl_forward()
CalibLoop->>CalibLoop: Align vision embeddings with img_context_token_id
CalibLoop->>CalibLoop: Run LM forward (no grad, eval mode)
end
hf_ptq->>Quantizer: quantize_main() with calibrated stats
Quantizer->>hf_ptq: Export quantized LM
hf_ptq->>hf_ptq: Restore tokenizer.pad_token
Estimated code review effort🎯 4 (Complex) | ⏱️ ~65 minutes 🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
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. Comment |
What does this PR do?
Type of change: New feature
Overview:
The primary goal of this PR is to allow the model optimizer to use image-text pair data during the calibration phase of quantization, which is likely help improve accuracy of quantized VLMs like Nemotron VL on visual understanding tasks particularly, compared to text-only calibration data.
Nemotron-VLM-Dataset-v2.hf_ptq.py) clean.Nemotron-Nano-VL-12B-V2model with image data.This PR complements #347 and we will consolidate llm_ptq and vlm_ptq examples in follow-up PRs.
Usage
Testing
Before your PR is "Ready for review"
Additional Information
Summary by CodeRabbit
New Features
--calib_with_imagesCLI flag to enable image-based calibration workflows.Documentation
✏️ Tip: You can customize this high-level summary in your review settings.