-
Notifications
You must be signed in to change notification settings - Fork 140
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
[Export Refactor][Transformers] Enable loading SparseModels #1921
Conversation
ad2ee33
to
ebf96ee
Compare
src/sparseml/export/export.py
Outdated
if task is not None: | ||
task = task.replace("_", "-").replace(" ", "-") | ||
if integration is not None: | ||
integration = integration.replace("_", "-").replace(" ", "-") |
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.
nit: helper fn?
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.
+1, this should ideally be resolved at the registry mixin level (all lower case, remove special characters and whitespace)
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.
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.
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}") |
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.
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
model = OPTForCausalLM.from_pretrained( | ||
model_name_or_path, | ||
torch_dtype=torch_dtype, | ||
config=config, | ||
trust_remote_code=trust_remote_code, | ||
**kwargs, | ||
) |
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.
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
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.
@alexm-nm can we have your buy-in here?
|
||
return model | ||
# TODO: Do we need to call eval() here? Why? | ||
model.eval() |
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.
Could we make eval vs train an argument? It depends on if we're doing training(train) or oneshot/export(eval)
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.
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 |
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 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 |
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.
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
Oh one other issue I see: the new |
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.
could you update the PR description to include an example of initialize_sparse_model
src/sparseml/export/export.py
Outdated
if task is not None: | ||
task = task.replace("_", "-").replace(" ", "-") | ||
if integration is not None: | ||
integration = integration.replace("_", "-").replace(" ", "-") |
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.
+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( |
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 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: |
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.
let's include a usage example here
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 - is the intention to hand off initialize_sparse_model
to MLR instead of the previously discussed SparseAutoModel?
Yes |
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, 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
_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. " |
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.
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"
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 think we can get rid of the if statement altogether, and just condition on the model for setting forward_fn
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 | ||
""" |
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.
Nice, the logging messages are really clear, and good to have this in a helper function
* initial commit * adressing review comments
* 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>
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 therecipe.yaml
is located side-by-side with the model, there will be an attempt to load it automaticallysrc/sparseml/pytorch/model_load/helpers.py
-> moving thelog_model_load
out of thetransformers.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 thecreate_model
function and adapting it to the new changessrc/sparseml/transformers/utils/helpers.py
-> just adding an extra transformer-specific wrapper around the generalapply_recipe_structure_to_model
method. Just in case we need some transformer-specific functionalities.src/sparseml/transformers/utils/initializers.py
-> refactoringinitialize_model
, so now it becomes a comprehensive, main entry point for loading aSparseModel
.src/sparseml/transformers/utils/load_task_model.py
-> look above, this function is an extension ofinitialize_model
(nowinitialize_sparse_model
)Testing
Tests in
tests/sparseml/export/transformers/test_generative_transformers.py
demonstrate the current capabilities of the newexport
module in the context of LLMs.