|
| 1 | +# Copyright (c) 2026 FlagScale CORPORATION & AFFILIATES. All rights reserved. |
| 2 | + |
| 3 | +"""Alternative GPT builder file. |
| 4 | +
|
| 5 | +This file is intentionally shaped like deepseek_builders.py so you can switch by |
| 6 | +changing only the import path in training scripts. |
| 7 | +""" |
| 8 | + |
| 9 | +from dataclasses import dataclass |
| 10 | +from typing import Optional, Union |
| 11 | + |
| 12 | +import torch |
| 13 | + |
| 14 | +from megatron.core.models.gpt.gpt_layer_specs import ( |
| 15 | + get_gpt_mtp_block_spec, |
| 16 | + get_gpt_layer_with_transformer_engine_spec, |
| 17 | + get_gpt_layer_local_spec, |
| 18 | + get_gpt_layer_with_inference_spec |
| 19 | +) |
| 20 | +from megatron.core.fusions.fused_bias_dropout import get_bias_dropout_add |
| 21 | +from megatron.core.transformer.spec_utils import ModuleSpec |
| 22 | +from megatron.core.transformer.transformer_config import TransformerConfig |
| 23 | +from megatron.core.transformer.transformer_layer import get_transformer_layer_offset |
| 24 | +from megatron.training import print_rank_0 |
| 25 | +from megatron.training.arguments import core_transformer_config_from_args |
| 26 | +from megatron.training.yaml_arguments import core_transformer_config_from_yaml |
| 27 | +from megatron.core.transformer.identity_op import IdentityOp |
| 28 | +from megatron.core.transformer.transformer_block import ( |
| 29 | + TransformerBlockSubmodules, |
| 30 | + get_num_layers_to_build, |
| 31 | +) |
| 32 | + |
| 33 | +from megatron.core.transformer.enums import LayerType |
| 34 | +from megatron.training.utils import get_args |
| 35 | +from megatron.core.models.gpt.experimental_attention_variant_module_specs import ( |
| 36 | + get_transformer_block_with_experimental_attention_variant_spec, |
| 37 | + _get_backend_spec_provider, |
| 38 | + get_dsv4_hybrid_module_spec_for_backend, |
| 39 | + _get_moe_module_spec, |
| 40 | + get_moe_layer_pattern |
| 41 | +) |
| 42 | +from megatron.core.transformer.hyper_connection import HyperConnectionModule |
| 43 | +from megatron.core.transformer.engram import EngramModule |
| 44 | +try: |
| 45 | + import transformer_engine as te # pylint: disable=unused-import |
| 46 | + |
| 47 | + from megatron.core.extensions.transformer_engine import TENorm |
| 48 | + from megatron.core.extensions.transformer_engine_spec_provider import TESpecProvider |
| 49 | + |
| 50 | + HAVE_TE = True |
| 51 | +except ImportError: |
| 52 | + HAVE_TE = False |
| 53 | + |
| 54 | +try: |
| 55 | + import nvidia_kitchen # pylint: disable=unused-import |
| 56 | + |
| 57 | + from megatron.core.extensions.kitchen import KitchenSpecProvider |
| 58 | + |
| 59 | + HAVE_KITCHEN = True |
| 60 | +except ImportError: |
| 61 | + HAVE_KITCHEN = False |
| 62 | + |
| 63 | +try: |
| 64 | + import apex # pylint: disable=unused-import |
| 65 | + |
| 66 | + from megatron.core.fusions.fused_layer_norm import FusedLayerNorm |
| 67 | + |
| 68 | + HAVE_APEX = True |
| 69 | + LNImpl = FusedLayerNorm |
| 70 | +except ImportError: |
| 71 | + import warnings |
| 72 | + |
| 73 | + from megatron.core.transformer.torch_norm import WrappedTorchNorm |
| 74 | + |
| 75 | + warnings.warn("Apex is not installed. Falling back to Torch Norm") |
| 76 | + LNImpl = WrappedTorchNorm |
| 77 | + HAVE_APEX = False |
| 78 | + |
| 79 | +from .deepseek_transformer_layer import DeepSeekTransformerLayer, DeepSeekTransformerLayerSubmodules |
| 80 | +from .deepseek_model import DeepSeekModel |
| 81 | + |
| 82 | + |
| 83 | + |
| 84 | +def get_deepseek_layer_spec( |
| 85 | + use_te: bool, |
| 86 | + config: TransformerConfig, |
| 87 | + build_engram: bool = False, |
| 88 | +) -> ModuleSpec: |
| 89 | + """ |
| 90 | + Build LayerSpec that inserts engram and mhc into TransformerLayer. |
| 91 | + Because not all layers have engram, we build the engram module as an optional submodule. |
| 92 | + """ |
| 93 | + backend = _get_backend_spec_provider(config=config) |
| 94 | + hybrid_attn_spec = get_dsv4_hybrid_module_spec_for_backend(config=config, backend=backend) |
| 95 | + |
| 96 | + moe_layer_spec = _get_moe_module_spec(config=config, backend=backend) |
| 97 | + rms_norm = config.normalization == "RMSNorm" |
| 98 | + input_layernorm = ( |
| 99 | + IdentityOp |
| 100 | + if hybrid_attn_spec.metainfo["fuse_input_layernorm"] |
| 101 | + else backend.layer_norm(rms_norm=rms_norm, for_qk=False) |
| 102 | + ) |
| 103 | + pre_mlp_layernorm = ( |
| 104 | + IdentityOp |
| 105 | + if moe_layer_spec.metainfo["fuse_pre_mlp_layernorm"] |
| 106 | + else backend.layer_norm(rms_norm=rms_norm, for_qk=False) |
| 107 | + ) |
| 108 | + if build_engram: |
| 109 | + engram_module = EngramModule |
| 110 | + else: |
| 111 | + engram_module = IdentityOp |
| 112 | + submodules = DeepSeekTransformerLayerSubmodules( |
| 113 | + input_layernorm=input_layernorm, |
| 114 | + self_attention=hybrid_attn_spec, |
| 115 | + self_attn_bda=get_bias_dropout_add, |
| 116 | + self_attention_hyper_connection=HyperConnectionModule, |
| 117 | + pre_mlp_layernorm=pre_mlp_layernorm, |
| 118 | + mlp=moe_layer_spec, |
| 119 | + mlp_bda=get_bias_dropout_add, |
| 120 | + mlp_hyper_connection=HyperConnectionModule, |
| 121 | + engram=ModuleSpec(module=engram_module) |
| 122 | + ) |
| 123 | + |
| 124 | + return ModuleSpec(module=DeepSeekTransformerLayer, submodules=submodules) |
| 125 | + |
| 126 | + |
| 127 | +def get_deepseek_decoder_block_spec( |
| 128 | + config: TransformerConfig, |
| 129 | + use_transformer_engine: bool, |
| 130 | + normalization: Optional[str] = None, |
| 131 | + qk_l2_norm: Optional[bool] = False, |
| 132 | + vp_stage: Optional[int] = None, |
| 133 | + pp_rank: int | None = None, |
| 134 | + is_dualpipev_first_chunk: bool | None = False, |
| 135 | + use_moe: bool | None = False, |
| 136 | +): |
| 137 | + """Build decoder block spec and attach STM/HC placeholders to each local layer.""" |
| 138 | + |
| 139 | + """GPT block spec.""" |
| 140 | + layer_norm_impl = TENorm |
| 141 | + moe_deepseek_engram_layer_spec = get_deepseek_layer_spec( |
| 142 | + use_te=use_transformer_engine, |
| 143 | + config=config, |
| 144 | + build_engram=True, |
| 145 | + ) |
| 146 | + moe_deepseek_layer_spec = get_deepseek_layer_spec( |
| 147 | + use_te=use_transformer_engine, |
| 148 | + config=config, |
| 149 | + build_engram=False, |
| 150 | + ) |
| 151 | + |
| 152 | + |
| 153 | + # Create the layer specs for the model. |
| 154 | + layer_specs = [] |
| 155 | + for layer_number in range(config.num_layers): |
| 156 | + if config.use_engram and layer_number in config.engram_layer_ids: |
| 157 | + is_engram_layer = True |
| 158 | + else: |
| 159 | + is_engram_layer = False |
| 160 | + layer_specs.append(moe_deepseek_engram_layer_spec if is_engram_layer else moe_deepseek_layer_spec) |
| 161 | + |
| 162 | + # Slice the layer specs to only include the layers that are built in this pipeline stage. |
| 163 | + # Note: MCore layer_number starts at 1 |
| 164 | + ######### FlagScale Modify ######## |
| 165 | + num_layers_to_build = get_num_layers_to_build( |
| 166 | + config, |
| 167 | + vp_stage=vp_stage, |
| 168 | + pp_rank=pp_rank, |
| 169 | + is_dualpipev_first_chunk=is_dualpipev_first_chunk, |
| 170 | + ) |
| 171 | + |
| 172 | + if config.pipeline_model_parallel_layout is not None: |
| 173 | + local_layer_specs = [ |
| 174 | + layer_specs[layer_id] |
| 175 | + for layer_id in config.pipeline_model_parallel_layout.get_layer_id_list( |
| 176 | + layer_type=LayerType.decoder, vp_stage=vp_stage, pp_rank=pp_rank |
| 177 | + ) |
| 178 | + ] |
| 179 | + else: |
| 180 | + ######### FlagScale Modify ######## |
| 181 | + offset = get_transformer_layer_offset( |
| 182 | + config, |
| 183 | + vp_stage=vp_stage, |
| 184 | + pp_rank=pp_rank, |
| 185 | + is_dualpipev_first_chunk=is_dualpipev_first_chunk, |
| 186 | + ) |
| 187 | + local_layer_specs = layer_specs[offset : offset + num_layers_to_build] |
| 188 | + |
| 189 | + # Block spec. |
| 190 | + block_spec = TransformerBlockSubmodules( |
| 191 | + layer_specs=local_layer_specs, layer_norm=layer_norm_impl |
| 192 | + ) |
| 193 | + |
| 194 | + return block_spec |
| 195 | + |
| 196 | + |
| 197 | +def deepseek_builder(args, pre_process, post_process, vp_stage=None, config=None, pg_collection=None): |
| 198 | + """Drop-in replacement builder compatible with model_provider(...).""" |
| 199 | + print_rank_0('building DeepSeek model (engram and mhc file) ...') |
| 200 | + |
| 201 | + if config is None: |
| 202 | + if args.yaml_cfg is not None: |
| 203 | + config = core_transformer_config_from_yaml(args, "language_model") |
| 204 | + else: |
| 205 | + config = core_transformer_config_from_args(args) |
| 206 | + |
| 207 | + |
| 208 | + if args.use_legacy_models: |
| 209 | + raise NotImplementedError("Legacy GPT models do not support deepseek module insertion.") |
| 210 | + else: |
| 211 | + if args.spec is not None: |
| 212 | + raise NotImplementedError("Using custom spec is not supported with deepseek builder.") |
| 213 | + else: |
| 214 | + use_te = args.transformer_impl == "transformer_engine" |
| 215 | + |
| 216 | + if args.heterogeneous_layers_config_path is not None: |
| 217 | + assert not (config.transformer_impl == "inference_optimized") |
| 218 | + raise NotImplementedError("Using heterogeneous layers is not supported with deepseek builder.") |
| 219 | + transformer_layer_spec = get_deepseek_decoder_block_spec( |
| 220 | + config=config, |
| 221 | + use_transformer_engine=use_te, |
| 222 | + normalization=args.normalization, |
| 223 | + qk_l2_norm=args.qk_l2_norm, |
| 224 | + vp_stage=vp_stage, |
| 225 | + use_moe=True |
| 226 | + ) |
| 227 | + |
| 228 | + mtp_block_spec = None |
| 229 | + if args.mtp_num_layers is not None: |
| 230 | + assert not (config.transformer_impl == "inference_optimized") |
| 231 | + transformer_layer_spec_for_mtp = get_deepseek_layer_spec(use_te, config, build_engram=False) |
| 232 | + mtp_block_spec = get_gpt_mtp_block_spec( |
| 233 | + config, |
| 234 | + transformer_layer_spec_for_mtp, |
| 235 | + use_transformer_engine=use_te, |
| 236 | + vp_stage=vp_stage, |
| 237 | + ) |
| 238 | + |
| 239 | + model = DeepSeekModel( |
| 240 | + config=config, |
| 241 | + transformer_layer_spec=transformer_layer_spec, |
| 242 | + vocab_size=args.padded_vocab_size, |
| 243 | + max_sequence_length=args.max_position_embeddings, |
| 244 | + pre_process=pre_process, |
| 245 | + post_process=post_process, |
| 246 | + fp16_lm_cross_entropy=args.fp16_lm_cross_entropy, |
| 247 | + parallel_output=True, |
| 248 | + share_embeddings_and_output_weights=not args.untie_embeddings_and_output_weights, |
| 249 | + position_embedding_type=args.position_embedding_type, |
| 250 | + rotary_percent=args.rotary_percent, |
| 251 | + rotary_base=args.rotary_base, |
| 252 | + rope_scaling=args.use_rope_scaling, |
| 253 | + mtp_block_spec=mtp_block_spec, |
| 254 | + vp_stage=vp_stage, |
| 255 | + pg_collection=pg_collection, |
| 256 | + ) |
| 257 | + print(f"Model = {model}") |
| 258 | + return model |
0 commit comments