-
Notifications
You must be signed in to change notification settings - Fork 200
1686 Logic matching refactor #1687
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
👋 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. |
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.
Summary of Changes
Hello @ved1beta, 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 refactors the AWQModifier
by replacing a custom utility function for accessing nested PyTorch model layers with Python's built-in operator.attrgetter
. The primary goal is to simplify the codebase and align with standard library practices for attribute lookup, thereby improving maintainability.
Highlights
- Refactor
get_layer_by_name
usage: Replaced direct calls to the custom utility functionget_layer_by_name
withoperator.attrgetter
for retrieving nestedtorch.nn.Module
instances by their string names. This change was applied in the_set_resolved_mappings
method and theget_lowest_common_parent
function withinsrc/llmcompressor/modifiers/awq/base.py
. - Dependency cleanup: Removed the import of
get_layer_by_name
fromllmcompressor.utils.pytorch.module
insrc/llmcompressor/modifiers/awq/base.py
as it is no longer utilized after the refactor. - Code simplification and standard library adoption: Introduced the import of
operator.attrgetter
to leverage a standard Python library function for attribute access, leading to a more concise and potentially more robust way of navigating the model's module hierarchy.
Using Gemini Code Assist
The 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 in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command>
or @gemini-code-assist <command>
. Below is a summary of the supported commands.
Feature | Command | Description |
---|---|---|
Code Review | /gemini review |
Performs a code review for the current pull request in its current state. |
Pull Request Summary | /gemini summary |
Provides a summary of the current pull request in its current state. |
Comment | @gemini-code-assist | Responds in comments when explicitly tagged, both in issue comments and review comments. |
Help | /gemini help |
Displays a list of available commands. |
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 .gemini/
folder in the base of the repository. Detailed instructions can be found here.
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 or fill out our survey to provide feedback.
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
-
Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution. ↩
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.
Code Review
This pull request refactors the usage of get_layer_by_name
in src/llmcompressor/modifiers/awq/base.py
to use operator.attrgetter
directly. This is a good simplification that removes an unnecessary layer of abstraction.
I've identified a critical issue where the new code could crash if a module name doesn't contain a dot, and I've provided a suggestion to fix it. This issue was also present in the previous implementation but is a good opportunity to address now.
Regarding your question in the pull request description, if get_layer_by_name
is no longer used anywhere else in the project after this change, then you should proceed with removing the function definition from src/llmcompressor/utils/pytorch/module.py
and its corresponding tests. This would complete the refactoring. I'd recommend a project-wide search for other usages before removing it.
@@ -323,7 +324,7 @@ def _set_resolved_mappings(self, model: Module) -> None: | |||
smooth_layer = smooth_layers[smooth_name] | |||
|
|||
smooth_parent_name = ".".join(smooth_name.split(".")[:-1]) | |||
smooth_parent = get_layer_by_name(smooth_parent_name, model) | |||
smooth_parent = attrgetter(smooth_parent_name)(model) |
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.
This line could raise an AttributeError
if smooth_parent_name
is an empty string. This can happen if smooth_name
refers to a top-level module in model
(i.e., its name does not contain any dots). In that case, smooth_name.split('.')[:-1]
results in an empty list, and smooth_parent_name
becomes ""
, which is not a valid input for attrgetter
.
To prevent a crash, you should handle this case by assigning model
as the parent when smooth_parent_name
is empty, as this indicates smooth_name
is a direct attribute of model
.
smooth_parent = attrgetter(smooth_parent_name)(model) | |
smooth_parent = attrgetter(smooth_parent_name)(model) if smooth_parent_name else model |
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.
: )
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.
Yeah I'm a bit concerned this has the potential to error out as well. what if there's no parent?
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.
Looks good so far, thanks for your help with this
This exclude_internal_modules
option is now always on by default, so there's no need to include it explicitly
Co-authored-by: Kyle Sayers <[email protected]>
hey any update on this ? |
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.
Hi @ved1beta , thanks for the contributions. I have some questions/changes requested before we have the ci/cd workflows run
@@ -76,7 +76,7 @@ def infer_sparsity_structure_from_model(model: torch.nn.Module) -> Optional[str] | |||
# check for the common sparsity structures | |||
structures = {"2:4"} | |||
for sparsity_structure in structures: | |||
linear_modules = get_linear_layers(model) | |||
linear_modules = match_named_modules(model, linear=True) |
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.
is this right? I don't see a linear
input to match_named_modules
balance_layers = [] | ||
for balance_suffix in to_balance: | ||
# find the submodule that matches the activation layer | ||
_, balance_layer = get_matching_layer( | ||
_, balance_layer =match_modules_set( |
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.
looks like you need to run formatting
@@ -149,11 +147,11 @@ def on_start(self, state: State, event: Event, **kwargs): | |||
layer_sparsity = self.sparsity[index] | |||
else: | |||
layer_sparsity = self.sparsity | |||
|
|||
for name, module in get_prunable_layers(layer).items(): | |||
prunable_targets = ["Linear", "Conv1d", "Conv2d", "Conv3d", "QATLinear", "QATConv2d", "QATConv3d", "Conv1D"] |
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.
we should move this to a helper function instead of having it here and on line 211. @kylesayrs should we add this to the compressed-tensors matching code?
@@ -109,8 +109,8 @@ def on_finalize(self, state: State, **kwargs) -> bool: | |||
|
|||
with summon_full_params_context(state.teacher_model, offload_to_cpu=True): | |||
for key, (student_wrapper, teacher_wrapper) in self.wrappers_.items(): | |||
set_layer(key, student_wrapper.layer, state.model) | |||
set_layer(key, teacher_wrapper.layer, state.teacher_model) | |||
Module.set_submodule(key, student_wrapper.layer, state.model) |
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.
we're sure we want to call a class method on Module
here and not a method on an instance?
@@ -323,7 +324,7 @@ def _set_resolved_mappings(self, model: Module) -> None: | |||
smooth_layer = smooth_layers[smooth_name] | |||
|
|||
smooth_parent_name = ".".join(smooth_name.split(".")[:-1]) | |||
smooth_parent = get_layer_by_name(smooth_parent_name, model) | |||
smooth_parent = attrgetter(smooth_parent_name)(model) |
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.
Yeah I'm a bit concerned this has the potential to error out as well. what if there's no parent?
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! Thanks!
SUMMARY:
Refactor
had some questions regarding this PR
also let me if i am on the right track
#1686