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,2119 @@
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
+ """Plugin to add EAGLE support for Megatron-Core GPT model."""
17
+
18
+ import copy
19
+ import warnings
20
+ from collections import deque
21
+
22
+ import megatron.core
23
+ import torch
24
+ import torch.nn.functional as F
25
+ from megatron.core import InferenceParams, tensor_parallel
26
+ from megatron.core.dist_checkpointing.mapping import ShardedStateDict
27
+ from megatron.core.dist_checkpointing.utils import replace_prefix_for_sharding
28
+ from megatron.core.extensions.transformer_engine import TENorm
29
+ from megatron.core.models.common.embeddings.language_model_embedding import LanguageModelEmbedding
30
+ from megatron.core.models.common.embeddings.rotary_pos_embedding import RotaryEmbedding
31
+ from megatron.core.models.gpt import GPTModel
32
+ from megatron.core.packed_seq_params import PackedSeqParams
33
+ from megatron.core.parallel_state import (
34
+ get_data_parallel_rank,
35
+ get_expert_tensor_parallel_world_size,
36
+ get_pipeline_model_parallel_world_size,
37
+ get_tensor_model_parallel_rank,
38
+ get_tensor_model_parallel_world_size,
39
+ )
40
+ from megatron.core.tensor_parallel.mappings import (
41
+ gather_from_sequence_parallel_region,
42
+ gather_from_tensor_model_parallel_region,
43
+ scatter_to_sequence_parallel_region,
44
+ )
45
+ from megatron.core.transformer.attention import SelfAttention
46
+ from megatron.core.transformer.identity_op import IdentityOp
47
+ from megatron.core.transformer.module import MegatronModule
48
+ from megatron.core.transformer.transformer_block import TransformerBlock
49
+ from megatron.core.transformer.transformer_config import TransformerConfig
50
+ from megatron.core.transformer.transformer_layer import TransformerLayer
51
+ from megatron.core.transformer.utils import sharded_state_dict_default
52
+ from megatron.core.utils import make_tp_sharded_tensor_for_checkpoint
53
+ from packaging.version import Version
54
+
55
+ from ..eagle.conversion import EagleDMRegistry, OfflineEagleDMRegistry
56
+ from ..eagle.eagle_model import EagleModel
57
+ from ..utils import (
58
+ AcceptanceRateValidation,
59
+ Tree,
60
+ TreeNode,
61
+ get_default_attention_mask_and_position_ids,
62
+ )
63
+
64
+ try:
65
+ from megatron.core.post_training.modelopt.gpt.model_specs import get_gpt_modelopt_spec
66
+ from megatron.core.post_training.modelopt.layers import Linear
67
+ except ImportError:
68
+ warnings.warn("Fail to import megatron.core.post_training! EAGLE feature will be disable!")
69
+
70
+
71
+ def dict_to_config(
72
+ architecture_config,
73
+ use_cpu_initialization=None,
74
+ fp16=False,
75
+ bf16=True,
76
+ sequence_parallel=False,
77
+ ):
78
+ """Helper function to convert a dictionary to TransformerConfig."""
79
+ config = TransformerConfig(
80
+ normalization="RMSNorm",
81
+ activation_func=F.silu,
82
+ gated_linear_unit=True,
83
+ hidden_dropout=0.0,
84
+ attention_softmax_in_fp32=False,
85
+ tensor_model_parallel_size=get_tensor_model_parallel_world_size(),
86
+ pipeline_model_parallel_size=get_pipeline_model_parallel_world_size(),
87
+ expert_tensor_parallel_size=get_expert_tensor_parallel_world_size(),
88
+ sequence_parallel=sequence_parallel,
89
+ use_cpu_initialization=use_cpu_initialization,
90
+ fp16=fp16,
91
+ bf16=bf16,
92
+ params_dtype=getattr(torch, architecture_config["torch_dtype"]),
93
+ pipeline_dtype=None,
94
+ num_layers=architecture_config.get("num_hidden_layers"),
95
+ hidden_size=architecture_config.get("hidden_size"),
96
+ ffn_hidden_size=architecture_config.get("intermediate_size"),
97
+ num_attention_heads=architecture_config.get("num_attention_heads"),
98
+ kv_channels=architecture_config.get(
99
+ "head_dim",
100
+ architecture_config.get("hidden_size")
101
+ // architecture_config.get("num_attention_heads"),
102
+ ),
103
+ num_query_groups=architecture_config.get("num_key_value_heads"),
104
+ init_method_std=architecture_config.get("initializer_range"),
105
+ layernorm_epsilon=architecture_config.get("rms_norm_eps"),
106
+ add_bias_linear=architecture_config.get("mlp_bias"),
107
+ attention_dropout=architecture_config.get("attention_dropout"),
108
+ )
109
+
110
+ config.transformer_layer_spec = None
111
+ config.seq_length = 8192
112
+ config.gradient_accumulation_fusion = False
113
+ config.vocab_size = architecture_config.get("vocab_size")
114
+ config.max_sequence_length = architecture_config.get("max_position_embeddings")
115
+ config.position_embedding_type = architecture_config.get("position_embedding_type")
116
+ config.rotary_percent = 1.0
117
+ config.rotary_base = architecture_config.get("rope_theta")
118
+ config.rope_scaling = "rope_scaling" in architecture_config
119
+ config.rope_scaling_factor = (
120
+ architecture_config.get("rope_scaling").get("factor")
121
+ if "rope_scaling" in architecture_config
122
+ else None
123
+ )
124
+
125
+ config.draft_vocab_size = architecture_config.get("draft_vocab_size")
126
+ config.use_input_layernorm_in_first_layer = architecture_config.get(
127
+ "use_input_layernorm_in_first_layer"
128
+ )
129
+ config.use_last_layernorm = architecture_config.get("use_last_layernorm")
130
+ config.use_aux_hidden_state = architecture_config.get("use_aux_hidden_state")
131
+ config.eagle_aux_hidden_state_layer_ids = architecture_config.get(
132
+ "eagle_aux_hidden_state_layer_ids"
133
+ )
134
+ config.use_mtp_layernorm = architecture_config.get("use_mtp_layernorm")
135
+ config.parallel_draft_step = architecture_config.get("parallel_draft_step")
136
+ config.has_lm_head = architecture_config.get("has_lm_head")
137
+
138
+ return config
139
+
140
+
141
+ def mcore_version_higher_than(target_version: str):
142
+ """Check if megatron-core is least this version."""
143
+ return Version(megatron.core.__version__) > Version(target_version)
144
+
145
+
146
+ def logits_kld_loss(logits, gt_logits, mapping=None):
147
+ """KL Divergence loss using ground truth logits."""
148
+ gathered_logits = gather_from_tensor_model_parallel_region(logits)
149
+ gathered_gt_logits = gather_from_tensor_model_parallel_region(gt_logits)
150
+ if mapping is not None:
151
+ reverse_mapping = torch.arange(len(mapping)).to(mapping.device) + mapping
152
+ gathered_gt_logits = gathered_gt_logits[:, :, reverse_mapping]
153
+ loss = torch.nn.Softmax(dim=2)(gathered_gt_logits) * torch.nn.LogSoftmax(dim=2)(gathered_logits)
154
+ loss = -torch.sum(loss, 2)
155
+ return loss.transpose(0, 1)
156
+
157
+
158
+ def right_padding(input_ids: torch.Tensor, hidden_states: torch.Tensor = None):
159
+ """Pad zeros to the right so that the padded_input_ids is a multiple of tp."""
160
+ tp = get_tensor_model_parallel_world_size()
161
+ seq_len = input_ids.shape[-1]
162
+ right_padding_len = 0 if seq_len % tp == 0 else (tp - seq_len % tp)
163
+
164
+ if right_padding_len > 0:
165
+ right_token_pad = torch.zeros(
166
+ (input_ids.shape[0], right_padding_len),
167
+ dtype=input_ids.dtype,
168
+ device=input_ids.device,
169
+ )
170
+ padded_input_ids = torch.cat((input_ids, right_token_pad), dim=-1)
171
+ if hidden_states is not None:
172
+ # If sequence_parallel is used, the input hidden_states is already gathered
173
+ padding_zeros = torch.zeros(
174
+ (right_padding_len, hidden_states.shape[1], hidden_states.shape[2]),
175
+ dtype=hidden_states.dtype,
176
+ device=hidden_states.device,
177
+ )
178
+ padded_hidden_states = torch.cat((hidden_states, padding_zeros), dim=0)
179
+ else:
180
+ padded_input_ids = input_ids
181
+ padded_hidden_states = hidden_states
182
+
183
+ if hidden_states is not None:
184
+ return padded_input_ids, seq_len, padded_hidden_states
185
+ else:
186
+ return padded_input_ids, seq_len
187
+
188
+
189
+ def set_multi_step_attention_mask(attn_mask, step):
190
+ """Given an original attention_mask, construct a multi-step attention_mask.
191
+
192
+ i0 i1 i2 i3 i4 i5 i6 i7 (base input_ids)
193
+ =======================
194
+ h0 h1 h2 h3 h4 h5 h6 h7 (base hidden_states)
195
+ l0 l1 l2 l3 l4 l5 l6 l7 (base labels)
196
+
197
+
198
+ (1st) | i1 i2 i3 i4 i5 i6 i7 -- |
199
+ (out) | h0 h1 h2 h3 h4 h5 h6 h7 |
200
+ =========================================
201
+ f1 l1 | i1 h0 | x |
202
+ f2 l2 | i2 h1 | x x |
203
+ f3 l3 | i3 h2 | x x x |
204
+ f4 l4 | i4 h3 | x x x x |
205
+ f5 l5 | i5 h4 | x x x x x |
206
+ f6 l6 | i6 h5 | x x x x x x |
207
+ f7 l7 | i7 h6 | x x x x x x x |
208
+ -- -- | -- h7 | o o o o o o o o |
209
+ =========================================
210
+
211
+
212
+ (2nd) | i1 i2 i3 i4 i5 i6 i7 -- | i1 i2 i3 i4 i5 i6 i7 -- |
213
+ (out) | h0 h1 h2 h3 h4 h5 h6 h7 | -- F1 F2 F3 F4 F5 F6 F7 |
214
+ ===================================================================
215
+ F1 l1 | i1 h0 | x | |
216
+ F2 l2 | i2 h1 | x x | |
217
+ F3 l3 | i3 h2 | x x x | |
218
+ F4 l4 | i4 h3 | x x x x | |
219
+ F5 l5 | i5 h4 | x x x x x | |
220
+ F6 l6 | i6 h5 | x x x x x x | |
221
+ F7 l7 | i7 h6 | x x x x x x x | |
222
+ -- -- | -- h7 | o o o o o o o o | |
223
+ ===================================================================
224
+ -- -- | i1 -- | | |
225
+ G2 l2 | i2 F1 | x o | x |
226
+ G3 l3 | i3 F2 | x x o | x |
227
+ G4 l4 | i4 F3 | x x x o | x |
228
+ G5 l5 | i5 F4 | x x x x o | x |
229
+ G6 l6 | i6 F5 | x x x x x o | x |
230
+ G7 l7 | i7 F6 | x x x x x x o | x |
231
+ -- -- | -- F7 | | |
232
+ ===================================================================
233
+
234
+
235
+ (3rd) | i1 i2 i3 i4 i5 i6 i7 -- | i1 i2 i3 i4 i5 i6 i7 -- | i1 i2 i3 i4 i5 i6 i7 -- |
236
+ (out) | h0 h1 h2 h3 h4 h5 h6 h7 | -- F1 F2 F3 F4 F5 F6 F7 | -- -- G2 G3 G4 G5 G6 G7 |
237
+ =============================================================================================
238
+ F1 l1 | i1 h0 | x | | |
239
+ F2 l2 | i2 h1 | x x | | |
240
+ F3 l3 | i3 h2 | x x x | | |
241
+ F4 l4 | i4 h3 | x x x x | | |
242
+ F5 l5 | i5 h4 | x x x x x | | |
243
+ F6 l6 | i6 h5 | x x x x x x | | |
244
+ F7 l7 | i7 h6 | x x x x x x x | | |
245
+ -- -- | -- h7 | o o o o o o o o | | |
246
+ =============================================================================================
247
+ -- -- | i1 -- | | | |
248
+ G2 l2 | i2 F1 | x o | x | |
249
+ G3 l3 | i3 F2 | x x o | x | |
250
+ G4 l4 | i4 F3 | x x x o | x | |
251
+ G5 l5 | i5 F4 | x x x x o | x | |
252
+ G6 l6 | i6 F5 | x x x x x o | x | |
253
+ G7 l7 | i7 F6 | x x x x x x o | x | |
254
+ -- -- | -- F7 | | | |
255
+ =============================================================================================
256
+ -- -- | i1 -- | | | |
257
+ -- -- | i2 -- | | | |
258
+ H3 l3 | i3 G2 | x o o | x o | x |
259
+ H4 l4 | i4 G3 | x x o o | x o | x |
260
+ H5 l5 | i5 G4 | x x x o o | x o | x |
261
+ H6 l6 | i6 G5 | x x x x o o | x o | x |
262
+ H7 l7 | i7 G6 | x x x x x o o | x o | x |
263
+ -- -- | -- G7 | | | |
264
+ =============================================================================================
265
+
266
+
267
+ (4th) | i1 i2 i3 i4 i5 i6 i7 -- | i1 i2 i3 i4 i5 i6 i7 -- | i1 i2 i3 i4 i5 i6 i7 -- | i1 i2 i3 i4 i5 i6 i7 -- |
268
+ (out) | h0 h1 h2 h3 h4 h5 h6 h7 | -- F1 F2 F3 F4 F5 F6 F7 | -- -- G2 G3 G4 G5 G6 G7 | -- -- -- H3 H4 H5 H6 H7 |
269
+ =======================================================================================================================
270
+ F1 l1 | i1 h0 | x | | | |
271
+ F2 l2 | i2 h1 | x x | | | |
272
+ F3 l3 | i3 h2 | x x x | | | |
273
+ F4 l4 | i4 h3 | x x x x | | | |
274
+ F5 l5 | i5 h4 | x x x x x | | | |
275
+ F6 l6 | i6 h5 | x x x x x x | | | |
276
+ F7 l7 | i7 h6 | x x x x x x x | | | |
277
+ -- -- | -- h7 | o o o o o o o o | | | |
278
+ =======================================================================================================================
279
+ -- -- | i1 -- | | | | |
280
+ G2 l2 | i2 F1 | x o | x | | |
281
+ G3 l3 | i3 F2 | x x o | x | | |
282
+ G4 l4 | i4 F3 | x x x o | x | | |
283
+ G5 l5 | i5 F4 | x x x x o | x | | |
284
+ G6 l6 | i6 F5 | x x x x x o | x | | |
285
+ G7 l7 | i7 F6 | x x x x x x o | x | | |
286
+ -- -- | -- F7 | | | | |
287
+ =======================================================================================================================
288
+ -- -- | i1 -- | | | | |
289
+ -- -- | i2 -- | | | | |
290
+ H3 l3 | i3 G2 | x o o | x o | x | |
291
+ H4 l4 | i4 G3 | x x o o | x o | x | |
292
+ H5 l5 | i5 G4 | x x x o o | x o | x | |
293
+ H6 l6 | i6 G5 | x x x x o o | x o | x | |
294
+ H7 l7 | i7 G6 | x x x x x o o | x o | x | |
295
+ -- -- | -- G7 | | | | |
296
+ =======================================================================================================================
297
+ -- -- | i1 -- | | | | |
298
+ -- -- | i2 -- | | | | |
299
+ -- -- | i3 -- | | | | |
300
+ K4 l4 | i4 H3 | x | x | x | x |
301
+ K5 l5 | i5 H4 | x x | x | x | x |
302
+ K6 l6 | i6 H5 | x x x | x | x | x |
303
+ K7 l7 | i7 H6 | x x x x | x | x | x |
304
+ -- -- | -- H7 | | | | |
305
+ =======================================================================================================================
306
+ """ # noqa: E501
307
+ assert step > 1, "step should be larger than 1 in multi-step attention mask."
308
+ assert step <= 4, "Currently only a step of 4 or smaller is supported!"
309
+
310
+ s = attn_mask.shape[-1]
311
+ zero_mask = torch.ones_like(attn_mask).bool()
312
+ mask_2_1 = attn_mask.clone().detach()
313
+ mask_2_1[:, :, :, :-1] = mask_2_1[:, :, :, 1:]
314
+ mask_2_2 = torch.ones_like(attn_mask).bool()
315
+ for i in range(1, s - 1):
316
+ mask_2_2[:, :, i, i] = False
317
+
318
+ if step == 2:
319
+ attn_mask = torch.cat(
320
+ (
321
+ torch.cat((attn_mask, zero_mask), dim=-1),
322
+ torch.cat((mask_2_1, mask_2_2), dim=-1),
323
+ ),
324
+ dim=-2,
325
+ )
326
+ return attn_mask
327
+
328
+ mask_3_1 = mask_2_1.clone().detach()
329
+ mask_3_1[:, :, :, :-1] = mask_3_1[:, :, :, 1:]
330
+ mask_3_2 = mask_2_2.clone().detach()
331
+ mask_3_2[:, :, :, :-1] = mask_3_2[:, :, :, 1:]
332
+ mask_3_2[:, :, 1, 0] = True
333
+ mask_3_3 = mask_2_2.clone().detach()
334
+ mask_3_3[:, :, 1, 1] = True
335
+
336
+ if step == 3:
337
+ attn_mask = torch.cat(
338
+ (
339
+ torch.cat((attn_mask, zero_mask, zero_mask), dim=-1),
340
+ torch.cat((mask_2_1, mask_2_2, zero_mask), dim=-1),
341
+ torch.cat((mask_3_1, mask_3_2, mask_3_3), dim=-1),
342
+ ),
343
+ dim=-2,
344
+ )
345
+ return attn_mask
346
+
347
+ mask_4_1 = mask_3_1.clone().detach()
348
+ mask_4_1[:, :, :, :-1] = mask_4_1[:, :, :, 1:]
349
+ mask_4_2 = mask_3_2.clone().detach()
350
+ mask_4_2[:, :, :, :-1] = mask_4_2[:, :, :, 1:]
351
+ mask_4_2[:, :, 2, 0] = True
352
+ mask_4_3 = mask_3_3.clone().detach()
353
+ mask_4_3[:, :, :, :-1] = mask_4_3[:, :, :, 1:]
354
+ mask_4_3[:, :, 2, 1] = True
355
+ mask_4_4 = mask_3_3.clone().detach()
356
+ mask_4_4[:, :, 2, 2] = True
357
+
358
+ attn_mask = torch.cat(
359
+ (
360
+ torch.cat((attn_mask, zero_mask, zero_mask, zero_mask), dim=-1),
361
+ torch.cat((mask_2_1, mask_2_2, zero_mask, zero_mask), dim=-1),
362
+ torch.cat((mask_3_1, mask_3_2, mask_3_3, zero_mask), dim=-1),
363
+ torch.cat((mask_4_1, mask_4_2, mask_4_3, mask_4_4), dim=-1),
364
+ ),
365
+ dim=-2,
366
+ )
367
+ return attn_mask
368
+
369
+
370
+ class EagleLanguageModelEmbedding(LanguageModelEmbedding):
371
+ """Allow last pp stage to also load the embedding."""
372
+
373
+ def sharded_state_dict(
374
+ self,
375
+ prefix: str = "",
376
+ sharded_offsets: tuple[tuple[int, int, int]] = (),
377
+ metadata: dict | None = None,
378
+ ) -> ShardedStateDict:
379
+ """Different from the default, we change the state_dict to have 1 replica at pp."""
380
+ state_dict = self.state_dict(prefix="", keep_vars=True)
381
+
382
+ weight_prefix = f"{prefix}word_embeddings.weight"
383
+ return {
384
+ weight_prefix: make_tp_sharded_tensor_for_checkpoint(
385
+ tensor=state_dict["word_embeddings.weight"],
386
+ key=weight_prefix,
387
+ allow_shape_mismatch=True,
388
+ prepend_offsets=sharded_offsets,
389
+ # (PP, TP, DP)
390
+ replica_id=(1, 0, get_data_parallel_rank(with_context_parallel=True)),
391
+ )
392
+ }
393
+
394
+
395
+ class EagleTransformerBlock(TransformerBlock):
396
+ """Only store the EAGLE decoder in the last pp stage."""
397
+
398
+ def sharded_state_dict(
399
+ self, prefix: str = "", sharded_offsets: tuple = (), metadata: dict | None = None
400
+ ) -> ShardedStateDict:
401
+ """Generate a sharded state dictionary for the transformer block.
402
+
403
+ Args:
404
+ prefix (str, optional): Prefix to be added to all keys in the state dict.
405
+ Defaults to an empty string.
406
+ sharded_offsets (tuple, optional): Tuple of sharding offsets.
407
+ metadata (dict, optional): Additional metadata for sharding.
408
+ Can specify if layers are non-homogeneous. Defaults to None.
409
+
410
+ Returns:
411
+ ShardedStateDict: A dictionary containing the sharded state of the model.
412
+ """
413
+ assert not sharded_offsets, "Unexpected sharded offsets"
414
+
415
+ sharded_state_dict = {}
416
+
417
+ layer_prefix = f"{prefix}layers."
418
+ num_layers = self.config.num_layers
419
+ for global_layer_offset, layer in enumerate(self.layers):
420
+ # global_layer_offset = layer.layer_number - 1 # self.layer_number starts at 1
421
+ state_dict_prefix = (
422
+ f"{layer_prefix}{global_layer_offset}." # module list index in TransformerBlock
423
+ )
424
+ sharded_prefix = layer_prefix
425
+ sharded_pp_offset = [
426
+ (0, global_layer_offset, num_layers)
427
+ ] # PP sharding offset for ShardedTensors
428
+
429
+ layer_sharded_state_dict = layer.sharded_state_dict(
430
+ state_dict_prefix, sharded_pp_offset, metadata
431
+ )
432
+ replace_prefix_for_sharding(layer_sharded_state_dict, state_dict_prefix, sharded_prefix)
433
+ sharded_state_dict.update(layer_sharded_state_dict)
434
+
435
+ # Add modules other than self.layers
436
+ for name, module in self.named_children():
437
+ if module is not self.layers:
438
+ sharded_state_dict.update(
439
+ sharded_state_dict_default(
440
+ module, f"{prefix}{name}.", sharded_offsets, metadata
441
+ )
442
+ )
443
+
444
+ return sharded_state_dict
445
+
446
+
447
+ class EagleModule(MegatronModule):
448
+ """EagleModule definition.
449
+
450
+ EagleModule consists of an FC projection and additional decoder layers.
451
+ """
452
+
453
+ def __init__(
454
+ self,
455
+ config,
456
+ rotary_pos_emb: torch.nn.Module,
457
+ bias: bool = False,
458
+ ):
459
+ """Constructor.
460
+
461
+ EagleModule is essentially a GPTModel except that it only exists in
462
+ the last pp stage. As a result, pre_process must be True (otherwise
463
+ the decoder expects the input is from the receive buffer).
464
+ post_process must be True to perform the final_layernorm.
465
+
466
+ Args:
467
+ config: MCore transformer config
468
+ rotary_pos_emb: nn.Module.
469
+ """
470
+ # Override transformer_config before superclass initialization
471
+ config.pipeline_model_parallel_size = 1
472
+ config.virtual_pipeline_model_parallel_size = None
473
+ config.num_layers_in_first_pipeline_stage = None
474
+ config.num_layers_in_last_pipeline_stage = None
475
+ super().__init__(config=config)
476
+
477
+ eagle_transformer_layer_spec = self._get_eagle_transformer_layer_spec(config)
478
+
479
+ self._num_aux_hidden_states = len(self.config.eagle_aux_hidden_state_layer_ids)
480
+ if self._num_aux_hidden_states > 0:
481
+ self.enorm = TENorm(config, config.hidden_size, config.layernorm_epsilon)
482
+ self._embeddings = None
483
+ elif self.config.use_mtp_layernorm:
484
+ self.enorm = TENorm(config, config.hidden_size, config.layernorm_epsilon)
485
+ self.hnorm = TENorm(config, config.hidden_size, config.layernorm_epsilon)
486
+
487
+ device = "cpu" if config.use_cpu_initialization else torch.cuda.current_device()
488
+
489
+ # EAGLE-3 uses aux_hidden_states (usually >= 3); otherwise EAGLE-1
490
+ fc_input_size_multiplier = (
491
+ self._num_aux_hidden_states if self._num_aux_hidden_states > 0 else 2
492
+ )
493
+
494
+ # This linear was previously a ColumnParallelLinear. We changed it to a normal linear
495
+ # since ColumnParallelLinear will have try to gather the input sequence when sequence
496
+ # parallel is used and does not allow gathering the outputs.
497
+ with torch.device(device):
498
+ self.fc = Linear(
499
+ config.hidden_size * fc_input_size_multiplier,
500
+ config.hidden_size,
501
+ config=config,
502
+ init_method=(lambda w: None), # not used
503
+ bias=bias,
504
+ )
505
+
506
+ self.rotary_pos_emb = rotary_pos_emb
507
+
508
+ # Eagle does not use the final_layernorm in decoder.
509
+ with torch.device(device):
510
+ self.decoder = EagleTransformerBlock(
511
+ config=config,
512
+ spec=eagle_transformer_layer_spec,
513
+ post_layer_norm=config.use_last_layernorm,
514
+ pre_process=True,
515
+ post_process=True,
516
+ )
517
+
518
+ if self._num_aux_hidden_states > 0:
519
+ layer = self.decoder.layers[0]
520
+ layer.register_forward_hook(self._eagle3_layer_forward_hook)
521
+
522
+ self_attention = layer.self_attention
523
+ if not isinstance(self_attention, SelfAttention):
524
+ raise ValueError("EAGLE-3 only support SelfAttention (MHA, GQA).")
525
+
526
+ # EAGLE-3's first attention require [input_layernorm_output, aux_hidden_states]
527
+ self_attention.register_forward_pre_hook(self._eagle3_attention_forward_pre_hook)
528
+
529
+ # EAGLE-3's first layer reduces hidden_states from 2h to h.
530
+ self_attention.linear_qkv = tensor_parallel.ColumnParallelLinear(
531
+ self_attention.config.hidden_size * 2,
532
+ self_attention.query_projection_size + 2 * self_attention.kv_projection_size,
533
+ config=self_attention.config,
534
+ init_method=self_attention.config.init_method,
535
+ gather_output=False,
536
+ bias=self_attention.config.add_bias_linear or self_attention.config.add_qkv_bias,
537
+ skip_bias_add=False,
538
+ is_expert=False,
539
+ tp_comm_buffer_name="qkv",
540
+ )
541
+
542
+ if self.config.draft_vocab_size != self.config.vocab_size:
543
+ # Need an extra lm_head for eagle module since vocab size is reduced.
544
+ assert self.config.draft_vocab_size <= self.config.vocab_size, (
545
+ "EAGLE module's vocab size should be <= base model vocab size!"
546
+ )
547
+
548
+ self.register_buffer(
549
+ "d2t", torch.zeros(self.config.draft_vocab_size, dtype=torch.int64)
550
+ )
551
+ if self.config.draft_vocab_size != self.config.vocab_size or self.config.has_lm_head:
552
+ self.eagle_output_layer = tensor_parallel.ColumnParallelLinear(
553
+ self.config.hidden_size,
554
+ self.config.draft_vocab_size,
555
+ config=self.config,
556
+ init_method=self.config.init_method,
557
+ bias=False,
558
+ skip_bias_add=False,
559
+ gather_output=False,
560
+ skip_weight_param_allocation=False,
561
+ )
562
+
563
+ def _get_eagle_transformer_layer_spec(self, config):
564
+ """Get the TransformerLayer implementation spec.
565
+
566
+ IMPORTANT: EagleModule must use arbitrary_attention_mask since we need to
567
+ manipulate the mask to compute the correct loss. The default
568
+ causal mask will result in leaking.
569
+ """
570
+ transformer_layer_spec = get_gpt_modelopt_spec(
571
+ config,
572
+ remap_te_layernorm=True,
573
+ use_arbitrary_attention_mask=True,
574
+ )
575
+ # If heterogenous layers (e.g. DeepSeek), transformer_layer_spec is a
576
+ # TransformerBlockSubmodules instead. We use the last layer_specs.
577
+ if "TransformerBlockSubmodules" in str(type(transformer_layer_spec)):
578
+ eagle_transformer_layer_spec = copy.deepcopy(transformer_layer_spec.layer_specs[-1])
579
+ else:
580
+ eagle_transformer_layer_spec = copy.deepcopy(transformer_layer_spec)
581
+
582
+ # Force TransformerLayer in case RealQuantTransformerLayer was used.
583
+ eagle_transformer_layer_spec.module = TransformerLayer
584
+
585
+ if not self.config.use_input_layernorm_in_first_layer:
586
+ eagle_transformer_layer_spec.submodules.input_layernorm = IdentityOp
587
+ return eagle_transformer_layer_spec
588
+
589
+ def _eagle3_layer_forward_hook(self, module, input, output) -> None:
590
+ if not isinstance(module, TransformerLayer):
591
+ raise ValueError(
592
+ "_eagle3_layer_forward_hook can only be registered to TransformerLayer"
593
+ )
594
+ hidden_states = (
595
+ output.clone().detach()
596
+ if isinstance(output, torch.Tensor)
597
+ else output[0].clone().detach()
598
+ )
599
+ self._next_hidden_states_input = hidden_states
600
+
601
+ def _eagle3_attention_forward_pre_hook(self, module, input_layernorm_output):
602
+ assert isinstance(input_layernorm_output[0], torch.Tensor)
603
+ assert self._embeddings is not None
604
+ embeddings = self._embeddings
605
+ self._embeddings = None
606
+ return (torch.cat((embeddings, input_layernorm_output[0]), dim=-1),)
607
+
608
+ def forward(
609
+ self,
610
+ embeddings: torch.Tensor,
611
+ hidden_states: torch.Tensor,
612
+ attention_mask: torch.Tensor,
613
+ rotary_pos_emb: torch.Tensor = None,
614
+ inference_params: InferenceParams = None,
615
+ packed_seq_params: PackedSeqParams = None,
616
+ extra_block_kwargs: dict | None = None,
617
+ ) -> torch.Tensor:
618
+ """Forward function."""
619
+ # NOTE: Even if sequence_parallel is used, the rotary_seq_len must be in the original
620
+ # length. Since we get the seq_len from hidden_states.shape[0], we need to
621
+ # multiply the the tp back.
622
+ rotary_seq_len = hidden_states.shape[0]
623
+ if self.config.sequence_parallel:
624
+ rotary_seq_len *= self.config.tensor_model_parallel_size
625
+
626
+ if self.config.use_mtp_layernorm:
627
+ embeddings = self.enorm(embeddings)
628
+ hidden_states = self.hnorm(hidden_states)
629
+
630
+ # EAGLE-1 uses [s, b, h] input but EAGLE-3 uses [s, b, 2h] input
631
+ if self._num_aux_hidden_states == 0:
632
+ # [s, b, 2h]
633
+ decoder_input = torch.cat((embeddings, hidden_states), dim=-1)
634
+ decoder_input = self.fc(decoder_input)[0]
635
+ else:
636
+ # EAGLE-3 forward
637
+ # EAGLE-3 uses self.fc outside eagle_module forward to convert hidden_states from [s, b, 3h]
638
+ self._embeddings = self.enorm(embeddings)
639
+ decoder_input = hidden_states
640
+
641
+ if rotary_pos_emb is None:
642
+ rotary_pos_emb = (
643
+ None if self.config.multi_latent_attention else self.rotary_pos_emb(rotary_seq_len)
644
+ )
645
+
646
+ self._next_hidden_states_input = None
647
+
648
+ decoder_input_list = [decoder_input]
649
+ self.decoder.set_input_tensor(decoder_input_list[0])
650
+ hidden_states = self.decoder(
651
+ hidden_states=decoder_input,
652
+ attention_mask=attention_mask,
653
+ inference_params=inference_params,
654
+ rotary_pos_emb=rotary_pos_emb,
655
+ packed_seq_params=packed_seq_params,
656
+ **(extra_block_kwargs or {}),
657
+ )
658
+
659
+ if self._next_hidden_states_input is None:
660
+ next_hidden_states_input = hidden_states
661
+ else:
662
+ next_hidden_states_input = self._next_hidden_states_input
663
+ self._next_hidden_states_input = None
664
+
665
+ return hidden_states, next_hidden_states_input
666
+
667
+
668
+ @EagleDMRegistry.register({GPTModel: "megatron.core.models.gpt.GPTModel"})
669
+ class _DynamicEagleGPTModel(EagleModel):
670
+ """A ``megatron.core.models.gpt.GPTModel`` model with dynamic hyperparams."""
671
+
672
+ def _set_default_aux_hidden_state_layers(self):
673
+ if hasattr(self.config, "original_num_layers"):
674
+ num_layers = self.config.original_num_layers
675
+ else:
676
+ num_layers = self.config.num_layers
677
+ self.eagle_config.eagle_aux_hidden_state_layer_ids = [
678
+ 1,
679
+ max(0, num_layers // 2 - 1),
680
+ max(0, num_layers - 4),
681
+ ]
682
+ self.eagle_config.eagle_aux_hidden_state_layer_ids = list(
683
+ set(self.eagle_config.eagle_aux_hidden_state_layer_ids)
684
+ )
685
+
686
+ def _transformer_layer_forward_hook(self, module, input, output) -> None:
687
+ if not isinstance(module, TransformerLayer):
688
+ raise ValueError(
689
+ "_transformer_layer_forward_hook can only be registered to TransformerLayer"
690
+ )
691
+ if module.layer_number - 1 not in self.eagle_config.eagle_aux_hidden_state_layer_ids:
692
+ return
693
+ hidden_states = (
694
+ output.clone().detach()
695
+ if isinstance(output, torch.Tensor)
696
+ else output[0].clone().detach()
697
+ )
698
+ self._aux_hidden_states.append(hidden_states)
699
+
700
+ def _setup(self):
701
+ super()._setup()
702
+ self._register_temp_attribute("eagle_freeze_base_model", True)
703
+ self._register_temp_attribute("calibration_mode", False)
704
+
705
+ def modify(
706
+ self,
707
+ eagle_offline,
708
+ eagle_hidden_state_distillation,
709
+ eagle_self_logit_distillation,
710
+ eagle_freeze_base_model,
711
+ eagle_report_acc,
712
+ eagle_reuse_base_decoder,
713
+ eagle_loss_decay_factor,
714
+ eagle_architecture_config,
715
+ ):
716
+ if self.config.pipeline_model_parallel_size > 1:
717
+ warnings.warn(
718
+ "Pipeline parallelism detected! _DynamicEagleGPTModel only supports "
719
+ "pipeline parallelism during TensorRT-LLM checkpoint export."
720
+ )
721
+
722
+ # Since there is a chance that EAGLE3 can have heterogenous layers (1st layer
723
+ # qkv is 2x large than the rest), we enable MCore hetereogeneous checkpoint.
724
+ if hasattr(self.config, "hetereogenous_dist_checkpoint"):
725
+ self.config.hetereogenous_dist_checkpoint = True
726
+
727
+ super().modify(
728
+ eagle_offline=eagle_offline,
729
+ eagle_hidden_state_distillation=eagle_hidden_state_distillation,
730
+ eagle_self_logit_distillation=eagle_self_logit_distillation,
731
+ eagle_freeze_base_model=eagle_freeze_base_model,
732
+ eagle_report_acc=eagle_report_acc,
733
+ eagle_reuse_base_decoder=eagle_reuse_base_decoder,
734
+ eagle_loss_decay_factor=eagle_loss_decay_factor,
735
+ eagle_architecture_config=eagle_architecture_config,
736
+ )
737
+
738
+ self.eagle_config = dict_to_config(
739
+ eagle_architecture_config,
740
+ self.config.use_cpu_initialization,
741
+ self.config.fp16,
742
+ self.config.bf16,
743
+ self.config.sequence_parallel,
744
+ )
745
+
746
+ if self.eagle_config.draft_vocab_size != self.eagle_config.vocab_size:
747
+ assert eagle_self_logit_distillation, (
748
+ "Only logit distillation is supported when draft_vocab_size != vocab_size!"
749
+ )
750
+
751
+ # Use default aux_hidden_state layers if use_aux_hidden_state is True
752
+ # but no layer id is given
753
+ if (
754
+ self.eagle_config.use_aux_hidden_state
755
+ and len(self.eagle_config.eagle_aux_hidden_state_layer_ids) == 0
756
+ ):
757
+ self._set_default_aux_hidden_state_layers()
758
+
759
+ if len(self.eagle_config.eagle_aux_hidden_state_layer_ids) > 0:
760
+ assert not self.eagle_hidden_state_distillation, (
761
+ "EAGLE-3 does not support hidden state distillation!"
762
+ )
763
+
764
+ # EAGLE-3 auxiliary hidden_states (only work for TP+EP, does not work for PP)
765
+ self._aux_hidden_states = []
766
+
767
+ if self.eagle_config.position_embedding_type not in ["rope", "yarn"]:
768
+ raise ValueError("For EAGLE, only RoPE or YaRN embedding are supported")
769
+
770
+ if not self.pre_process and self.post_process:
771
+ self.embedding = EagleLanguageModelEmbedding(
772
+ config=self.config,
773
+ vocab_size=self.vocab_size,
774
+ max_sequence_length=self.max_sequence_length,
775
+ position_embedding_type=self.position_embedding_type,
776
+ )
777
+
778
+ # Register TransformerLayer forward hook to extract aux hidden_states.
779
+ if len(self.eagle_config.eagle_aux_hidden_state_layer_ids) > 0:
780
+ for layer in self.decoder.layers:
781
+ layer.register_forward_hook(self._transformer_layer_forward_hook)
782
+
783
+ # Freeze all parameters
784
+ if self.eagle_freeze_base_model:
785
+ for name, param in self.named_parameters():
786
+ param.requires_grad = False
787
+
788
+ # Only the last PP stage has the additional projection and decoder layer.
789
+ # This is to simplify the export.
790
+ if self.post_process:
791
+ if self.eagle_reuse_base_decoder:
792
+ eagle_config = copy.deepcopy(self.config)
793
+ # Overwrite values from the eagle config
794
+ eagle_config.num_layers = self.eagle_config.num_layers
795
+ eagle_config.use_last_layernorm = self.eagle_config.use_last_layernorm
796
+ eagle_config.use_input_layernorm_in_first_layer = (
797
+ self.eagle_config.use_input_layernorm_in_first_layer
798
+ )
799
+ eagle_config.eagle_aux_hidden_state_layer_ids = (
800
+ self.eagle_config.eagle_aux_hidden_state_layer_ids
801
+ )
802
+ eagle_config.use_mtp_layernorm = self.eagle_config.use_mtp_layernorm
803
+ self.eagle_module = EagleModule(
804
+ eagle_config,
805
+ self.rotary_pos_emb,
806
+ bias=False,
807
+ )
808
+ else:
809
+ rotary_pos_emb = RotaryEmbedding(
810
+ kv_channels=self.eagle_config.kv_channels,
811
+ rotary_percent=self.eagle_config.rotary_percent,
812
+ rotary_interleaved=False,
813
+ seq_len_interpolation_factor=None,
814
+ rotary_base=self.eagle_config.rotary_base,
815
+ rope_scaling=self.eagle_config.rope_scaling,
816
+ rope_scaling_factor=self.eagle_config.rope_scaling_factor,
817
+ use_cpu_initialization=self.eagle_config.use_cpu_initialization,
818
+ )
819
+
820
+ self.eagle_module = EagleModule(
821
+ self.eagle_config,
822
+ rotary_pos_emb,
823
+ bias=False,
824
+ )
825
+
826
+ # Eagle loss functions
827
+ self.kld = logits_kld_loss
828
+
829
+ def _get_eagle_input_hidden_states(self, hidden_states: torch.Tensor, apply_fc: bool = True):
830
+ """When _aux_hidden_states is not empty, then this is EAGLE-3.
831
+
832
+ Args:
833
+ hidden_states: last hidden_states
834
+ apply_fc: whether to apply EAGLE3 fc
835
+ """
836
+ if len(self._aux_hidden_states) == 0:
837
+ return hidden_states
838
+
839
+ # [s / TP, b, len(self._aux_hidden_states) * h]
840
+ aux_hidden_states = torch.cat(self._aux_hidden_states, dim=-1)
841
+ self._aux_hidden_states.clear()
842
+
843
+ if apply_fc:
844
+ # [s / TP, b, 3h] -> [s / TP, b, h]
845
+ return self.eagle_module.fc(aux_hidden_states)[0]
846
+ else:
847
+ return aux_hidden_states
848
+
849
+ def _get_eagle_module_inputs(
850
+ self,
851
+ input_ids: torch.Tensor,
852
+ hidden_states: torch.Tensor,
853
+ attention_mask: torch.Tensor,
854
+ position_ids: torch.Tensor,
855
+ features: torch.Tensor | None = None,
856
+ ):
857
+ """Getting EAGLE module inputs."""
858
+ b = hidden_states.shape[1]
859
+ h = hidden_states.shape[2]
860
+
861
+ # [b, 1]
862
+ id_padding = torch.zeros((b, 1), dtype=input_ids.dtype, device=input_ids.device)
863
+ padded_input_ids = torch.cat((input_ids[:, 1:], id_padding), dim=-1)
864
+
865
+ rotary_pos_emb = self.eagle_module.rotary_pos_emb(padded_input_ids.shape[-1])
866
+
867
+ attn_mask = attention_mask.clone().detach()
868
+ attn_mask[:, :, :-1, :-1] = attention_mask[:, :, 1:, 1:]
869
+ attn_mask[:, :, -1, :] = True
870
+ attn_mask[:, :, :, -1] = True
871
+
872
+ eagle_inputs = {}
873
+
874
+ if self.eagle_config.parallel_draft_step > 1:
875
+ eagle_inputs["input_ids"] = padded_input_ids
876
+ eagle_inputs["position_ids"] = position_ids
877
+ if rotary_pos_emb is not None:
878
+ eagle_inputs["rotary_pos_emb"] = rotary_pos_emb
879
+ else:
880
+ # [TODO] (yeyu): there will be problem here with MLA
881
+ eagle_inputs["rotary_pos_emb"] = None
882
+
883
+ if self.config.sequence_parallel:
884
+ gathered_hidden_states = gather_from_sequence_parallel_region(hidden_states)
885
+ else:
886
+ gathered_hidden_states = hidden_states
887
+ eagle_inputs["hidden_states"] = gathered_hidden_states
888
+
889
+ for i in range(self.eagle_config.parallel_draft_step - 1):
890
+ eagle_inputs["input_ids"] = torch.cat(
891
+ (
892
+ eagle_inputs["input_ids"],
893
+ torch.full(
894
+ padded_input_ids.shape,
895
+ getattr(self, f"mask_token_{i}"),
896
+ device=padded_input_ids.device,
897
+ dtype=padded_input_ids.dtype,
898
+ ),
899
+ ),
900
+ dim=-1,
901
+ )
902
+
903
+ eagle_inputs["hidden_states"] = torch.cat(
904
+ (
905
+ eagle_inputs["hidden_states"],
906
+ torch.zeros(
907
+ (1 + i, b, h), dtype=hidden_states.dtype, device=hidden_states.device
908
+ ),
909
+ gathered_hidden_states[: -(1 + i)],
910
+ ),
911
+ dim=0,
912
+ )
913
+
914
+ eagle_inputs["position_ids"] = torch.cat(
915
+ (eagle_inputs["position_ids"], position_ids), dim=-1
916
+ )
917
+
918
+ if rotary_pos_emb is not None:
919
+ eagle_inputs["rotary_pos_emb"] = torch.cat(
920
+ (eagle_inputs["rotary_pos_emb"], rotary_pos_emb), dim=0
921
+ )
922
+
923
+ if self.config.sequence_parallel:
924
+ eagle_inputs["hidden_states"] = scatter_to_sequence_parallel_region(
925
+ eagle_inputs["hidden_states"]
926
+ )
927
+
928
+ eagle_inputs["attention_mask"] = set_multi_step_attention_mask(
929
+ attn_mask, self.eagle_config.parallel_draft_step
930
+ )
931
+ elif features is None:
932
+ eagle_inputs["input_ids"] = padded_input_ids
933
+ eagle_inputs["hidden_states"] = hidden_states
934
+ eagle_inputs["attention_mask"] = attn_mask
935
+ eagle_inputs["position_ids"] = position_ids
936
+ eagle_inputs["rotary_pos_emb"] = rotary_pos_emb
937
+ elif features.shape[0] == hidden_states.shape[0]:
938
+ eagle_inputs["input_ids"] = torch.cat(
939
+ (padded_input_ids, padded_input_ids),
940
+ dim=-1,
941
+ )
942
+
943
+ if self.config.sequence_parallel:
944
+ gathered_hidden_states = gather_from_sequence_parallel_region(hidden_states)
945
+ gathered_features = gather_from_sequence_parallel_region(features)
946
+ else:
947
+ gathered_hidden_states = hidden_states
948
+ gathered_features = features
949
+ eagle_inputs["hidden_states"] = torch.cat(
950
+ (
951
+ gathered_hidden_states,
952
+ torch.zeros((1, b, h), dtype=hidden_states.dtype, device=hidden_states.device),
953
+ gathered_features[:-1, :, :],
954
+ ),
955
+ dim=0,
956
+ )
957
+ if self.config.sequence_parallel:
958
+ eagle_inputs["hidden_states"] = scatter_to_sequence_parallel_region(
959
+ eagle_inputs["hidden_states"]
960
+ )
961
+
962
+ eagle_inputs["attention_mask"] = set_multi_step_attention_mask(attn_mask, 2)
963
+ eagle_inputs["position_ids"] = torch.cat((position_ids, position_ids), dim=-1)
964
+
965
+ if rotary_pos_emb is not None:
966
+ eagle_inputs["rotary_pos_emb"] = torch.cat((rotary_pos_emb, rotary_pos_emb), dim=0)
967
+ else:
968
+ # [TODO] (yeyu): there will be problem here with MLA
969
+ eagle_inputs["rotary_pos_emb"] = None
970
+ elif features.shape[0] == hidden_states.shape[0] * 2:
971
+ eagle_inputs["input_ids"] = torch.cat(
972
+ (padded_input_ids, padded_input_ids, padded_input_ids),
973
+ dim=-1,
974
+ )
975
+
976
+ if self.config.sequence_parallel:
977
+ gathered_hidden_states = gather_from_sequence_parallel_region(hidden_states)
978
+ gathered_features = gather_from_sequence_parallel_region(features)
979
+ else:
980
+ gathered_hidden_states = hidden_states
981
+ gathered_features = features
982
+ eagle_inputs["hidden_states"] = torch.cat(
983
+ (
984
+ gathered_hidden_states,
985
+ torch.zeros((1, b, h), dtype=hidden_states.dtype, device=hidden_states.device),
986
+ gathered_features[:-1, :, :],
987
+ ),
988
+ dim=0,
989
+ )
990
+ if self.config.sequence_parallel:
991
+ eagle_inputs["hidden_states"] = scatter_to_sequence_parallel_region(
992
+ eagle_inputs["hidden_states"]
993
+ )
994
+
995
+ eagle_inputs["attention_mask"] = set_multi_step_attention_mask(attn_mask, 3)
996
+ eagle_inputs["position_ids"] = torch.cat(
997
+ (position_ids, position_ids, position_ids), dim=-1
998
+ )
999
+
1000
+ if rotary_pos_emb is not None:
1001
+ eagle_inputs["rotary_pos_emb"] = torch.cat(
1002
+ (rotary_pos_emb, rotary_pos_emb, rotary_pos_emb),
1003
+ dim=0,
1004
+ )
1005
+ else:
1006
+ # [TODO] (yeyu): there will be problem here with MLA
1007
+ eagle_inputs["rotary_pos_emb"] = None
1008
+ else:
1009
+ eagle_inputs["input_ids"] = torch.cat(
1010
+ (padded_input_ids, padded_input_ids, padded_input_ids, padded_input_ids),
1011
+ dim=-1,
1012
+ )
1013
+
1014
+ if self.config.sequence_parallel:
1015
+ gathered_hidden_states = gather_from_sequence_parallel_region(hidden_states)
1016
+ gathered_features = gather_from_sequence_parallel_region(features)
1017
+ else:
1018
+ gathered_hidden_states = hidden_states
1019
+ gathered_features = features
1020
+ eagle_inputs["hidden_states"] = torch.cat(
1021
+ (
1022
+ gathered_hidden_states,
1023
+ torch.zeros((1, b, h), dtype=hidden_states.dtype, device=hidden_states.device),
1024
+ gathered_features[:-1, :, :],
1025
+ ),
1026
+ dim=0,
1027
+ )
1028
+ if self.config.sequence_parallel:
1029
+ eagle_inputs["hidden_states"] = scatter_to_sequence_parallel_region(
1030
+ eagle_inputs["hidden_states"]
1031
+ )
1032
+
1033
+ eagle_inputs["attention_mask"] = set_multi_step_attention_mask(attn_mask, 4)
1034
+ eagle_inputs["position_ids"] = torch.cat(
1035
+ (position_ids, position_ids, position_ids, position_ids), dim=-1
1036
+ )
1037
+
1038
+ if rotary_pos_emb is not None:
1039
+ eagle_inputs["rotary_pos_emb"] = torch.cat(
1040
+ (rotary_pos_emb, rotary_pos_emb, rotary_pos_emb, rotary_pos_emb),
1041
+ dim=0,
1042
+ )
1043
+ else:
1044
+ # [TODO] (yeyu): there will be problem here with MLA
1045
+ eagle_inputs["rotary_pos_emb"] = None
1046
+
1047
+ eagle_inputs["embedding"] = self.embedding(
1048
+ input_ids=eagle_inputs["input_ids"],
1049
+ position_ids=eagle_inputs["position_ids"],
1050
+ )
1051
+
1052
+ return eagle_inputs
1053
+
1054
+ def _compute_eagle_loss(self, logits, labels, eagle_logits):
1055
+ """Compute the total loss for EAGLE.
1056
+
1057
+ logits: [s, b, vocab // TP]
1058
+ labels: [b, s]
1059
+ eagle_logits: [s, b, vocab // TP]
1060
+ """
1061
+ # Compute lm loss (classification loss) or KLDivergence
1062
+ if self.eagle_self_logit_distillation:
1063
+ mapping = self.eagle_module.d2t if hasattr(self.eagle_module, "d2t") else None
1064
+ token_loss = self.kld(eagle_logits[:-1, :, :], logits[1:, :, :], mapping)
1065
+ else:
1066
+ token_loss = self.compute_language_model_loss(labels[:, 1:], eagle_logits[:-1, :, :])
1067
+
1068
+ # [b, s - 1]
1069
+ return token_loss
1070
+
1071
+ def _base_model_forward(
1072
+ self,
1073
+ input_ids: torch.Tensor,
1074
+ position_ids: torch.Tensor,
1075
+ attention_mask: torch.Tensor,
1076
+ decoder_input: torch.Tensor = None,
1077
+ inference_params: InferenceParams = None,
1078
+ packed_seq_params: PackedSeqParams = None,
1079
+ extra_block_kwargs: dict | None = None,
1080
+ return_eagle_inputs: bool = False,
1081
+ ):
1082
+ # Word and rotary positional embeddings
1083
+ if decoder_input is not None:
1084
+ pass
1085
+ elif self.pre_process:
1086
+ decoder_input = self.embedding(input_ids=input_ids, position_ids=position_ids)
1087
+ else:
1088
+ # intermediate stage of pipeline
1089
+ # decoder will get hidden_states from decoder.input_tensor
1090
+ decoder_input = None
1091
+
1092
+ extra_kwargs = {"packed_seq_params": None} if mcore_version_higher_than("0.9.0") else {}
1093
+
1094
+ rotary_pos_emb = None
1095
+ yarn_mscale = 1.0
1096
+ if self.config.multi_latent_attention:
1097
+ # For MLA, rotary_pos_emb is computed per attention.
1098
+ rotary_pos_emb = None
1099
+ elif self.position_embedding_type == "rope":
1100
+ rotary_seq_len = self.rotary_pos_emb.get_rotary_seq_len(
1101
+ inference_params,
1102
+ self.decoder,
1103
+ decoder_input,
1104
+ self.config,
1105
+ **extra_kwargs,
1106
+ )
1107
+ rotary_pos_emb = self.rotary_pos_emb(rotary_seq_len)
1108
+ elif self.position_embedding_type == "yarn":
1109
+ rotary_seq_len = self.rotary_pos_emb.get_rotary_seq_len(
1110
+ inference_params,
1111
+ None,
1112
+ decoder_input,
1113
+ self.config,
1114
+ **extra_kwargs,
1115
+ )
1116
+ rotary_pos_emb, yarn_mscale = self.rotary_pos_emb(rotary_seq_len)
1117
+ else:
1118
+ raise ValueError(
1119
+ f"Only RoPE or YaRN are supported but got {self.position_embedding_type}"
1120
+ )
1121
+
1122
+ # [TODO]: yarn_mscale needs to be passed into TransformerBlock forward when supported.
1123
+ # Now the default value for yarn_mscale = 1.0
1124
+ hidden_states = self.decoder(
1125
+ hidden_states=decoder_input,
1126
+ attention_mask=attention_mask,
1127
+ inference_params=inference_params,
1128
+ rotary_pos_emb=rotary_pos_emb,
1129
+ packed_seq_params=packed_seq_params,
1130
+ **(extra_block_kwargs or {}),
1131
+ )
1132
+
1133
+ if return_eagle_inputs:
1134
+ return hidden_states, decoder_input
1135
+ else:
1136
+ return hidden_states, None
1137
+
1138
+ def _eagle_forward(
1139
+ self,
1140
+ eagle_inputs,
1141
+ output_weight,
1142
+ inference_params: InferenceParams = None,
1143
+ packed_seq_params: PackedSeqParams = None,
1144
+ extra_block_kwargs: dict | None = None,
1145
+ ):
1146
+ eagle_hidden_states, eagle_hidden_states_pre_final_layernorm = self.eagle_module(
1147
+ eagle_inputs["embedding"],
1148
+ eagle_inputs["hidden_states"],
1149
+ eagle_inputs["attention_mask"],
1150
+ eagle_inputs["rotary_pos_emb"],
1151
+ inference_params=inference_params,
1152
+ packed_seq_params=packed_seq_params,
1153
+ **(extra_block_kwargs or {}),
1154
+ )
1155
+
1156
+ if hasattr(self.eagle_module, "eagle_output_layer"):
1157
+ eagle_logits, _ = self.eagle_module.eagle_output_layer(eagle_hidden_states)
1158
+ else:
1159
+ eagle_logits, _ = self.output_layer(eagle_hidden_states, weight=output_weight)
1160
+
1161
+ return eagle_hidden_states, eagle_logits, eagle_hidden_states_pre_final_layernorm
1162
+
1163
+ def forward(
1164
+ self,
1165
+ input_ids: torch.Tensor,
1166
+ position_ids: torch.Tensor = None,
1167
+ attention_mask: torch.Tensor = None,
1168
+ decoder_input: torch.Tensor = None,
1169
+ labels: torch.Tensor = None,
1170
+ inference_params: InferenceParams = None,
1171
+ packed_seq_params: PackedSeqParams = None,
1172
+ extra_block_kwargs: dict | None = None,
1173
+ return_eagle_inputs: bool = False,
1174
+ **kwargs,
1175
+ ) -> torch.Tensor:
1176
+ if input_ids is not None and (position_ids is None or attention_mask is None):
1177
+ attention_mask, position_ids = get_default_attention_mask_and_position_ids(input_ids)
1178
+
1179
+ # When return_eagle_inputs is True, return decoder_input_for_eagle.
1180
+ # When LLM, decoder_input_for_eagle is just the text embeddings. However, when VLM
1181
+ # decoder_input_for_eagle will also contain projected image/video embeddings.
1182
+ hidden_states, decoder_input_for_eagle = self._base_model_forward(
1183
+ input_ids,
1184
+ position_ids,
1185
+ attention_mask,
1186
+ decoder_input,
1187
+ inference_params,
1188
+ packed_seq_params,
1189
+ extra_block_kwargs,
1190
+ return_eagle_inputs=return_eagle_inputs,
1191
+ )
1192
+
1193
+ # Typically, this is only the case when PP > 1.
1194
+ if not self.post_process:
1195
+ return hidden_states
1196
+
1197
+ output_weight = None
1198
+ if self.share_embeddings_and_output_weights:
1199
+ output_weight = self.shared_embedding_or_output_weight()
1200
+ logits_sbh, _ = self.output_layer(hidden_states, weight=output_weight)
1201
+
1202
+ # If EAGLE-3, aux_hidden_states are gathered by the forward_hook
1203
+ if return_eagle_inputs:
1204
+ eagle_module_input_hidden_states = self._get_eagle_input_hidden_states(
1205
+ hidden_states, apply_fc=False
1206
+ )
1207
+
1208
+ if self.config.sequence_parallel:
1209
+ eagle_module_input_hidden_states = gather_from_sequence_parallel_region(
1210
+ eagle_module_input_hidden_states
1211
+ )
1212
+ hidden_states = gather_from_sequence_parallel_region(hidden_states)
1213
+ logits_sbh = gather_from_tensor_model_parallel_region(logits_sbh)
1214
+ # In case of VLM, there will be other fields for pixels.
1215
+ return {
1216
+ "input_ids": input_ids.squeeze(0).cpu(),
1217
+ "aux_hidden_states": eagle_module_input_hidden_states.squeeze(1).cpu(),
1218
+ "hidden_states": hidden_states.squeeze(1).cpu(),
1219
+ }
1220
+ else:
1221
+ eagle_module_input_hidden_states = self._get_eagle_input_hidden_states(
1222
+ hidden_states, apply_fc=True
1223
+ )
1224
+
1225
+ # Either inference or calibration mode, we want to make sure all weights have been exercised.
1226
+ # This makes sure all quantized weights have amax calibrated
1227
+ if inference_params is None or self.calibration_mode:
1228
+ eagle_inputs_0 = self._get_eagle_module_inputs(
1229
+ input_ids=input_ids,
1230
+ hidden_states=eagle_module_input_hidden_states,
1231
+ attention_mask=attention_mask,
1232
+ position_ids=position_ids,
1233
+ )
1234
+
1235
+ _, eagle_logits_0, eagle_hidden_states_0_pre_norm = self._eagle_forward(
1236
+ eagle_inputs_0,
1237
+ output_weight,
1238
+ inference_params=inference_params,
1239
+ packed_seq_params=packed_seq_params,
1240
+ **(extra_block_kwargs or {}),
1241
+ )
1242
+
1243
+ # If labels are not provided, return the original logits. We only return after
1244
+ # all eagle weights have been exercised for quantization calibration purpose.
1245
+ if labels is None:
1246
+ return logits_sbh.transpose(0, 1).contiguous()
1247
+
1248
+ # If eagle_freeze_base_model is set to True,
1249
+ # the base model is frozen .
1250
+ loss = self.compute_language_model_loss(labels, logits_sbh)
1251
+ loss = 0.0 * loss
1252
+
1253
+ if self.eagle_config.parallel_draft_step > 1:
1254
+ for i in range(self.eagle_config.parallel_draft_step):
1255
+ eagle_logits = eagle_logits_0[i * labels.shape[1] : (i + 1) * labels.shape[1]]
1256
+ loss_ = self._compute_eagle_loss(logits_sbh, labels, eagle_logits)
1257
+ loss_ = loss_[:, i:]
1258
+ loss[:, i + 1 :] += 1.0 * loss_
1259
+ return loss
1260
+
1261
+ loss_0 = self._compute_eagle_loss(logits_sbh, labels, eagle_logits_0)
1262
+ loss[:, 1:] += self.eagle_loss_decay_factor * loss_0
1263
+
1264
+ if self.eagle_report_acc and not self.training:
1265
+ acc = []
1266
+ with torch.no_grad():
1267
+ gathered_logits = gather_from_tensor_model_parallel_region(
1268
+ eagle_logits_0[:-1, :, :]
1269
+ )
1270
+ eagle_top1 = gathered_logits.transpose(0, 1).argmax(dim=-1)
1271
+ if self.eagle_config.draft_vocab_size != self.eagle_config.vocab_size:
1272
+ eagle_top1 += self.eagle_module.d2t[eagle_top1]
1273
+ top1_p = torch.eq(labels[:, 1:], eagle_top1).sum() / eagle_top1.numel()
1274
+ acc.append(top1_p)
1275
+
1276
+ if get_tensor_model_parallel_rank() == 0:
1277
+ print(
1278
+ f"{torch.distributed.get_rank():3}/{torch.distributed.get_world_size():3} EAGLE 1st Top-1: {acc}",
1279
+ flush=True,
1280
+ )
1281
+
1282
+ # Second round of EAGLE loss
1283
+ eagle_inputs_1 = self._get_eagle_module_inputs(
1284
+ input_ids=input_ids,
1285
+ hidden_states=eagle_module_input_hidden_states,
1286
+ attention_mask=attention_mask,
1287
+ position_ids=position_ids,
1288
+ features=eagle_hidden_states_0_pre_norm,
1289
+ )
1290
+
1291
+ _, eagle_logits_2x, eagle_hidden_states_2x_pre_norm = self._eagle_forward(
1292
+ eagle_inputs_1,
1293
+ output_weight,
1294
+ inference_params=inference_params,
1295
+ packed_seq_params=packed_seq_params,
1296
+ **(extra_block_kwargs or {}),
1297
+ )
1298
+ eagle_logits_1 = eagle_logits_2x[labels.shape[1] :, :, :]
1299
+
1300
+ loss_1 = self._compute_eagle_loss(logits_sbh, labels, eagle_logits_1)
1301
+ # [b, s - 2]
1302
+ loss_1 = loss_1[:, 1:]
1303
+ loss[:, 2:] += self.eagle_loss_decay_factor**2 * loss_1
1304
+
1305
+ if self.eagle_report_acc and not self.training:
1306
+ acc = []
1307
+ with torch.no_grad():
1308
+ gathered_logits = gather_from_tensor_model_parallel_region(
1309
+ eagle_logits_1[1:-1, :, :]
1310
+ )
1311
+ eagle_top1 = gathered_logits.transpose(0, 1).argmax(dim=-1)
1312
+ if self.eagle_config.draft_vocab_size != self.eagle_config.vocab_size:
1313
+ eagle_top1 += self.eagle_module.d2t[eagle_top1]
1314
+ top1_p = torch.eq(labels[:, 2:], eagle_top1).sum() / eagle_top1.numel()
1315
+ acc.append(top1_p)
1316
+
1317
+ if get_tensor_model_parallel_rank() == 0:
1318
+ print(
1319
+ f"{torch.distributed.get_rank():3}/{torch.distributed.get_world_size():3} EAGLE 2nd Top-1: {acc}",
1320
+ flush=True,
1321
+ )
1322
+
1323
+ # Third EAGLE loss
1324
+ eagle_inputs_2 = self._get_eagle_module_inputs(
1325
+ input_ids=input_ids,
1326
+ hidden_states=eagle_module_input_hidden_states,
1327
+ attention_mask=attention_mask,
1328
+ position_ids=position_ids,
1329
+ features=eagle_hidden_states_2x_pre_norm,
1330
+ )
1331
+
1332
+ _, eagle_logits_3x, eagle_hidden_states_3x_pre_norm = self._eagle_forward(
1333
+ eagle_inputs_2,
1334
+ output_weight,
1335
+ inference_params=inference_params,
1336
+ packed_seq_params=packed_seq_params,
1337
+ **(extra_block_kwargs or {}),
1338
+ )
1339
+
1340
+ eagle_logits_2 = eagle_logits_3x[-labels.shape[1] :, :, :]
1341
+
1342
+ loss_2 = self._compute_eagle_loss(logits_sbh, labels, eagle_logits_2)
1343
+ # [b, s - 3]
1344
+ loss_2 = loss_2[:, 2:]
1345
+ loss[:, 3:] += self.eagle_loss_decay_factor**3 * loss_2
1346
+
1347
+ if self.eagle_report_acc and not self.training:
1348
+ acc = []
1349
+ with torch.no_grad():
1350
+ gathered_logits = gather_from_tensor_model_parallel_region(
1351
+ eagle_logits_2[2:-1, :, :]
1352
+ )
1353
+ eagle_top1 = gathered_logits.transpose(0, 1).argmax(dim=-1)
1354
+ if self.eagle_config.draft_vocab_size != self.eagle_config.vocab_size:
1355
+ eagle_top1 += self.eagle_module.d2t[eagle_top1]
1356
+ top1_p = torch.eq(labels[:, 3:], eagle_top1).sum() / eagle_top1.numel()
1357
+ acc.append(top1_p)
1358
+
1359
+ if get_tensor_model_parallel_rank() == 0:
1360
+ print(
1361
+ f"{torch.distributed.get_rank():3}/{torch.distributed.get_world_size():3} EAGLE 3rd Top-1: {acc}",
1362
+ flush=True,
1363
+ )
1364
+
1365
+ # Forth EAGLE loss
1366
+ eagle_inputs_3 = self._get_eagle_module_inputs(
1367
+ input_ids=input_ids,
1368
+ hidden_states=eagle_module_input_hidden_states,
1369
+ attention_mask=attention_mask,
1370
+ position_ids=position_ids,
1371
+ features=eagle_hidden_states_3x_pre_norm,
1372
+ )
1373
+
1374
+ _, eagle_logits_4x, eagle_hidden_states_4x_pre_norm = self._eagle_forward(
1375
+ eagle_inputs_3,
1376
+ output_weight,
1377
+ inference_params=inference_params,
1378
+ packed_seq_params=packed_seq_params,
1379
+ **(extra_block_kwargs or {}),
1380
+ )
1381
+
1382
+ eagle_logits_3 = eagle_logits_4x[-labels.shape[1] :, :, :]
1383
+
1384
+ loss_3 = self._compute_eagle_loss(logits_sbh, labels, eagle_logits_3)
1385
+ # [b, s - 4]
1386
+ loss_3 = loss_3[:, 3:]
1387
+ loss[:, 4:] += self.eagle_loss_decay_factor**4 * loss_3
1388
+
1389
+ if self.eagle_report_acc and not self.training:
1390
+ acc = []
1391
+ with torch.no_grad():
1392
+ gathered_logits = gather_from_tensor_model_parallel_region(
1393
+ eagle_logits_3[3:-1, :, :]
1394
+ )
1395
+ eagle_top1 = gathered_logits.transpose(0, 1).argmax(dim=-1)
1396
+ if self.eagle_config.draft_vocab_size != self.eagle_config.vocab_size:
1397
+ eagle_top1 += self.eagle_module.d2t[eagle_top1]
1398
+ top1_p = torch.eq(labels[:, 4:], eagle_top1).sum() / eagle_top1.numel()
1399
+ acc.append(top1_p)
1400
+
1401
+ if get_tensor_model_parallel_rank() == 0:
1402
+ print(
1403
+ f"{torch.distributed.get_rank():3}/{torch.distributed.get_world_size():3} EAGLE 4th Top-1: {acc}",
1404
+ flush=True,
1405
+ )
1406
+
1407
+ return loss
1408
+
1409
+ def tree_decode(self, input_ids: torch.Tensor, tree: Tree):
1410
+ """Tree-based decoding for EAGLE model using a mask-based approach.
1411
+
1412
+ This function implements a tree-based decoding strategy where each path of the tree
1413
+ represents potential token sequences. The function uses attention masks to control
1414
+ token dependencies and generate multiple candidate sequences in parallel.
1415
+
1416
+ Args:
1417
+ input_ids (torch.Tensor): Input token IDs of shape [batch_size, seq_len]
1418
+ treepaths (list[list[int]]): List of treepaths to decode
1419
+
1420
+ Returns:
1421
+ tuple: (base_token, base_draft_node, draft_tokens)
1422
+ - base_token: The next token predicted by the base model
1423
+ - base_draft_node: A TreeNode containing the base token prediction with a
1424
+ hierarchical structure of child nodes, where each child node
1425
+ represents a draft token generated by EAGLE
1426
+ - draft_tokens: all the draft tokens generated by EAGLE
1427
+ """
1428
+ # Initial setup and base model forward pass
1429
+ padded_input_ids, seq_len = right_padding(input_ids)
1430
+ attention_mask, position_ids = get_default_attention_mask_and_position_ids(padded_input_ids)
1431
+
1432
+ # Get base model hidden states
1433
+ hidden_states, _ = self._base_model_forward(
1434
+ padded_input_ids,
1435
+ position_ids,
1436
+ attention_mask,
1437
+ )
1438
+
1439
+ if not self.post_process:
1440
+ return hidden_states
1441
+
1442
+ # Generate base token prediction
1443
+ output_weight = (
1444
+ self.shared_embedding_or_output_weight()
1445
+ if self.share_embeddings_and_output_weights
1446
+ else None
1447
+ )
1448
+ logits_sbh, _ = self.output_layer(hidden_states, weight=output_weight)
1449
+ logits_sbh = logits_sbh[:seq_len, :, :]
1450
+
1451
+ base_token = (
1452
+ gather_from_tensor_model_parallel_region(logits_sbh)[-1:, :, :]
1453
+ .argmax(dim=-1)
1454
+ .transpose(0, 1)
1455
+ )
1456
+
1457
+ # Early return if no steps needed
1458
+ if not tree.root.children:
1459
+ self._aux_hidden_states.clear()
1460
+ return base_token, None, None
1461
+
1462
+ # Prepare for tree decoding
1463
+ eagle_ids = torch.cat((input_ids[:, 1:], base_token), dim=-1)
1464
+ # EAGLE-3
1465
+ # Only the first iteration input_hidden_states are from aux_hidden_state layers
1466
+ hidden_states = self._get_eagle_input_hidden_states(hidden_states)
1467
+
1468
+ if self.config.sequence_parallel:
1469
+ hidden_states = gather_from_sequence_parallel_region(hidden_states)
1470
+ hidden_states = hidden_states[:seq_len, :, :]
1471
+
1472
+ # relative id from [seq_len-1, seq_len] contains draft token position
1473
+ # [seq_len, seq_len + num_child_level_1] contains the number of children for level 1 and so on
1474
+ relative_ids = torch.tensor(
1475
+ [seq_len - 1, *list(tree.num_children.values())],
1476
+ device=input_ids.device,
1477
+ ).cumsum(dim=0)
1478
+
1479
+ draft_position_ids = torch.arange(relative_ids[-1], device=input_ids.device)
1480
+ cur_pos = seq_len - 1
1481
+ for idx in range(len(relative_ids) - 1):
1482
+ draft_position_ids[relative_ids[idx] : relative_ids[idx + 1]] = cur_pos
1483
+ cur_pos += 1
1484
+
1485
+ draft_attention_mask = torch.full(
1486
+ (1, 1, relative_ids[-1], relative_ids[-1]), True, device=input_ids.device
1487
+ ).triu_(1)
1488
+ draft_attention_mask[:, :, :, seq_len:] = True
1489
+ draft_attention_mask[:, :, seq_len - 1 :, seq_len - 1 :] = tree.attention_mask
1490
+
1491
+ draft_rotary_pos_emb = self.eagle_module.rotary_pos_emb(seq_len + tree.max_depth)
1492
+ draft_rotary_pos_emb = torch.cat(
1493
+ [draft_rotary_pos_emb[index : index + 1] for index in draft_position_ids], dim=0
1494
+ )
1495
+
1496
+ base_draft_node = TreeNode(base_token)
1497
+ queue = deque([(base_draft_node, tree.root)])
1498
+ draft_tokens = []
1499
+ # Tree decoding loop
1500
+ for step in range(tree.max_depth):
1501
+ # Prepare inputs for EAGLE forward pass
1502
+ padded_eagle_ids, seq_len, padded_hidden_states = right_padding(
1503
+ eagle_ids, hidden_states
1504
+ )
1505
+
1506
+ if self.config.sequence_parallel:
1507
+ padded_hidden_states = scatter_to_sequence_parallel_region(padded_hidden_states)
1508
+
1509
+ eagle_attention_mask, eagle_position_ids = get_default_attention_mask_and_position_ids(
1510
+ padded_eagle_ids
1511
+ )
1512
+ length = eagle_ids.shape[-1]
1513
+ eagle_attention_mask[:, :, :length, :length] = draft_attention_mask[
1514
+ :, :, :length, :length
1515
+ ]
1516
+ eagle_attention_mask[:, :, length:, length:] = True
1517
+ eagle_position_ids[:length] = draft_position_ids[:length]
1518
+ padded_rotary_pos_emb = self.eagle_module.rotary_pos_emb(padded_eagle_ids.shape[-1])
1519
+ padded_rotary_pos_emb[:length] = draft_rotary_pos_emb[:length]
1520
+
1521
+ eagle_inputs = {
1522
+ "input_ids": padded_eagle_ids,
1523
+ "embedding": self.embedding(
1524
+ input_ids=padded_eagle_ids,
1525
+ position_ids=eagle_position_ids,
1526
+ ),
1527
+ "hidden_states": padded_hidden_states,
1528
+ "attention_mask": eagle_attention_mask,
1529
+ "rotary_pos_emb": padded_rotary_pos_emb,
1530
+ }
1531
+
1532
+ # Forward pass through EAGLE
1533
+ _, eagle_logits, eagle_next_hidden_states_input = self._eagle_forward(
1534
+ eagle_inputs,
1535
+ output_weight,
1536
+ )
1537
+ # Process EAGLE outputs
1538
+ eagle_logits = eagle_logits[:seq_len, :, :]
1539
+ if self.config.sequence_parallel:
1540
+ eagle_next_hidden_states_input = gather_from_sequence_parallel_region(
1541
+ eagle_next_hidden_states_input
1542
+ )
1543
+ eagle_next_hidden_states_input = eagle_next_hidden_states_input[:seq_len, :, :]
1544
+ # Generate and store top-k tokens for each tree node
1545
+ for rel_idx in range(relative_ids[step], relative_ids[step + 1]):
1546
+ draft_node, tree_node = queue.popleft()
1547
+ n_topk = max(tree_node.children.keys()) + 1 if tree_node.children else 0
1548
+ # Get top-k tokens for current position
1549
+ new_ids = (
1550
+ gather_from_tensor_model_parallel_region(eagle_logits)[
1551
+ rel_idx : rel_idx + 1, :, :
1552
+ ]
1553
+ .topk(n_topk, dim=-1)[1]
1554
+ .squeeze(0)
1555
+ )
1556
+
1557
+ for child_idx, child_node in tree_node.children.items():
1558
+ eagle_ids = torch.cat(
1559
+ (eagle_ids, new_ids[:, child_idx : child_idx + 1]), dim=-1
1560
+ )
1561
+ # value of the node is token id
1562
+ new_draft_node = TreeNode(new_ids[:, child_idx])
1563
+ draft_tokens.append(new_ids[:, child_idx])
1564
+ draft_node.children[child_idx] = new_draft_node
1565
+ queue.append((new_draft_node, child_node))
1566
+
1567
+ # Update hidden states for each branch
1568
+ hidden_states = torch.cat(
1569
+ (
1570
+ hidden_states,
1571
+ eagle_next_hidden_states_input[rel_idx : rel_idx + 1].repeat(
1572
+ len(tree_node.children), 1, 1
1573
+ ),
1574
+ ),
1575
+ dim=0,
1576
+ )
1577
+ draft_tokens = torch.cat(draft_tokens, dim=-1)
1578
+ return base_token, base_draft_node, draft_tokens
1579
+
1580
+ def pseudo_speculative_generate(
1581
+ self,
1582
+ input_ids: torch.Tensor,
1583
+ steps: int = 1,
1584
+ ):
1585
+ """Pseudo generate of the EAGLE GPTModel.
1586
+
1587
+ Returns:
1588
+ base_token (torch.Tensor): token from base model
1589
+ draft_tokens (torch.Tensor): draft tokens from eagle module
1590
+ """
1591
+ padded_input_ids, seq_len = right_padding(input_ids)
1592
+
1593
+ attention_mask, position_ids = get_default_attention_mask_and_position_ids(padded_input_ids)
1594
+
1595
+ hidden_states, _ = self._base_model_forward(
1596
+ padded_input_ids,
1597
+ position_ids,
1598
+ attention_mask,
1599
+ )
1600
+
1601
+ if not self.post_process:
1602
+ return hidden_states
1603
+
1604
+ output_weight = None
1605
+ if self.share_embeddings_and_output_weights:
1606
+ output_weight = self.shared_embedding_or_output_weight()
1607
+ logits_sbh, _ = self.output_layer(hidden_states, weight=output_weight)
1608
+
1609
+ # Remove the padding
1610
+ logits_sbh = logits_sbh[:seq_len, :, :]
1611
+
1612
+ base_token = (
1613
+ gather_from_tensor_model_parallel_region(logits_sbh)[-1:, :, :]
1614
+ .argmax(dim=-1)
1615
+ .transpose(0, 1)
1616
+ )
1617
+
1618
+ # Early return
1619
+ if steps < 1:
1620
+ self._aux_hidden_states.clear()
1621
+ return base_token, None
1622
+
1623
+ eagle_ids = torch.cat((input_ids[:, 1:], base_token), dim=-1)
1624
+
1625
+ # EAGLE-3
1626
+ # Only the first iteration input_hidden_states are from aux_hidden_state layers
1627
+ hidden_states = self._get_eagle_input_hidden_states(hidden_states, apply_fc=True)
1628
+ # Remove the padding
1629
+ if self.config.sequence_parallel:
1630
+ hidden_states = gather_from_sequence_parallel_region(hidden_states)
1631
+ hidden_states = hidden_states[:seq_len, :, :]
1632
+
1633
+ draft_tokens = []
1634
+ for _ in range(steps):
1635
+ if self.eagle_config.parallel_draft_step > 1:
1636
+ for i in range(self.eagle_config.parallel_draft_step - 1):
1637
+ eagle_ids = torch.cat(
1638
+ (eagle_ids, getattr(self, f"mask_token_{i}").view((1, 1))), dim=-1
1639
+ )
1640
+ hidden_states = torch.cat((hidden_states, hidden_states[-1:]), dim=0)
1641
+ padded_eagle_ids, seq_len, padded_hidden_states = right_padding(
1642
+ eagle_ids, hidden_states
1643
+ )
1644
+ if self.config.sequence_parallel:
1645
+ padded_hidden_states = scatter_to_sequence_parallel_region(padded_hidden_states)
1646
+ eagle_attention_mask, eagle_position_ids = get_default_attention_mask_and_position_ids(
1647
+ padded_eagle_ids
1648
+ )
1649
+
1650
+ eagle_inputs = {}
1651
+ eagle_inputs["input_ids"] = padded_eagle_ids
1652
+ eagle_inputs["embedding"] = self.embedding(
1653
+ input_ids=padded_eagle_ids,
1654
+ position_ids=eagle_position_ids,
1655
+ )
1656
+ eagle_inputs["hidden_states"] = padded_hidden_states
1657
+ eagle_inputs["attention_mask"] = eagle_attention_mask
1658
+
1659
+ # [TODO] (chenhany): let the module compute itself
1660
+ eagle_inputs["rotary_pos_emb"] = None
1661
+
1662
+ _, eagle_logits, eagle_next_hidden_states_input = self._eagle_forward(
1663
+ eagle_inputs,
1664
+ output_weight,
1665
+ )
1666
+
1667
+ eagle_logits = eagle_logits[:seq_len, :, :]
1668
+ if self.config.sequence_parallel:
1669
+ eagle_next_hidden_states_input = gather_from_sequence_parallel_region(
1670
+ eagle_next_hidden_states_input
1671
+ )
1672
+ eagle_next_hidden_states_input = eagle_next_hidden_states_input[:seq_len, :, :]
1673
+
1674
+ if self.eagle_config.parallel_draft_step > 1:
1675
+ draft_token = (
1676
+ gather_from_tensor_model_parallel_region(eagle_logits)[
1677
+ -self.eagle_config.parallel_draft_step :, :, :
1678
+ ]
1679
+ .argmax(dim=-1)
1680
+ .transpose(0, 1)
1681
+ )
1682
+ else:
1683
+ draft_token = (
1684
+ gather_from_tensor_model_parallel_region(eagle_logits)[-1:, :, :]
1685
+ .argmax(dim=-1)
1686
+ .transpose(0, 1)
1687
+ )
1688
+ if self.eagle_config.draft_vocab_size != self.eagle_config.vocab_size:
1689
+ draft_token += self.eagle_module.d2t[draft_token]
1690
+
1691
+ if self.eagle_config.parallel_draft_step > 1:
1692
+ return base_token, draft_token
1693
+
1694
+ draft_tokens.append(draft_token)
1695
+
1696
+ eagle_ids = torch.cat((eagle_ids, draft_token), dim=-1)
1697
+ hidden_states = torch.cat(
1698
+ (hidden_states, eagle_next_hidden_states_input[-1:, :, :]), dim=0
1699
+ )
1700
+
1701
+ draft_tokens = torch.cat(draft_tokens, dim=-1)
1702
+
1703
+ return base_token, draft_tokens
1704
+
1705
+
1706
+ @OfflineEagleDMRegistry.register({GPTModel: "megatron.core.models.gpt.GPTModel"})
1707
+ class _DetachedEagleGPTModel(_DynamicEagleGPTModel):
1708
+ """A wrapper for detached Eagle module."""
1709
+
1710
+ def modify(
1711
+ self,
1712
+ eagle_offline,
1713
+ eagle_hidden_state_distillation,
1714
+ eagle_self_logit_distillation,
1715
+ eagle_freeze_base_model,
1716
+ eagle_report_acc,
1717
+ eagle_reuse_base_decoder,
1718
+ eagle_loss_decay_factor,
1719
+ eagle_architecture_config,
1720
+ ):
1721
+ super(_DynamicEagleGPTModel, self).modify(
1722
+ eagle_offline=eagle_offline,
1723
+ eagle_hidden_state_distillation=eagle_hidden_state_distillation,
1724
+ eagle_self_logit_distillation=eagle_self_logit_distillation,
1725
+ eagle_freeze_base_model=eagle_freeze_base_model,
1726
+ eagle_report_acc=eagle_report_acc,
1727
+ eagle_reuse_base_decoder=eagle_reuse_base_decoder,
1728
+ eagle_loss_decay_factor=eagle_loss_decay_factor,
1729
+ eagle_architecture_config=eagle_architecture_config,
1730
+ )
1731
+
1732
+ # Freeze all parameters
1733
+ if self.eagle_freeze_base_model:
1734
+ for name, param in self.named_parameters():
1735
+ param.requires_grad = False
1736
+
1737
+ self.eagle_config = dict_to_config(
1738
+ eagle_architecture_config,
1739
+ self.config.use_cpu_initialization,
1740
+ self.config.fp16,
1741
+ self.config.bf16,
1742
+ )
1743
+
1744
+ assert not eagle_reuse_base_decoder, (
1745
+ "_DetachedEagleGPTModel does not have a base model so eagle_reuse_base_decoder must be False!"
1746
+ )
1747
+
1748
+ if self.eagle_config.draft_vocab_size != self.eagle_config.vocab_size:
1749
+ assert eagle_self_logit_distillation, (
1750
+ "Only logit distillation is supported when draft_vocab_size != vocab_size!"
1751
+ )
1752
+
1753
+ # Use default aux_hidden_state layers if use_aux_hidden_state is True
1754
+ # but no layer id is given
1755
+ # layer ids are not used in detached eagle, but we need to set this to have correct fc_input_size_multiplier
1756
+ if (
1757
+ self.eagle_config.use_aux_hidden_state
1758
+ and len(self.eagle_config.eagle_aux_hidden_state_layer_ids) == 0
1759
+ ):
1760
+ self._set_default_aux_hidden_state_layers()
1761
+
1762
+ # Only the last PP stage has the additional projection and decoder layer.
1763
+ # This is to simplify the export.
1764
+ if self.post_process:
1765
+ rotary_pos_emb = RotaryEmbedding(
1766
+ kv_channels=self.eagle_config.kv_channels,
1767
+ rotary_percent=self.eagle_config.rotary_percent,
1768
+ rotary_interleaved=False,
1769
+ seq_len_interpolation_factor=None,
1770
+ rotary_base=self.eagle_config.rotary_base,
1771
+ rope_scaling=self.eagle_config.rope_scaling,
1772
+ rope_scaling_factor=self.eagle_config.rope_scaling_factor,
1773
+ use_cpu_initialization=self.eagle_config.use_cpu_initialization,
1774
+ )
1775
+
1776
+ self.eagle_module = EagleModule(
1777
+ self.eagle_config,
1778
+ rotary_pos_emb,
1779
+ bias=False,
1780
+ )
1781
+
1782
+ # Eagle loss functions
1783
+ self.kld = logits_kld_loss
1784
+
1785
+ def _get_eagle_input_hidden_states(self, hidden_states: torch.Tensor, apply_fc: bool = True):
1786
+ if apply_fc:
1787
+ # [s / TP, b, 3h] -> [s / TP, b, h]
1788
+ return self.eagle_module.fc(hidden_states)[0]
1789
+ else:
1790
+ return hidden_states
1791
+
1792
+ def _get_detached_eagle_module_inputs(
1793
+ self,
1794
+ input_ids: torch.Tensor,
1795
+ hidden_states: torch.Tensor,
1796
+ attention_mask: torch.Tensor,
1797
+ position_ids: torch.Tensor,
1798
+ features: torch.Tensor | None = None,
1799
+ ):
1800
+ """Getting EAGLE module inputs."""
1801
+ b = hidden_states.shape[1]
1802
+ h = hidden_states.shape[2]
1803
+
1804
+ # [b, 1]
1805
+ id_padding = torch.zeros((b, 1), dtype=input_ids.dtype, device=input_ids.device)
1806
+ padded_input_ids = torch.cat((input_ids[:, 1:], id_padding), dim=-1)
1807
+
1808
+ rotary_pos_emb = self.eagle_module.rotary_pos_emb(padded_input_ids.shape[-1])
1809
+
1810
+ attn_mask = attention_mask.clone().detach()
1811
+ attn_mask[:, :, :-1, :-1] = attention_mask[:, :, 1:, 1:]
1812
+ attn_mask[:, :, -1, :] = True
1813
+ attn_mask[:, :, :, -1] = True
1814
+
1815
+ eagle_inputs = {}
1816
+
1817
+ assert self.eagle_config.parallel_draft_step == 1, (
1818
+ "Detached Eagle module does not support parallel draft yet!"
1819
+ )
1820
+ if features is None:
1821
+ eagle_inputs["input_ids"] = padded_input_ids
1822
+ eagle_inputs["hidden_states"] = hidden_states
1823
+ eagle_inputs["attention_mask"] = attn_mask
1824
+ eagle_inputs["position_ids"] = position_ids
1825
+ eagle_inputs["rotary_pos_emb"] = rotary_pos_emb
1826
+ elif features.shape[0] == hidden_states.shape[0]:
1827
+ eagle_inputs["input_ids"] = torch.cat(
1828
+ (padded_input_ids, padded_input_ids),
1829
+ dim=-1,
1830
+ )
1831
+ eagle_inputs["hidden_states"] = torch.cat(
1832
+ (
1833
+ hidden_states,
1834
+ torch.zeros((1, b, h), dtype=hidden_states.dtype, device=hidden_states.device),
1835
+ features[:-1, :, :],
1836
+ ),
1837
+ dim=0,
1838
+ )
1839
+ eagle_inputs["attention_mask"] = set_multi_step_attention_mask(attn_mask, 2)
1840
+ eagle_inputs["position_ids"] = torch.cat((position_ids, position_ids), dim=-1)
1841
+
1842
+ if rotary_pos_emb is not None:
1843
+ eagle_inputs["rotary_pos_emb"] = torch.cat((rotary_pos_emb, rotary_pos_emb), dim=0)
1844
+ else:
1845
+ # [TODO] (yeyu): there will be problem here with MLA
1846
+ eagle_inputs["rotary_pos_emb"] = None
1847
+ elif features.shape[0] == hidden_states.shape[0] * 2:
1848
+ eagle_inputs["input_ids"] = torch.cat(
1849
+ (padded_input_ids, padded_input_ids, padded_input_ids),
1850
+ dim=-1,
1851
+ )
1852
+ eagle_inputs["hidden_states"] = torch.cat(
1853
+ (
1854
+ hidden_states,
1855
+ torch.zeros((1, b, h), dtype=hidden_states.dtype, device=hidden_states.device),
1856
+ features[:-1, :, :],
1857
+ ),
1858
+ dim=0,
1859
+ )
1860
+
1861
+ eagle_inputs["attention_mask"] = set_multi_step_attention_mask(attn_mask, 3)
1862
+ eagle_inputs["position_ids"] = torch.cat(
1863
+ (position_ids, position_ids, position_ids), dim=-1
1864
+ )
1865
+
1866
+ if rotary_pos_emb is not None:
1867
+ eagle_inputs["rotary_pos_emb"] = torch.cat(
1868
+ (rotary_pos_emb, rotary_pos_emb, rotary_pos_emb),
1869
+ dim=0,
1870
+ )
1871
+ else:
1872
+ # [TODO] (yeyu): there will be problem here with MLA
1873
+ eagle_inputs["rotary_pos_emb"] = None
1874
+ else:
1875
+ eagle_inputs["input_ids"] = torch.cat(
1876
+ (padded_input_ids, padded_input_ids, padded_input_ids, padded_input_ids),
1877
+ dim=-1,
1878
+ )
1879
+ eagle_inputs["hidden_states"] = torch.cat(
1880
+ (
1881
+ hidden_states,
1882
+ torch.zeros((1, b, h), dtype=hidden_states.dtype, device=hidden_states.device),
1883
+ features[:-1, :, :],
1884
+ ),
1885
+ dim=0,
1886
+ )
1887
+
1888
+ eagle_inputs["attention_mask"] = set_multi_step_attention_mask(attn_mask, 4)
1889
+ eagle_inputs["position_ids"] = torch.cat(
1890
+ (position_ids, position_ids, position_ids, position_ids), dim=-1
1891
+ )
1892
+
1893
+ if rotary_pos_emb is not None:
1894
+ eagle_inputs["rotary_pos_emb"] = torch.cat(
1895
+ (rotary_pos_emb, rotary_pos_emb, rotary_pos_emb, rotary_pos_emb),
1896
+ dim=0,
1897
+ )
1898
+ else:
1899
+ # [TODO] (yeyu): there will be problem here with MLA
1900
+ eagle_inputs["rotary_pos_emb"] = None
1901
+
1902
+ eagle_inputs["embedding"] = self.embedding(
1903
+ input_ids=eagle_inputs["input_ids"],
1904
+ position_ids=eagle_inputs["position_ids"],
1905
+ )
1906
+
1907
+ return eagle_inputs
1908
+
1909
+ def forward(
1910
+ self,
1911
+ input_ids: torch.Tensor = None,
1912
+ position_ids: torch.Tensor = None,
1913
+ attention_mask: torch.Tensor = None,
1914
+ decoder_input: torch.Tensor = None,
1915
+ labels: torch.Tensor = None,
1916
+ inference_params: InferenceParams = None,
1917
+ packed_seq_params: PackedSeqParams = None,
1918
+ extra_block_kwargs: dict | None = None,
1919
+ return_eagle_inputs: bool = False, # Not used in Detached Eagle
1920
+ **kwargs,
1921
+ ) -> torch.Tensor:
1922
+ assert "aux_hidden_states" in kwargs, (
1923
+ "aux_hidden_states is required as input to _DetachedEagleGPTModel"
1924
+ )
1925
+ assert "hidden_states" in kwargs, (
1926
+ "hidden_states is required as input to _DetachedEagleGPTModel"
1927
+ )
1928
+ aux_hidden_states = kwargs.get("aux_hidden_states")
1929
+ hidden_states = kwargs.get("hidden_states")
1930
+
1931
+ # Note: labels is 1 token shorter than logits in detached mode
1932
+
1933
+ if position_ids is None or attention_mask is None:
1934
+ attention_mask, position_ids = get_default_attention_mask_and_position_ids(input_ids)
1935
+
1936
+ eagle_module_input_hidden_states = self._get_eagle_input_hidden_states(aux_hidden_states)
1937
+ output_weight = None
1938
+ if self.share_embeddings_and_output_weights:
1939
+ output_weight = self.shared_embedding_or_output_weight()
1940
+ logits_sbh, _ = self.output_layer(hidden_states, weight=output_weight)
1941
+
1942
+ eagle_inputs_0 = self._get_detached_eagle_module_inputs(
1943
+ input_ids=input_ids,
1944
+ hidden_states=eagle_module_input_hidden_states,
1945
+ attention_mask=attention_mask,
1946
+ position_ids=position_ids,
1947
+ )
1948
+
1949
+ _, eagle_logits_0, eagle_hidden_states_0_pre_norm = self._eagle_forward(
1950
+ eagle_inputs_0,
1951
+ None,
1952
+ inference_params=inference_params,
1953
+ packed_seq_params=packed_seq_params,
1954
+ **(extra_block_kwargs or {}),
1955
+ )
1956
+
1957
+ loss = torch.zeros(input_ids.shape).to(input_ids.device)
1958
+
1959
+ loss_0 = self._compute_eagle_loss(logits_sbh, labels, eagle_logits_0)
1960
+ loss[:, 1:] += self.eagle_loss_decay_factor * loss_0
1961
+
1962
+ if self.eagle_report_acc and not self.training:
1963
+ acc = []
1964
+ with torch.no_grad():
1965
+ gathered_logits = gather_from_tensor_model_parallel_region(
1966
+ eagle_logits_0[:-2, :, :]
1967
+ )
1968
+ eagle_top1 = gathered_logits.transpose(0, 1).argmax(dim=-1)
1969
+ if self.eagle_config.draft_vocab_size != self.eagle_config.vocab_size:
1970
+ eagle_top1 += self.eagle_module.d2t[eagle_top1]
1971
+ top1_p = torch.eq(labels[:, 1:], eagle_top1).sum() / eagle_top1.numel()
1972
+ acc.append(top1_p)
1973
+
1974
+ if get_tensor_model_parallel_rank() == 0:
1975
+ print(
1976
+ f"{torch.distributed.get_rank():3}/{torch.distributed.get_world_size():3} EAGLE 1st Top-1: {acc}",
1977
+ flush=True,
1978
+ )
1979
+
1980
+ # Second round of EAGLE loss
1981
+ eagle_inputs_1 = self._get_detached_eagle_module_inputs(
1982
+ input_ids=input_ids,
1983
+ hidden_states=eagle_module_input_hidden_states,
1984
+ attention_mask=attention_mask,
1985
+ position_ids=position_ids,
1986
+ features=eagle_hidden_states_0_pre_norm,
1987
+ )
1988
+
1989
+ _, eagle_logits_2x, eagle_hidden_states_2x_pre_norm = self._eagle_forward(
1990
+ eagle_inputs_1,
1991
+ None,
1992
+ inference_params=inference_params,
1993
+ packed_seq_params=packed_seq_params,
1994
+ **(extra_block_kwargs or {}),
1995
+ )
1996
+ eagle_logits_1 = eagle_logits_2x[logits_sbh.shape[0] :, :, :]
1997
+
1998
+ loss_1 = self._compute_eagle_loss(logits_sbh, labels, eagle_logits_1)
1999
+ # [b, s - 2]
2000
+ loss_1 = loss_1[:, 1:]
2001
+ loss[:, 2:] += self.eagle_loss_decay_factor**2 * loss_1
2002
+
2003
+ if self.eagle_report_acc and not self.training:
2004
+ acc = []
2005
+ with torch.no_grad():
2006
+ gathered_logits = gather_from_tensor_model_parallel_region(
2007
+ eagle_logits_1[1:-2, :, :]
2008
+ )
2009
+ eagle_top1 = gathered_logits.transpose(0, 1).argmax(dim=-1)
2010
+ if self.eagle_config.draft_vocab_size != self.eagle_config.vocab_size:
2011
+ eagle_top1 += self.eagle_module.d2t[eagle_top1]
2012
+ top1_p = torch.eq(labels[:, 2:], eagle_top1).sum() / eagle_top1.numel()
2013
+ acc.append(top1_p)
2014
+
2015
+ if get_tensor_model_parallel_rank() == 0:
2016
+ print(
2017
+ f"{torch.distributed.get_rank():3}/{torch.distributed.get_world_size():3} EAGLE 2nd Top-1: {acc}",
2018
+ flush=True,
2019
+ )
2020
+
2021
+ # Third EAGLE loss
2022
+ eagle_inputs_2 = self._get_detached_eagle_module_inputs(
2023
+ input_ids=input_ids,
2024
+ hidden_states=eagle_module_input_hidden_states,
2025
+ attention_mask=attention_mask,
2026
+ position_ids=position_ids,
2027
+ features=eagle_hidden_states_2x_pre_norm,
2028
+ )
2029
+
2030
+ _, eagle_logits_3x, eagle_hidden_states_3x_pre_norm = self._eagle_forward(
2031
+ eagle_inputs_2,
2032
+ None,
2033
+ inference_params=inference_params,
2034
+ packed_seq_params=packed_seq_params,
2035
+ **(extra_block_kwargs or {}),
2036
+ )
2037
+
2038
+ eagle_logits_2 = eagle_logits_3x[-logits_sbh.shape[0] :, :, :]
2039
+
2040
+ loss_2 = self._compute_eagle_loss(logits_sbh, labels, eagle_logits_2)
2041
+ # [b, s - 3]
2042
+ loss_2 = loss_2[:, 2:]
2043
+ loss[:, 3:] += self.eagle_loss_decay_factor**3 * loss_2
2044
+
2045
+ if self.eagle_report_acc and not self.training:
2046
+ acc = []
2047
+ with torch.no_grad():
2048
+ gathered_logits = gather_from_tensor_model_parallel_region(
2049
+ eagle_logits_2[2:-2, :, :]
2050
+ )
2051
+ eagle_top1 = gathered_logits.transpose(0, 1).argmax(dim=-1)
2052
+ if self.eagle_config.draft_vocab_size != self.eagle_config.vocab_size:
2053
+ eagle_top1 += self.eagle_module.d2t[eagle_top1]
2054
+ top1_p = torch.eq(labels[:, 3:], eagle_top1).sum() / eagle_top1.numel()
2055
+ acc.append(top1_p)
2056
+
2057
+ if get_tensor_model_parallel_rank() == 0:
2058
+ print(
2059
+ f"{torch.distributed.get_rank():3}/{torch.distributed.get_world_size():3} EAGLE 3rd Top-1: {acc}",
2060
+ flush=True,
2061
+ )
2062
+
2063
+ # Forth EAGLE loss
2064
+ eagle_inputs_3 = self._get_detached_eagle_module_inputs(
2065
+ input_ids=input_ids,
2066
+ hidden_states=eagle_module_input_hidden_states,
2067
+ attention_mask=attention_mask,
2068
+ position_ids=position_ids,
2069
+ features=eagle_hidden_states_3x_pre_norm,
2070
+ )
2071
+
2072
+ _, eagle_logits_4x, eagle_hidden_states_4x_pre_norm = self._eagle_forward(
2073
+ eagle_inputs_3,
2074
+ None,
2075
+ inference_params=inference_params,
2076
+ packed_seq_params=packed_seq_params,
2077
+ **(extra_block_kwargs or {}),
2078
+ )
2079
+
2080
+ eagle_logits_3 = eagle_logits_4x[-logits_sbh.shape[0] :, :, :]
2081
+
2082
+ loss_3 = self._compute_eagle_loss(logits_sbh, labels, eagle_logits_3)
2083
+ # [b, s - 4]
2084
+ loss_3 = loss_3[:, 3:]
2085
+ loss[:, 4:] += self.eagle_loss_decay_factor**4 * loss_3
2086
+
2087
+ if self.eagle_report_acc and not self.training:
2088
+ acc = []
2089
+ with torch.no_grad():
2090
+ gathered_logits = gather_from_tensor_model_parallel_region(
2091
+ eagle_logits_3[3:-2, :, :]
2092
+ )
2093
+ eagle_top1 = gathered_logits.transpose(0, 1).argmax(dim=-1)
2094
+ if self.eagle_config.draft_vocab_size != self.eagle_config.vocab_size:
2095
+ eagle_top1 += self.eagle_module.d2t[eagle_top1]
2096
+ top1_p = torch.eq(labels[:, 4:], eagle_top1).sum() / eagle_top1.numel()
2097
+ acc.append(top1_p)
2098
+
2099
+ if get_tensor_model_parallel_rank() == 0:
2100
+ print(
2101
+ f"{torch.distributed.get_rank():3}/{torch.distributed.get_world_size():3} EAGLE 4th Top-1: {acc}",
2102
+ flush=True,
2103
+ )
2104
+
2105
+ return loss
2106
+
2107
+
2108
+ class MegatronARValidation(AcceptanceRateValidation):
2109
+ """This is the subclass for megatron model AR validation."""
2110
+
2111
+ def get_ground_truth(self, input_ids, osl):
2112
+ """This function returns ground truth output tokens from the base model."""
2113
+ input_ids = copy.deepcopy(input_ids)
2114
+ for _ in range(osl):
2115
+ input_id, _ = self.model.pseudo_speculative_generate(input_ids, steps=0)
2116
+ input_ids = torch.cat((input_ids, input_id), dim=-1)
2117
+ if input_id[0, 0] == self.end_token:
2118
+ break
2119
+ return input_ids