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.
Files changed (272) hide show
  1. modelopt/__init__.py +20 -0
  2. modelopt/deploy/__init__.py +16 -0
  3. modelopt/deploy/llm/__init__.py +30 -0
  4. modelopt/deploy/llm/generate.py +345 -0
  5. modelopt/onnx/__init__.py +34 -0
  6. modelopt/onnx/autocast/__init__.py +19 -0
  7. modelopt/onnx/autocast/__main__.py +187 -0
  8. modelopt/onnx/autocast/convert.py +202 -0
  9. modelopt/onnx/autocast/graphsanitizer.py +422 -0
  10. modelopt/onnx/autocast/logging_config.py +78 -0
  11. modelopt/onnx/autocast/nodeclassifier.py +416 -0
  12. modelopt/onnx/autocast/precisionconverter.py +1032 -0
  13. modelopt/onnx/autocast/referencerunner.py +159 -0
  14. modelopt/onnx/autocast/utils.py +117 -0
  15. modelopt/onnx/llm_export_utils/__init__.py +16 -0
  16. modelopt/onnx/llm_export_utils/export_utils.py +162 -0
  17. modelopt/onnx/llm_export_utils/quantization_utils.py +122 -0
  18. modelopt/onnx/llm_export_utils/surgeon_utils.py +120 -0
  19. modelopt/onnx/logging_config.py +77 -0
  20. modelopt/onnx/op_types.py +300 -0
  21. modelopt/onnx/quantization/__init__.py +20 -0
  22. modelopt/onnx/quantization/__main__.py +291 -0
  23. modelopt/onnx/quantization/calib_utils.py +178 -0
  24. modelopt/onnx/quantization/extensions.py +35 -0
  25. modelopt/onnx/quantization/fp8.py +375 -0
  26. modelopt/onnx/quantization/graph_utils.py +1479 -0
  27. modelopt/onnx/quantization/gs_patching.py +112 -0
  28. modelopt/onnx/quantization/int4.py +1347 -0
  29. modelopt/onnx/quantization/int8.py +283 -0
  30. modelopt/onnx/quantization/operators.py +121 -0
  31. modelopt/onnx/quantization/ort_patching.py +1766 -0
  32. modelopt/onnx/quantization/ort_utils.py +346 -0
  33. modelopt/onnx/quantization/partitioning.py +439 -0
  34. modelopt/onnx/quantization/qdq_utils.py +1349 -0
  35. modelopt/onnx/quantization/quant_utils.py +283 -0
  36. modelopt/onnx/quantization/quantize.py +528 -0
  37. modelopt/onnx/quantization/src/modelopt_round_and_pack_ext.cpp +127 -0
  38. modelopt/onnx/trt_utils.py +424 -0
  39. modelopt/onnx/utils.py +753 -0
  40. modelopt/torch/__init__.py +41 -0
  41. modelopt/torch/_deploy/__init__.py +23 -0
  42. modelopt/torch/_deploy/_runtime/__init__.py +29 -0
  43. modelopt/torch/_deploy/_runtime/common.py +72 -0
  44. modelopt/torch/_deploy/_runtime/ort_client.py +193 -0
  45. modelopt/torch/_deploy/_runtime/registry.py +83 -0
  46. modelopt/torch/_deploy/_runtime/runtime_client.py +154 -0
  47. modelopt/torch/_deploy/_runtime/tensorrt/constants.py +108 -0
  48. modelopt/torch/_deploy/_runtime/tensorrt/engine_builder.py +324 -0
  49. modelopt/torch/_deploy/_runtime/tensorrt/hw_param_config.py +51 -0
  50. modelopt/torch/_deploy/_runtime/tensorrt/layerwise_profiling.py +178 -0
  51. modelopt/torch/_deploy/_runtime/tensorrt/parse_trtexec_log.py +151 -0
  52. modelopt/torch/_deploy/_runtime/tensorrt/tensorrt_utils.py +200 -0
  53. modelopt/torch/_deploy/_runtime/trt_client.py +219 -0
  54. modelopt/torch/_deploy/compilation.py +142 -0
  55. modelopt/torch/_deploy/device_model.py +157 -0
  56. modelopt/torch/_deploy/profiling.py +193 -0
  57. modelopt/torch/_deploy/utils/__init__.py +18 -0
  58. modelopt/torch/_deploy/utils/onnx_optimizer.py +120 -0
  59. modelopt/torch/_deploy/utils/onnx_utils.py +58 -0
  60. modelopt/torch/_deploy/utils/torch_onnx.py +593 -0
  61. modelopt/torch/distill/__init__.py +28 -0
  62. modelopt/torch/distill/config.py +130 -0
  63. modelopt/torch/distill/distillation.py +84 -0
  64. modelopt/torch/distill/distillation_model.py +318 -0
  65. modelopt/torch/distill/loss_balancers.py +140 -0
  66. modelopt/torch/distill/losses.py +275 -0
  67. modelopt/torch/distill/mode.py +223 -0
  68. modelopt/torch/distill/plugins/__init__.py +24 -0
  69. modelopt/torch/distill/plugins/huggingface.py +110 -0
  70. modelopt/torch/distill/plugins/megatron.py +476 -0
  71. modelopt/torch/distill/registry.py +23 -0
  72. modelopt/torch/export/__init__.py +24 -0
  73. modelopt/torch/export/convert_hf_config.py +117 -0
  74. modelopt/torch/export/distribute.py +300 -0
  75. modelopt/torch/export/hf_config_map.py +84 -0
  76. modelopt/torch/export/layer_utils.py +1893 -0
  77. modelopt/torch/export/mcore_config_map.py +25 -0
  78. modelopt/torch/export/model_config.py +623 -0
  79. modelopt/torch/export/model_config_export.py +552 -0
  80. modelopt/torch/export/model_config_utils.py +392 -0
  81. modelopt/torch/export/model_utils.py +71 -0
  82. modelopt/torch/export/plugins/__init__.py +21 -0
  83. modelopt/torch/export/plugins/mcore_common.py +67 -0
  84. modelopt/torch/export/plugins/mcore_custom.py +530 -0
  85. modelopt/torch/export/plugins/mcore_deepseek.py +143 -0
  86. modelopt/torch/export/plugins/mcore_gptoss.py +71 -0
  87. modelopt/torch/export/plugins/mcore_llama.py +164 -0
  88. modelopt/torch/export/plugins/mcore_nemotron.py +90 -0
  89. modelopt/torch/export/plugins/mcore_qwen.py +99 -0
  90. modelopt/torch/export/plugins/megatron_importer.py +647 -0
  91. modelopt/torch/export/postprocess.py +847 -0
  92. modelopt/torch/export/quant_utils.py +1069 -0
  93. modelopt/torch/export/tensorrt_llm_type.py +42 -0
  94. modelopt/torch/export/tensorrt_llm_utils.py +405 -0
  95. modelopt/torch/export/transformer_engine.py +94 -0
  96. modelopt/torch/export/unified_export_hf.py +537 -0
  97. modelopt/torch/export/unified_export_megatron.py +1164 -0
  98. modelopt/torch/nas/__init__.py +27 -0
  99. modelopt/torch/nas/algorithms.py +856 -0
  100. modelopt/torch/nas/autonas.py +808 -0
  101. modelopt/torch/nas/conversion.py +119 -0
  102. modelopt/torch/nas/hparams/__init__.py +19 -0
  103. modelopt/torch/nas/hparams/concat.py +319 -0
  104. modelopt/torch/nas/hparams/container.py +48 -0
  105. modelopt/torch/nas/modules/__init__.py +21 -0
  106. modelopt/torch/nas/modules/container.py +99 -0
  107. modelopt/torch/nas/modules/conv.py +254 -0
  108. modelopt/torch/nas/modules/linear.py +76 -0
  109. modelopt/torch/nas/modules/norm.py +193 -0
  110. modelopt/torch/nas/modules/utils.py +61 -0
  111. modelopt/torch/nas/patch.py +261 -0
  112. modelopt/torch/nas/plugins/__init__.py +29 -0
  113. modelopt/torch/nas/plugins/megatron.py +1497 -0
  114. modelopt/torch/nas/plugins/torch.py +71 -0
  115. modelopt/torch/nas/plugins/transformer_engine.py +42 -0
  116. modelopt/torch/nas/plugins/transformers.py +210 -0
  117. modelopt/torch/nas/registry.py +23 -0
  118. modelopt/torch/nas/search_space.py +260 -0
  119. modelopt/torch/nas/traced_hp.py +149 -0
  120. modelopt/torch/nas/utils.py +408 -0
  121. modelopt/torch/opt/__init__.py +41 -0
  122. modelopt/torch/opt/_hooks.py +98 -0
  123. modelopt/torch/opt/config.py +383 -0
  124. modelopt/torch/opt/conversion.py +620 -0
  125. modelopt/torch/opt/dynamic.py +1367 -0
  126. modelopt/torch/opt/hparam.py +275 -0
  127. modelopt/torch/opt/mode.py +353 -0
  128. modelopt/torch/opt/plugins/__init__.py +38 -0
  129. modelopt/torch/opt/plugins/diffusers.py +40 -0
  130. modelopt/torch/opt/plugins/huggingface.py +162 -0
  131. modelopt/torch/opt/plugins/mcore_dist_checkpointing.py +211 -0
  132. modelopt/torch/opt/plugins/megatron.py +142 -0
  133. modelopt/torch/opt/plugins/peft.py +108 -0
  134. modelopt/torch/opt/plugins/transformers.py +160 -0
  135. modelopt/torch/opt/searcher.py +363 -0
  136. modelopt/torch/opt/utils.py +125 -0
  137. modelopt/torch/prune/__init__.py +26 -0
  138. modelopt/torch/prune/fastnas.py +376 -0
  139. modelopt/torch/prune/gradnas.py +349 -0
  140. modelopt/torch/prune/plugins/__init__.py +24 -0
  141. modelopt/torch/prune/plugins/mcore_minitron.py +263 -0
  142. modelopt/torch/prune/plugins/transformers.py +41 -0
  143. modelopt/torch/prune/pruning.py +211 -0
  144. modelopt/torch/quantization/__init__.py +26 -0
  145. modelopt/torch/quantization/algorithms.py +671 -0
  146. modelopt/torch/quantization/backends/__init__.py +20 -0
  147. modelopt/torch/quantization/backends/fp8_per_tensor_gemm.py +204 -0
  148. modelopt/torch/quantization/backends/gemm_registry.py +156 -0
  149. modelopt/torch/quantization/backends/nvfp4_gemm.py +201 -0
  150. modelopt/torch/quantization/backends/utils.py +28 -0
  151. modelopt/torch/quantization/calib/__init__.py +25 -0
  152. modelopt/torch/quantization/calib/bias.py +172 -0
  153. modelopt/torch/quantization/calib/calibrator.py +63 -0
  154. modelopt/torch/quantization/calib/histogram.py +434 -0
  155. modelopt/torch/quantization/calib/max.py +110 -0
  156. modelopt/torch/quantization/compress.py +227 -0
  157. modelopt/torch/quantization/config.py +1180 -0
  158. modelopt/torch/quantization/conversion.py +389 -0
  159. modelopt/torch/quantization/export_onnx.py +639 -0
  160. modelopt/torch/quantization/extensions.py +89 -0
  161. modelopt/torch/quantization/mode.py +428 -0
  162. modelopt/torch/quantization/model_calib.py +949 -0
  163. modelopt/torch/quantization/model_quant.py +477 -0
  164. modelopt/torch/quantization/nn/__init__.py +26 -0
  165. modelopt/torch/quantization/nn/functional.py +109 -0
  166. modelopt/torch/quantization/nn/modules/__init__.py +16 -0
  167. modelopt/torch/quantization/nn/modules/quant_activations.py +22 -0
  168. modelopt/torch/quantization/nn/modules/quant_batchnorm.py +24 -0
  169. modelopt/torch/quantization/nn/modules/quant_conv.py +123 -0
  170. modelopt/torch/quantization/nn/modules/quant_instancenorm.py +39 -0
  171. modelopt/torch/quantization/nn/modules/quant_linear.py +258 -0
  172. modelopt/torch/quantization/nn/modules/quant_module.py +211 -0
  173. modelopt/torch/quantization/nn/modules/quant_pooling.py +99 -0
  174. modelopt/torch/quantization/nn/modules/quant_rnn.py +527 -0
  175. modelopt/torch/quantization/nn/modules/tensor_quantizer.py +1293 -0
  176. modelopt/torch/quantization/plugins/__init__.py +73 -0
  177. modelopt/torch/quantization/plugins/accelerate.py +214 -0
  178. modelopt/torch/quantization/plugins/apex.py +52 -0
  179. modelopt/torch/quantization/plugins/attention.py +312 -0
  180. modelopt/torch/quantization/plugins/custom.py +192 -0
  181. modelopt/torch/quantization/plugins/diffusers.py +237 -0
  182. modelopt/torch/quantization/plugins/fairscale.py +45 -0
  183. modelopt/torch/quantization/plugins/huggingface.py +736 -0
  184. modelopt/torch/quantization/plugins/megatron.py +462 -0
  185. modelopt/torch/quantization/plugins/peft.py +148 -0
  186. modelopt/torch/quantization/plugins/transformer_engine.py +60 -0
  187. modelopt/torch/quantization/plugins/transformers.py +52 -0
  188. modelopt/torch/quantization/plugins/transformers_trainer.py +426 -0
  189. modelopt/torch/quantization/plugins/trl.py +27 -0
  190. modelopt/torch/quantization/plugins/vllm.py +199 -0
  191. modelopt/torch/quantization/qtensor/__init__.py +24 -0
  192. modelopt/torch/quantization/qtensor/base_qtensor.py +370 -0
  193. modelopt/torch/quantization/qtensor/fp8_tensor.py +151 -0
  194. modelopt/torch/quantization/qtensor/int4_tensor.py +130 -0
  195. modelopt/torch/quantization/qtensor/int8_tensor.py +124 -0
  196. modelopt/torch/quantization/qtensor/mxfp4_tensor.py +144 -0
  197. modelopt/torch/quantization/qtensor/nf4_tensor.py +199 -0
  198. modelopt/torch/quantization/qtensor/nvfp4_tensor.py +295 -0
  199. modelopt/torch/quantization/src/tensor_quant.cpp +77 -0
  200. modelopt/torch/quantization/src/tensor_quant.h +69 -0
  201. modelopt/torch/quantization/src/tensor_quant_fp8.cpp +48 -0
  202. modelopt/torch/quantization/src/tensor_quant_gpu.cu +361 -0
  203. modelopt/torch/quantization/src/tensor_quant_gpu_fp8.cu +122 -0
  204. modelopt/torch/quantization/src/tensor_quant_mx.cu +411 -0
  205. modelopt/torch/quantization/src/tensor_quant_mx.h +247 -0
  206. modelopt/torch/quantization/tensor_quant.py +816 -0
  207. modelopt/torch/quantization/triton/__init__.py +36 -0
  208. modelopt/torch/quantization/triton/fp4_kernel.py +303 -0
  209. modelopt/torch/quantization/utils.py +443 -0
  210. modelopt/torch/sparsity/__init__.py +19 -0
  211. modelopt/torch/sparsity/config.py +51 -0
  212. modelopt/torch/sparsity/magnitude.py +148 -0
  213. modelopt/torch/sparsity/mode.py +203 -0
  214. modelopt/torch/sparsity/module.py +87 -0
  215. modelopt/torch/sparsity/plugins/__init__.py +27 -0
  216. modelopt/torch/sparsity/plugins/megatron.py +93 -0
  217. modelopt/torch/sparsity/searcher.py +84 -0
  218. modelopt/torch/sparsity/sparsegpt.py +276 -0
  219. modelopt/torch/sparsity/sparsification.py +123 -0
  220. modelopt/torch/speculative/__init__.py +20 -0
  221. modelopt/torch/speculative/config.py +100 -0
  222. modelopt/torch/speculative/eagle/__init__.py +20 -0
  223. modelopt/torch/speculative/eagle/conversion.py +67 -0
  224. modelopt/torch/speculative/eagle/default_config.py +50 -0
  225. modelopt/torch/speculative/eagle/eagle_model.py +51 -0
  226. modelopt/torch/speculative/eagle/utils.py +91 -0
  227. modelopt/torch/speculative/medusa/__init__.py +19 -0
  228. modelopt/torch/speculative/medusa/conversion.py +59 -0
  229. modelopt/torch/speculative/medusa/medusa_model.py +32 -0
  230. modelopt/torch/speculative/mode.py +86 -0
  231. modelopt/torch/speculative/plugins/__init__.py +33 -0
  232. modelopt/torch/speculative/plugins/megatron_eagle.py +2119 -0
  233. modelopt/torch/speculative/plugins/megatron_medusa.py +312 -0
  234. modelopt/torch/speculative/plugins/transformers.py +1138 -0
  235. modelopt/torch/speculative/speculative_decoding.py +59 -0
  236. modelopt/torch/speculative/utils.py +364 -0
  237. modelopt/torch/trace/__init__.py +25 -0
  238. modelopt/torch/trace/analyzer.py +1368 -0
  239. modelopt/torch/trace/modules/__init__.py +19 -0
  240. modelopt/torch/trace/modules/concat.py +384 -0
  241. modelopt/torch/trace/modules/nn.py +153 -0
  242. modelopt/torch/trace/plugins/__init__.py +34 -0
  243. modelopt/torch/trace/plugins/megatron.py +36 -0
  244. modelopt/torch/trace/plugins/transformers.py +58 -0
  245. modelopt/torch/trace/symbols.py +545 -0
  246. modelopt/torch/trace/tracer.py +331 -0
  247. modelopt/torch/utils/__init__.py +28 -0
  248. modelopt/torch/utils/_pytree.py +133 -0
  249. modelopt/torch/utils/cpp_extension.py +91 -0
  250. modelopt/torch/utils/dataset_utils.py +484 -0
  251. modelopt/torch/utils/distributed.py +311 -0
  252. modelopt/torch/utils/graph.py +123 -0
  253. modelopt/torch/utils/image_processor.py +112 -0
  254. modelopt/torch/utils/import_utils.py +35 -0
  255. modelopt/torch/utils/list.py +54 -0
  256. modelopt/torch/utils/logging.py +127 -0
  257. modelopt/torch/utils/memory_monitor.py +146 -0
  258. modelopt/torch/utils/network.py +658 -0
  259. modelopt/torch/utils/perf.py +174 -0
  260. modelopt/torch/utils/plugins/__init__.py +27 -0
  261. modelopt/torch/utils/plugins/megatron_generate.py +299 -0
  262. modelopt/torch/utils/plugins/megatron_mmlu.py +152 -0
  263. modelopt/torch/utils/plugins/megatron_preprocess_data.py +200 -0
  264. modelopt/torch/utils/random.py +163 -0
  265. modelopt/torch/utils/speech_dataset_utils.py +134 -0
  266. modelopt/torch/utils/tensor.py +87 -0
  267. modelopt/torch/utils/vlm_dataset_utils.py +110 -0
  268. nvidia_modelopt-0.35.0.dist-info/METADATA +171 -0
  269. nvidia_modelopt-0.35.0.dist-info/RECORD +272 -0
  270. nvidia_modelopt-0.35.0.dist-info/WHEEL +5 -0
  271. nvidia_modelopt-0.35.0.dist-info/licenses/LICENSE +14 -0
  272. 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)