Skip to content
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

[Export Refactor][Transformers] Enable loading SparseModels #1921

Conversation

dbogunowicz
Copy link
Contributor

@dbogunowicz dbogunowicz commented Dec 20, 2023

Feature Description

The main functionality introduced by this PR enables loading and applying the recipe in the new format to the text-generation models.

The notable changes are:

src/sparseml/export/export.py -> allowing the user to provide recipe explicitely to the exporter. If the recipe is not provided, but the recipe.yaml is located side-by-side with the model, there will be an attempt to load it automatically

src/sparseml/pytorch/model_load/helpers.py -> moving the log_model_load out of the transformers.SparseModel, otherwise we would get nasty import dependencies. Plus, it just make sense for it to be more general function.

src/sparseml/transformers/integration_helper_functions.py -> simplifying the create_model function and adapting it to the new changes

src/sparseml/transformers/utils/helpers.py -> just adding an extra transformer-specific wrapper around the general apply_recipe_structure_to_model method. Just in case we need some transformer-specific functionalities.

src/sparseml/transformers/utils/initializers.py -> refactoring initialize_model, so now it becomes a comprehensive, main entry point for loading a SparseModel.

src/sparseml/transformers/utils/load_task_model.py -> look above, this function is an extension of initialize_model (now initialize_sparse_model)

Testing

Tests in tests/sparseml/export/transformers/test_generative_transformers.py demonstrate the current capabilities of the new export module in the context of LLMs.

@dbogunowicz dbogunowicz changed the base branch from main to feature/damian/feature_branch_export December 20, 2023 13:07
@dbogunowicz dbogunowicz force-pushed the feature/damian/sparse_auto_model branch from ad2ee33 to ebf96ee Compare December 20, 2023 18:11
@dbogunowicz dbogunowicz changed the title sparse auto model [Export Refactor][Transformers] Enable loading SparseModels Dec 20, 2023
@dbogunowicz dbogunowicz requested review from Satrat and bfineran and removed request for Satrat December 20, 2023 18:28
@dbogunowicz dbogunowicz marked this pull request as ready for review December 20, 2023 18:32
Comment on lines 116 to 119
if task is not None:
task = task.replace("_", "-").replace(" ", "-")
if integration is not None:
integration = integration.replace("_", "-").replace(" ", "-")
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: helper fn?

Copy link
Member

Choose a reason for hiding this comment

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

+1, this should ideally be resolved at the registry mixin level (all lower case, remove special characters and whitespace)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Please take a look at: neuralmagic/sparsezoo#404
It's been sitting for a while in the "purgatory", but has already been reviewed once by Sara.
@Satrat , @bfineran if you approved this sparsezoo feature, we could remove the need for unifiying the integration string (RegistryMixin will take care of it). For the task itself, I have also a good solution, will implement in a second.

src/sparseml/pytorch/model_load/helpers.py Show resolved Hide resolved
Comment on lines 81 to 84
if recipe is None:
_LOGGER.info(f"Attempting to apply default recipe: {RECIPE_NAME}")
else:
_LOGGER.info(f"Attempting to apply user-specified recipe: {recipe}")
Copy link
Contributor

Choose a reason for hiding this comment

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

lets clean up this logic to something like this:

if default_recipe_exists and recipe_provided:
     warn that we're overwriting the model's input recipe, probably a bad idea
      use recipe_provided
elif recipe_provided:
    warn that this recipe should have been previously applied to the model
    use recipe_provided
elif default_recipe:
    just the info log needed
    use default_recipe
else: # neither recipe exists
    warn that no recipe was applied
     carry on

Comment on lines +270 to +276
model = OPTForCausalLM.from_pretrained(
model_name_or_path,
torch_dtype=torch_dtype,
config=config,
trust_remote_code=trust_remote_code,
**kwargs,
)
Copy link
Contributor

Choose a reason for hiding this comment

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

It should be safe to change this to the automodel, I'm just not sure if these torch.nn..... = skip lines can be deleted or not

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@alexm-nm can we have your buy-in here?


return model
# TODO: Do we need to call eval() here? Why?
model.eval()
Copy link
Contributor

Choose a reason for hiding this comment

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

Could we make eval vs train an argument? It depends on if we're doing training(train) or oneshot/export(eval)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Can we just set this appropriately in the code paths themselves? I feel like adding a boolean argument would be a bit weird. It's just more verbose and informative to call model.eval() or model.train() explicitly in the code.

@@ -25,7 +25,7 @@
from sparseml.transformers.data import TransformersDataset
from sparseml.transformers.sparsification.obcq.obcq import one_shot
from sparseml.transformers.sparsification.obcq.utils.helpers import llama_forward
from sparseml.transformers.utils.model import SparseCausalLM
from sparseml.transformers.utils.sparse_model import SparseCausalLM
Copy link
Contributor

Choose a reason for hiding this comment

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

I think we can remove this and just use the SparseAutoModel?

@@ -34,7 +34,7 @@
llama_forward,
opt_forward,
)
from sparseml.transformers.utils.model import SparseCausalLM
from sparseml.transformers.utils.sparse_model import SparseCausalLM
Copy link
Contributor

Choose a reason for hiding this comment

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

Was there a reason not to replace this with the SparseAutoModel? Other than the OPT edge case, I think we only need to add in precision support

@Satrat
Copy link
Contributor

Satrat commented Dec 20, 2023

Oh one other issue I see: the new text_generation.py v2 finetuning script uses the pretrained_from_distil function, that needs to be updated

Copy link
Member

@bfineran bfineran left a comment

Choose a reason for hiding this comment

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

could you update the PR description to include an example of initialize_sparse_model

Comment on lines 116 to 119
if task is not None:
task = task.replace("_", "-").replace(" ", "-")
if integration is not None:
integration = integration.replace("_", "-").replace(" ", "-")
Copy link
Member

Choose a reason for hiding this comment

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

+1, this should ideally be resolved at the registry mixin level (all lower case, remove special characters and whitespace)

"from the HF transformers config. Please specify "
"the sequence length with --sequence_length"
)
_LOGGER.info(
Copy link
Member

Choose a reason for hiding this comment

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

should be debug for any non critical logs on our regular path

) -> AutoModel:
"""
Initialize a model from a given path

Initialize a sparse model from a given path. This will:
Copy link
Member

Choose a reason for hiding this comment

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

let's include a usage example here

Copy link
Member

@bfineran bfineran left a comment

Choose a reason for hiding this comment

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

LGTM - is the intention to hand off initialize_sparse_model to MLR instead of the previously discussed SparseAutoModel?

@dbogunowicz
Copy link
Contributor Author

Yes

Copy link
Contributor

@Satrat Satrat left a comment

Choose a reason for hiding this comment

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

LGTM, had one nitpick on the obcq script. Should we update the OBCQ and finetuning scripts to use the new initialize_sparse_model funcion? That can also be a later PR though

Comment on lines 100 to +103
_LOGGER.warning(
f"A supported model type({SUPPORTED_MODELS}) could not be "
f"parsed from model_path={model_path}. Defaulting to "
"AutoModelForCausalLM loading. "
"SparseAutoModel loading. "
Copy link
Contributor

Choose a reason for hiding this comment

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

Now that we're using SparseAutoModel for everything this warning message doesn't make much sense. The only thing we lose from not using a supported model is perplexity evaluation, and thats more of a debugging feature anyways. Can we change the message to this:

f"A supported model type({SUPPORTED_MODELS}) could not be "
f"parsed from model_path={model_path}. Perplexity evaluation will only work for supported models"

Copy link
Contributor

Choose a reason for hiding this comment

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

I think we can get rid of the if statement altogether, and just condition on the model for setting forward_fn

Comment on lines 204 to 215
def resolve_recipe_application(
recipe: Union[str, Path, None], model_path: Union[str, Path]
) -> Union[str, Path, None]:
"""
Resolve the recipe to apply to the model.
If the recipe is None, will look for a recipe in the model_path

:param recipe: the recipe to apply to the model.
If None, will look for a recipe in the model_path
:param model_path: the path to the model to load
:return: the resolved recipe
"""
Copy link
Contributor

Choose a reason for hiding this comment

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

Nice, the logging messages are really clear, and good to have this in a helper function

@dbogunowicz dbogunowicz merged commit b2c9939 into feature/damian/feature_branch_export Dec 21, 2023
@dbogunowicz dbogunowicz deleted the feature/damian/sparse_auto_model branch December 21, 2023 17:27
dbogunowicz added a commit that referenced this pull request Dec 29, 2023
* initial commit

* adressing review comments
bfineran added a commit that referenced this pull request Jan 10, 2024
* initial commit

* respond to PR comments

* [Export Refactor][Image Classification] `create_model` function (#1878)

* initial commit

* looking good, time to cleanup

* Delete src/sparseml/export/helpers.py

* Delete tests/sparseml/export/test_helpers.py

* ready for review

* improve design

* tests pass

* reuse _validate_dataset_num_classes

* [Export Refactor][Image Classification] `create_dummy_input` function (#1880)

* initial commit

* looking good, time to cleanup

* Delete src/sparseml/export/helpers.py

* Delete tests/sparseml/export/test_helpers.py

* ready for review

* improve design

* tests pass

* reuse _validate_dataset_num_classes

* initial commit

* Update src/sparseml/pytorch/image_classification/integration_helper_functions.py

* Update src/sparseml/pytorch/image_classification/integration_helper_functions.py

* ready for review

* Update src/sparseml/export/export.py

* Update src/sparseml/integration_helper_functions.py

* [Export Refactor][Image Classification] `export_model` function (#1883)

* initial commit

* looking good, time to cleanup

* Delete src/sparseml/export/helpers.py

* Delete tests/sparseml/export/test_helpers.py

* ready for review

* improve design

* tests pass

* reuse _validate_dataset_num_classes

* initial commit

* Update src/sparseml/pytorch/image_classification/integration_helper_functions.py

* Update src/sparseml/pytorch/image_classification/integration_helper_functions.py

* ready for review

* Update src/sparseml/export/export.py

* Update src/sparseml/integration_helper_functions.py

* initial commit

* fixes

* ready for review

* nit

* add return

* make export function more general

* [Export Refactor][Image Classification] `apply_optimizations` function (#1884)

* initial commit

* looking good, time to cleanup

* Delete src/sparseml/export/helpers.py

* Delete tests/sparseml/export/test_helpers.py

* ready for review

* improve design

* tests pass

* reuse _validate_dataset_num_classes

* initial commit

* Update src/sparseml/pytorch/image_classification/integration_helper_functions.py

* Update src/sparseml/pytorch/image_classification/integration_helper_functions.py

* ready for review

* Update src/sparseml/export/export.py

* Update src/sparseml/integration_helper_functions.py

* initial commit

* fixes

* ready for review

* nit

* add return

* initial commit

* [Export Refactor][Image Classification] `export_sample_inputs_outputs` function (#1888)

* initial commit

* looking good, time to cleanup

* Delete src/sparseml/export/helpers.py

* Delete tests/sparseml/export/test_helpers.py

* ready for review

* improve design

* tests pass

* reuse _validate_dataset_num_classes

* initial commit

* Update src/sparseml/pytorch/image_classification/integration_helper_functions.py

* Update src/sparseml/pytorch/image_classification/integration_helper_functions.py

* ready for review

* Update src/sparseml/export/export.py

* Update src/sparseml/integration_helper_functions.py

* initial commit

* fixes

* ready for review

* nit

* add return

* initial commit

* initial commit

* PR comments

* beautification

* remove duplicated function

* [Export Refactor][Image Classification] `create_deployment_folder` function (#1889)

* initial commit

* looking good, time to cleanup

* Delete src/sparseml/export/helpers.py

* Delete tests/sparseml/export/test_helpers.py

* ready for review

* improve design

* tests pass

* reuse _validate_dataset_num_classes

* initial commit

* Update src/sparseml/pytorch/image_classification/integration_helper_functions.py

* Update src/sparseml/pytorch/image_classification/integration_helper_functions.py

* ready for review

* Update src/sparseml/export/export.py

* Update src/sparseml/integration_helper_functions.py

* initial commit

* fixes

* ready for review

* nit

* add return

* initial commit

* initial commit

* initial commit

* fix rebase, tests_work

* ready to push

* [Export Refactor][Image Classification] `validate_correctness` function (#1890)

* initial commit

* looking good, time to cleanup

* Delete src/sparseml/export/helpers.py

* Delete tests/sparseml/export/test_helpers.py

* ready for review

* improve design

* tests pass

* reuse _validate_dataset_num_classes

* initial commit

* Update src/sparseml/pytorch/image_classification/integration_helper_functions.py

* Update src/sparseml/pytorch/image_classification/integration_helper_functions.py

* ready for review

* Update src/sparseml/export/export.py

* Update src/sparseml/integration_helper_functions.py

* initial commit

* fixes

* ready for review

* nit

* add return

* initial commit

* initial commit

* initial commit

* initial commit

* Delete tests/sparseml/test_integration_helper_functions.py

* ready to merge

* [Export Refactor] End to end testing (#1898)

* initial commit

* looking good, time to cleanup

* Delete src/sparseml/export/helpers.py

* Delete tests/sparseml/export/test_helpers.py

* ready for review

* improve design

* tests pass

* reuse _validate_dataset_num_classes

* initial commit

* Update src/sparseml/pytorch/image_classification/integration_helper_functions.py

* Update src/sparseml/pytorch/image_classification/integration_helper_functions.py

* ready for review

* Update src/sparseml/export/export.py

* Update src/sparseml/integration_helper_functions.py

* initial commit

* fixes

* ready for review

* nit

* add return

* initial commit

* initial commit

* initial commit

* initial commit

* Delete tests/sparseml/test_integration_helper_functions.py

* ready to merge

* add structure validator

* ready for review

* Delete tests/sparseml/export/model.onnx

* Delete tests/sparseml/export/image_classification/model.onnx

* Delete tests/sparseml/export/image_classification/conftest.py

* PR comments

* remove onnx

* [Export Refactor] Prepare the module to be more general (before including `transformers`) (#1908)

* adapt the export script to handle transformers

* Update src/sparseml/pytorch/image_classification/integration_helper_functions.py

* Delete tests/sparseml/export/transformers/__init__.py

* Delete tests/sparseml/export/transformers/test_generative_transformers.py

* Delete tests/sparseml/export/transformers/test_transformers.py

* Update src/sparseml/export/export.py

Co-authored-by: Benjamin Fineran <bfineran@users.noreply.github.com>

* addressing review comments

* [Export Refactor] Export `transformers` (#1909)

* cleanup

* Delete src/sparseml/transformers/integration_helper_functions_generative.py

* Delete src/sparseml/transformers/utils/optimizations.py

* Delete tests/sparseml/export/transformers/test_generative_transformers.py

* Delete tests/sparseml/transformers/test_integration_helper_functions_generative.py

* addressing PR reviews

* [Export Refactor] Export generative transformers(#1910)

* make tests green, remove using task to resolve the integration type

* fix all the tests after the merge, make integration resolution independent of the task name

* fold generative transformers into transformer helper functions

* complete tests for export_data.py

* Update src/sparseml/export/export.py

* add tests that confirms that kv cache injection has been added

* move applying optimizations into integration helper functions

---------

Co-authored-by: Benjamin Fineran <bfineran@users.noreply.github.com>

* [Export Refactor][Transformers] Enable loading SparseModels (#1921)

* initial commit

* adressing review comments

* Fix the tests

* fix tests with help from sara

* [Export][Transformers] Enable loading `text-generation` datasets (#1938)

* add suport for past_key_values in sample-outputs

* [Export][Transformers] Implementation of correctness validation (#1935)

* fix tests with help from sara

* Update src/sparseml/transformers/utils/initializers.py

* swap sparsezoo validator for custom one (top k match)

* add more informative error message

* add correctness validation for LLMs

* remove past_key_values from outputs

* remove past_key_values from outputs (2)

* small note comment for the future

* tests fixed

* fix test

* [Export refactor] final manual testing fixes (#1948)

* [Export refactor] final manual testing fixes

* review

---------

Co-authored-by: Benjamin Fineran <bfineran@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants