Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions megatron/core/distributed/finalize_model_grads.py
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,11 @@ def reset_model_temporary_tensors(config: TransformerConfig, model: List[torch.n
"""
for model_chunk in model:
for module in get_attr_wrapped_model(model_chunk, 'modules')():
if config.moe_router_enable_expert_bias and hasattr(module, 'expert_bias'):
if (
config.moe_router_enable_expert_bias
and hasattr(module, 'expert_bias')
and module.expert_bias is not None
):
module.local_tokens_per_expert.zero_()
if (
config.moe_router_load_balancing_type == "global_aux_loss"
Expand All @@ -303,7 +307,11 @@ def _update_router_expert_bias(model: List[torch.nn.Module], config: Transformer
# cases where only the student is in training mode but the teacher is in eval mode
# when using online knoweldge-distillation with Model-Optimizer. In this case, we want
# to avoid updating teacher's expert_bias.
if hasattr(module, 'expert_bias') and module.training:
if (
hasattr(module, 'expert_bias')
and module.training
and module.expert_bias is not None
):
tokens_per_expert_list.append(module.local_tokens_per_expert)
expert_bias_list.append(module.expert_bias)
# For hybrid models with both MoE and Dense layers, this list can be empty.
Expand Down
68 changes: 61 additions & 7 deletions megatron/core/fusions/fused_bias_swiglu.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,23 @@ def weighted_swiglu(y, weights):
return res.to(dtype)


@jit_fuser
def clamped_swiglu(y, clamp_value):
dtype = y.dtype
y_1, y_2 = torch.chunk(y.to(torch.float32), 2, -1)
y_1 = y_1.clamp(min=None, max=clamp_value)
y_2 = y_2.clamp(min=-clamp_value, max=clamp_value)
res = F.silu(y_1) * y_2
return res.to(dtype)

Comment thread
Victarry marked this conversation as resolved.

@jit_fuser
def clamped_weighted_swiglu(y, weights, clamp_value):
dtype = y.dtype
res = clamped_swiglu(y, clamp_value) * weights
return res.to(dtype)


# gradient of tanh approximation of gelu
# gradient of actual gelu is:
# 0.5 * (1. + torch.erf(x * 0.70710678)) + 0.3989423 * x * torch.exp(-0.5 * x * x)
Expand Down Expand Up @@ -97,6 +114,36 @@ def weighted_swiglu_back(g, y, weights):
return input_grad.to(input_dtype), weights_grad.to(w_dtype)


@jit_fuser
def clamped_swiglu_back(g, y, clamp_value):
dtype = y.dtype
y_1, y_2 = torch.chunk(y.to(torch.float32), 2, -1)
y_1c = y_1.clamp(min=None, max=clamp_value)
y_2c = y_2.clamp(min=-clamp_value, max=clamp_value)
res = torch.cat(
(
g
* torch.sigmoid(y_1c)
* (1 + y_1c * (1 - torch.sigmoid(y_1c)))
* y_2c
* (y_1 <= clamp_value).to(g.dtype),
g * F.silu(y_1c) * ((y_2 >= -clamp_value) & (y_2 <= clamp_value)).to(g.dtype),
),
-1,
)
return res.to(dtype)


@jit_fuser
def clamped_weighted_swiglu_back(g, y, weights, clamp_value):
input_dtype = y.dtype
w_dtype = weights.dtype
input_grad = clamped_swiglu_back(g * weights, y, clamp_value)
weights_grad = clamped_swiglu(y, clamp_value) * g.to(w_dtype)
weights_grad = torch.sum(weights_grad, dim=-1, keepdim=True)
return input_grad.to(input_dtype), weights_grad.to(w_dtype)


class BiasSwiGLUFunction(torch.autograd.Function):
"""Custom autograd function for SwiGLU activation with bias support."""

Expand Down Expand Up @@ -190,20 +237,27 @@ def backward(ctx, grad_output):

class WeightedSwiGLUFunction(torch.autograd.Function):
@staticmethod
# bias is an optional argument
def forward(ctx, input, weights, fp8_input_store):
def forward(ctx, input, weights, fp8_input_store, clamp_value):
input_for_backward = input.to(torch.float8_e4m3fn) if fp8_input_store else input
ctx.save_for_backward(input_for_backward, weights)
ctx.ori_input_dtype = input.dtype
ctx.fp8_input_store = fp8_input_store
return weighted_swiglu(input, weights)
ctx.clamp_value = clamp_value
if clamp_value is not None and clamp_value > 0:
res = clamped_weighted_swiglu(input, weights, clamp_value)
else:
res = weighted_swiglu(input, weights)
return res

@staticmethod
def backward(ctx, grad_output):
input, weights = ctx.saved_tensors
input = input.to(ctx.ori_input_dtype) if ctx.fp8_input_store else input
tmp, wgrad = weighted_swiglu_back(grad_output, input, weights)
return tmp, wgrad, None
if ctx.clamp_value is not None and ctx.clamp_value > 0:
tmp, wgrad = clamped_weighted_swiglu_back(grad_output, input, weights, ctx.clamp_value)
else:
tmp, wgrad = weighted_swiglu_back(grad_output, input, weights)
return tmp, wgrad, None, None


def bias_swiglu_impl(input, bias, fp8_input_store=False, cpu_offload_input=False):
Expand Down Expand Up @@ -236,7 +290,7 @@ def bias_swiglu_impl(input, bias, fp8_input_store=False, cpu_offload_input=False
return output if len(ori_shape) == 2 else output.view(ori_shape[0], ori_shape[1], -1)


def weighted_bias_swiglu_impl(input, bias, weights, fp8_input_store=False):
def weighted_bias_swiglu_impl(input, bias, weights, fp8_input_store=False, clamp_value=None):
"""
Token-wise-weighted bias swiglu fusion.
"""
Expand All @@ -246,7 +300,7 @@ def weighted_bias_swiglu_impl(input, bias, weights, fp8_input_store=False):
if bias is not None:
raise NotImplementedError("Bias is not supported for weighted swiglu fusion")
else:
output = WeightedSwiGLUFunction.apply(input, weights, fp8_input_store)
output = WeightedSwiGLUFunction.apply(input, weights, fp8_input_store, clamp_value)

return output if len(ori_shape) == 2 else output.view(ori_shape[0], ori_shape[1], -1)

Expand Down
7 changes: 6 additions & 1 deletion megatron/core/models/gpt/gpt_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -551,6 +551,11 @@ def forward(

rotary_pos_cos_sin = preproc_output[6] if len(preproc_output) == 7 else None

# Pass input_ids to decoder for hash-based MoE routing
decoder_extra_block_kwargs = extra_block_kwargs or {}
if self.config.moe_n_hash_layers > 0 and input_ids is not None:
decoder_extra_block_kwargs['input_ids'] = input_ids

# Run decoder.
hidden_states = self.decoder(
hidden_states=decoder_input,
Expand All @@ -563,7 +568,7 @@ def forward(
packed_seq_params=packed_seq_params,
sequence_len_offset=sequence_len_offset,
padding_mask=padding_mask,
**(extra_block_kwargs or {}),
**decoder_extra_block_kwargs,
)

return self._postprocess(
Expand Down
1 change: 1 addition & 0 deletions megatron/core/transformer/moe/experts.py
Original file line number Diff line number Diff line change
Expand Up @@ -1195,6 +1195,7 @@ def remove_glu_interleaving(x: torch.Tensor) -> torch.Tensor:
bias_parallel,
permuted_probs,
self.config.activation_func_fp8_input_store,
self.config.activation_func_clamp_value,
)
elif self.activation_func == quick_gelu and self.config.gated_linear_unit:
intermediate_parallel = weighted_bias_quick_geglu_impl(
Expand Down
19 changes: 15 additions & 4 deletions megatron/core/transformer/moe/moe_layer.py
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,10 @@ def __init__(

# Initialize router.
self.router = self.submodules.router(
config=self.config, pg_collection=pg_collection, is_mtp_layer=is_mtp_layer
config=self.config,
pg_collection=pg_collection,
is_mtp_layer=is_mtp_layer,
layer_number=layer_number,
)
self.tp_group = pg_collection.tp

Expand Down Expand Up @@ -421,13 +424,18 @@ def unset_inference_cuda_graphed_iteration(self):
self.shared_expert_overlap = self._saved_shared_expert_overlap

@maybe_skip_or_early_return_by_cudagraph("route")
def route(self, hidden_states: torch.Tensor, padding_mask: Optional[torch.Tensor] = None):
def route(
self,
hidden_states: torch.Tensor,
padding_mask: Optional[torch.Tensor] = None,
input_ids: Optional[torch.Tensor] = None,
):
"""Compute token routing for preprocessing.

This method uses the router to determine which experts to send each token to,
producing routing probabilities and a mapping.
"""
probs, routing_map = apply_module(self.router)(hidden_states, padding_mask)
probs, routing_map = apply_module(self.router)(hidden_states, padding_mask, input_ids)
return probs, routing_map

@maybe_skip_or_early_return_by_cudagraph("preprocess")
Expand Down Expand Up @@ -599,6 +607,7 @@ def forward(
hidden_states: torch.Tensor,
intermediate_tensors=None,
padding_mask: Optional[torch.Tensor] = None,
input_ids: Optional[torch.Tensor] = None,
):
"""Forward pass for the MoE layer.

Expand All @@ -613,6 +622,8 @@ def forward(
padding_mask (torch.Tensor, optional): Boolean mask indicating non-padding tokens.
Shape [seq_length, bsz]. True for valid tokens,
False for padding tokens. Defaults to None.
input_ids (torch.Tensor, optional): The input IDs tensor. Shape [seq_length, bsz].
Defaults to None.
Returns:
A tuple containing the output tensor and the MLP bias, if any.
"""
Expand All @@ -634,7 +645,7 @@ def custom_forward(hidden_states, intermediate_tensors=None, padding_mask=None):
self._overload_log_num_local_tokens = (
self._num_token_rows_from_moe_hidden_states(hidden_states)
)
probs, routing_map = self.route(hidden_states, padding_mask)
probs, routing_map = self.route(hidden_states, padding_mask, input_ids)
hidden_states, probs = self.preprocess(hidden_states, probs, routing_map)

if intermediate_tensors is not None:
Expand Down
Loading
Loading