[Distributed] Extend QuantizationModifier to support distributed activation calibration#2391
[Distributed] Extend QuantizationModifier to support distributed activation calibration#2391Etelis wants to merge 22 commits intovllm-project:mainfrom
Conversation
|
👋 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. |
Summary of ChangesHello @Etelis, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request significantly enhances the Highlights
🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console. Changelog
Activity
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
|
This pull request has merge conflicts that must be resolved before it can be |
There was a problem hiding this comment.
Code Review
The pull request introduces distributed support for the QuantizationModifier, enabling weight calibration and activation observer synchronization across multiple GPUs. This is a significant improvement for scaling quantization to large models. The implementation uses a greedy bin-packing algorithm for load balancing weight calibration, which is a solid choice. However, the current approach to synchronization involves a large number of individual collective communication calls (all-reduces and broadcasts) within loops, which will likely become a performance bottleneck due to network latency. Additionally, there are a few issues with device indexing in multi-node environments that should be addressed to ensure robustness.
examples/big_models_with_sequential_onloading/llama3_8b_w8a8_distributed.py
Outdated
Show resolved
Hide resolved
Add shared utility functions for multi-GPU weight calibration and activation observer synchronization. All functions are no-ops when torch.distributed is not initialized. Signed-off-by: Itay Etelis <itay.etelis@ibm.com>
Add a helper function to recompute scale and zero_point from an observer's accumulated min/max after DDP all-reduce synchronization. Signed-off-by: Itay Etelis <itay.etelis@ibm.com>
Refactor QuantizationModifier.on_start to support distributed weight calibration. Each rank calibrates a subset of modules (assigned by greedy bin-packing on weight size) and broadcasts results to all ranks. Signed-off-by: Itay Etelis <itay.etelis@ibm.com>
Signed-off-by: Itay Etelis <itay.etelis@ibm.com>
Signed-off-by: Itay Etelis <itay.etelis@ibm.com>
Signed-off-by: Itay Etelis <itay.etelis@ibm.com>
Use each rank's own GPU device for NCCL broadcast instead of the module's execution device, which may be CPU or shared across ranks when the model is not GPU-resident. Signed-off-by: Itay Etelis <itay.etelis@ibm.com>
61c255a to
72ed4b2
Compare
72ed4b2 to
9975edc
Compare
examples/big_models_with_sequential_onloading/llama3_8b_w8a8_distributed.py
Outdated
Show resolved
Hide resolved
Remove distributed weight calibration (partition, broadcast, rank assignment) and focus exclusively on activation observer synchronization. Key changes: - Add synchronize(), recompute_qparams(), recompute_global_scale() to Observer base class for clean DDP interface - Move sync_activation_observers() to QuantizationMixin for reuse by both QuantizationModifier and GPTQModifier - Batch all async all_reduce ops and wait once, matching GPTQ pattern - Delete distributed.py (consolidated into Observer methods + dist.py) - Remove recompute_qparams_from_observer from calibration.py - Align example with existing DDP patterns (init_dist, get_rank_partition) - Update unit and multi-GPU tests for new observer-based sync Signed-off-by: Itay Etelis <itay.etelis@ibm.com>
|
All review comments have been addressed:
Runtime & eval results added to PR description (Llama-3-8B, W8A8 static activations, 256 samples, A100-80GB):
|
kylesayrs
left a comment
There was a problem hiding this comment.
I think this code looks really great, the benchmarks look great as well. A couple notes from me:
- The fact that the 4x DDP setup does not increase perplexity gives me confidence that syncing once per epoch (rather than once per batch) is good enough, nice work.
- From your speedup benchmarks, it seems like repeating work (
calculate_q/gparams) across ranks is not too much of a cost. That seems to match expectations as well, nice work.
I'll make sure this code gets merged as part of the next LLM Compressor release.
|
Thanks for the latest round of feedback! Addressed all three points: |
- Replace custom _all_reduce_fp8_safe with as_broadcastable from compressed_tensors, matching the GPTQ pattern - Divide by world_size before SUM all-reduce in moving-average observers, removing the need for finalize_synchronize - Remove _FP8_DTYPES set and _all_reduce_fp8_safe helper Signed-off-by: Itay Etelis <itay.etelis@ibm.com>
…m/Etelis/llm-compressor into feature/quantization-modifier-ddp
|
Looks good to me! Please use an average when synchronizing moving average observers across ranks |
|
The quality checks have failed. Please run |
Co-authored-by: Kyle Sayers <kylesayrs@gmail.com> Signed-off-by: Itay Etelis <92247226+Etelis@users.noreply.github.com>
|
The quality checks have failed. Please run |
|
The quality checks have failed. Please run |
- Run ruff format on observers/base.py - Fix test_moving_avg_synchronize_issues_all_reduce to mock moving_base.dist (not base.dist) and use SUM/get_world_size Signed-off-by: Itay Etelis <itay.etelis@ibm.com>
…m/Etelis/llm-compressor into feature/quantization-modifier-ddp
Head branch was pushed to by a user without write access
Closes #2220
Adds DDP support to
QuantizationModifierfor activation observer synchronization across multiple GPUs during calibration.At
SEQUENTIAL_EPOCH_ENDandCALIBRATION_EPOCH_END, activation observer min/max values are all-reduced across ranks. Scale/zp are then recomputed from the global statistics so all ranks have identical quantization parameters.Changes
synchronize(),recompute_qparams(),recompute_global_scale()toObserverbase classsync_activation_observers()toQuantizationMixin(shared byQuantizationModifierandGPTQModifier)dist.all_reduceoperations and wait once, matching GPTQ DDP patternrecompute_qparams_from_observerfromcalibration.py(now encapsulated in Observer methods)init_dist,get_rank_partition)Runtime & Evaluation Results
Model:
Meta-Llama-3-8B-Instruct, W8A8 (static input activations), 256 calibration samplesTest plan
pytest tests/llmcompressor/utils/test_distributed.py(8 tests)torchrun --nproc_per_node=2 -m pytest tests/llmcompressor/modifiers/quantization/test_quantization_ddp.py(2 tests)