nvidia-modelopt 0.35.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- modelopt/__init__.py +20 -0
- modelopt/deploy/__init__.py +16 -0
- modelopt/deploy/llm/__init__.py +30 -0
- modelopt/deploy/llm/generate.py +345 -0
- modelopt/onnx/__init__.py +34 -0
- modelopt/onnx/autocast/__init__.py +19 -0
- modelopt/onnx/autocast/__main__.py +187 -0
- modelopt/onnx/autocast/convert.py +202 -0
- modelopt/onnx/autocast/graphsanitizer.py +422 -0
- modelopt/onnx/autocast/logging_config.py +78 -0
- modelopt/onnx/autocast/nodeclassifier.py +416 -0
- modelopt/onnx/autocast/precisionconverter.py +1032 -0
- modelopt/onnx/autocast/referencerunner.py +159 -0
- modelopt/onnx/autocast/utils.py +117 -0
- modelopt/onnx/llm_export_utils/__init__.py +16 -0
- modelopt/onnx/llm_export_utils/export_utils.py +162 -0
- modelopt/onnx/llm_export_utils/quantization_utils.py +122 -0
- modelopt/onnx/llm_export_utils/surgeon_utils.py +120 -0
- modelopt/onnx/logging_config.py +77 -0
- modelopt/onnx/op_types.py +300 -0
- modelopt/onnx/quantization/__init__.py +20 -0
- modelopt/onnx/quantization/__main__.py +291 -0
- modelopt/onnx/quantization/calib_utils.py +178 -0
- modelopt/onnx/quantization/extensions.py +35 -0
- modelopt/onnx/quantization/fp8.py +375 -0
- modelopt/onnx/quantization/graph_utils.py +1479 -0
- modelopt/onnx/quantization/gs_patching.py +112 -0
- modelopt/onnx/quantization/int4.py +1347 -0
- modelopt/onnx/quantization/int8.py +283 -0
- modelopt/onnx/quantization/operators.py +121 -0
- modelopt/onnx/quantization/ort_patching.py +1766 -0
- modelopt/onnx/quantization/ort_utils.py +346 -0
- modelopt/onnx/quantization/partitioning.py +439 -0
- modelopt/onnx/quantization/qdq_utils.py +1349 -0
- modelopt/onnx/quantization/quant_utils.py +283 -0
- modelopt/onnx/quantization/quantize.py +528 -0
- modelopt/onnx/quantization/src/modelopt_round_and_pack_ext.cpp +127 -0
- modelopt/onnx/trt_utils.py +424 -0
- modelopt/onnx/utils.py +753 -0
- modelopt/torch/__init__.py +41 -0
- modelopt/torch/_deploy/__init__.py +23 -0
- modelopt/torch/_deploy/_runtime/__init__.py +29 -0
- modelopt/torch/_deploy/_runtime/common.py +72 -0
- modelopt/torch/_deploy/_runtime/ort_client.py +193 -0
- modelopt/torch/_deploy/_runtime/registry.py +83 -0
- modelopt/torch/_deploy/_runtime/runtime_client.py +154 -0
- modelopt/torch/_deploy/_runtime/tensorrt/constants.py +108 -0
- modelopt/torch/_deploy/_runtime/tensorrt/engine_builder.py +324 -0
- modelopt/torch/_deploy/_runtime/tensorrt/hw_param_config.py +51 -0
- modelopt/torch/_deploy/_runtime/tensorrt/layerwise_profiling.py +178 -0
- modelopt/torch/_deploy/_runtime/tensorrt/parse_trtexec_log.py +151 -0
- modelopt/torch/_deploy/_runtime/tensorrt/tensorrt_utils.py +200 -0
- modelopt/torch/_deploy/_runtime/trt_client.py +219 -0
- modelopt/torch/_deploy/compilation.py +142 -0
- modelopt/torch/_deploy/device_model.py +157 -0
- modelopt/torch/_deploy/profiling.py +193 -0
- modelopt/torch/_deploy/utils/__init__.py +18 -0
- modelopt/torch/_deploy/utils/onnx_optimizer.py +120 -0
- modelopt/torch/_deploy/utils/onnx_utils.py +58 -0
- modelopt/torch/_deploy/utils/torch_onnx.py +593 -0
- modelopt/torch/distill/__init__.py +28 -0
- modelopt/torch/distill/config.py +130 -0
- modelopt/torch/distill/distillation.py +84 -0
- modelopt/torch/distill/distillation_model.py +318 -0
- modelopt/torch/distill/loss_balancers.py +140 -0
- modelopt/torch/distill/losses.py +275 -0
- modelopt/torch/distill/mode.py +223 -0
- modelopt/torch/distill/plugins/__init__.py +24 -0
- modelopt/torch/distill/plugins/huggingface.py +110 -0
- modelopt/torch/distill/plugins/megatron.py +476 -0
- modelopt/torch/distill/registry.py +23 -0
- modelopt/torch/export/__init__.py +24 -0
- modelopt/torch/export/convert_hf_config.py +117 -0
- modelopt/torch/export/distribute.py +300 -0
- modelopt/torch/export/hf_config_map.py +84 -0
- modelopt/torch/export/layer_utils.py +1893 -0
- modelopt/torch/export/mcore_config_map.py +25 -0
- modelopt/torch/export/model_config.py +623 -0
- modelopt/torch/export/model_config_export.py +552 -0
- modelopt/torch/export/model_config_utils.py +392 -0
- modelopt/torch/export/model_utils.py +71 -0
- modelopt/torch/export/plugins/__init__.py +21 -0
- modelopt/torch/export/plugins/mcore_common.py +67 -0
- modelopt/torch/export/plugins/mcore_custom.py +530 -0
- modelopt/torch/export/plugins/mcore_deepseek.py +143 -0
- modelopt/torch/export/plugins/mcore_gptoss.py +71 -0
- modelopt/torch/export/plugins/mcore_llama.py +164 -0
- modelopt/torch/export/plugins/mcore_nemotron.py +90 -0
- modelopt/torch/export/plugins/mcore_qwen.py +99 -0
- modelopt/torch/export/plugins/megatron_importer.py +647 -0
- modelopt/torch/export/postprocess.py +847 -0
- modelopt/torch/export/quant_utils.py +1069 -0
- modelopt/torch/export/tensorrt_llm_type.py +42 -0
- modelopt/torch/export/tensorrt_llm_utils.py +405 -0
- modelopt/torch/export/transformer_engine.py +94 -0
- modelopt/torch/export/unified_export_hf.py +537 -0
- modelopt/torch/export/unified_export_megatron.py +1164 -0
- modelopt/torch/nas/__init__.py +27 -0
- modelopt/torch/nas/algorithms.py +856 -0
- modelopt/torch/nas/autonas.py +808 -0
- modelopt/torch/nas/conversion.py +119 -0
- modelopt/torch/nas/hparams/__init__.py +19 -0
- modelopt/torch/nas/hparams/concat.py +319 -0
- modelopt/torch/nas/hparams/container.py +48 -0
- modelopt/torch/nas/modules/__init__.py +21 -0
- modelopt/torch/nas/modules/container.py +99 -0
- modelopt/torch/nas/modules/conv.py +254 -0
- modelopt/torch/nas/modules/linear.py +76 -0
- modelopt/torch/nas/modules/norm.py +193 -0
- modelopt/torch/nas/modules/utils.py +61 -0
- modelopt/torch/nas/patch.py +261 -0
- modelopt/torch/nas/plugins/__init__.py +29 -0
- modelopt/torch/nas/plugins/megatron.py +1497 -0
- modelopt/torch/nas/plugins/torch.py +71 -0
- modelopt/torch/nas/plugins/transformer_engine.py +42 -0
- modelopt/torch/nas/plugins/transformers.py +210 -0
- modelopt/torch/nas/registry.py +23 -0
- modelopt/torch/nas/search_space.py +260 -0
- modelopt/torch/nas/traced_hp.py +149 -0
- modelopt/torch/nas/utils.py +408 -0
- modelopt/torch/opt/__init__.py +41 -0
- modelopt/torch/opt/_hooks.py +98 -0
- modelopt/torch/opt/config.py +383 -0
- modelopt/torch/opt/conversion.py +620 -0
- modelopt/torch/opt/dynamic.py +1367 -0
- modelopt/torch/opt/hparam.py +275 -0
- modelopt/torch/opt/mode.py +353 -0
- modelopt/torch/opt/plugins/__init__.py +38 -0
- modelopt/torch/opt/plugins/diffusers.py +40 -0
- modelopt/torch/opt/plugins/huggingface.py +162 -0
- modelopt/torch/opt/plugins/mcore_dist_checkpointing.py +211 -0
- modelopt/torch/opt/plugins/megatron.py +142 -0
- modelopt/torch/opt/plugins/peft.py +108 -0
- modelopt/torch/opt/plugins/transformers.py +160 -0
- modelopt/torch/opt/searcher.py +363 -0
- modelopt/torch/opt/utils.py +125 -0
- modelopt/torch/prune/__init__.py +26 -0
- modelopt/torch/prune/fastnas.py +376 -0
- modelopt/torch/prune/gradnas.py +349 -0
- modelopt/torch/prune/plugins/__init__.py +24 -0
- modelopt/torch/prune/plugins/mcore_minitron.py +263 -0
- modelopt/torch/prune/plugins/transformers.py +41 -0
- modelopt/torch/prune/pruning.py +211 -0
- modelopt/torch/quantization/__init__.py +26 -0
- modelopt/torch/quantization/algorithms.py +671 -0
- modelopt/torch/quantization/backends/__init__.py +20 -0
- modelopt/torch/quantization/backends/fp8_per_tensor_gemm.py +204 -0
- modelopt/torch/quantization/backends/gemm_registry.py +156 -0
- modelopt/torch/quantization/backends/nvfp4_gemm.py +201 -0
- modelopt/torch/quantization/backends/utils.py +28 -0
- modelopt/torch/quantization/calib/__init__.py +25 -0
- modelopt/torch/quantization/calib/bias.py +172 -0
- modelopt/torch/quantization/calib/calibrator.py +63 -0
- modelopt/torch/quantization/calib/histogram.py +434 -0
- modelopt/torch/quantization/calib/max.py +110 -0
- modelopt/torch/quantization/compress.py +227 -0
- modelopt/torch/quantization/config.py +1180 -0
- modelopt/torch/quantization/conversion.py +389 -0
- modelopt/torch/quantization/export_onnx.py +639 -0
- modelopt/torch/quantization/extensions.py +89 -0
- modelopt/torch/quantization/mode.py +428 -0
- modelopt/torch/quantization/model_calib.py +949 -0
- modelopt/torch/quantization/model_quant.py +477 -0
- modelopt/torch/quantization/nn/__init__.py +26 -0
- modelopt/torch/quantization/nn/functional.py +109 -0
- modelopt/torch/quantization/nn/modules/__init__.py +16 -0
- modelopt/torch/quantization/nn/modules/quant_activations.py +22 -0
- modelopt/torch/quantization/nn/modules/quant_batchnorm.py +24 -0
- modelopt/torch/quantization/nn/modules/quant_conv.py +123 -0
- modelopt/torch/quantization/nn/modules/quant_instancenorm.py +39 -0
- modelopt/torch/quantization/nn/modules/quant_linear.py +258 -0
- modelopt/torch/quantization/nn/modules/quant_module.py +211 -0
- modelopt/torch/quantization/nn/modules/quant_pooling.py +99 -0
- modelopt/torch/quantization/nn/modules/quant_rnn.py +527 -0
- modelopt/torch/quantization/nn/modules/tensor_quantizer.py +1293 -0
- modelopt/torch/quantization/plugins/__init__.py +73 -0
- modelopt/torch/quantization/plugins/accelerate.py +214 -0
- modelopt/torch/quantization/plugins/apex.py +52 -0
- modelopt/torch/quantization/plugins/attention.py +312 -0
- modelopt/torch/quantization/plugins/custom.py +192 -0
- modelopt/torch/quantization/plugins/diffusers.py +237 -0
- modelopt/torch/quantization/plugins/fairscale.py +45 -0
- modelopt/torch/quantization/plugins/huggingface.py +736 -0
- modelopt/torch/quantization/plugins/megatron.py +462 -0
- modelopt/torch/quantization/plugins/peft.py +148 -0
- modelopt/torch/quantization/plugins/transformer_engine.py +60 -0
- modelopt/torch/quantization/plugins/transformers.py +52 -0
- modelopt/torch/quantization/plugins/transformers_trainer.py +426 -0
- modelopt/torch/quantization/plugins/trl.py +27 -0
- modelopt/torch/quantization/plugins/vllm.py +199 -0
- modelopt/torch/quantization/qtensor/__init__.py +24 -0
- modelopt/torch/quantization/qtensor/base_qtensor.py +370 -0
- modelopt/torch/quantization/qtensor/fp8_tensor.py +151 -0
- modelopt/torch/quantization/qtensor/int4_tensor.py +130 -0
- modelopt/torch/quantization/qtensor/int8_tensor.py +124 -0
- modelopt/torch/quantization/qtensor/mxfp4_tensor.py +144 -0
- modelopt/torch/quantization/qtensor/nf4_tensor.py +199 -0
- modelopt/torch/quantization/qtensor/nvfp4_tensor.py +295 -0
- modelopt/torch/quantization/src/tensor_quant.cpp +77 -0
- modelopt/torch/quantization/src/tensor_quant.h +69 -0
- modelopt/torch/quantization/src/tensor_quant_fp8.cpp +48 -0
- modelopt/torch/quantization/src/tensor_quant_gpu.cu +361 -0
- modelopt/torch/quantization/src/tensor_quant_gpu_fp8.cu +122 -0
- modelopt/torch/quantization/src/tensor_quant_mx.cu +411 -0
- modelopt/torch/quantization/src/tensor_quant_mx.h +247 -0
- modelopt/torch/quantization/tensor_quant.py +816 -0
- modelopt/torch/quantization/triton/__init__.py +36 -0
- modelopt/torch/quantization/triton/fp4_kernel.py +303 -0
- modelopt/torch/quantization/utils.py +443 -0
- modelopt/torch/sparsity/__init__.py +19 -0
- modelopt/torch/sparsity/config.py +51 -0
- modelopt/torch/sparsity/magnitude.py +148 -0
- modelopt/torch/sparsity/mode.py +203 -0
- modelopt/torch/sparsity/module.py +87 -0
- modelopt/torch/sparsity/plugins/__init__.py +27 -0
- modelopt/torch/sparsity/plugins/megatron.py +93 -0
- modelopt/torch/sparsity/searcher.py +84 -0
- modelopt/torch/sparsity/sparsegpt.py +276 -0
- modelopt/torch/sparsity/sparsification.py +123 -0
- modelopt/torch/speculative/__init__.py +20 -0
- modelopt/torch/speculative/config.py +100 -0
- modelopt/torch/speculative/eagle/__init__.py +20 -0
- modelopt/torch/speculative/eagle/conversion.py +67 -0
- modelopt/torch/speculative/eagle/default_config.py +50 -0
- modelopt/torch/speculative/eagle/eagle_model.py +51 -0
- modelopt/torch/speculative/eagle/utils.py +91 -0
- modelopt/torch/speculative/medusa/__init__.py +19 -0
- modelopt/torch/speculative/medusa/conversion.py +59 -0
- modelopt/torch/speculative/medusa/medusa_model.py +32 -0
- modelopt/torch/speculative/mode.py +86 -0
- modelopt/torch/speculative/plugins/__init__.py +33 -0
- modelopt/torch/speculative/plugins/megatron_eagle.py +2119 -0
- modelopt/torch/speculative/plugins/megatron_medusa.py +312 -0
- modelopt/torch/speculative/plugins/transformers.py +1138 -0
- modelopt/torch/speculative/speculative_decoding.py +59 -0
- modelopt/torch/speculative/utils.py +364 -0
- modelopt/torch/trace/__init__.py +25 -0
- modelopt/torch/trace/analyzer.py +1368 -0
- modelopt/torch/trace/modules/__init__.py +19 -0
- modelopt/torch/trace/modules/concat.py +384 -0
- modelopt/torch/trace/modules/nn.py +153 -0
- modelopt/torch/trace/plugins/__init__.py +34 -0
- modelopt/torch/trace/plugins/megatron.py +36 -0
- modelopt/torch/trace/plugins/transformers.py +58 -0
- modelopt/torch/trace/symbols.py +545 -0
- modelopt/torch/trace/tracer.py +331 -0
- modelopt/torch/utils/__init__.py +28 -0
- modelopt/torch/utils/_pytree.py +133 -0
- modelopt/torch/utils/cpp_extension.py +91 -0
- modelopt/torch/utils/dataset_utils.py +484 -0
- modelopt/torch/utils/distributed.py +311 -0
- modelopt/torch/utils/graph.py +123 -0
- modelopt/torch/utils/image_processor.py +112 -0
- modelopt/torch/utils/import_utils.py +35 -0
- modelopt/torch/utils/list.py +54 -0
- modelopt/torch/utils/logging.py +127 -0
- modelopt/torch/utils/memory_monitor.py +146 -0
- modelopt/torch/utils/network.py +658 -0
- modelopt/torch/utils/perf.py +174 -0
- modelopt/torch/utils/plugins/__init__.py +27 -0
- modelopt/torch/utils/plugins/megatron_generate.py +299 -0
- modelopt/torch/utils/plugins/megatron_mmlu.py +152 -0
- modelopt/torch/utils/plugins/megatron_preprocess_data.py +200 -0
- modelopt/torch/utils/random.py +163 -0
- modelopt/torch/utils/speech_dataset_utils.py +134 -0
- modelopt/torch/utils/tensor.py +87 -0
- modelopt/torch/utils/vlm_dataset_utils.py +110 -0
- nvidia_modelopt-0.35.0.dist-info/METADATA +171 -0
- nvidia_modelopt-0.35.0.dist-info/RECORD +272 -0
- nvidia_modelopt-0.35.0.dist-info/WHEEL +5 -0
- nvidia_modelopt-0.35.0.dist-info/licenses/LICENSE +14 -0
- nvidia_modelopt-0.35.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,620 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
|
2
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
|
|
16
|
+
"""Module to handle model converting and restoring for optimization methods.
|
|
17
|
+
|
|
18
|
+
When applying a model optimization algorithm, we usually need to modify the model in each step
|
|
19
|
+
(mode) of the algorithm. This module provides the state manager, which is a standardized interface
|
|
20
|
+
(class) to record and store state information in the model.
|
|
21
|
+
|
|
22
|
+
Op top of the state manager, this module provides utilities to save a history of these modifications
|
|
23
|
+
("modelopt state dict") and restoring a unmodified model to the state indicated in the state dict.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
import copy
|
|
27
|
+
import os
|
|
28
|
+
import warnings
|
|
29
|
+
from collections import deque
|
|
30
|
+
from collections.abc import Iterator
|
|
31
|
+
from typing import Any, BinaryIO
|
|
32
|
+
|
|
33
|
+
import torch
|
|
34
|
+
import torch.nn as nn
|
|
35
|
+
|
|
36
|
+
from modelopt import __version__
|
|
37
|
+
from modelopt.torch.utils import ModelLike, init_model_from_model_like, unwrap_model
|
|
38
|
+
|
|
39
|
+
from .config import ConfigDict, ModeloptBaseConfig
|
|
40
|
+
from .mode import (
|
|
41
|
+
MetadataDict,
|
|
42
|
+
ModeDescriptor,
|
|
43
|
+
ModeKwargsType,
|
|
44
|
+
ModeLike,
|
|
45
|
+
ModeState,
|
|
46
|
+
ModeType,
|
|
47
|
+
_ModeRegistryCls,
|
|
48
|
+
get_mode_config,
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
__all__ = [
|
|
52
|
+
"ModeloptStateManager",
|
|
53
|
+
"apply_mode",
|
|
54
|
+
"modelopt_state",
|
|
55
|
+
"restore",
|
|
56
|
+
"restore_from_modelopt_state",
|
|
57
|
+
"save",
|
|
58
|
+
]
|
|
59
|
+
|
|
60
|
+
ModeloptStateList = list[tuple[str, ModeState]] # state data structure for multiple modes
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
class ModeloptStateManager:
|
|
64
|
+
"""A class to handle the modelopt state stored for each mode corresponding to a task/mode."""
|
|
65
|
+
|
|
66
|
+
_state_key = "_modelopt_state"
|
|
67
|
+
_state_version_key = "_modelopt_state_version"
|
|
68
|
+
|
|
69
|
+
def __init__(self, model: nn.Module | None = None, init_state: bool = False) -> None:
|
|
70
|
+
"""Initialize state manager.
|
|
71
|
+
|
|
72
|
+
Args:
|
|
73
|
+
model: Module that has modelopt_state stored. If None, a fake module is created to store
|
|
74
|
+
any state that might be added with the manager.
|
|
75
|
+
init_state: Whether to initialize the modelopt state for the model if it does not exist.
|
|
76
|
+
"""
|
|
77
|
+
# just assume fake module for easy implementation below
|
|
78
|
+
if not model:
|
|
79
|
+
model = nn.Module()
|
|
80
|
+
init_state = True # always initialize fake module
|
|
81
|
+
|
|
82
|
+
# initialize modelopt state if desired. Note that by default we don't do that to avoid
|
|
83
|
+
# accidentally modifying a user-provided model.
|
|
84
|
+
if init_state:
|
|
85
|
+
assert not hasattr(model, self._state_key), "Model already has modelopt state!"
|
|
86
|
+
setattr(model, self._state_key, [])
|
|
87
|
+
setattr(model, self._state_version_key, [__version__])
|
|
88
|
+
|
|
89
|
+
# sanity check that root module has modelopt state now
|
|
90
|
+
assert self.is_converted(model, is_root=True), "Model must have modelopt state!"
|
|
91
|
+
|
|
92
|
+
# store reference to state
|
|
93
|
+
self._state: ModeloptStateList = getattr(model, self._state_key)
|
|
94
|
+
self._state_version = getattr(model, self._state_version_key)
|
|
95
|
+
|
|
96
|
+
@property
|
|
97
|
+
def has_state(self) -> bool:
|
|
98
|
+
"""Return whether the model has a non-trivial modelopt state."""
|
|
99
|
+
return bool(self._state)
|
|
100
|
+
|
|
101
|
+
@classmethod
|
|
102
|
+
def is_converted(cls, model: nn.Module, is_root: bool = False) -> bool:
|
|
103
|
+
"""Check if model is converted.
|
|
104
|
+
|
|
105
|
+
Args:
|
|
106
|
+
model: A model to be checked for state/metadata from the convert process.
|
|
107
|
+
is_root: Additionally check whether the module with state is the root module.
|
|
108
|
+
|
|
109
|
+
Returns:
|
|
110
|
+
True if the model contains modelopt state indicating that it has been converted.
|
|
111
|
+
|
|
112
|
+
This method raises an assertion when multiple modelopt_states are detected or when is_root is
|
|
113
|
+
set to True but the module with state is not the root module.
|
|
114
|
+
"""
|
|
115
|
+
# check for submodules with state
|
|
116
|
+
mods_with_state = [name for name, m in model.named_modules() if hasattr(m, cls._state_key)]
|
|
117
|
+
# check if there is multiple submodules with state
|
|
118
|
+
assert len(mods_with_state) <= 1, "Model has multiple modelopt states!"
|
|
119
|
+
is_converted = bool(mods_with_state)
|
|
120
|
+
|
|
121
|
+
# check if mod with state is root module if desired
|
|
122
|
+
if is_converted:
|
|
123
|
+
assert not is_root or mods_with_state[0] == "", (
|
|
124
|
+
"Model has modelopt state but not the root!"
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
return is_converted
|
|
128
|
+
|
|
129
|
+
# TODO: consider renaming state_dict???
|
|
130
|
+
def state_dict(self) -> ModeloptStateList:
|
|
131
|
+
"""Return the metadata of the model."""
|
|
132
|
+
return self._state
|
|
133
|
+
|
|
134
|
+
@property
|
|
135
|
+
def state_version(self) -> str:
|
|
136
|
+
"""Return the version of modelopt state contained in the state manager."""
|
|
137
|
+
return self._state_version[0]
|
|
138
|
+
|
|
139
|
+
def load_state_dict(self, state_dict: ModeloptStateList, version: str) -> None:
|
|
140
|
+
"""Load the provided ``state_dict`` to the modelopt_state."""
|
|
141
|
+
assert not self.has_state, "Cannot load state_dict if there is already one."
|
|
142
|
+
|
|
143
|
+
# Alert if the first 2 version numbers do not match, e.g., 0.3.2 vs 0.4.0.
|
|
144
|
+
if tuple(version.split(".")[:2]) != tuple(__version__.split(".")[:2]):
|
|
145
|
+
warnings.warn(
|
|
146
|
+
f"The checkpoint is stored with version {version}, but current version is"
|
|
147
|
+
f" {__version__}. Compatibility of checkpoint with current version is not guaranteed!"
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
# make sure we operate on deepcopy
|
|
151
|
+
state_dict = copy.deepcopy(state_dict)
|
|
152
|
+
# add modes one-by-one
|
|
153
|
+
for m_str, m_state in state_dict:
|
|
154
|
+
# adds config and metadata with sanity checks
|
|
155
|
+
config = self.get_config_class(m_str, m_state["config"])
|
|
156
|
+
self.add_mode(m_str, config, m_state["metadata"])
|
|
157
|
+
|
|
158
|
+
# overwrite state manually afterwards to ensure exact consistency with provided state_dict
|
|
159
|
+
self._state.clear()
|
|
160
|
+
self._state.extend(state_dict)
|
|
161
|
+
self._state_version[0] = version
|
|
162
|
+
|
|
163
|
+
@classmethod
|
|
164
|
+
def transfer_state_dict(cls, model_from: nn.Module, model_to: nn.Module) -> None:
|
|
165
|
+
"""Transfer the state (same instance) from one model to another."""
|
|
166
|
+
manager_from = ModeloptStateManager(model_from, init_state=False) # state must exist
|
|
167
|
+
manager_to = ModeloptStateManager(model_to, init_state=True) # state must NOT exist
|
|
168
|
+
|
|
169
|
+
# transfer state_dict (this uses sanity checks + deepcopy)
|
|
170
|
+
manager_to.load_state_dict(manager_from.state_dict(), manager_from.state_version)
|
|
171
|
+
|
|
172
|
+
# manually set the state dict to be the exact same instance
|
|
173
|
+
setattr(model_to, cls._state_key, manager_from.state_dict())
|
|
174
|
+
manager_to = ModeloptStateManager(model_to, init_state=False) # state must exist now
|
|
175
|
+
|
|
176
|
+
# remove state from model_from
|
|
177
|
+
cls.remove_state(model_from)
|
|
178
|
+
|
|
179
|
+
@staticmethod
|
|
180
|
+
def has_state_for_mode_type(
|
|
181
|
+
mode_type: str,
|
|
182
|
+
*,
|
|
183
|
+
model: nn.Module | None = None,
|
|
184
|
+
state: dict[str, Any] | None = None,
|
|
185
|
+
) -> bool:
|
|
186
|
+
"""Check if the model or modelopt state contains state from any modes of a given type.
|
|
187
|
+
|
|
188
|
+
Args:
|
|
189
|
+
mode_type: The type of mode to check for.
|
|
190
|
+
Example types: ``quantization``, ``distill``, ``nas``, ``prune``, ``speculative``, etc.
|
|
191
|
+
model: A model to check for state.
|
|
192
|
+
state: A modelopt state extracted from a model.
|
|
193
|
+
"""
|
|
194
|
+
if (model and state) or (not model and not state):
|
|
195
|
+
raise ValueError("Must provide either model or state!")
|
|
196
|
+
if model:
|
|
197
|
+
state = modelopt_state(model)
|
|
198
|
+
mode_registry = _ModeRegistryCls.get_registry_by_name(mode_type)
|
|
199
|
+
return any(m_str in mode_registry for m_str, _ in state["modelopt_state_dict"]) # type: ignore [index]
|
|
200
|
+
|
|
201
|
+
@classmethod
|
|
202
|
+
def remove_state(cls, model: nn.Module) -> None:
|
|
203
|
+
"""Delete the state dict from the model."""
|
|
204
|
+
delattr(model, cls._state_key)
|
|
205
|
+
|
|
206
|
+
def modes_with_states(
|
|
207
|
+
self,
|
|
208
|
+
) -> Iterator[tuple[ModeDescriptor, ModeloptBaseConfig, MetadataDict]]:
|
|
209
|
+
"""Yield the mode together with the full config and metadata from the state."""
|
|
210
|
+
for m_str, m_state in self._state:
|
|
211
|
+
config = self.get_config_class(m_str, m_state["config"])
|
|
212
|
+
yield _ModeRegistryCls.get_from_any(m_str), config, m_state["metadata"]
|
|
213
|
+
|
|
214
|
+
@property
|
|
215
|
+
def last_mode(self) -> ModeDescriptor | None:
|
|
216
|
+
"""Return the last mode applied to the model (last stored mode)."""
|
|
217
|
+
return _ModeRegistryCls.get_from_any(self._state[-1][0]) if self._state else None
|
|
218
|
+
|
|
219
|
+
@property
|
|
220
|
+
def _last_metadata(self) -> MetadataDict:
|
|
221
|
+
"""Return the metadata of the last mode applied to the model (must exist!)."""
|
|
222
|
+
return self._state[-1][1]["metadata"]
|
|
223
|
+
|
|
224
|
+
@property
|
|
225
|
+
def _last_config(self) -> ModeloptBaseConfig:
|
|
226
|
+
"""Return the config of the last mode applied to the model (must exist!)."""
|
|
227
|
+
return self.get_config_class(self._state[-1][0], self._state[-1][1]["config"])
|
|
228
|
+
|
|
229
|
+
@_last_config.setter
|
|
230
|
+
def _last_config(self, config: ModeloptBaseConfig) -> None:
|
|
231
|
+
"""Set the config of the last mode applied to the model (must exist!)."""
|
|
232
|
+
self._state[-1][1]["config"] = config.model_dump()
|
|
233
|
+
|
|
234
|
+
@property
|
|
235
|
+
def _export_stack(self) -> deque[tuple[str, str]]:
|
|
236
|
+
"""Infer the stack of export modes that still must be applied from existing modes.
|
|
237
|
+
|
|
238
|
+
Returns:
|
|
239
|
+
A deque of tuples of the form ``(mode_str, export_mode_str)`` representing the mode
|
|
240
|
+
which requires an export mode and the export mode itself.
|
|
241
|
+
"""
|
|
242
|
+
stack = deque()
|
|
243
|
+
for m, _, _ in self.modes_with_states():
|
|
244
|
+
if m.export_mode is not None:
|
|
245
|
+
stack.append((str(m), m.export_mode))
|
|
246
|
+
elif m.is_export_mode:
|
|
247
|
+
assert str(m) == stack.pop()[1], "Inconsistent export stack!"
|
|
248
|
+
return stack
|
|
249
|
+
|
|
250
|
+
@staticmethod
|
|
251
|
+
def get_config_class(mode: ModeType, config: ConfigDict) -> ModeloptBaseConfig:
|
|
252
|
+
"""Standardize the provided config to the corresponding config class."""
|
|
253
|
+
# validate and standardize to the config class and return
|
|
254
|
+
return _ModeRegistryCls.get_from_any(mode).config_class(**config)
|
|
255
|
+
|
|
256
|
+
def check_mode(self, mode: ModeType) -> None:
|
|
257
|
+
"""Check if the proposed mode is compatible with the current state."""
|
|
258
|
+
# standardize mode to descriptor
|
|
259
|
+
mode_d = _ModeRegistryCls.get_from_any(mode)
|
|
260
|
+
|
|
261
|
+
# check for export mode compatibility
|
|
262
|
+
export_stack = self._export_stack
|
|
263
|
+
if mode_d.is_export_mode:
|
|
264
|
+
assert export_stack and str(mode_d) == export_stack[-1][1], (
|
|
265
|
+
f"Cannot add {mode_d} according to the current export stack: {export_stack}."
|
|
266
|
+
)
|
|
267
|
+
|
|
268
|
+
# sanity checks for next mode compatibilities according to the current last mode
|
|
269
|
+
last_mode = self.last_mode
|
|
270
|
+
if last_mode:
|
|
271
|
+
mode_d.assert_compatibility_as_next_mode_of(last_mode)
|
|
272
|
+
|
|
273
|
+
# sanity checks for next mode compatible with last mode in the stack. These
|
|
274
|
+
# compatibilities still apply since we did not apply corresponding export mode yet.
|
|
275
|
+
if export_stack:
|
|
276
|
+
# last_m_stack := last mode on the stack that has a corresponding export mode
|
|
277
|
+
last_m_stack = _ModeRegistryCls.get_from_any(export_stack[-1][0])
|
|
278
|
+
mode_d.assert_compatibility_as_next_mode_of(last_m_stack)
|
|
279
|
+
|
|
280
|
+
def add_mode(self, mode: ModeType, config: ModeloptBaseConfig, metadata: MetadataDict) -> None:
|
|
281
|
+
"""Add mode and update state in-place.
|
|
282
|
+
|
|
283
|
+
Note that self._state is a list (preserves insertion order of keys) and we can therefore
|
|
284
|
+
recall the order of modes!
|
|
285
|
+
"""
|
|
286
|
+
# standardize mode to descriptor
|
|
287
|
+
mode_d = _ModeRegistryCls.get_from_any(mode)
|
|
288
|
+
|
|
289
|
+
# sanity checks for mode incompatibilities
|
|
290
|
+
self.check_mode(mode_d)
|
|
291
|
+
|
|
292
|
+
# store mode information
|
|
293
|
+
m_state: ModeState = {"config": config.model_dump(), "metadata": metadata}
|
|
294
|
+
|
|
295
|
+
self._state.append((str(mode_d), m_state))
|
|
296
|
+
|
|
297
|
+
def update_last_state_before_new_mode(self, model: nn.Module) -> None:
|
|
298
|
+
"""Update the metadata and config of the last mode applied to the model."""
|
|
299
|
+
last_mode = self.last_mode
|
|
300
|
+
if last_mode is not None:
|
|
301
|
+
last_config = self._last_config
|
|
302
|
+
last_mode.update_for_new_mode(model, last_config, self._last_metadata)
|
|
303
|
+
self._last_config = last_config
|
|
304
|
+
|
|
305
|
+
def update_last_state_before_save(self, model: nn.Module) -> None:
|
|
306
|
+
"""Update the metadata and config of the last mode applied to the model."""
|
|
307
|
+
last_mode = self.last_mode
|
|
308
|
+
if last_mode is not None:
|
|
309
|
+
last_config = self._last_config
|
|
310
|
+
last_mode.update_for_save(model, last_config, self._last_metadata)
|
|
311
|
+
self._last_config = last_config
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
class ApplyModeError(RuntimeError):
|
|
315
|
+
"""Error raised when applying a mode to a model fails."""
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
class ModelLikeModule(nn.Module):
|
|
319
|
+
"""Just a temp module type to store the initialization recipe for the actual model."""
|
|
320
|
+
|
|
321
|
+
def __init__(self, modellike: ModelLike) -> None:
|
|
322
|
+
super().__init__()
|
|
323
|
+
assert not isinstance(modellike, nn.Module), "modellike should not be a nn.Module!"
|
|
324
|
+
self.modellike = modellike
|
|
325
|
+
|
|
326
|
+
def init_modellike(self) -> nn.Module:
|
|
327
|
+
"""Initialize the modellike to be an actual model."""
|
|
328
|
+
model = init_model_from_model_like(self.modellike)
|
|
329
|
+
ModeloptStateManager.transfer_state_dict(self, model)
|
|
330
|
+
return model
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
def _check_init_modellike(model: nn.Module, mode: ModeDescriptor) -> nn.Module:
|
|
334
|
+
"""Utility to initialize a ModelLikeModule if needed according to the mode."""
|
|
335
|
+
if mode.require_model_like:
|
|
336
|
+
assert isinstance(model, ModelLikeModule), "Model must be a ModelLikeModule!"
|
|
337
|
+
elif isinstance(model, ModelLikeModule):
|
|
338
|
+
model = model.init_modellike()
|
|
339
|
+
return model
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
def apply_mode(
|
|
343
|
+
model: ModelLike,
|
|
344
|
+
mode: ModeLike,
|
|
345
|
+
registry: _ModeRegistryCls | None = None,
|
|
346
|
+
init_state: bool | None = None,
|
|
347
|
+
mode_kwargs: ModeKwargsType | None = None,
|
|
348
|
+
) -> nn.Module:
|
|
349
|
+
"""Apply the provided modes the model, record the changes, and return the model.
|
|
350
|
+
|
|
351
|
+
Args:
|
|
352
|
+
model: A model-like object. Can be an nn.Module, a model class type, or a tuple.
|
|
353
|
+
tuple must be of the form ``(model_cls,)`` or ``(model_cls, args)`` or
|
|
354
|
+
``(model_cls, args, kwargs)``. Model will be initialized as
|
|
355
|
+
``model_cls(*args, **kwargs)``.
|
|
356
|
+
mode: A mode, a list of modes or a list of tuples containing the mode and its config. The
|
|
357
|
+
mode may be specified as a string or as the actual
|
|
358
|
+
:class:`ModeDescriptor<modelopt.torch.opt.mode.ModeDescriptor>` class such as
|
|
359
|
+
:class:`QuantizeModeDescriptor<modelopt.torch.opt.quantization.QuantizeModeDescriptor>` class.
|
|
360
|
+
registry: An optional mode registry from which to retrieve the mode. If not provided, all
|
|
361
|
+
registries will be searched.
|
|
362
|
+
init_state: Flag indicating whether we should initialize the state manager for the model. If
|
|
363
|
+
not provided, it will be inferred from the model. This flag can be used to enforce a
|
|
364
|
+
certain behavior. For example, for ``init_state=True`` the state manager will raise an
|
|
365
|
+
error if the model already contains state.
|
|
366
|
+
mode_kwargs: Optional keyword arguments for mode conversion. Can be a single dictionary
|
|
367
|
+
(applied to all modes) or a list of dictionaries (one per mode). These arguments
|
|
368
|
+
are passed to each mode's convert entrypoint but are not saved in modelopt state.
|
|
369
|
+
This is useful for passing non-serializable objects (like custom functions) that aren't
|
|
370
|
+
needed when restoring the model.
|
|
371
|
+
|
|
372
|
+
Returns:
|
|
373
|
+
The converted model after applying the desired modes.
|
|
374
|
+
"""
|
|
375
|
+
# initialize ModelLikeModule if needed.
|
|
376
|
+
model = model if isinstance(model, nn.Module) else ModelLikeModule(model)
|
|
377
|
+
|
|
378
|
+
# vanilla case (just initialize+return)
|
|
379
|
+
if not mode:
|
|
380
|
+
return model.init_modellike() if isinstance(model, ModelLikeModule) else model
|
|
381
|
+
|
|
382
|
+
# check if the model is in a wrapper
|
|
383
|
+
model = unwrap_model(model, raise_error=True)
|
|
384
|
+
|
|
385
|
+
# standardize mode to ModeConfigList
|
|
386
|
+
mode_and_config = get_mode_config(mode)
|
|
387
|
+
|
|
388
|
+
# get or initialize the state manager for the model
|
|
389
|
+
manager = ModeloptStateManager(
|
|
390
|
+
model,
|
|
391
|
+
init_state=(
|
|
392
|
+
not ModeloptStateManager.is_converted(model) if init_state is None else init_state
|
|
393
|
+
),
|
|
394
|
+
)
|
|
395
|
+
|
|
396
|
+
# get mode function based on registry argument
|
|
397
|
+
get_mode = registry.__getitem__ if registry else _ModeRegistryCls.get_from_any
|
|
398
|
+
|
|
399
|
+
# update metadata of currently last mode before adding new modes
|
|
400
|
+
manager.update_last_state_before_new_mode(model)
|
|
401
|
+
|
|
402
|
+
# check whether a ModelLike should be initialized
|
|
403
|
+
model = _check_init_modellike(model, get_mode(mode_and_config[0][0]))
|
|
404
|
+
|
|
405
|
+
if mode_kwargs is not None:
|
|
406
|
+
if isinstance(mode_kwargs, dict):
|
|
407
|
+
mode_kwargs = [mode_kwargs] * len(mode_and_config)
|
|
408
|
+
assert len(mode_kwargs) == len(mode_and_config), (
|
|
409
|
+
"Number of mode kwargs must match number of modes!"
|
|
410
|
+
)
|
|
411
|
+
else:
|
|
412
|
+
mode_kwargs = [{}] * len(mode_and_config)
|
|
413
|
+
|
|
414
|
+
# loop through modes and call convert entrypoint for each mode and record data in manager.
|
|
415
|
+
for (m, config), kwargs in zip(mode_and_config, mode_kwargs):
|
|
416
|
+
manager.check_mode(m)
|
|
417
|
+
config = manager.get_config_class(m, config)
|
|
418
|
+
model, metadata = get_mode(m).convert(model, config, **kwargs) # type: ignore [call-arg]
|
|
419
|
+
manager.add_mode(m, config, metadata)
|
|
420
|
+
|
|
421
|
+
# If the existing mode is empty, create an model instance from ModelLikeModule.
|
|
422
|
+
if not manager.has_state and isinstance(model, ModelLikeModule):
|
|
423
|
+
model = model.init_modellike()
|
|
424
|
+
|
|
425
|
+
# it cannot be a ModelLikeModule anymore at the end
|
|
426
|
+
assert not isinstance(model, ModelLikeModule), "Model must be a regular Module now!"
|
|
427
|
+
|
|
428
|
+
# return model with state recorded
|
|
429
|
+
return model
|
|
430
|
+
|
|
431
|
+
|
|
432
|
+
def get_mode(model: nn.Module) -> ModeDescriptor | None:
|
|
433
|
+
"""Get mode of converted network.
|
|
434
|
+
|
|
435
|
+
model: A model that contains modelopt_state
|
|
436
|
+
|
|
437
|
+
The mode of the model is defined as the last mode activated during the convert process.
|
|
438
|
+
"""
|
|
439
|
+
if ModeloptStateManager.is_converted(model):
|
|
440
|
+
return ModeloptStateManager(model).last_mode
|
|
441
|
+
return None
|
|
442
|
+
|
|
443
|
+
|
|
444
|
+
def modelopt_state(model: nn.Module) -> dict[str, Any]:
|
|
445
|
+
"""Return the modelopt state dict describing the modifications to the model.
|
|
446
|
+
|
|
447
|
+
Note that the returned ``modelopt_state`` does not contain the model parameters such as weights and biases.
|
|
448
|
+
``modelopt_state`` is useful for saving and loading various modelopt optimization states separately from the
|
|
449
|
+
model parameters. For example:
|
|
450
|
+
|
|
451
|
+
.. code-block::
|
|
452
|
+
|
|
453
|
+
import modelopt.torch.opt as mto
|
|
454
|
+
|
|
455
|
+
# Save the modelopt state and model weights separately
|
|
456
|
+
torch.save(mto.modelopt_state(model), "modelopt_state.pt") # Save the modelopt state
|
|
457
|
+
torch.save(model.state_dict(), "model_weights.pt") # Save the model weights
|
|
458
|
+
|
|
459
|
+
If you want to save the model weights and the modelopt state together, please use
|
|
460
|
+
:meth:`mto.save()<modelopt.torch.opt.conversion.save>`.
|
|
461
|
+
|
|
462
|
+
Args:
|
|
463
|
+
model: the modelopt-modified model.
|
|
464
|
+
|
|
465
|
+
Returns:
|
|
466
|
+
An modelopt state dictionary describing the modifications to the model.
|
|
467
|
+
"""
|
|
468
|
+
# unwrap model
|
|
469
|
+
model = unwrap_model(model, force_unwrap=True)
|
|
470
|
+
|
|
471
|
+
# retrieve state manager
|
|
472
|
+
manager = ModeloptStateManager(
|
|
473
|
+
model=model if ModeloptStateManager.is_converted(model) else None
|
|
474
|
+
)
|
|
475
|
+
|
|
476
|
+
# update metadata of current mode as needed
|
|
477
|
+
manager.update_last_state_before_save(model)
|
|
478
|
+
|
|
479
|
+
# construct state dict and return it
|
|
480
|
+
objs = {
|
|
481
|
+
"modelopt_state_dict": (
|
|
482
|
+
manager.state_dict()
|
|
483
|
+
), # empty state_dict is okay (saving regular models)
|
|
484
|
+
"modelopt_version": __version__,
|
|
485
|
+
}
|
|
486
|
+
return objs
|
|
487
|
+
|
|
488
|
+
|
|
489
|
+
def save(model: nn.Module, f: str | os.PathLike | BinaryIO, **kwargs) -> None:
|
|
490
|
+
"""Save a model's state dict together with the modelopt state dict to restore its architecture.
|
|
491
|
+
|
|
492
|
+
Args:
|
|
493
|
+
model: Any model.
|
|
494
|
+
f: Target file location.
|
|
495
|
+
**kwargs: additional args for ``torch.save()``.
|
|
496
|
+
|
|
497
|
+
.. note::
|
|
498
|
+
|
|
499
|
+
If model is a wrapper such as DistributedDataParallel, it will be unwrapped for saving.
|
|
500
|
+
"""
|
|
501
|
+
# unwrap model
|
|
502
|
+
model = unwrap_model(model, warn=True)
|
|
503
|
+
|
|
504
|
+
# store ckpt
|
|
505
|
+
ckpt_dict = {
|
|
506
|
+
"modelopt_state": modelopt_state(model),
|
|
507
|
+
"model_state_dict": model.state_dict(),
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
# store object
|
|
511
|
+
torch.save(ckpt_dict, f, **kwargs)
|
|
512
|
+
|
|
513
|
+
|
|
514
|
+
def restore_from_modelopt_state(model: ModelLike, modelopt_state: dict[str, Any]) -> nn.Module:
|
|
515
|
+
"""Restore the model architecture from the modelopt state dictionary based on the user-provided model.
|
|
516
|
+
|
|
517
|
+
This method does not restore the model parameters such as weights, biases and quantization scales.
|
|
518
|
+
Please load the weights and biases with the original checkpoint loading method after restoring
|
|
519
|
+
modelopt states with `restore_from_modelopt_state`. For example:
|
|
520
|
+
|
|
521
|
+
.. code-block:: python
|
|
522
|
+
|
|
523
|
+
import modelopt.torch.opt as mto
|
|
524
|
+
|
|
525
|
+
model = ... # Create the model-like object
|
|
526
|
+
|
|
527
|
+
# Restore the previously saved modelopt state followed by model weights
|
|
528
|
+
mto.restore_from_modelopt_state(
|
|
529
|
+
model, torch.load("modelopt_state.pt", weights_only=False)
|
|
530
|
+
) # Restore modelopt state
|
|
531
|
+
model.load_state_dict(torch.load("model_weights.pt"), ...) # Load the model weights
|
|
532
|
+
|
|
533
|
+
If you want to restore the model weights and the modelopt state with saved scales, please use
|
|
534
|
+
:meth:`mto.restore()<modelopt.torch.opt.conversion.restore>`.
|
|
535
|
+
|
|
536
|
+
Args:
|
|
537
|
+
model: A model-like object. Can be an nn.Module, a model class type, or a tuple.
|
|
538
|
+
tuple must be of the form ``(model_cls,)`` or ``(model_cls, args)`` or
|
|
539
|
+
``(model_cls, args, kwargs)``. Model will be initialized as
|
|
540
|
+
``model_cls(*args, **kwargs)``.
|
|
541
|
+
modelopt_state: The modelopt state dict describing the modelopt modifications to the model. The
|
|
542
|
+
``modelopt_state`` can be generated via
|
|
543
|
+
:meth:`mto.modelopt_state()<modelopt.torch.opt.conversion.modelopt_state>`.
|
|
544
|
+
|
|
545
|
+
Returns:
|
|
546
|
+
A modified model architecture based on the restored modifications with the unmodified
|
|
547
|
+
weights as stored in the provided ``model`` argument.
|
|
548
|
+
|
|
549
|
+
.. note::
|
|
550
|
+
|
|
551
|
+
Note that wrappers such as DistributedDataParallel are `not` supported during the restore
|
|
552
|
+
process. Please wrap the model after the restore process.
|
|
553
|
+
"""
|
|
554
|
+
# initialize ModelLikeModule if needed.
|
|
555
|
+
model = model if isinstance(model, nn.Module) else ModelLikeModule(model)
|
|
556
|
+
|
|
557
|
+
# initialize state manager and load state
|
|
558
|
+
manager = ModeloptStateManager(model=model, init_state=True)
|
|
559
|
+
manager.load_state_dict(
|
|
560
|
+
modelopt_state["modelopt_state_dict"], modelopt_state["modelopt_version"]
|
|
561
|
+
)
|
|
562
|
+
|
|
563
|
+
# apply restore entrypoints for each of the modes
|
|
564
|
+
for i, (m, config, metadata) in enumerate(manager.modes_with_states()):
|
|
565
|
+
if i == 0:
|
|
566
|
+
model = _check_init_modellike(model, m)
|
|
567
|
+
model = m.restore(model, config, metadata)
|
|
568
|
+
|
|
569
|
+
# If the existing mode is empty, create an model instance from ModelLikeModule.
|
|
570
|
+
if not manager.has_state and isinstance(model, ModelLikeModule):
|
|
571
|
+
model = model.init_modellike()
|
|
572
|
+
|
|
573
|
+
# it cannot be a ModelLikeModule anymore at the end
|
|
574
|
+
assert not isinstance(model, ModelLikeModule), "Model must be a regular Module now!"
|
|
575
|
+
|
|
576
|
+
return model
|
|
577
|
+
|
|
578
|
+
|
|
579
|
+
def restore(model: ModelLike, f: str | os.PathLike | BinaryIO, **kwargs) -> nn.Module:
|
|
580
|
+
"""Load the checkpoint, restore the modelopt model modifications, and load the model's weights.
|
|
581
|
+
|
|
582
|
+
Args:
|
|
583
|
+
model: A model-like object. Can be an nn.Module, a model class type, or a tuple.
|
|
584
|
+
tuple must be of the form ``(model_cls,)`` or ``(model_cls, args)`` or ``(model_cls, args, kwargs)``.
|
|
585
|
+
Model will be initialized as ``model_cls(*args, **kwargs)``.
|
|
586
|
+
f: Target file location generated by :meth:`mto.save()<modelopt.torch.opt.conversion.save>`.
|
|
587
|
+
**kwargs: additional args for ``torch.load()``.
|
|
588
|
+
|
|
589
|
+
Returns:
|
|
590
|
+
The model with original weights and stored architecture.
|
|
591
|
+
|
|
592
|
+
.. note::
|
|
593
|
+
|
|
594
|
+
Note that wrappers such as DistributedDataParallel are `not` supported during the restore
|
|
595
|
+
process. Please wrap the model after the restore process.
|
|
596
|
+
"""
|
|
597
|
+
# initialize ModelLikeModule if needed.
|
|
598
|
+
model = model if isinstance(model, nn.Module) else ModelLikeModule(model)
|
|
599
|
+
|
|
600
|
+
# load checkpoint
|
|
601
|
+
kwargs.setdefault("map_location", "cpu")
|
|
602
|
+
kwargs.setdefault("weights_only", False)
|
|
603
|
+
objs = torch.load(f, **kwargs)
|
|
604
|
+
|
|
605
|
+
# restore model architecture
|
|
606
|
+
model_restored = restore_from_modelopt_state(model, objs["modelopt_state"])
|
|
607
|
+
|
|
608
|
+
# load weights from checkpoint
|
|
609
|
+
model_restored.load_state_dict(objs["model_state_dict"])
|
|
610
|
+
|
|
611
|
+
# it cannot be a ModelLikeModule anymore at the end
|
|
612
|
+
assert not isinstance(model_restored, ModelLikeModule), "Model must be a regular Module now!"
|
|
613
|
+
|
|
614
|
+
return model_restored
|
|
615
|
+
|
|
616
|
+
|
|
617
|
+
# TODO: add a generic export function that will apply all remaining export modes.
|
|
618
|
+
def export(model: nn.Module) -> nn.Module:
|
|
619
|
+
"""Fully export the model to a regular model and finalize any model modifications."""
|
|
620
|
+
raise NotImplementedError
|