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,484 @@
|
|
|
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
|
+
"""Utility functions for getting samples and forward loop function for different datasets."""
|
|
17
|
+
|
|
18
|
+
import copy
|
|
19
|
+
import math
|
|
20
|
+
from collections.abc import Callable
|
|
21
|
+
from typing import TYPE_CHECKING, Any
|
|
22
|
+
from warnings import warn
|
|
23
|
+
|
|
24
|
+
import torch
|
|
25
|
+
from torch.utils.data import DataLoader
|
|
26
|
+
from tqdm import tqdm
|
|
27
|
+
|
|
28
|
+
if TYPE_CHECKING:
|
|
29
|
+
from transformers import PreTrainedTokenizerBase
|
|
30
|
+
|
|
31
|
+
# Use dict to store the config for each dataset.
|
|
32
|
+
# If we want to export more options to user like target languages, we need more standardized approach like dataclass.
|
|
33
|
+
SUPPORTED_DATASET_CONFIG: dict[str, Any] = {
|
|
34
|
+
"open_code_reasoning": {
|
|
35
|
+
"config": {"path": "nvidia/OpenCodeReasoning", "name": "split_0", "split": ["split_0"]},
|
|
36
|
+
"preprocess": lambda sample: "\n".join([sample["input"], sample["output"]]),
|
|
37
|
+
},
|
|
38
|
+
"open_math_reasoning": {
|
|
39
|
+
"config": {
|
|
40
|
+
"path": "nvidia/OpenMathReasoning",
|
|
41
|
+
"split": ["cot", "tir", "genselect"],
|
|
42
|
+
},
|
|
43
|
+
"preprocess": lambda sample: "\n".join([sample["problem"], sample["generated_solution"]]),
|
|
44
|
+
},
|
|
45
|
+
"llama-nemotron-post-training-dataset": {
|
|
46
|
+
"config": {
|
|
47
|
+
"path": "nvidia/Llama-Nemotron-Post-Training-Dataset",
|
|
48
|
+
"name": "SFT",
|
|
49
|
+
"split": ["code", "math", "science", "chat", "safety"],
|
|
50
|
+
},
|
|
51
|
+
"preprocess": lambda sample: "\n".join(turn["content"] for turn in sample["input"])
|
|
52
|
+
+ "\n"
|
|
53
|
+
+ sample["output"],
|
|
54
|
+
},
|
|
55
|
+
"magpie": {
|
|
56
|
+
"config": {
|
|
57
|
+
"path": "Magpie-Align/Magpie-Pro-MT-300K-v0.1",
|
|
58
|
+
"split": ["train"],
|
|
59
|
+
},
|
|
60
|
+
"preprocess": lambda sample: "\n".join(turn["value"] for turn in sample["conversations"]),
|
|
61
|
+
},
|
|
62
|
+
"cnn_dailymail": {
|
|
63
|
+
"config": {"path": "cnn_dailymail", "name": "3.0.0", "split": ["train"]},
|
|
64
|
+
"preprocess": lambda sample: sample["article"],
|
|
65
|
+
},
|
|
66
|
+
"pile": {
|
|
67
|
+
"config": {"path": "monology/pile-uncopyrighted", "name": "v1.0", "split": ["train"]},
|
|
68
|
+
"preprocess": lambda sample: sample["text"],
|
|
69
|
+
},
|
|
70
|
+
"pg19": {
|
|
71
|
+
"config": {"path": "pg19", "name": "v1.0", "split": ["train"]},
|
|
72
|
+
"preprocess": lambda sample: sample["text"],
|
|
73
|
+
},
|
|
74
|
+
"wikipedia": {
|
|
75
|
+
"config": {"path": "wikipedia", "name": "20220301.en", "split": ["train"]},
|
|
76
|
+
"preprocess": lambda sample: sample["text"],
|
|
77
|
+
},
|
|
78
|
+
"c4": {
|
|
79
|
+
"config": {"path": "c4", "name": "en", "split": ["train"]},
|
|
80
|
+
"preprocess": lambda sample: sample["text"],
|
|
81
|
+
},
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
__all__ = [
|
|
85
|
+
"create_forward_loop",
|
|
86
|
+
"get_dataset_dataloader",
|
|
87
|
+
"get_max_batch_size",
|
|
88
|
+
"get_supported_datasets",
|
|
89
|
+
]
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def _get_dataset_samples(dataset_name: str, num_samples: int) -> list[str]:
|
|
93
|
+
"""Load a portion of train dataset with the dataset name and a given size.
|
|
94
|
+
|
|
95
|
+
Args:
|
|
96
|
+
dataset_name: Name of the dataset to load.
|
|
97
|
+
num_samples: Number of samples to load from the dataset.
|
|
98
|
+
|
|
99
|
+
Returns:
|
|
100
|
+
Samples: The list of samples.
|
|
101
|
+
"""
|
|
102
|
+
# Load the dataset
|
|
103
|
+
if dataset_name not in SUPPORTED_DATASET_CONFIG:
|
|
104
|
+
raise NotImplementedError(
|
|
105
|
+
f"dataset {dataset_name} is not supported. Please use one of the following:"
|
|
106
|
+
f" {get_supported_datasets()}."
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
from datasets import load_dataset
|
|
110
|
+
|
|
111
|
+
dataset_config = SUPPORTED_DATASET_CONFIG[dataset_name]
|
|
112
|
+
# It's unfortunate that the load_dataset function does not support split a list while streaming.
|
|
113
|
+
# So we need to load the dataset for each split.
|
|
114
|
+
config = dataset_config["config"].copy()
|
|
115
|
+
splits = config.pop("split", [None])
|
|
116
|
+
dataset_splits = [
|
|
117
|
+
load_dataset(
|
|
118
|
+
streaming=True,
|
|
119
|
+
**config,
|
|
120
|
+
split=split,
|
|
121
|
+
)
|
|
122
|
+
for split in splits
|
|
123
|
+
]
|
|
124
|
+
|
|
125
|
+
# Split the samples evenly across the splits
|
|
126
|
+
# For streaming datasets, there is no reliable way to get the number of samples in each split
|
|
127
|
+
# other than loading the entire dataset. So, we just use the same number of samples for each split.
|
|
128
|
+
num_samples_splits = [num_samples // len(dataset_splits) for _ in dataset_splits]
|
|
129
|
+
num_samples_splits[-1] += num_samples - sum(num_samples_splits)
|
|
130
|
+
samples = []
|
|
131
|
+
for dataset, num_samples_split in zip(dataset_splits, num_samples_splits):
|
|
132
|
+
for i, sample in enumerate(dataset):
|
|
133
|
+
if i >= num_samples_split:
|
|
134
|
+
break
|
|
135
|
+
|
|
136
|
+
# Apply preprocess function to the sample
|
|
137
|
+
samples.append(dataset_config["preprocess"](sample))
|
|
138
|
+
|
|
139
|
+
return samples
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
class _CustomDataset(torch.utils.data.Dataset):
|
|
143
|
+
def __init__(self, encodings):
|
|
144
|
+
self.encodings = encodings
|
|
145
|
+
|
|
146
|
+
def __getitem__(self, idx):
|
|
147
|
+
item = {
|
|
148
|
+
key: val[idx] if torch.is_tensor(val[idx]) else torch.tensor(val[idx])
|
|
149
|
+
for key, val in self.encodings.items()
|
|
150
|
+
}
|
|
151
|
+
return item
|
|
152
|
+
|
|
153
|
+
def __len__(self):
|
|
154
|
+
return len(next(iter(self.encodings.values())))
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def get_dataset_dataloader(
|
|
158
|
+
dataset_name: str | list[str] = "cnn_dailymail",
|
|
159
|
+
tokenizer: "PreTrainedTokenizerBase | None" = None,
|
|
160
|
+
batch_size: int = 1,
|
|
161
|
+
num_samples: int | list[int] = 512,
|
|
162
|
+
max_sample_length: int = 512,
|
|
163
|
+
device: str | None = None,
|
|
164
|
+
include_labels: bool = False,
|
|
165
|
+
) -> DataLoader:
|
|
166
|
+
"""Get a dataloader with the dataset name and toknizer of the target model.
|
|
167
|
+
|
|
168
|
+
Args:
|
|
169
|
+
dataset_name: Name of the dataset to load.
|
|
170
|
+
tokenizer: Instancne of Hugginface tokenizer.
|
|
171
|
+
batch_size: Batch size of the returned dataloader.
|
|
172
|
+
num_samples: Number of samples from the dataset.
|
|
173
|
+
max_sample_length: Maximum length of a sample.
|
|
174
|
+
device: Target device for the returned dataloader.
|
|
175
|
+
include_labels: Whether to include labels in the dataloader.
|
|
176
|
+
|
|
177
|
+
Returns:
|
|
178
|
+
A instance of dataloader.
|
|
179
|
+
"""
|
|
180
|
+
assert tokenizer is not None, "Please provide a tokenizer."
|
|
181
|
+
# batch_encode_plus will modify the tokenizer in place, so we need to clone it.
|
|
182
|
+
tokenizer = copy.deepcopy(tokenizer)
|
|
183
|
+
|
|
184
|
+
if tokenizer.padding_side != "left":
|
|
185
|
+
warn(
|
|
186
|
+
"Tokenizer with the right padding_side may impact calibration accuracy. Recommend set to left"
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
if isinstance(num_samples, int):
|
|
190
|
+
num_samples = [num_samples]
|
|
191
|
+
|
|
192
|
+
if isinstance(dataset_name, str):
|
|
193
|
+
dataset_name = [dataset_name]
|
|
194
|
+
|
|
195
|
+
num_samples = [math.ceil(num_sample / batch_size) * batch_size for num_sample in num_samples]
|
|
196
|
+
|
|
197
|
+
assert len(dataset_name) == len(num_samples), (
|
|
198
|
+
"dataset_name and num_samples must be the same length"
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
all_samples = []
|
|
202
|
+
for ds_name, num_sample in zip(dataset_name, num_samples):
|
|
203
|
+
samples = _get_dataset_samples(ds_name, num_sample)
|
|
204
|
+
all_samples.extend(samples)
|
|
205
|
+
|
|
206
|
+
batch_encoded = tokenizer.batch_encode_plus(
|
|
207
|
+
all_samples,
|
|
208
|
+
return_tensors="pt",
|
|
209
|
+
padding=True,
|
|
210
|
+
truncation=True,
|
|
211
|
+
max_length=max_sample_length,
|
|
212
|
+
)
|
|
213
|
+
if device:
|
|
214
|
+
batch_encoded = batch_encoded.to(device)
|
|
215
|
+
|
|
216
|
+
if include_labels:
|
|
217
|
+
# Labels are needed when backward is called in the model.
|
|
218
|
+
# The labels should be a shifted version of the input_ids.
|
|
219
|
+
# However, we should not shift the input_ids here since the labels are shifted by
|
|
220
|
+
# Huggingface models during loss calculation as shown here -
|
|
221
|
+
# https://github.com/huggingface/transformers/blob/7f79a97399bb52aad8460e1da2f36577d5dccfed/src/transformers/models/llama/modeling_llama.py#L1093-L1095
|
|
222
|
+
batch_encoded["labels"] = torch.where(
|
|
223
|
+
batch_encoded["attention_mask"] > 0.5, batch_encoded["input_ids"], -100
|
|
224
|
+
)
|
|
225
|
+
tokenized_dataset = _CustomDataset(batch_encoded)
|
|
226
|
+
else:
|
|
227
|
+
# For backward compatibility, if labels are not needed, we only return the input_ids.
|
|
228
|
+
tokenized_dataset = _CustomDataset({"input_ids": batch_encoded["input_ids"]})
|
|
229
|
+
|
|
230
|
+
calib_dataloader = DataLoader(tokenized_dataset, batch_size=batch_size, shuffle=False)
|
|
231
|
+
|
|
232
|
+
return calib_dataloader
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
def get_supported_datasets() -> list[str]:
|
|
236
|
+
"""Retrieves a list of datasets supported.
|
|
237
|
+
|
|
238
|
+
Returns:
|
|
239
|
+
A list of strings, where each string is the name of a supported dataset.
|
|
240
|
+
|
|
241
|
+
Example usage:
|
|
242
|
+
|
|
243
|
+
.. code-block:: python
|
|
244
|
+
|
|
245
|
+
from modelopt.torch.utils import get_supported_datasets
|
|
246
|
+
|
|
247
|
+
print("Supported datasets:", get_supported_datasets())
|
|
248
|
+
"""
|
|
249
|
+
return list(SUPPORTED_DATASET_CONFIG.keys())
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
def get_max_batch_size(
|
|
253
|
+
model: torch.nn.Module,
|
|
254
|
+
max_sample_length: int = 512,
|
|
255
|
+
sample_memory_usage_ratio: float = 1.0,
|
|
256
|
+
sample_input_single_batch: torch.Tensor = None,
|
|
257
|
+
enable_grad: bool = False,
|
|
258
|
+
):
|
|
259
|
+
"""Get the maximum batch size that can be used for the model."""
|
|
260
|
+
|
|
261
|
+
def _get_free_gpu_mem():
|
|
262
|
+
min_gpu_free_mem = torch.cuda.get_device_properties(0).total_memory
|
|
263
|
+
max_allocated_mem = 0
|
|
264
|
+
for device in range(torch.cuda.device_count()):
|
|
265
|
+
free_mem = torch.cuda.mem_get_info(device)[0]
|
|
266
|
+
if free_mem < min_gpu_free_mem:
|
|
267
|
+
min_gpu_free_mem = free_mem
|
|
268
|
+
max_allocated_mem = torch.cuda.max_memory_allocated(device)
|
|
269
|
+
return min_gpu_free_mem, max_allocated_mem
|
|
270
|
+
|
|
271
|
+
torch.cuda.empty_cache()
|
|
272
|
+
|
|
273
|
+
free_mem_before, max_allocated_before = _get_free_gpu_mem()
|
|
274
|
+
is_enc_dec = model_type_is_enc_dec(model)
|
|
275
|
+
infer_method = model.generate if is_enc_dec else model.forward
|
|
276
|
+
|
|
277
|
+
if sample_input_single_batch is None:
|
|
278
|
+
sample_input_single_batch = (
|
|
279
|
+
torch.ones([1, max_sample_length], dtype=torch.int32, device=model.device) * 100
|
|
280
|
+
)
|
|
281
|
+
|
|
282
|
+
# Calculate single batch inference with dummy input.
|
|
283
|
+
with torch.set_grad_enabled(enable_grad):
|
|
284
|
+
infer_method(sample_input_single_batch)
|
|
285
|
+
free_mem_after, max_allocated_after = _get_free_gpu_mem()
|
|
286
|
+
|
|
287
|
+
mem_diff_per_data_batch = (
|
|
288
|
+
max(
|
|
289
|
+
(free_mem_before - free_mem_after),
|
|
290
|
+
(max_allocated_after - max_allocated_before),
|
|
291
|
+
)
|
|
292
|
+
* sample_memory_usage_ratio
|
|
293
|
+
)
|
|
294
|
+
if mem_diff_per_data_batch <= 0:
|
|
295
|
+
print(
|
|
296
|
+
"Warning: No measurable memory usage found for a single batch. "
|
|
297
|
+
"Falling back to batch_size=1."
|
|
298
|
+
)
|
|
299
|
+
target_data_batch = 1
|
|
300
|
+
else:
|
|
301
|
+
target_data_batch = max(int(free_mem_before / mem_diff_per_data_batch), 1)
|
|
302
|
+
target_input = sample_input_single_batch.expand(
|
|
303
|
+
[
|
|
304
|
+
target_data_batch if index == 0 else dim
|
|
305
|
+
for index, dim in enumerate(sample_input_single_batch.shape)
|
|
306
|
+
]
|
|
307
|
+
)
|
|
308
|
+
|
|
309
|
+
# For some models on multi GPU, we observe the memory per batch is not a constant.
|
|
310
|
+
# So we just test the target batch size and make sure we do not go OOM.
|
|
311
|
+
while target_data_batch > 1:
|
|
312
|
+
with torch.set_grad_enabled(enable_grad):
|
|
313
|
+
try:
|
|
314
|
+
infer_method(target_input)
|
|
315
|
+
break
|
|
316
|
+
except torch.cuda.OutOfMemoryError:
|
|
317
|
+
target_data_batch = target_data_batch // 2
|
|
318
|
+
|
|
319
|
+
# Regulate the data batch target to be 1, 2, 4, 8, 12, ..., capped at 64
|
|
320
|
+
if target_data_batch < 2:
|
|
321
|
+
return 1
|
|
322
|
+
elif target_data_batch < 4:
|
|
323
|
+
return 2
|
|
324
|
+
elif target_data_batch < 64:
|
|
325
|
+
return target_data_batch // 4 * 4
|
|
326
|
+
else:
|
|
327
|
+
return 64
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
def _process_batch(batch_data, infer_method, max_working_batch_size=None):
|
|
331
|
+
"""Process a batch of data through the model's inference method.
|
|
332
|
+
|
|
333
|
+
Args:
|
|
334
|
+
batch_data: Dictionary containing the batch data
|
|
335
|
+
infer_method: Model's inference method (either forward or generate)
|
|
336
|
+
max_working_batch_size: Maximum batch size known to work without OOM
|
|
337
|
+
|
|
338
|
+
Returns:
|
|
339
|
+
The maximum batch size that worked successfully
|
|
340
|
+
"""
|
|
341
|
+
assert all(torch.is_tensor(data) or data is None for data in batch_data.values()), (
|
|
342
|
+
"batch_data values must be tensors"
|
|
343
|
+
)
|
|
344
|
+
# Get the batch size of current data
|
|
345
|
+
batch_size = batch_data[next(iter(batch_data.keys()))].shape[0]
|
|
346
|
+
|
|
347
|
+
# If we know a smaller batch size works, preemptively split
|
|
348
|
+
if max_working_batch_size is not None and batch_size > max_working_batch_size:
|
|
349
|
+
# Split the batch to avoid OOM
|
|
350
|
+
for i in range(0, batch_size, max_working_batch_size):
|
|
351
|
+
end_idx = min(i + max_working_batch_size, batch_size)
|
|
352
|
+
split_data = {}
|
|
353
|
+
for key in batch_data:
|
|
354
|
+
if batch_data[key] is None:
|
|
355
|
+
split_data[key] = None
|
|
356
|
+
else:
|
|
357
|
+
split_data[key] = batch_data[key][i:end_idx, ...]
|
|
358
|
+
|
|
359
|
+
max_working_batch_size = _process_batch(
|
|
360
|
+
split_data, infer_method, max_working_batch_size
|
|
361
|
+
)
|
|
362
|
+
|
|
363
|
+
return max_working_batch_size
|
|
364
|
+
|
|
365
|
+
# Try processing with current batch size
|
|
366
|
+
try:
|
|
367
|
+
infer_method(**batch_data)
|
|
368
|
+
return (
|
|
369
|
+
batch_size
|
|
370
|
+
if max_working_batch_size is None
|
|
371
|
+
else max(batch_size, max_working_batch_size)
|
|
372
|
+
) # This batch size worked successfully
|
|
373
|
+
except torch.cuda.OutOfMemoryError:
|
|
374
|
+
assert batch_size > 1, (
|
|
375
|
+
"CUDA out of memory error occurred while processing a single sample. "
|
|
376
|
+
"This indicates the model is too large for the available GPU memory. "
|
|
377
|
+
"Consider reducing the model size, using a smaller max_sample_length, "
|
|
378
|
+
"or using a GPU with more memory."
|
|
379
|
+
)
|
|
380
|
+
|
|
381
|
+
# Split the batch in half
|
|
382
|
+
mid = (batch_size + 1) // 2
|
|
383
|
+
warn(f"CUDA out of memory with batch size {batch_size}, trying with batch size {mid}")
|
|
384
|
+
split_data_1 = {key: batch_data[key][:mid, ...] for key in batch_data}
|
|
385
|
+
split_data_2 = {key: batch_data[key][mid:, ...] for key in batch_data}
|
|
386
|
+
|
|
387
|
+
# Recursively process each half and track max working batch size
|
|
388
|
+
max_working_batch_size = _process_batch(split_data_1, infer_method)
|
|
389
|
+
max_working_batch_size = _process_batch(split_data_2, infer_method, max_working_batch_size)
|
|
390
|
+
|
|
391
|
+
# Return the minimum of the two (to be conservative)
|
|
392
|
+
return max_working_batch_size
|
|
393
|
+
|
|
394
|
+
|
|
395
|
+
def _forward_loop(model: torch.nn.Module, dataloader: DataLoader) -> None:
|
|
396
|
+
"""Runs forward passes through the model using data from the dataloader.
|
|
397
|
+
|
|
398
|
+
Args:
|
|
399
|
+
model: The PyTorch model to run inference on
|
|
400
|
+
dataloader: DataLoader containing the batched input data
|
|
401
|
+
"""
|
|
402
|
+
with torch.no_grad():
|
|
403
|
+
is_enc_dec = model_type_is_enc_dec(model)
|
|
404
|
+
infer_method = model.generate if is_enc_dec else model.forward
|
|
405
|
+
max_working_batch_size = None # Initialize max working batch size as None
|
|
406
|
+
|
|
407
|
+
for _, data in enumerate(tqdm(dataloader)):
|
|
408
|
+
# Process batch and update max working batch size
|
|
409
|
+
max_working_batch_size = _process_batch(data, infer_method, max_working_batch_size)
|
|
410
|
+
|
|
411
|
+
|
|
412
|
+
def create_forward_loop(
|
|
413
|
+
model: torch.nn.Module | None = None,
|
|
414
|
+
dataset_name: str = "cnn_dailymail",
|
|
415
|
+
tokenizer: "PreTrainedTokenizerBase | None" = None,
|
|
416
|
+
batch_size: int = 1,
|
|
417
|
+
num_samples: int = 512,
|
|
418
|
+
max_sample_length: int = 512,
|
|
419
|
+
device: str | None = None,
|
|
420
|
+
include_labels: bool = False,
|
|
421
|
+
dataloader: DataLoader | None = None,
|
|
422
|
+
) -> Callable:
|
|
423
|
+
"""Creates and returns a forward loop function configured for a specific model, dataset, and tokenizer.
|
|
424
|
+
|
|
425
|
+
This function initializes a forward loop function tailored to process batches of data from the specified dataset
|
|
426
|
+
using the given model and tokenizer. The forward loop function, when called, iterates over the dataset, applies the
|
|
427
|
+
tokenizer to prepare the input data, feeds it into the model, and returns the model's predictions.
|
|
428
|
+
|
|
429
|
+
Args:
|
|
430
|
+
model: The PyTorch model for inference.
|
|
431
|
+
dataset_name: The name of the dataset to be used. Must be one of the datasets in get_supported_datasets().
|
|
432
|
+
tokenizer: The tokenizer used to preprocess text data into a format suitable
|
|
433
|
+
for the model.
|
|
434
|
+
batch_size: Batch size of the returned dataloader. If 0 is provided, we auto determine the batch_size.
|
|
435
|
+
num_samples: Number of samples from the dataset.
|
|
436
|
+
max_sample_length: Maximum length of a sample.
|
|
437
|
+
device: Target device for the returned dataloader.
|
|
438
|
+
include_labels: Whether to include labels in the dataloader.
|
|
439
|
+
dataloader: If provided, use the provided dataloader instead.
|
|
440
|
+
|
|
441
|
+
Example usage for quantization:
|
|
442
|
+
|
|
443
|
+
.. code-block:: python
|
|
444
|
+
|
|
445
|
+
import modelopt.torch.quantization as mtq
|
|
446
|
+
from modelopt.torch.utils import create_forward_loop
|
|
447
|
+
|
|
448
|
+
# Initialize model and tokenizer
|
|
449
|
+
# ...
|
|
450
|
+
|
|
451
|
+
# Create forward loop for calibration
|
|
452
|
+
forward_loop = create_forward_loop(
|
|
453
|
+
model=model, dataset_name="cnn_dailymail", tokenizer=tokenizer
|
|
454
|
+
)
|
|
455
|
+
|
|
456
|
+
# Quantize the model with the calibration dataset
|
|
457
|
+
mtq.quantize(model, quant_cfg, forward_loop=forward_loop)
|
|
458
|
+
|
|
459
|
+
Returns:
|
|
460
|
+
A forward loop function that can be called with no arguments. When called, this function iterates over
|
|
461
|
+
the dataset specified by `dataset_name`.
|
|
462
|
+
"""
|
|
463
|
+
if dataloader is None:
|
|
464
|
+
if batch_size == 0:
|
|
465
|
+
# We let the system to determine the max data batch for each forward.
|
|
466
|
+
batch_size = get_max_batch_size(model, max_sample_length)
|
|
467
|
+
print(f"Update calib batch {batch_size}")
|
|
468
|
+
|
|
469
|
+
dataloader = get_dataset_dataloader(
|
|
470
|
+
dataset_name=dataset_name,
|
|
471
|
+
tokenizer=tokenizer,
|
|
472
|
+
batch_size=batch_size,
|
|
473
|
+
num_samples=num_samples,
|
|
474
|
+
max_sample_length=max_sample_length,
|
|
475
|
+
device=device,
|
|
476
|
+
include_labels=include_labels,
|
|
477
|
+
)
|
|
478
|
+
|
|
479
|
+
return lambda model: _forward_loop(model, dataloader)
|
|
480
|
+
|
|
481
|
+
|
|
482
|
+
def model_type_is_enc_dec(model):
|
|
483
|
+
enc_dec_model_list = ["t5", "bart", "whisper"]
|
|
484
|
+
return any(model_name in model.__class__.__name__.lower() for model_name in enc_dec_model_list)
|