-
Notifications
You must be signed in to change notification settings - Fork 4.4k
standalone hypercontraction module #5669
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -195,10 +195,9 @@ def __init__(self, config: TransformerConfig, layer_number: int): | |
| ) | ||
|
|
||
| init_alpha = config.mhc_init_gating_factor | ||
| # Learnable scaling factors (Eq. 5 in paper) | ||
| self.alpha_pre = nn.Parameter(torch.full((1,), init_alpha)) | ||
| self.alpha_post = nn.Parameter(torch.full((1,), init_alpha)) | ||
| self.alpha_res = nn.Parameter(torch.full((1,), init_alpha)) | ||
| # Learnable scaling factors (Eq. 5 in paper): pre, post, res in one (3,) tensor | ||
| # matching HF checkpoint layout (attn_hc.scale / ffn_hc.scale). | ||
| self.scale = nn.Parameter(torch.full((3,), init_alpha)) | ||
|
|
||
| # Static bias terms | ||
| self.bias = nn.Parameter(torch.zeros(self.n * self.n + 2 * self.n)) | ||
|
|
@@ -246,9 +245,7 @@ def _init_weights(self) -> None: | |
| # (nn.Linear, nn.RMSNorm) whose gradients need to be all-reduced. | ||
| if self.config.sequence_parallel: | ||
| setattr(self.mapping_proj.weight, 'sequence_parallel', True) | ||
| setattr(self.alpha_pre, 'sequence_parallel', True) | ||
| setattr(self.alpha_post, 'sequence_parallel', True) | ||
| setattr(self.alpha_res, 'sequence_parallel', True) | ||
| setattr(self.scale, 'sequence_parallel', True) | ||
| setattr(self.bias, 'sequence_parallel', True) | ||
|
|
||
| def _projection_and_get_norm(self, x: Tensor) -> Tuple[Tensor, Tensor]: | ||
|
|
@@ -280,9 +277,9 @@ def _compute_h(self, proj: Tensor, r: Tensor) -> Tuple[Tensor, Tensor, Tensor]: | |
| """ | ||
| alpha_ = torch.cat( | ||
| [ | ||
| self.alpha_pre.expand(self.n), | ||
| self.alpha_post.expand(self.n), | ||
| self.alpha_res.expand(self.n * self.n), | ||
| self.scale[0:1].expand(self.n), | ||
| self.scale[1:2].expand(self.n), | ||
| self.scale[2:3].expand(self.n * self.n), | ||
| ], | ||
| dim=-1, | ||
| ) | ||
|
|
@@ -319,9 +316,9 @@ def compute_mappings(self, x: Tensor) -> Tuple[Tensor, Tensor, Tensor]: | |
| h_pre, h_post, h_res, _ = self._proj_rms_compute_h_op( | ||
| x_2d, | ||
| self.mapping_proj.weight, | ||
| self.alpha_pre, | ||
| self.alpha_post, | ||
| self.alpha_res, | ||
| self.scale[0:1], | ||
| self.scale[1:2], | ||
| self.scale[2:3], | ||
| self.bias, | ||
| self.n, | ||
| self.norm_eps, | ||
|
|
@@ -831,3 +828,37 @@ def compute_optimal_block_size(num_layers: int, num_streams: int) -> int: | |
| """ | ||
| block_size = int(math.sqrt(num_streams * num_layers / (num_streams + 2))) | ||
| return max(1, block_size) | ||
|
|
||
|
|
||
| # DSv4 mHC output contraction: n residual streams → single stream. | ||
| class HyperConnectionContractModule(MegatronModule): | ||
| """Encapsulates the DSv4 mHC output-contraction parameters and forward. | ||
|
|
||
| Parameters are named ``hc_head_fn`` / ``hc_head_base`` / ``hc_head_scale`` | ||
| (matching their legacy flat checkpoint keys) so that owners only need to | ||
| strip the ``mhc_contract.`` prefix when remapping for backward-compatible | ||
| checkpoint loading via ``apply_prefix_mapping``. | ||
|
Comment on lines
+837
to
+840
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [SUGGESTION Other] This docstring describes backward-compatible checkpoint loading "via |
||
| """ | ||
|
|
||
| def __init__(self, config: TransformerConfig) -> None: | ||
| super().__init__(config) | ||
| hc_mult = config.num_residual_streams | ||
| hc_dim = config.hidden_size * hc_mult | ||
| self.hc_head_fn = nn.Parameter(torch.randn(hc_mult, hc_dim)) | ||
| self.hc_head_base = nn.Parameter(torch.zeros(hc_mult)) | ||
| self.hc_head_scale = nn.Parameter(torch.ones(1)) | ||
| nn.init.xavier_uniform_(self.hc_head_fn) | ||
| if config.sequence_parallel: | ||
| setattr(self.hc_head_fn, 'sequence_parallel', True) | ||
| setattr(self.hc_head_base, 'sequence_parallel', True) | ||
| setattr(self.hc_head_scale, 'sequence_parallel', True) | ||
|
|
||
| def forward(self, hidden_states: Tensor) -> Tensor: | ||
| return learned_output_contract( | ||
| hidden_states, | ||
| self.hc_head_fn, | ||
| self.hc_head_base, | ||
| self.hc_head_scale, | ||
| self.config.num_residual_streams, | ||
| self.config.layernorm_epsilon, | ||
| ) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -28,7 +28,7 @@ | |
| inference_all_gather_from_tensor_model_parallel_region, | ||
| ) | ||
| from megatron.core.transformer.enums import AttnMaskType, LayerType | ||
| from megatron.core.transformer.hyper_connection import learned_output_contract | ||
| from megatron.core.transformer.hyper_connection import HyperConnectionContractModule | ||
| from megatron.core.transformer.module import MegatronModule | ||
| from megatron.core.transformer.spec_utils import ModuleSpec, build_module | ||
| from megatron.core.transformer.torch_norm import LayerNormBuilder | ||
|
|
@@ -1235,16 +1235,7 @@ def __init__( | |
| ) | ||
|
|
||
| if self.mhc_enabled: | ||
| hc_mult = self.config.num_residual_streams | ||
| hc_dim = self.config.hidden_size * hc_mult | ||
| self.hc_head_fn = nn.Parameter(torch.randn(hc_mult, hc_dim)) | ||
| self.hc_head_base = nn.Parameter(torch.zeros(hc_mult)) | ||
| self.hc_head_scale = nn.Parameter(torch.ones(1)) | ||
| nn.init.xavier_uniform_(self.hc_head_fn) | ||
| if self.config.sequence_parallel: | ||
| setattr(self.hc_head_fn, 'sequence_parallel', True) | ||
| setattr(self.hc_head_base, 'sequence_parallel', True) | ||
| setattr(self.hc_head_scale, 'sequence_parallel', True) | ||
| self.mhc_contract = HyperConnectionContractModule(self.config) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [IMPORTANT Compatibility] Same checkpoint-key rename issue as in This layer already has a
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yup, pretty much my concern as well, we need to make sure that checkpointing works as a requirement to performing this refactor. |
||
|
|
||
| self.offload_context = nullcontext() | ||
|
|
||
|
|
@@ -1453,14 +1444,7 @@ def _postprocess(self, hidden_states: torch.Tensor): | |
| """ | ||
|
|
||
| if self.mhc_enabled: | ||
| hidden_states = learned_output_contract( | ||
| hidden_states, | ||
| self.hc_head_fn, | ||
| self.hc_head_base, | ||
| self.hc_head_scale, | ||
| self.config.num_residual_streams, | ||
| self.config.layernorm_epsilon, | ||
| ) | ||
| hidden_states = self.mhc_contract(hidden_states) | ||
|
|
||
| # Layer norm before shared head layer. | ||
| hidden_states = apply_module(self.final_layernorm)(hidden_states) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -25,8 +25,8 @@ | |
| from megatron.core.tensor_parallel.random import CheckpointManager | ||
| from megatron.core.transformer.enums import InferenceCudaGraphScope, LayerType | ||
| from megatron.core.transformer.hyper_connection import ( | ||
| HyperConnectionContractModule, | ||
| HyperConnectionModule, | ||
| learned_output_contract, | ||
| ) | ||
| from megatron.core.transformer.module import GraphableMegatronModule, MegatronModule | ||
| from megatron.core.transformer.spec_utils import ModuleSpec, build_module | ||
|
|
@@ -391,16 +391,7 @@ def build_layer(layer_spec, layer_number): | |
| eps=self.config.layernorm_epsilon, | ||
| ) | ||
| if self.config.enable_hyper_connections: | ||
| hc_mult = self.config.num_residual_streams | ||
| hc_dim = self.config.hidden_size * hc_mult | ||
| self.hc_head_fn = nn.Parameter(torch.randn(hc_mult, hc_dim)) | ||
| self.hc_head_base = nn.Parameter(torch.zeros(hc_mult)) | ||
| self.hc_head_scale = nn.Parameter(torch.ones(1)) | ||
| nn.init.xavier_uniform_(self.hc_head_fn) | ||
| if self.config.sequence_parallel: | ||
| setattr(self.hc_head_fn, 'sequence_parallel', True) | ||
| setattr(self.hc_head_base, 'sequence_parallel', True) | ||
| setattr(self.hc_head_scale, 'sequence_parallel', True) | ||
| self.mhc_contract = HyperConnectionContractModule(self.config) | ||
| else: | ||
| self.final_layernorm = None # Either this or nn.Identity | ||
|
|
||
|
|
@@ -956,14 +947,7 @@ def forward( | |
| mhc_multistream = hidden_states | ||
| # DSv4 introduced the new output contraction for mHC. | ||
| # [s, b, n*C] -> [s, b, C] | ||
| hidden_states = learned_output_contract( | ||
| hidden_states, | ||
| self.hc_head_fn, | ||
| self.hc_head_base, | ||
| self.hc_head_scale, | ||
| self.config.num_residual_streams, | ||
| self.config.layernorm_epsilon, | ||
| ) | ||
| hidden_states = self.mhc_contract(hidden_states) | ||
|
|
||
| # Final layer norm. | ||
| if self.final_layernorm is not None: | ||
|
|
@@ -1080,10 +1064,9 @@ def sharded_state_dict( | |
| ) | ||
|
|
||
| # Save bare parameters/buffers that are direct attributes of this block | ||
| # (e.g. hyper-connection learned weights: hc_head_fn, hc_head_base, | ||
| # hc_head_scale). The named_children loop above would silently drop | ||
| # these since they are not nn.Module children. Mirrors the handling in | ||
| # MegatronModule.sharded_state_dict. | ||
| # (not nn.Module children — the named_children loop above would silently | ||
| # drop them). mhc_contract is now a proper child module and is handled | ||
| # above; this catches any other bare params on the block itself. | ||
|
Comment on lines
1066
to
+1069
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [IMPORTANT Compatibility] This refactor silently renames the checkpoint keys for the mHC contraction params without any migration path. Before this PR, Impact: existing checkpoints from PR #4518 (already on Fix: wire the remap the new module's own docstring promises. In this block's from megatron.core.dist_checkpointing.utils import apply_prefix_mapping
if self.config.enable_hyper_connections:
apply_prefix_mapping(
sharded_state_dict,
{f'{prefix}mhc_contract.hc_head_fn': f'{prefix}hc_head_fn',
f'{prefix}mhc_contract.hc_head_base': f'{prefix}hc_head_base',
f'{prefix}mhc_contract.hc_head_scale': f'{prefix}hc_head_scale'},
)(or otherwise document that this breaks existing mHC checkpoints). As written, the docstring claims a migration that no callsite actually performs. |
||
| local_state_dict: dict = {} | ||
| self._save_to_state_dict(local_state_dict, '', keep_vars=True) | ||
| if local_state_dict: | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will affect backwards compatibility with earlier checkpoints right?
Can you handle the HF parameter format online during checkpoint loading?