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,1138 @@
1
+ # Adapted from: https://github.com/ctlllll/axolotl/blob/f86767e/src/axolotl/monkeypatch/medusa_utils.py
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ # SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
16
+ # SPDX-License-Identifier: Apache-2.0
17
+ #
18
+ # Licensed under the Apache License, Version 2.0 (the "License");
19
+ # you may not use this file except in compliance with the License.
20
+ # You may obtain a copy of the License at
21
+ #
22
+ # http://www.apache.org/licenses/LICENSE-2.0
23
+ #
24
+ # Unless required by applicable law or agreed to in writing, software
25
+ # distributed under the License is distributed on an "AS IS" BASIS,
26
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
27
+ # See the License for the specific language governing permissions and
28
+ # limitations under the License.
29
+
30
+ """Support speculative decoding for huggingface models."""
31
+
32
+ import contextlib
33
+ import copy
34
+ from typing import Any
35
+
36
+ import torch
37
+ from torch import nn
38
+ from torch.nn import CrossEntropyLoss
39
+ from transformers import Cache, DynamicCache, PretrainedConfig, PreTrainedModel
40
+ from transformers.models.llama.modeling_llama import (
41
+ LlamaAttention,
42
+ LlamaDecoderLayer,
43
+ LlamaRMSNorm,
44
+ LlamaRotaryEmbedding,
45
+ )
46
+ from transformers.trainer_pt_utils import LabelSmoother
47
+ from transformers.utils import ModelOutput
48
+
49
+ from ..eagle.conversion import EagleDMRegistry, OfflineEagleDMRegistry
50
+ from ..eagle.eagle_model import EagleModel
51
+ from ..eagle.utils import RMSNorm, expand_mask, make_causal_mask
52
+ from ..medusa.conversion import MedusaDMRegistry
53
+ from ..medusa.medusa_model import MedusaModel
54
+ from ..utils import AcceptanceRateValidation, ResBlock
55
+
56
+ IGNORE_TOKEN_ID = LabelSmoother.ignore_index
57
+
58
+
59
+ @MedusaDMRegistry.register({PreTrainedModel: "hf.PreTrainedModel"})
60
+ class HFMedusaModel(MedusaModel):
61
+ """Medusa Model Class for huggingface models."""
62
+
63
+ def modify(self, medusa_num_heads=0, medusa_num_layers=0):
64
+ """Constructor.
65
+
66
+ Args:
67
+ medusa_num_heads: number of medusa heads.
68
+ medusa_num_layers: number of ResBlock layers in each head.
69
+ """
70
+ super().modify(medusa_num_heads=medusa_num_heads, medusa_num_layers=medusa_num_layers)
71
+ self.config.medusa = {
72
+ "num_medusa_heads": medusa_num_heads,
73
+ "num_medusa_layers": medusa_num_layers,
74
+ }
75
+
76
+ hidden_size = self.lm_head.weight.shape[-1]
77
+ vocab_size = self.lm_head.weight.shape[0]
78
+
79
+ # Create a list of Medusa heads
80
+ self.medusa_heads = nn.ModuleList(
81
+ [
82
+ nn.Sequential(
83
+ *([ResBlock(hidden_size)] * self.medusa_num_layers),
84
+ nn.Linear(hidden_size, vocab_size, bias=False),
85
+ )
86
+ for _ in range(self.medusa_num_heads)
87
+ ]
88
+ )
89
+
90
+ # Ensure medusa_head's dtype and device align with the base_model
91
+ self.medusa_heads.to(self.lm_head.weight.dtype).to(self.lm_head.weight.device)
92
+ self.medusa_heads.device = self.lm_head.weight.device
93
+ if hasattr(self, "hf_device_map") and "lm_head" in self.hf_device_map:
94
+ self.hf_device_map["medusa_heads"] = self.hf_device_map["lm_head"]
95
+
96
+ def forward(
97
+ self,
98
+ input_ids: torch.LongTensor | None = None,
99
+ attention_mask: torch.Tensor | None = None,
100
+ position_ids: torch.LongTensor | None = None,
101
+ past_key_values: Cache | None = None,
102
+ inputs_embeds: torch.FloatTensor | None = None,
103
+ labels: torch.LongTensor | None = None,
104
+ use_cache: bool | None = None,
105
+ output_attentions: bool | None = None,
106
+ output_hidden_states: bool | None = None,
107
+ cache_position: torch.LongTensor | None = None,
108
+ logits_to_keep: int | torch.Tensor = 0,
109
+ freeze_base_model: bool = True,
110
+ medusa_heads_coefficient: float | None = 0.2,
111
+ medusa_decay_coefficient: float | None = 0.8,
112
+ **kwargs,
113
+ ) -> Any:
114
+ """Forward pass of the MedusaModel.
115
+
116
+ Returns:
117
+ torch.Tensor: A tensor containing predictions from all Medusa heads.
118
+ """
119
+ # Pass input through the base model
120
+ with torch.no_grad() if freeze_base_model else contextlib.nullcontext():
121
+ outputs = self.model(
122
+ input_ids=input_ids,
123
+ attention_mask=attention_mask,
124
+ position_ids=position_ids,
125
+ past_key_values=past_key_values,
126
+ inputs_embeds=inputs_embeds,
127
+ use_cache=use_cache,
128
+ output_attentions=output_attentions,
129
+ output_hidden_states=output_hidden_states,
130
+ rcache_position=cache_position,
131
+ **kwargs,
132
+ )
133
+ hidden_states = outputs.last_hidden_state
134
+ # Only compute necessary logits, and do not upcast them to float if we are not computing the loss
135
+ slice_indices = (
136
+ slice(-logits_to_keep, None) if isinstance(logits_to_keep, int) else logits_to_keep
137
+ )
138
+ logits = self.lm_head(hidden_states[:, slice_indices, :])
139
+
140
+ medusa_logits = [
141
+ self.medusa_heads[i](hidden_states[:, slice_indices, :])
142
+ for i in range(self.medusa_num_heads)
143
+ ]
144
+
145
+ if labels is not None:
146
+ loss = 0
147
+ loss_fct = CrossEntropyLoss()
148
+ # Base model loss
149
+ if not freeze_base_model:
150
+ loss_logits = logits.view(-1, logits.shape[-1])
151
+ loss_labels = labels.view(-1)
152
+ base_model_loss = loss_fct(loss_logits, loss_labels)
153
+ loss += base_model_loss
154
+ # Medusa loss
155
+ for i in range(self.medusa_num_heads):
156
+ labels = labels[..., 1:].contiguous()
157
+ loss_logits = medusa_logits[i][:, : -(1 + i)].contiguous()
158
+ loss_logits = loss_logits.view(-1, loss_logits.shape[-1])
159
+ loss_labels = labels.view(-1)
160
+ loss += (
161
+ loss_fct(loss_logits, loss_labels)
162
+ * medusa_decay_coefficient**i
163
+ * medusa_heads_coefficient
164
+ )
165
+ else:
166
+ loss = None
167
+
168
+ return ModelOutput(
169
+ loss=loss,
170
+ logits=logits,
171
+ medusa_logits=medusa_logits,
172
+ past_key_values=outputs.past_key_values,
173
+ hidden_states=outputs.hidden_states,
174
+ attentions=outputs.attentions,
175
+ )
176
+
177
+
178
+ class EagleModule(nn.Module):
179
+ """Eagle module used in EAGLE model."""
180
+
181
+ def __init__(self, config, decoder_layer_cls, bias=False):
182
+ """Init function for EagleModule."""
183
+ super().__init__()
184
+ self.config = config
185
+
186
+ # NOTE:This is a temporary fix to support Qwen and Mixtral in current release.
187
+ # This is refactored in following MR.
188
+ config_overwrite = {
189
+ "mlp_bias": False,
190
+ "attention_bias": False,
191
+ "head_dim": self.config.hidden_size // self.config.num_attention_heads,
192
+ }
193
+ for key, value in config_overwrite.items():
194
+ setattr(self.config, key, value)
195
+
196
+ self.layers = nn.ModuleList(
197
+ [decoder_layer_cls(config, layer_idx) for layer_idx in range(config.num_hidden_layers)]
198
+ )
199
+ if config.use_last_layernorm:
200
+ self.norm = RMSNorm(config.hidden_size, config.rms_norm_eps)
201
+
202
+ # Optionally, we use a smaller vocab table for eagle module
203
+ if config.draft_vocab_size != config.vocab_size or config.has_lm_head:
204
+ # Need an extra lm_head for eagle module since vocab size is reduced.
205
+ assert config.draft_vocab_size <= config.vocab_size, (
206
+ "EAGLE module's vocab size should be <= base model vocab size!"
207
+ )
208
+
209
+ # Initialize the buffers to zero.
210
+ # Their values depend on specific tokenzier and calibrate dataset, and should be set in training script.
211
+ if config.draft_vocab_size < config.vocab_size:
212
+ self.register_buffer("d2t", torch.zeros(config.draft_vocab_size, dtype=torch.int64))
213
+ self.eagle_lm_head = nn.Linear(
214
+ config.hidden_size,
215
+ config.draft_vocab_size,
216
+ bias=False,
217
+ )
218
+
219
+ if not config.use_aux_hidden_state:
220
+ # In Eagle-1, the FC concentrate input embeddings and hidden states
221
+ self.fc = nn.Linear(2 * config.hidden_size, config.hidden_size, bias=bias)
222
+ else:
223
+ # In EAGLE-3, the FC concentrate hidden states from multiple base model layers
224
+ self.fc = nn.Linear(
225
+ len(config.eagle_aux_hidden_state_layer_ids) * config.hidden_size,
226
+ config.hidden_size,
227
+ bias=bias,
228
+ )
229
+
230
+ first_layer_attn = self.layers[0].self_attn
231
+ if not isinstance(first_layer_attn, LlamaAttention):
232
+ raise ValueError("EAGLE-3 only support LlamaAttention.")
233
+
234
+ # EAGLE-3's first attention require [input_layernorm_output, aux_hidden_states]
235
+ first_layer_attn.register_forward_pre_hook(
236
+ self._eagle3_attention_forward_pre_hook, with_kwargs=True
237
+ )
238
+
239
+ # Modify qkv projection in first layer to accept 2h hidden size.
240
+ first_layer_attn.q_proj = nn.Linear(
241
+ first_layer_attn.q_proj.in_features * 2,
242
+ first_layer_attn.q_proj.out_features,
243
+ bias=first_layer_attn.config.attention_bias,
244
+ )
245
+ first_layer_attn.k_proj = nn.Linear(
246
+ first_layer_attn.k_proj.in_features * 2,
247
+ first_layer_attn.k_proj.out_features,
248
+ bias=first_layer_attn.config.attention_bias,
249
+ )
250
+ first_layer_attn.v_proj = nn.Linear(
251
+ first_layer_attn.v_proj.in_features * 2,
252
+ first_layer_attn.v_proj.out_features,
253
+ bias=first_layer_attn.config.attention_bias,
254
+ )
255
+
256
+ # In EAGLE-3, input_embeds and hidden_states are normalized separately before concatenation.
257
+ self.input_embeds_norm = LlamaRMSNorm(config.hidden_size, eps=config.rms_norm_eps)
258
+ self.hidden_norm = LlamaRMSNorm(config.hidden_size, eps=config.rms_norm_eps)
259
+
260
+ # Disable input norm in first layer. We normed embeds and h individually before.
261
+ self.layers[0].input_layernorm = nn.Identity()
262
+
263
+ def _eagle3_attention_forward_pre_hook(self, module, args, kwargs):
264
+ """Concat input_embeds and hidden_states for EAGLE-3's first attention layer."""
265
+ if "hidden_states" not in kwargs:
266
+ raise ValueError("hidden_states not found in kwargs")
267
+ if self._input_embeds is None:
268
+ raise ValueError("self._input_embeds is None")
269
+
270
+ input_embeds = self._input_embeds
271
+ self._input_embeds = None
272
+ kwargs["hidden_states"] = torch.cat(
273
+ (input_embeds, self.hidden_norm(kwargs["hidden_states"])), dim=-1
274
+ )
275
+
276
+ return args, kwargs
277
+
278
+ def forward(
279
+ self,
280
+ hidden_states: torch.Tensor,
281
+ inputs_embeds: torch.Tensor,
282
+ attention_mask: torch.Tensor,
283
+ loss_mask: torch.Tensor | None = None,
284
+ logits: torch.Tensor | None = None,
285
+ position_ids: torch.LongTensor | None = None,
286
+ past_key_values: Cache | None = None,
287
+ use_cache: bool | None = None,
288
+ output_attentions: bool | None = False,
289
+ position_embeddings: torch.Tensor | None = None,
290
+ ):
291
+ """Forward function for EagleModule."""
292
+ batch_size, seq_length, _ = hidden_states.shape
293
+ seq_length_with_past = seq_length
294
+ past_key_values_length = 0
295
+
296
+ if past_key_values is not None:
297
+ past_key_values_length = past_key_values.get_seq_length()
298
+ seq_length_with_past = seq_length_with_past + past_key_values_length
299
+ if position_ids is None:
300
+ device = hidden_states.device if hidden_states is not None else inputs_embeds.device
301
+ position_ids = torch.arange(
302
+ past_key_values_length,
303
+ seq_length + past_key_values_length,
304
+ dtype=torch.long,
305
+ device=device,
306
+ )
307
+ position_ids = position_ids.unsqueeze(0).view(-1, seq_length)
308
+ else:
309
+ position_ids = position_ids.view(-1, seq_length).long()
310
+
311
+ inputs_embeds = inputs_embeds.to(hidden_states.dtype).to(hidden_states.device)
312
+ if self.config.use_aux_hidden_state:
313
+ # In EAGLE-3, we save input embeddings to attribute, and use it in first decoder layer by hook function
314
+ # Also, we normalize input embeddings and hidden states before concatenating them.
315
+ # The default input norm in first layer attn will be disabled.
316
+ self._input_embeds = self.input_embeds_norm(inputs_embeds)
317
+ else: # EAGLE-1
318
+ hidden_states = self.fc(torch.cat((inputs_embeds, hidden_states), dim=-1))
319
+
320
+ for decoder_layer in self.layers:
321
+ layer_outputs = decoder_layer(
322
+ hidden_states,
323
+ attention_mask=attention_mask,
324
+ position_ids=position_ids,
325
+ past_key_value=past_key_values,
326
+ output_attentions=output_attentions,
327
+ use_cache=use_cache,
328
+ position_embeddings=position_embeddings,
329
+ )
330
+ # For HF>= 4.54.0, the layer_outputs is a tensor, for older, it is a tuple.
331
+ if isinstance(layer_outputs, tuple):
332
+ hidden_states = layer_outputs[0]
333
+ else:
334
+ hidden_states = layer_outputs
335
+
336
+ pre_norm_h = hidden_states
337
+
338
+ post_norm_h = self.norm(hidden_states) if hasattr(self, "norm") else hidden_states
339
+
340
+ return post_norm_h, pre_norm_h, past_key_values
341
+
342
+
343
+ @EagleDMRegistry.register({PreTrainedModel: "hf.PreTrainedModel"})
344
+ class HFEagleModel(EagleModel):
345
+ """Eagle Model Class for huggingface models."""
346
+
347
+ def _set_default_aux_hidden_state_layers(self):
348
+ num_layers = self.config.num_hidden_layers
349
+ self.eagle_config.eagle_aux_hidden_state_layer_ids = [
350
+ 1,
351
+ max(0, num_layers // 2 - 1),
352
+ max(0, num_layers - 4),
353
+ ]
354
+ self.eagle_config.eagle_aux_hidden_state_layer_ids = list(
355
+ set(self.eagle_config.eagle_aux_hidden_state_layer_ids)
356
+ )
357
+
358
+ def _collect_aux_hidden_states_forward_hook(self, module, input, output) -> None:
359
+ """Collect auxiliary hidden states from base model intermediate layers, save them in attribute."""
360
+ hidden_states = (
361
+ output.clone().detach()
362
+ if isinstance(output, torch.Tensor)
363
+ else output[0].clone().detach()
364
+ )
365
+ self._aux_hidden_states.append(hidden_states)
366
+
367
+ def pop_aux_hidden_states(self):
368
+ """Return aux hidden states from base model, and clear the list."""
369
+ # In PTQ, forward method will be called with try and except to find max batch size.
370
+ # This leads to uncleared aux hidden states in the front of the list.
371
+ # To fix it, we only return the last num_aux_h items in the list.
372
+ num_aux_h = len(self.eagle_config.eagle_aux_hidden_state_layer_ids)
373
+ aux_h_list = self._aux_hidden_states[-num_aux_h:]
374
+ self._aux_hidden_states.clear()
375
+
376
+ return aux_h_list
377
+
378
+ def modify(
379
+ self,
380
+ eagle_offline,
381
+ eagle_hidden_state_distillation,
382
+ eagle_self_logit_distillation,
383
+ eagle_freeze_base_model,
384
+ eagle_report_acc,
385
+ eagle_reuse_base_decoder,
386
+ eagle_loss_decay_factor,
387
+ eagle_architecture_config,
388
+ ):
389
+ """Constructor.
390
+
391
+ Args:
392
+ config: The config for eagle decoder layers.
393
+ """
394
+ super().modify(
395
+ eagle_offline=eagle_offline,
396
+ eagle_hidden_state_distillation=eagle_hidden_state_distillation,
397
+ eagle_self_logit_distillation=eagle_self_logit_distillation,
398
+ eagle_freeze_base_model=eagle_freeze_base_model,
399
+ eagle_report_acc=eagle_report_acc,
400
+ eagle_reuse_base_decoder=eagle_reuse_base_decoder,
401
+ eagle_loss_decay_factor=eagle_loss_decay_factor,
402
+ eagle_architecture_config=eagle_architecture_config,
403
+ )
404
+ self.eagle_config = PretrainedConfig.from_dict(eagle_architecture_config)
405
+ self.eagle_config._attn_implementation = "sdpa"
406
+ decoder_cls = (
407
+ type(self.model.layers[-1]) if self.eagle_reuse_base_decoder else LlamaDecoderLayer
408
+ )
409
+
410
+ # Use default aux_hidden_state layers if use_aux_hidden_state is True
411
+ # but no layer id is given
412
+ if (
413
+ self.eagle_config.use_aux_hidden_state
414
+ and len(self.eagle_config.eagle_aux_hidden_state_layer_ids) == 0
415
+ ):
416
+ self._set_default_aux_hidden_state_layers()
417
+
418
+ if self.config.hidden_size != self.eagle_config.hidden_size:
419
+ raise ValueError(
420
+ "EAGLE module hidden size "
421
+ f"{self.eagle_config.hidden_size} must match base model hidden size "
422
+ f"{self.config.hidden_size}!"
423
+ )
424
+
425
+ self.eagle_module = EagleModule(
426
+ self.eagle_config,
427
+ decoder_cls,
428
+ )
429
+ self.eagle_rotary_emb = LlamaRotaryEmbedding(config=self.eagle_config)
430
+
431
+ if hasattr(self.model.layers[-1].self_attn, "o_proj"):
432
+ device = self.model.layers[-1].self_attn.o_proj.weight.device
433
+ elif hasattr(self.model.layers[-1].self_attn, "q_proj"):
434
+ device = self.model.layers[-1].self_attn.q_proj.weight.device
435
+ elif hasattr(self.model.layers[-1].self_attn, "qkv_proj"):
436
+ device = self.model.layers[-1].self_attn.qkv_proj.weight.device
437
+ self.eagle_module.to(self.dtype).to(device)
438
+
439
+ # Make sure self.model.embed_tokens and self.lm_head are frozen
440
+ for param in self.model.embed_tokens.parameters():
441
+ param.requires_grad = False
442
+ for param in self.lm_head.parameters():
443
+ param.requires_grad = False
444
+
445
+ # EAGLE-3 auxiliary hidden_states
446
+ if self.eagle_config.use_aux_hidden_state:
447
+ self._aux_hidden_states = []
448
+ for layer_idx, layer in enumerate(self.model.layers):
449
+ if layer_idx in self.eagle_config.eagle_aux_hidden_state_layer_ids:
450
+ layer.register_forward_hook(self._collect_aux_hidden_states_forward_hook)
451
+
452
+ def _prepare_decoder_attention_mask(
453
+ self, attention_mask, input_shape, inputs_embeds, past_key_values_length
454
+ ):
455
+ """Expand the 2-D attention mask to 4-D and apply causal mask."""
456
+ # create causal mask
457
+ # [bsz, seq_len] -> [bsz, 1, tgt_seq_len, src_seq_len]
458
+ combined_attention_mask = None
459
+ if input_shape[-1] > 1:
460
+ combined_attention_mask = make_causal_mask(
461
+ input_shape,
462
+ inputs_embeds.dtype,
463
+ device=inputs_embeds.device,
464
+ past_key_values_length=past_key_values_length,
465
+ )
466
+
467
+ if attention_mask is not None:
468
+ # [bsz, seq_len] -> [bsz, 1, tgt_seq_len, src_seq_len]
469
+ expanded_attn_mask = expand_mask(
470
+ attention_mask, inputs_embeds.dtype, tgt_len=input_shape[-1]
471
+ ).to(inputs_embeds.device)
472
+ combined_attention_mask = (
473
+ expanded_attn_mask
474
+ if combined_attention_mask is None
475
+ else expanded_attn_mask + combined_attention_mask
476
+ )
477
+
478
+ return combined_attention_mask
479
+
480
+ def _get_eagle_module_inputs(
481
+ self,
482
+ input_ids,
483
+ eagle_input_hidden_states,
484
+ attention_mask,
485
+ position_ids,
486
+ eagle_cache,
487
+ ):
488
+ """Helper function to prepare eagle inputs for the 0th eagle forward pass."""
489
+ b, seq_length, _ = eagle_input_hidden_states.shape
490
+ past_key_values_length = eagle_cache.get_seq_length() if eagle_cache is not None else 0
491
+ seq_length_with_past = seq_length + past_key_values_length
492
+
493
+ # Prepare eagle_input_ids: Shift left 1 token
494
+ zeropadding = torch.zeros(
495
+ input_ids.shape[0], 1, dtype=input_ids.dtype, device=input_ids.device
496
+ )
497
+ eagle_input_ids = torch.cat((input_ids[:, 1:], zeropadding), dim=1)
498
+
499
+ # Prepare attention_mask
500
+ if attention_mask is not None: # Shift left 1 token for attention_mask
501
+ zeropadding = torch.zeros(
502
+ attention_mask.shape[0], 1, dtype=attention_mask.dtype, device=attention_mask.device
503
+ )
504
+ attention_mask = torch.cat((attention_mask[:, 1:], zeropadding), dim=1)
505
+ else:
506
+ attention_mask = torch.ones( # Initialize default attention_mask
507
+ (b, seq_length_with_past), dtype=torch.bool, device=eagle_input_hidden_states.device
508
+ )
509
+
510
+ # Expand the 2-D attention mask to 4-D and apply causal mask.
511
+ attention_mask = self._prepare_decoder_attention_mask(
512
+ attention_mask, (b, seq_length), eagle_input_hidden_states, past_key_values_length
513
+ )
514
+
515
+ # Prepare position_ids
516
+ if position_ids is None:
517
+ position_ids = torch.arange(
518
+ past_key_values_length,
519
+ seq_length + past_key_values_length,
520
+ dtype=torch.long,
521
+ device=eagle_input_hidden_states.device,
522
+ )
523
+ position_ids = position_ids.unsqueeze(0).view(-1, seq_length)
524
+ else:
525
+ position_ids = position_ids.view(-1, seq_length).long()
526
+
527
+ return eagle_input_ids, attention_mask, position_ids
528
+
529
+ def _concat_eagle_inputs(
530
+ self,
531
+ input_ids_0,
532
+ eagle_input_hidden_states_0,
533
+ attention_mask_0,
534
+ position_ids_0,
535
+ eagle_generated_hs,
536
+ ):
537
+ """Helper function to prepare eagle inputs for second-fourth eagle forward pass during training-time-testing.
538
+
539
+ This is a slow version, focusing on the correctness only. TODO: optimize this.
540
+ Parameters:
541
+ input_ids_0: [b, seq_length], input_ids from the 0th eagle step
542
+ base_model_hidden_states: [b, seq_length, h]
543
+ eagle_input_hidden_states_0: [b, seq_length, h]
544
+ attention_mask_0: [b, seq_length, seq_length], from the 0th eagle step.
545
+ position_ids_0: [b, seq_length], from the 0th eagle step.
546
+ eagle_generated_hs: [b, seq_length * n_steps, h], from the LAST eagle step.
547
+ """
548
+ b, seq_length, h = eagle_input_hidden_states_0.shape
549
+ dtypemin = torch.finfo(attention_mask_0.dtype).min
550
+
551
+ if eagle_generated_hs.shape[1] == seq_length:
552
+ # This is the second step of eagle forward
553
+
554
+ # Concat input_ids
555
+ cat_input_ids = torch.cat((input_ids_0, input_ids_0), dim=-1)
556
+
557
+ # Concat hidden_states
558
+ cat_eagle_input_hidden_states = torch.cat(
559
+ (
560
+ eagle_input_hidden_states_0,
561
+ torch.zeros(
562
+ (b, 1, h),
563
+ dtype=eagle_input_hidden_states_0.dtype,
564
+ device=eagle_input_hidden_states_0.device,
565
+ ),
566
+ eagle_generated_hs[:, :-1, :],
567
+ ),
568
+ dim=1,
569
+ )
570
+
571
+ # Expand attn_mask
572
+ zero_mask = torch.ones_like(attention_mask_0).bool()
573
+ mask_2_1 = attention_mask_0.clone().detach()
574
+ mask_2_1[:, :, :, :-1] = mask_2_1[:, :, :, 1:]
575
+ mask_2_2 = torch.ones_like(attention_mask_0).bool()
576
+ for i in range(1, seq_length - 1):
577
+ mask_2_2[:, :, i, i] = False
578
+ cat_attention_mask = torch.cat(
579
+ (
580
+ torch.cat((attention_mask_0, zero_mask), dim=-1),
581
+ torch.cat((mask_2_1, mask_2_2), dim=-1),
582
+ ),
583
+ dim=-2,
584
+ )
585
+ cat_attention_mask = cat_attention_mask.masked_fill(cat_attention_mask == 1, dtypemin)
586
+
587
+ # Concat position_ids
588
+ cat_position_ids = torch.cat((position_ids_0, position_ids_0), dim=-1)
589
+
590
+ elif eagle_generated_hs.shape[1] == seq_length * 2:
591
+ cat_input_ids = torch.cat((input_ids_0, input_ids_0, input_ids_0), dim=-1)
592
+ cat_eagle_input_hidden_states = torch.cat(
593
+ (
594
+ eagle_input_hidden_states_0,
595
+ torch.zeros(
596
+ (b, 1, h),
597
+ dtype=eagle_input_hidden_states_0.dtype,
598
+ device=eagle_input_hidden_states_0.device,
599
+ ),
600
+ eagle_generated_hs[:, :-1, :],
601
+ ),
602
+ dim=1,
603
+ )
604
+ zero_mask = torch.ones_like(attention_mask_0).bool()
605
+ mask_2_1 = attention_mask_0.clone().detach()
606
+ mask_2_1[:, :, :, :-1] = mask_2_1[:, :, :, 1:]
607
+ mask_2_2 = torch.ones_like(attention_mask_0).bool()
608
+ for i in range(1, seq_length - 1):
609
+ mask_2_2[:, :, i, i] = False
610
+
611
+ mask_3_1 = mask_2_1.clone().detach()
612
+ mask_3_1[:, :, :, :-1] = mask_3_1[:, :, :, 1:]
613
+ mask_3_2 = mask_2_2.clone().detach()
614
+ mask_3_2[:, :, :, :-1] = mask_3_2[:, :, :, 1:]
615
+ mask_3_2[:, :, 1, 0] = True
616
+ mask_3_3 = mask_2_2.clone().detach()
617
+ mask_3_3[:, :, 1, 1] = True
618
+ cat_attention_mask = torch.cat(
619
+ (
620
+ torch.cat((attention_mask_0, zero_mask, zero_mask), dim=-1),
621
+ torch.cat((mask_2_1, mask_2_2, zero_mask), dim=-1),
622
+ torch.cat((mask_3_1, mask_3_2, mask_3_3), dim=-1),
623
+ ),
624
+ dim=-2,
625
+ )
626
+
627
+ cat_attention_mask = cat_attention_mask.masked_fill(cat_attention_mask == 1, dtypemin)
628
+ cat_position_ids = torch.cat((position_ids_0, position_ids_0, position_ids_0), dim=-1)
629
+
630
+ elif eagle_generated_hs.shape[1] == seq_length * 3:
631
+ cat_input_ids = torch.cat((input_ids_0, input_ids_0, input_ids_0, input_ids_0), dim=-1)
632
+ cat_eagle_input_hidden_states = torch.cat(
633
+ (
634
+ eagle_input_hidden_states_0,
635
+ torch.zeros(
636
+ (b, 1, h),
637
+ dtype=eagle_input_hidden_states_0.dtype,
638
+ device=eagle_input_hidden_states_0.device,
639
+ ),
640
+ eagle_generated_hs[:, :-1, :],
641
+ ),
642
+ dim=1,
643
+ )
644
+ zero_mask = torch.ones_like(attention_mask_0).bool()
645
+ mask_2_1 = attention_mask_0.clone().detach()
646
+ mask_2_1[:, :, :, :-1] = mask_2_1[:, :, :, 1:]
647
+ mask_2_2 = torch.ones_like(attention_mask_0).bool()
648
+ for i in range(1, seq_length - 1):
649
+ mask_2_2[:, :, i, i] = False
650
+
651
+ mask_3_1 = mask_2_1.clone().detach()
652
+ mask_3_1[:, :, :, :-1] = mask_3_1[:, :, :, 1:]
653
+ mask_3_2 = mask_2_2.clone().detach()
654
+ mask_3_2[:, :, :, :-1] = mask_3_2[:, :, :, 1:]
655
+ mask_3_2[:, :, 1, 0] = True
656
+ mask_3_3 = mask_2_2.clone().detach()
657
+ mask_3_3[:, :, 1, 1] = True
658
+
659
+ mask_4_1 = mask_3_1.clone().detach()
660
+ mask_4_1[:, :, :, :-1] = mask_4_1[:, :, :, 1:]
661
+ mask_4_2 = mask_3_2.clone().detach()
662
+ mask_4_2[:, :, :, :-1] = mask_4_2[:, :, :, 1:]
663
+ mask_4_2[:, :, 2, 0] = True
664
+ mask_4_3 = mask_3_3.clone().detach()
665
+ mask_4_3[:, :, :, :-1] = mask_4_3[:, :, :, 1:]
666
+ mask_4_3[:, :, 2, 1] = True
667
+ mask_4_4 = mask_3_3.clone().detach()
668
+ mask_4_4[:, :, 2, 2] = True
669
+
670
+ cat_attention_mask = torch.cat(
671
+ (
672
+ torch.cat((attention_mask_0, zero_mask, zero_mask, zero_mask), dim=-1),
673
+ torch.cat((mask_2_1, mask_2_2, zero_mask, zero_mask), dim=-1),
674
+ torch.cat((mask_3_1, mask_3_2, mask_3_3, zero_mask), dim=-1),
675
+ torch.cat((mask_4_1, mask_4_2, mask_4_3, mask_4_4), dim=-1),
676
+ ),
677
+ dim=-2,
678
+ )
679
+ cat_attention_mask = cat_attention_mask.masked_fill(cat_attention_mask == 1, dtypemin)
680
+ cat_position_ids = torch.cat(
681
+ (position_ids_0, position_ids_0, position_ids_0, position_ids_0), dim=-1
682
+ )
683
+
684
+ else:
685
+ raise ValueError(
686
+ f"EAGLE generated hidden states shape {eagle_generated_hs.shape} is not supported"
687
+ )
688
+
689
+ return cat_eagle_input_hidden_states, cat_input_ids, cat_attention_mask, cat_position_ids
690
+
691
+ def _base_model_forward(
692
+ self,
693
+ input_ids,
694
+ attention_mask,
695
+ position_ids,
696
+ past_key_values,
697
+ freeze_base_model,
698
+ labels,
699
+ kwargs,
700
+ ):
701
+ with torch.no_grad() if freeze_base_model else contextlib.nullcontext():
702
+ outputs = super().forward(
703
+ input_ids=input_ids,
704
+ attention_mask=attention_mask,
705
+ position_ids=position_ids,
706
+ past_key_values=past_key_values,
707
+ output_hidden_states=True,
708
+ **kwargs,
709
+ )
710
+ past_key_values = outputs.past_key_values
711
+ if not isinstance(past_key_values, Cache):
712
+ past_key_values = DynamicCache.from_legacy_cache(past_key_values)
713
+ base_model_hidden_states = outputs.hidden_states[-1]
714
+ base_model_logits = outputs.logits
715
+
716
+ # Optionally, compute base model loss when we want to tune the base model.
717
+ base_model_loss = None
718
+ if not freeze_base_model and labels is not None: # Base model loss
719
+ loss_fct = CrossEntropyLoss()
720
+ loss_logits = base_model_logits.view(-1, base_model_logits.shape[-1])
721
+ labels = labels.view(-1)
722
+ base_model_loss = loss_fct(loss_logits, labels)
723
+
724
+ # Map the base model logits to the draft vocab
725
+ if self.eagle_config.draft_vocab_size != self.eagle_config.vocab_size and self.training:
726
+ reverse_mapping = (
727
+ torch.arange(len(self.eagle_module.d2t)).to(self.eagle_module.d2t.device)
728
+ + self.eagle_module.d2t
729
+ )
730
+ base_model_logits = base_model_logits[:, :, reverse_mapping]
731
+
732
+ return base_model_hidden_states, base_model_logits, base_model_loss, past_key_values
733
+
734
+ def _eagle_forward(
735
+ self,
736
+ eagle_input_hidden_states,
737
+ inputs_embeds,
738
+ attention_mask,
739
+ position_ids,
740
+ position_embeddings,
741
+ ):
742
+ eagle_postnorm_h, eagle_prenorm_h, eagle_cache = self.eagle_module(
743
+ eagle_input_hidden_states,
744
+ inputs_embeds,
745
+ attention_mask=attention_mask,
746
+ position_ids=position_ids,
747
+ use_cache=True,
748
+ position_embeddings=position_embeddings,
749
+ )
750
+ eagle_lm_head = (
751
+ self.eagle_module.eagle_lm_head
752
+ if hasattr(self.eagle_module, "eagle_lm_head")
753
+ else self.lm_head
754
+ )
755
+ eagle_logits = eagle_lm_head(eagle_postnorm_h)
756
+
757
+ return eagle_postnorm_h, eagle_prenorm_h, eagle_logits, eagle_cache
758
+
759
+ def forward(
760
+ self,
761
+ input_ids: torch.LongTensor,
762
+ attention_mask: torch.Tensor | None = None,
763
+ position_ids: torch.LongTensor | None = None,
764
+ past_key_values: Cache | None = None,
765
+ inputs_embeds: torch.FloatTensor | None = None,
766
+ labels: torch.LongTensor | None = None,
767
+ use_cache: bool | None = None,
768
+ output_attentions: bool | None = None,
769
+ output_hidden_states: bool | None = None,
770
+ cache_position: torch.LongTensor | None = None,
771
+ logits_to_keep: int = 0,
772
+ loss_mask: torch.Tensor | None = None,
773
+ classification_loss_coefficient: float | None = 1,
774
+ regression_loss_coefficient: float | None = 0,
775
+ **kwargs,
776
+ ) -> Any:
777
+ """Forward pass of the EagleModel.
778
+
779
+ Returns:
780
+ hidden_states: The hidden state from the base model.
781
+ logits: logits from the base model.
782
+ eagle_hidden_states: The hidden state from eagle_module.
783
+ eagle_logits: logits from the eagle_module.
784
+ """
785
+ if past_key_values is not None and hasattr(past_key_values, "eagle_cache"):
786
+ eagle_cache = past_key_values.eagle_cache
787
+ else:
788
+ eagle_cache = None
789
+
790
+ if self.training:
791
+ assert eagle_cache is None, "eagle_cache should be None in training"
792
+ assert past_key_values is None, "past_key_values should be None in training"
793
+
794
+ if loss_mask is None:
795
+ loss_mask = torch.ones_like(input_ids, dtype=torch.bool, device=input_ids.device)
796
+
797
+ # ====First, we run base model forward====
798
+ base_model_hidden_states, base_model_logits, base_model_loss, past_key_values = (
799
+ self._base_model_forward(
800
+ input_ids,
801
+ attention_mask,
802
+ position_ids,
803
+ past_key_values,
804
+ self.eagle_freeze_base_model,
805
+ labels,
806
+ kwargs,
807
+ )
808
+ )
809
+
810
+ # ====Run eagle forward====
811
+ eagle_loss = None
812
+ if self.training:
813
+ # In EAGLE-3, we have an additional FC layer to concentrate hidden states from multiple base model layers
814
+ batch_size, seq_length, _ = base_model_hidden_states.shape
815
+ if self.eagle_config.use_aux_hidden_state:
816
+ eagle_input_hidden_states = self.eagle_module.fc(
817
+ torch.cat(self.pop_aux_hidden_states(), dim=-1)
818
+ )
819
+ else:
820
+ eagle_input_hidden_states = base_model_hidden_states
821
+
822
+ # Get eagle inputs for the first eagle forward pass
823
+ eagle_input_ids, attention_mask_0, position_ids = self._get_eagle_module_inputs(
824
+ input_ids,
825
+ eagle_input_hidden_states,
826
+ attention_mask,
827
+ position_ids,
828
+ eagle_cache,
829
+ )
830
+ with torch.no_grad():
831
+ inputs_embeds = self.model.embed_tokens(eagle_input_ids)
832
+ position_embeddings = self.eagle_rotary_emb(eagle_input_hidden_states, position_ids)
833
+
834
+ # Then, we run eagle forward
835
+ eagle_postnorm_h, eagle_prenorm_h, eagle_logits, eagle_cache = self._eagle_forward(
836
+ eagle_input_hidden_states,
837
+ inputs_embeds,
838
+ attention_mask_0,
839
+ position_ids,
840
+ position_embeddings,
841
+ )
842
+
843
+ if not isinstance(eagle_cache, Cache):
844
+ eagle_cache = DynamicCache.from_legacy_cache(eagle_cache)
845
+ past_key_values.eagle_cache = eagle_cache
846
+
847
+ # Compute loss on the eagle modules
848
+ regression_loss, classification_loss = self._eagle_loss(
849
+ base_model_hidden_states[:, 1:],
850
+ base_model_logits[:, 1:],
851
+ eagle_postnorm_h[:, :-1],
852
+ eagle_logits[:, :-1],
853
+ loss_mask[:, 1:],
854
+ )
855
+ eagle_loss = (
856
+ regression_loss_coefficient * regression_loss
857
+ + classification_loss_coefficient * classification_loss
858
+ )
859
+
860
+ # ====Perform training-time-testing with 3 extra eagle forward passes====
861
+ # ====Second step of eagle forward====
862
+ eagle_input_hidden_states_1, eagle_input_ids_1, attention_mask_1, position_ids_1 = (
863
+ self._concat_eagle_inputs(
864
+ eagle_input_ids,
865
+ eagle_input_hidden_states,
866
+ attention_mask_0,
867
+ position_ids,
868
+ eagle_prenorm_h,
869
+ )
870
+ )
871
+ with torch.no_grad():
872
+ inputs_embeds = self.model.embed_tokens(eagle_input_ids_1)
873
+ position_embeddings = self.eagle_rotary_emb(eagle_input_hidden_states_1, position_ids_1)
874
+ eagle_postnorm_h, eagle_prenorm_h, eagle_logits, eagle_cache = self._eagle_forward(
875
+ eagle_input_hidden_states_1,
876
+ inputs_embeds,
877
+ attention_mask_1,
878
+ position_ids_1,
879
+ position_embeddings,
880
+ )
881
+
882
+ regression_loss, classification_loss = self._eagle_loss(
883
+ # base model predict +1 tok, while eagle predict +2
884
+ # so we shift base model outputs compared to eagle outputs
885
+ base_model_hidden_states[:, 1:],
886
+ base_model_logits[:, 1:],
887
+ eagle_postnorm_h[
888
+ :,
889
+ -seq_length:-1,
890
+ ],
891
+ eagle_logits[
892
+ :,
893
+ -seq_length:-1,
894
+ ],
895
+ # additionally, we mask the first n tok of eagle outputs at nth TTT step
896
+ torch.cat(
897
+ (
898
+ torch.zeros(batch_size, 1, dtype=loss_mask.dtype, device=loss_mask.device),
899
+ loss_mask[:, 2:],
900
+ ),
901
+ dim=1,
902
+ ),
903
+ )
904
+ eagle_loss += (
905
+ regression_loss_coefficient * regression_loss
906
+ + classification_loss_coefficient * classification_loss
907
+ )
908
+
909
+ # ====Third step of eagle forward====
910
+ eagle_input_hidden_states_2, eagle_input_ids_2, attention_mask_2, position_ids_2 = (
911
+ self._concat_eagle_inputs(
912
+ eagle_input_ids,
913
+ eagle_input_hidden_states,
914
+ attention_mask_0,
915
+ position_ids,
916
+ eagle_prenorm_h,
917
+ )
918
+ )
919
+ with torch.no_grad():
920
+ inputs_embeds = self.model.embed_tokens(eagle_input_ids_2)
921
+ position_embeddings = self.eagle_rotary_emb(eagle_input_hidden_states_2, position_ids_2)
922
+ eagle_postnorm_h, eagle_prenorm_h, eagle_logits, eagle_cache = self._eagle_forward(
923
+ eagle_input_hidden_states_2,
924
+ inputs_embeds,
925
+ attention_mask_2,
926
+ position_ids_2,
927
+ position_embeddings,
928
+ )
929
+
930
+ regression_loss, classification_loss = self._eagle_loss(
931
+ base_model_hidden_states[:, 1:],
932
+ base_model_logits[:, 1:],
933
+ eagle_postnorm_h[:, -seq_length:-1, :],
934
+ eagle_logits[
935
+ :,
936
+ -seq_length:-1,
937
+ ],
938
+ torch.cat(
939
+ (
940
+ torch.zeros(batch_size, 2, dtype=loss_mask.dtype, device=loss_mask.device),
941
+ loss_mask[:, 3:],
942
+ ),
943
+ dim=1,
944
+ ),
945
+ )
946
+ eagle_loss += (
947
+ regression_loss_coefficient * regression_loss
948
+ + classification_loss_coefficient * classification_loss
949
+ )
950
+
951
+ # ====Fourth step of eagle forward====
952
+ eagle_input_hidden_states_3, eagle_input_ids_3, attention_mask_3, position_ids_3 = (
953
+ self._concat_eagle_inputs(
954
+ eagle_input_ids,
955
+ eagle_input_hidden_states,
956
+ attention_mask_0,
957
+ position_ids,
958
+ eagle_prenorm_h,
959
+ )
960
+ )
961
+ with torch.no_grad():
962
+ inputs_embeds = self.model.embed_tokens(eagle_input_ids_3)
963
+ position_embeddings = self.eagle_rotary_emb(eagle_input_hidden_states_3, position_ids_3)
964
+ eagle_postnorm_h, _, eagle_logits, eagle_cache = self._eagle_forward(
965
+ eagle_input_hidden_states_3,
966
+ inputs_embeds,
967
+ attention_mask_3,
968
+ position_ids_3,
969
+ position_embeddings,
970
+ )
971
+
972
+ regression_loss, classification_loss = self._eagle_loss(
973
+ base_model_hidden_states[:, 1:],
974
+ base_model_logits[:, 1:],
975
+ eagle_postnorm_h[
976
+ :,
977
+ -seq_length:-1,
978
+ ],
979
+ eagle_logits[
980
+ :,
981
+ -seq_length:-1,
982
+ ],
983
+ torch.cat(
984
+ (
985
+ torch.zeros(batch_size, 3, dtype=loss_mask.dtype, device=loss_mask.device),
986
+ loss_mask[:, 4:],
987
+ ),
988
+ dim=1,
989
+ ),
990
+ )
991
+ eagle_loss += (
992
+ regression_loss_coefficient * regression_loss
993
+ + classification_loss_coefficient * classification_loss
994
+ )
995
+
996
+ # Finally, we merge base model loss and eagle loss, raise error if both are None
997
+ if base_model_loss is not None and eagle_loss is not None:
998
+ loss = base_model_loss + eagle_loss
999
+ elif base_model_loss is not None:
1000
+ loss = base_model_loss
1001
+ elif eagle_loss is not None:
1002
+ loss = eagle_loss
1003
+ else:
1004
+ loss = None
1005
+ assert not self.training, ValueError(
1006
+ "Both base_model_loss and eagle_loss are skipped. At least one loss must be computed."
1007
+ )
1008
+
1009
+ return ModelOutput(
1010
+ loss=loss,
1011
+ logits=base_model_logits,
1012
+ past_key_values=past_key_values,
1013
+ hidden_states=base_model_hidden_states,
1014
+ )
1015
+
1016
+ def _eagle_loss(
1017
+ self,
1018
+ base_model_hidden_states,
1019
+ base_model_logits,
1020
+ eagle_hidden_states,
1021
+ eagle_logits,
1022
+ loss_mask,
1023
+ ):
1024
+ """Function for EAGLE loss computing."""
1025
+ loss_mask = loss_mask[:, :, None]
1026
+ criterion = nn.SmoothL1Loss(reduction="none")
1027
+ classification_loss = nn.Softmax(dim=2)(base_model_logits) * nn.LogSoftmax(dim=2)(
1028
+ eagle_logits
1029
+ )
1030
+ classification_loss = -torch.sum(torch.sum(loss_mask * classification_loss, 2)) / (
1031
+ loss_mask.sum() + 1e-5
1032
+ )
1033
+ regression_loss = criterion(eagle_hidden_states, base_model_hidden_states)
1034
+ regression_loss = torch.sum(torch.mean(loss_mask * regression_loss, 2)) / (
1035
+ loss_mask.sum() + 1e-5
1036
+ )
1037
+ return regression_loss, classification_loss
1038
+
1039
+ @torch.no_grad()
1040
+ def pseudo_speculative_generate(
1041
+ self,
1042
+ input_ids: torch.Tensor,
1043
+ steps: int = 1,
1044
+ ):
1045
+ """Pseudo generate of the EAGLE GPTModel.
1046
+
1047
+ Returns:
1048
+ base_token (torch.Tensor): token from base model
1049
+ draft_tokens (torch.Tensor): draft tokens from eagle module
1050
+ """
1051
+ base_model_outputs = super().forward(
1052
+ input_ids=input_ids,
1053
+ output_hidden_states=True,
1054
+ )
1055
+
1056
+ base_model_hidden_states = base_model_outputs.hidden_states[-1]
1057
+ base_model_logits = base_model_outputs.logits
1058
+ base_token = base_model_logits[:, -1:, :].argmax(dim=-1)
1059
+
1060
+ # Early return
1061
+ if steps < 1:
1062
+ if hasattr(self, "_aux_hidden_states"):
1063
+ _ = self.pop_aux_hidden_states()
1064
+ return base_token, None
1065
+
1066
+ eagle_ids = torch.cat((input_ids[:, 1:], base_token), dim=-1)
1067
+
1068
+ if self.eagle_config.use_aux_hidden_state:
1069
+ # EAGLE-3
1070
+ # Only the first iteration input_hidden_states are from aux_hidden_state layers
1071
+ # Gather _aux_hidden_states from all devices before concatenation
1072
+ gathered_aux_hidden_states = self.pop_aux_hidden_states()
1073
+ gathered_aux_hidden_states = [
1074
+ h.to(input_ids.device) for h in gathered_aux_hidden_states
1075
+ ]
1076
+ eagle_input_hidden_states = self.eagle_module.fc(
1077
+ torch.cat(gathered_aux_hidden_states, dim=-1)
1078
+ )
1079
+
1080
+ else:
1081
+ eagle_input_hidden_states = base_model_hidden_states
1082
+
1083
+ draft_tokens = []
1084
+ for _ in range(steps):
1085
+ # Get eagle inputs for the first eagle forward pass
1086
+ _, eagle_attention_mask, eagle_position_ids = self._get_eagle_module_inputs(
1087
+ input_ids,
1088
+ eagle_input_hidden_states,
1089
+ None,
1090
+ None,
1091
+ None,
1092
+ )
1093
+ position_embeddings = self.eagle_rotary_emb(
1094
+ eagle_input_hidden_states, eagle_position_ids
1095
+ )
1096
+
1097
+ _, eagle_prenorm_h, eagle_logits, _ = self._eagle_forward(
1098
+ eagle_input_hidden_states,
1099
+ self.model.embed_tokens(eagle_ids),
1100
+ eagle_attention_mask,
1101
+ eagle_position_ids,
1102
+ position_embeddings,
1103
+ )
1104
+
1105
+ draft_token = eagle_logits[:, -1:, :].argmax(dim=-1)
1106
+ if self.eagle_config.draft_vocab_size != self.eagle_config.vocab_size:
1107
+ draft_token += self.eagle_module.d2t[draft_token]
1108
+ draft_tokens.append(draft_token)
1109
+
1110
+ eagle_ids = torch.cat((eagle_ids, draft_token.to(eagle_ids.device)), dim=-1)
1111
+ eagle_input_hidden_states = torch.cat(
1112
+ (eagle_input_hidden_states, eagle_prenorm_h[:, -1:, :]), dim=1
1113
+ )
1114
+
1115
+ draft_tokens = torch.cat(draft_tokens, dim=-1).to(base_token.device)
1116
+
1117
+ return base_token, draft_tokens
1118
+
1119
+
1120
+ @OfflineEagleDMRegistry.register({PreTrainedModel: "hf.PreTrainedModel"})
1121
+ class DetachedHFEagleModel(HFEagleModel):
1122
+ """A wrapper for detached Eagle module."""
1123
+
1124
+ # TODO: Implement DetachedHFEagleModel class for offline eagle.
1125
+
1126
+
1127
+ class HFARValidation(AcceptanceRateValidation):
1128
+ """This is the subclass for HF model AR validation."""
1129
+
1130
+ def get_ground_truth(self, input_ids, osl):
1131
+ """This function returns ground truth output tokens from the base model."""
1132
+ input_ids = copy.deepcopy(input_ids).to(torch.cuda.current_device())
1133
+ for _ in range(osl):
1134
+ input_id, _ = self.model.pseudo_speculative_generate(input_ids, steps=0)
1135
+ input_ids = torch.cat((input_ids, input_id), dim=-1)
1136
+ if input_id[0, 0] == self.end_token:
1137
+ break
1138
+ return input_ids