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,254 @@
|
|
|
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
|
+
"""Dynamic Conv implementations based on torch.nn.modules.conv."""
|
|
17
|
+
|
|
18
|
+
import itertools
|
|
19
|
+
|
|
20
|
+
import torch
|
|
21
|
+
from torch import nn
|
|
22
|
+
|
|
23
|
+
from modelopt.torch.opt.dynamic import DynamicModule
|
|
24
|
+
from modelopt.torch.utils import make_divisible, val2tuple
|
|
25
|
+
|
|
26
|
+
from ..registry import DMRegistry
|
|
27
|
+
from ..traced_hp import TracedHp
|
|
28
|
+
from .utils import get_sliced_tensor, get_sliced_tensor_by_slices
|
|
29
|
+
|
|
30
|
+
__all__ = ["_DynamicConvNd", "_DynamicConvTransposeNd"]
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@DMRegistry.register({nn.Conv1d: "nn.Conv1d", nn.Conv2d: "nn.Conv2d", nn.Conv3d: "nn.Conv3d"})
|
|
34
|
+
class _DynamicConvNd(DynamicModule):
|
|
35
|
+
@property
|
|
36
|
+
def ndim(self):
|
|
37
|
+
return len(self.kernel_size)
|
|
38
|
+
|
|
39
|
+
@staticmethod
|
|
40
|
+
def _assert_input_format(
|
|
41
|
+
mod: "_DynamicConvNd", input: tuple[torch.Tensor] | torch.Tensor
|
|
42
|
+
) -> None:
|
|
43
|
+
if isinstance(input, tuple):
|
|
44
|
+
assert len(input) == 1, f"Expected single input, but got {input}."
|
|
45
|
+
input = input[0]
|
|
46
|
+
if input.dim() != mod.ndim + 2:
|
|
47
|
+
raise ValueError(f"Expected batched input (e.g. NCHW vs CHW), but got {input.shape}.")
|
|
48
|
+
|
|
49
|
+
@staticmethod
|
|
50
|
+
def _get_padding(
|
|
51
|
+
mod: "_DynamicConvNd", padding: str | tuple[int, ...]
|
|
52
|
+
) -> str | tuple[int, ...]:
|
|
53
|
+
"""New padding such that output size stays the same as with max kernel size and padding."""
|
|
54
|
+
if isinstance(padding, str):
|
|
55
|
+
return padding
|
|
56
|
+
|
|
57
|
+
active_padding = []
|
|
58
|
+
max_kernel_size = mod.get_hparam("kernel_size").max
|
|
59
|
+
for dim in range(mod.ndim):
|
|
60
|
+
max_ks = max_kernel_size[dim] # type: ignore[index]
|
|
61
|
+
active_ks = mod.kernel_size[dim]
|
|
62
|
+
assert max_ks % 2 == active_ks % 2, (max_ks, active_ks)
|
|
63
|
+
|
|
64
|
+
max_p = padding[dim]
|
|
65
|
+
active_p = max_p - (max_ks - active_ks) * mod.dilation[dim] // 2
|
|
66
|
+
assert active_p >= 0, (max_p, active_p)
|
|
67
|
+
|
|
68
|
+
active_padding.append(active_p)
|
|
69
|
+
return tuple(active_padding)
|
|
70
|
+
|
|
71
|
+
@staticmethod
|
|
72
|
+
def _get_bias(mod: "_DynamicConvNd", bias: torch.Tensor | None) -> torch.Tensor | None:
|
|
73
|
+
return get_sliced_tensor(mod, bias, "out_channels")
|
|
74
|
+
|
|
75
|
+
@staticmethod
|
|
76
|
+
def _get_channel_order() -> list[str]:
|
|
77
|
+
return ["out_channels", "in_channels"]
|
|
78
|
+
|
|
79
|
+
@staticmethod
|
|
80
|
+
def _get_weight(mod: "_DynamicConvNd", weight: torch.Tensor) -> torch.Tensor:
|
|
81
|
+
slices = []
|
|
82
|
+
|
|
83
|
+
# get channel hparams in correct order
|
|
84
|
+
hps_c = [mod.get_hparam(c_name) for c_name in mod._get_channel_order()]
|
|
85
|
+
c_active = [hp.active for hp in hps_c]
|
|
86
|
+
|
|
87
|
+
# add slice for 1st channel dimension
|
|
88
|
+
slices.append(hps_c[0].active_slice)
|
|
89
|
+
|
|
90
|
+
# slice for 2nd channel dimension depends on groups
|
|
91
|
+
slice_1 = hps_c[1].active_slice
|
|
92
|
+
groups = mod.groups
|
|
93
|
+
if groups == 1:
|
|
94
|
+
slices.append(slice_1)
|
|
95
|
+
elif all(c % groups == 0 for c in c_active):
|
|
96
|
+
assert slice_1 == slice(c_active[1]) or c_active[0] == c_active[1] == groups
|
|
97
|
+
slices.append(slice(c_active[1] // groups))
|
|
98
|
+
else:
|
|
99
|
+
raise NotImplementedError(f"Group size {groups} not supported!")
|
|
100
|
+
|
|
101
|
+
# kernel size slices
|
|
102
|
+
max_kernel_size = mod.get_hparam("kernel_size").max
|
|
103
|
+
active_kernel_size = mod.kernel_size
|
|
104
|
+
assert isinstance(max_kernel_size, tuple)
|
|
105
|
+
for max_ks, active_ks in zip(max_kernel_size, active_kernel_size):
|
|
106
|
+
a = max_ks // 2 - active_ks // 2
|
|
107
|
+
b = max_ks // 2 + active_ks // 2 + max_ks % 2
|
|
108
|
+
slices.append(slice(a, b))
|
|
109
|
+
|
|
110
|
+
return get_sliced_tensor_by_slices(weight, slices)
|
|
111
|
+
|
|
112
|
+
@staticmethod
|
|
113
|
+
def _get_groups(mod: "_DynamicConvNd", groups: int) -> int:
|
|
114
|
+
# retrieve channel hparams
|
|
115
|
+
hp_oc = mod.get_hparam("out_channels")
|
|
116
|
+
hp_ic = mod.get_hparam("in_channels")
|
|
117
|
+
|
|
118
|
+
# vanilla cases
|
|
119
|
+
if groups == 1 or (hp_oc.active == hp_oc.original and hp_ic.active == hp_ic.original):
|
|
120
|
+
return groups
|
|
121
|
+
|
|
122
|
+
# only support out_channels == in_channels if grouped
|
|
123
|
+
assert hp_oc.active == hp_ic.active, (hp_oc.active, hp_ic.active)
|
|
124
|
+
|
|
125
|
+
# compute current number of groups
|
|
126
|
+
assert hp_oc.original % groups == 0, (hp_oc.original, groups)
|
|
127
|
+
active_groups = (hp_oc.active * groups) // hp_oc.original
|
|
128
|
+
|
|
129
|
+
# sanity checks
|
|
130
|
+
assert isinstance(active_groups, int)
|
|
131
|
+
assert hp_oc.active % active_groups == 0, (hp_oc.active, active_groups)
|
|
132
|
+
assert hp_ic.active % active_groups == 0, (hp_ic.active, active_groups)
|
|
133
|
+
|
|
134
|
+
return active_groups
|
|
135
|
+
|
|
136
|
+
def _estimate_importance(self) -> TracedHp.Importance:
|
|
137
|
+
# for group > 1, we do not know how to handle it yet
|
|
138
|
+
if self.groups > 1:
|
|
139
|
+
return None
|
|
140
|
+
weight = self._parameters["weight"] # retrieve full weight tensor
|
|
141
|
+
c_in = weight.shape[1]
|
|
142
|
+
return torch.linalg.vector_norm(
|
|
143
|
+
torch.reshape(weight.detach().transpose(0, 1), (c_in, -1)), dim=1
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
def _setup(self):
|
|
147
|
+
# only support ungrouped conv or grouped conv with in_channels == out_channels
|
|
148
|
+
if self.groups == 1:
|
|
149
|
+
oc_step = ic_step = 1
|
|
150
|
+
elif self.out_channels == self.in_channels:
|
|
151
|
+
oc_step = ic_step = self.out_channels // self.groups
|
|
152
|
+
else:
|
|
153
|
+
oc_step = self.out_channels
|
|
154
|
+
ic_step = self.in_channels
|
|
155
|
+
oc_choices = [c for c in range(1, self.out_channels + 1) if c % oc_step == 0]
|
|
156
|
+
ic_choices = [c for c in range(1, self.in_channels + 1) if c % ic_step == 0]
|
|
157
|
+
|
|
158
|
+
# construct choices for kernel size hyperparameter
|
|
159
|
+
ks_set = {self.kernel_size}
|
|
160
|
+
# TODO: padding mode other than "zeros" is not supported since in other padding mode, conv
|
|
161
|
+
# will use "_reversed_padding_repeated_twice" instead of "padding" in the forward function.
|
|
162
|
+
if self.padding_mode == "zeros":
|
|
163
|
+
for ks in itertools.product(*[range(1, k + 1) for k in self.kernel_size]):
|
|
164
|
+
for d in range(self.ndim):
|
|
165
|
+
# check kernel size: smaller than original, same parity
|
|
166
|
+
if ks[d] > self.kernel_size[d] or ks[d] % 2 != self.kernel_size[d] % 2:
|
|
167
|
+
break
|
|
168
|
+
|
|
169
|
+
# check padding: non-negative
|
|
170
|
+
if (
|
|
171
|
+
isinstance(self.padding, tuple)
|
|
172
|
+
and self.padding[d] < (self.kernel_size[d] - ks[d]) * self.dilation[d] // 2
|
|
173
|
+
):
|
|
174
|
+
break
|
|
175
|
+
else:
|
|
176
|
+
ks_set.add(ks)
|
|
177
|
+
ks_choices = list(ks_set)
|
|
178
|
+
|
|
179
|
+
# register hyperparameters
|
|
180
|
+
self._register_hparam("out_channels", TracedHp(oc_choices, self.out_channels))
|
|
181
|
+
self._register_hparam("in_channels", TracedHp(ic_choices, self.in_channels))
|
|
182
|
+
self._register_hparam("kernel_size", TracedHp(ks_choices, self.kernel_size))
|
|
183
|
+
|
|
184
|
+
# We restrict the input to be batched (e.g. NCHW) format so searchable_tensor_dims can be 1.
|
|
185
|
+
# Ideally searchable_tensor_dims for Conv2d would be -3, but its more common to use
|
|
186
|
+
# torch.cat([...], dim=1), and enforcing batched input would allow us to support these.
|
|
187
|
+
hook_handle = self.register_forward_pre_hook(self._assert_input_format)
|
|
188
|
+
self._register_temp_attribute(
|
|
189
|
+
"_hook_handle", hook_handle, del_hook=lambda m, n: m._hook_handle.remove()
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
# register dynamic attributes
|
|
193
|
+
self._register_dynamic_attribute("padding", self._get_padding)
|
|
194
|
+
self._register_dynamic_attribute("weight", self._get_weight)
|
|
195
|
+
self._register_dynamic_attribute("bias", self._get_bias)
|
|
196
|
+
self._register_dynamic_attribute("groups", self._get_groups)
|
|
197
|
+
|
|
198
|
+
# register importance for in_channels
|
|
199
|
+
self.get_hparam("in_channels").register_importance(self._estimate_importance)
|
|
200
|
+
|
|
201
|
+
def modify(
|
|
202
|
+
self,
|
|
203
|
+
*,
|
|
204
|
+
channels_ratio: tuple[float, ...] | None = None,
|
|
205
|
+
channel_divisor: int = 1,
|
|
206
|
+
kernel_size: tuple[int | tuple[int, ...], ...] = (),
|
|
207
|
+
):
|
|
208
|
+
"""Modify the dynamic choices of the module according to provided keyword arguments.
|
|
209
|
+
|
|
210
|
+
Args:
|
|
211
|
+
channels_ratio: The ratios of the desired number of out/in channels over original
|
|
212
|
+
number of out/in channels.
|
|
213
|
+
channel_divisor: The divisor of the out/in channels.
|
|
214
|
+
kernel_sizes: The desired kernel sizes.
|
|
215
|
+
"""
|
|
216
|
+
# modify both in_channels and out_channels
|
|
217
|
+
channels = ["in_channels", "out_channels"]
|
|
218
|
+
choices: set[float]
|
|
219
|
+
for channel in channels:
|
|
220
|
+
hp = self.get_hparam(channel)
|
|
221
|
+
if channels_ratio is not None:
|
|
222
|
+
assert isinstance(hp.original, int)
|
|
223
|
+
choices = {r * hp.original for r in channels_ratio}
|
|
224
|
+
else:
|
|
225
|
+
choices = set(hp.choices) # type: ignore[arg-type]
|
|
226
|
+
choices_rounded: set[int] = {int(make_divisible(c, channel_divisor)) for c in choices}
|
|
227
|
+
hp.choices = list(set(hp.choices) & choices_rounded | {hp.original})
|
|
228
|
+
|
|
229
|
+
# modify kernel size choices
|
|
230
|
+
hp_ks = self.get_hparam("kernel_size")
|
|
231
|
+
kernel_size = hp_ks.choices if kernel_size is None else kernel_size
|
|
232
|
+
ks_choices = {val2tuple(ks, self.ndim) for ks in kernel_size}
|
|
233
|
+
hp_ks.choices = list(set(hp_ks.choices) & ks_choices | {hp_ks.original})
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
@DMRegistry.register(
|
|
237
|
+
{
|
|
238
|
+
nn.ConvTranspose1d: "nn.ConvTranspose1d",
|
|
239
|
+
nn.ConvTranspose2d: "nn.ConvTranspose2d",
|
|
240
|
+
nn.ConvTranspose3d: "nn.ConvTranspose3d",
|
|
241
|
+
}
|
|
242
|
+
)
|
|
243
|
+
class _DynamicConvTransposeNd(_DynamicConvNd):
|
|
244
|
+
@staticmethod
|
|
245
|
+
def _get_channel_order() -> list[str]:
|
|
246
|
+
return ["in_channels", "out_channels"]
|
|
247
|
+
|
|
248
|
+
def _estimate_importance(self) -> TracedHp.Importance:
|
|
249
|
+
# for group > 1, we do not know how to handle it yet
|
|
250
|
+
if self.groups > 1:
|
|
251
|
+
return None
|
|
252
|
+
weight = self._parameters["weight"] # retrieve full weight tensor
|
|
253
|
+
c_in = weight.shape[0]
|
|
254
|
+
return torch.linalg.vector_norm(torch.reshape(weight.detach(), (c_in, -1)), dim=1)
|
|
@@ -0,0 +1,76 @@
|
|
|
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
|
+
"""Dynamic linear implementations based on torch.nn.modules.linear."""
|
|
17
|
+
|
|
18
|
+
import torch
|
|
19
|
+
from torch import nn
|
|
20
|
+
|
|
21
|
+
from modelopt.torch.opt.dynamic import DynamicModule
|
|
22
|
+
from modelopt.torch.utils import make_divisible
|
|
23
|
+
|
|
24
|
+
from ..registry import DMRegistry
|
|
25
|
+
from ..traced_hp import TracedHp
|
|
26
|
+
from .utils import get_sliced_tensor
|
|
27
|
+
|
|
28
|
+
__all__ = ["_DynamicLinear"]
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@DMRegistry.register({nn.Linear: "nn.Linear"})
|
|
32
|
+
class _DynamicLinear(DynamicModule):
|
|
33
|
+
"""An ``nn.Linear`` layer with dynamic hyperparams."""
|
|
34
|
+
|
|
35
|
+
@staticmethod
|
|
36
|
+
def _get_weight(mod: "_DynamicLinear", weight: torch.Tensor) -> torch.Tensor:
|
|
37
|
+
return get_sliced_tensor(mod, weight, "out_features", "in_features")
|
|
38
|
+
|
|
39
|
+
@staticmethod
|
|
40
|
+
def _get_bias(mod: "_DynamicLinear", bias: torch.Tensor | None) -> torch.Tensor | None:
|
|
41
|
+
return get_sliced_tensor(mod, bias, "out_features")
|
|
42
|
+
|
|
43
|
+
def _estimate_importance(self) -> TracedHp.Importance:
|
|
44
|
+
return torch.linalg.vector_norm(self._parameters["weight"].detach(), dim=0)
|
|
45
|
+
|
|
46
|
+
def _setup(self):
|
|
47
|
+
# register hyperparameters
|
|
48
|
+
self._register_hparam("in_features", TracedHp(list(range(1, self.in_features + 1))))
|
|
49
|
+
self._register_hparam("out_features", TracedHp(list(range(1, self.out_features + 1))))
|
|
50
|
+
|
|
51
|
+
# register dynamic attributes of the class
|
|
52
|
+
self._register_dynamic_attribute("weight", self._get_weight)
|
|
53
|
+
self._register_dynamic_attribute("bias", self._get_bias)
|
|
54
|
+
|
|
55
|
+
# register importance for in_features
|
|
56
|
+
self.get_hparam("in_features").register_importance(self._estimate_importance)
|
|
57
|
+
|
|
58
|
+
def modify(self, *, features_ratio: tuple[float, ...] | None = None, feature_divisor: int = 1):
|
|
59
|
+
"""Modify the dynamic choices of the module according to provided keyword arguments.
|
|
60
|
+
|
|
61
|
+
Args:
|
|
62
|
+
features_ratio: The ratios of the desired number of output/input features over original
|
|
63
|
+
number of output/input features.
|
|
64
|
+
feature_divisor: The divisor of the output/input features.
|
|
65
|
+
"""
|
|
66
|
+
# modify both in_features and out_features
|
|
67
|
+
features = ["in_features", "out_features"]
|
|
68
|
+
for feature in features:
|
|
69
|
+
hp = self.get_hparam(feature)
|
|
70
|
+
choices = (
|
|
71
|
+
{r * hp.original for r in features_ratio}
|
|
72
|
+
if features_ratio is not None
|
|
73
|
+
else set(hp.choices)
|
|
74
|
+
)
|
|
75
|
+
choices = {int(make_divisible(c, feature_divisor)) for c in choices}
|
|
76
|
+
hp.choices = list(set(hp.choices) & choices | {hp.original})
|
|
@@ -0,0 +1,193 @@
|
|
|
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
|
+
"""Dynamic norm implementations based on norm modules in torch.nn.modules."""
|
|
17
|
+
|
|
18
|
+
from collections.abc import Sequence
|
|
19
|
+
|
|
20
|
+
import torch
|
|
21
|
+
from torch import nn
|
|
22
|
+
|
|
23
|
+
from modelopt.torch.opt.dynamic import DynamicModule
|
|
24
|
+
from modelopt.torch.utils import make_divisible
|
|
25
|
+
|
|
26
|
+
from ..registry import DMRegistry
|
|
27
|
+
from ..traced_hp import TracedHp
|
|
28
|
+
from .utils import get_sliced_tensor
|
|
29
|
+
|
|
30
|
+
__all__ = ["_DynamicBatchNorm", "_DynamicGroupNorm", "_DynamicInstanceNorm", "_DynamicLayerNorm"]
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class _DynamicBatchInstance(DynamicModule):
|
|
34
|
+
"""Dynamic base class for batch norm and instance norm layers.
|
|
35
|
+
|
|
36
|
+
NOTE: Don't use this class for instance checks. Use _DynamicBatchNorm or _DynamicInstanceNorm
|
|
37
|
+
instead!
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
@staticmethod
|
|
41
|
+
def _cut_to_active_features(mod: "_DynamicBatchInstance", value: torch.Tensor | None):
|
|
42
|
+
return get_sliced_tensor(mod, value, "num_features")
|
|
43
|
+
|
|
44
|
+
def _setup(self):
|
|
45
|
+
# register hyperparameters
|
|
46
|
+
self._register_hparam("num_features", TracedHp(list(range(1, self.num_features + 1))))
|
|
47
|
+
|
|
48
|
+
# register dynamic attributes
|
|
49
|
+
dyn_attrs = ["running_mean", "running_var", "weight", "bias"]
|
|
50
|
+
for attr in dyn_attrs:
|
|
51
|
+
self._register_dynamic_attribute(attr, self._cut_to_active_features)
|
|
52
|
+
|
|
53
|
+
def modify(self, *, features_ratio: tuple[float, ...] | None = None, feature_divisor: int = 1):
|
|
54
|
+
"""Modify the dynamic choices of the module according to provided keyword arguments.
|
|
55
|
+
|
|
56
|
+
Args:
|
|
57
|
+
features_ratio: The ratios of the desired number of features over original number of
|
|
58
|
+
features.
|
|
59
|
+
feature_divisor: The divisor of the number of features.
|
|
60
|
+
"""
|
|
61
|
+
hp = self.get_hparam("num_features")
|
|
62
|
+
choices = (
|
|
63
|
+
{r * hp.original for r in features_ratio}
|
|
64
|
+
if features_ratio is not None
|
|
65
|
+
else set(hp.choices)
|
|
66
|
+
)
|
|
67
|
+
choices = {int(make_divisible(c, feature_divisor)) for c in choices}
|
|
68
|
+
hp.choices = list(set(hp.choices) & choices | {hp.original})
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
@DMRegistry.register(
|
|
72
|
+
{
|
|
73
|
+
nn.BatchNorm1d: "nn.BatchNorm1d",
|
|
74
|
+
nn.BatchNorm2d: "nn.BatchNorm2d",
|
|
75
|
+
nn.BatchNorm3d: "nn.BatchNorm3d",
|
|
76
|
+
nn.SyncBatchNorm: "nn.SyncBatchNorm",
|
|
77
|
+
}
|
|
78
|
+
)
|
|
79
|
+
class _DynamicBatchNorm(_DynamicBatchInstance):
|
|
80
|
+
"""Just syntactic sugar so we have a common base class for batch norm only."""
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
@DMRegistry.register(
|
|
84
|
+
{
|
|
85
|
+
nn.InstanceNorm1d: "nn.InstanceNorm1d",
|
|
86
|
+
nn.InstanceNorm2d: "nn.InstanceNorm2d",
|
|
87
|
+
nn.InstanceNorm3d: "nn.InstanceNorm3d",
|
|
88
|
+
}
|
|
89
|
+
)
|
|
90
|
+
class _DynamicInstanceNorm(_DynamicBatchInstance):
|
|
91
|
+
"""Just syntactic sugar so we have a common base class for instance norm only."""
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
@DMRegistry.register({nn.LayerNorm: "nn.LayerNorm"})
|
|
95
|
+
class _DynamicLayerNorm(DynamicModule):
|
|
96
|
+
"""An ``nn.LayerNorm`` layer with dynamic hyperparams."""
|
|
97
|
+
|
|
98
|
+
@staticmethod
|
|
99
|
+
def _get_normalized_shape(mod: "_DynamicLayerNorm", value: Sequence[int | TracedHp]) -> tuple:
|
|
100
|
+
return (*tuple(value[:-1]), mod.num_features)
|
|
101
|
+
|
|
102
|
+
@staticmethod
|
|
103
|
+
def _cut_to_active_features(
|
|
104
|
+
mod: "_DynamicLayerNorm", value: torch.Tensor | None
|
|
105
|
+
) -> torch.Tensor | None:
|
|
106
|
+
if value is None:
|
|
107
|
+
return value
|
|
108
|
+
nf_slice = mod.get_hparam("num_features").active_slice
|
|
109
|
+
return value[..., nf_slice].contiguous()
|
|
110
|
+
|
|
111
|
+
def _setup(self):
|
|
112
|
+
# construct normalized shape with Hparam as last dimension
|
|
113
|
+
normalized_shape = list(self.normalized_shape)
|
|
114
|
+
normalized_shape[-1] = TracedHp(list(range(1, normalized_shape[-1] + 1)))
|
|
115
|
+
|
|
116
|
+
# register the hyperparameter with a new name
|
|
117
|
+
self._register_hparam("num_features", normalized_shape[-1])
|
|
118
|
+
|
|
119
|
+
# register dynamic attributes
|
|
120
|
+
dyn_attrs = ["weight", "bias"]
|
|
121
|
+
for attr in dyn_attrs:
|
|
122
|
+
self._register_dynamic_attribute(attr, self._cut_to_active_features)
|
|
123
|
+
|
|
124
|
+
self._register_dynamic_attribute("normalized_shape", self._get_normalized_shape)
|
|
125
|
+
|
|
126
|
+
def modify(self, *, features_ratio: tuple[float, ...] | None = None, feature_divisor: int = 1):
|
|
127
|
+
"""Modify the dynamic choices of the module according to provided keyword arguments.
|
|
128
|
+
|
|
129
|
+
Args:
|
|
130
|
+
features_ratio: The ratios of the desired number of features over original number of
|
|
131
|
+
features.
|
|
132
|
+
feature_divisor: The divisor of the number of features.
|
|
133
|
+
"""
|
|
134
|
+
hp = self.get_hparam("num_features")
|
|
135
|
+
choices = (
|
|
136
|
+
{r * hp.original for r in features_ratio}
|
|
137
|
+
if features_ratio is not None
|
|
138
|
+
else set(hp.choices)
|
|
139
|
+
)
|
|
140
|
+
choices = {int(make_divisible(c, feature_divisor)) for c in choices}
|
|
141
|
+
hp.choices = list(set(hp.choices) & choices | {hp.original})
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
@DMRegistry.register({nn.GroupNorm: "nn.GroupNorm"})
|
|
145
|
+
class _DynamicGroupNorm(DynamicModule):
|
|
146
|
+
"""An ``nn.GroupNorm`` layer with dynamic hyperparams."""
|
|
147
|
+
|
|
148
|
+
_group_size: int
|
|
149
|
+
|
|
150
|
+
@staticmethod
|
|
151
|
+
def _get_num_groups(mod: "_DynamicGroupNorm", value: int) -> int:
|
|
152
|
+
return mod.num_channels // mod._group_size
|
|
153
|
+
|
|
154
|
+
@staticmethod
|
|
155
|
+
def _cut_to_active_channels(mod: "_DynamicGroupNorm", value: torch.Tensor | None):
|
|
156
|
+
return get_sliced_tensor(mod, value, "num_channels")
|
|
157
|
+
|
|
158
|
+
def _setup(self):
|
|
159
|
+
# register num_channels as hyperparameter
|
|
160
|
+
group_size = self.num_channels // self.num_groups
|
|
161
|
+
choices = [
|
|
162
|
+
c
|
|
163
|
+
for c in range(self.num_groups, self.num_channels + 1)
|
|
164
|
+
if c % self.num_groups == 0 and c % group_size == 0
|
|
165
|
+
]
|
|
166
|
+
self._register_hparam("num_channels", TracedHp(choices, original=self.num_channels))
|
|
167
|
+
|
|
168
|
+
# register num_groups as a dynamic attribute so group size is same
|
|
169
|
+
self._register_temp_attribute("_group_size", group_size)
|
|
170
|
+
self._register_dynamic_attribute("num_groups", self._get_num_groups)
|
|
171
|
+
|
|
172
|
+
# register dynamic attributes
|
|
173
|
+
dyn_attrs = ["weight", "bias"]
|
|
174
|
+
for attr in dyn_attrs:
|
|
175
|
+
self._register_dynamic_attribute(attr, self._cut_to_active_channels)
|
|
176
|
+
|
|
177
|
+
def modify(self, *, channels_ratio: tuple[float, ...] | None = None, channel_divisor: int = 1):
|
|
178
|
+
"""Modify the dynamic choices of the module according to provided keyword arguments.
|
|
179
|
+
|
|
180
|
+
Args:
|
|
181
|
+
channels_ratio: The ratios of the desired number of out/in channels over original
|
|
182
|
+
number of out/in channels.
|
|
183
|
+
channel_divisor: The divisor of the out/in channels.
|
|
184
|
+
"""
|
|
185
|
+
hp = self.get_hparam("num_channels")
|
|
186
|
+
choices: list[int]
|
|
187
|
+
choices = (
|
|
188
|
+
{r * hp.original for r in channels_ratio}
|
|
189
|
+
if channels_ratio is not None
|
|
190
|
+
else set(hp.choices)
|
|
191
|
+
)
|
|
192
|
+
choices = {int(make_divisible(c, channel_divisor)) for c in choices}
|
|
193
|
+
hp.choices = list(set(hp.choices) & choices | {hp.original})
|
|
@@ -0,0 +1,61 @@
|
|
|
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
|
+
"""Internal module for utility functions."""
|
|
17
|
+
|
|
18
|
+
import torch
|
|
19
|
+
|
|
20
|
+
from modelopt.torch.opt.dynamic import DynamicModule
|
|
21
|
+
from modelopt.torch.opt.hparam import Hparam
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def get_sliced_tensor_by_slices(
|
|
25
|
+
tensor: torch.Tensor | None,
|
|
26
|
+
slices: list[Hparam.ActiveSlice],
|
|
27
|
+
) -> torch.Tensor | None:
|
|
28
|
+
"""Get the tensor based on the active slice."""
|
|
29
|
+
if tensor is None:
|
|
30
|
+
return tensor
|
|
31
|
+
|
|
32
|
+
# check if we can return the original tensor
|
|
33
|
+
if all(
|
|
34
|
+
isinstance(s, slice) and (s.stop is None or s.indices(s.stop) == (0, tensor.shape[i], 1))
|
|
35
|
+
for i, s in enumerate(slices)
|
|
36
|
+
):
|
|
37
|
+
return tensor
|
|
38
|
+
|
|
39
|
+
# slice tensor with minimal number of index operations
|
|
40
|
+
tensor_sliced = tensor
|
|
41
|
+
for i, _ in enumerate(slices):
|
|
42
|
+
if sum(not isinstance(s, slice) for s in slices) < 2:
|
|
43
|
+
tensor_sliced = tensor_sliced[tuple(slices)]
|
|
44
|
+
break
|
|
45
|
+
tensor_sliced = tensor_sliced[tuple(slices[: i + 1])]
|
|
46
|
+
slices[i] = slice(None) # replace with a vanilla slice ("[:]") for next slicing iteration
|
|
47
|
+
|
|
48
|
+
# return sliced, contiguous tensor
|
|
49
|
+
return tensor_sliced.contiguous()
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def get_sliced_tensor(
|
|
53
|
+
mod: DynamicModule,
|
|
54
|
+
tensor: torch.Tensor | None,
|
|
55
|
+
*hp_names: str | None,
|
|
56
|
+
) -> torch.Tensor | None:
|
|
57
|
+
"""Get the tensor based on the slices."""
|
|
58
|
+
slices = [
|
|
59
|
+
mod.get_hparam(hp_name).active_slice if hp_name else slice(None) for hp_name in hp_names
|
|
60
|
+
]
|
|
61
|
+
return get_sliced_tensor_by_slices(tensor, slices)
|