diff --git a/megatron/core/models/gpt/gpt_layer_specs.py b/megatron/core/models/gpt/gpt_layer_specs.py index 8636929c062..64faa80fce2 100755 --- a/megatron/core/models/gpt/gpt_layer_specs.py +++ b/megatron/core/models/gpt/gpt_layer_specs.py @@ -79,7 +79,6 @@ def get_gpt_layer_with_inference_submodules( qk_l2_norm: Optional[bool] = False, num_experts: Optional[int] = None, moe_grouped_gemm: Optional[bool] = False, - moe_use_legacy_grouped_gemm: Optional[bool] = False, ) -> TransformerLayerSubmodules: """Use these submodules for inference optimized linear layers. Args: @@ -635,7 +634,6 @@ def get_gpt_decoder_layer_specs( qk_l2_norm=qk_l2_norm, num_experts=config.num_moe_experts, moe_grouped_gemm=config.moe_grouped_gemm, - moe_use_legacy_grouped_gemm=config.moe_use_legacy_grouped_gemm, ) else: dense_layer_spec = get_gpt_layer_local_spec( diff --git a/megatron/core/models/gpt/moe_module_specs.py b/megatron/core/models/gpt/moe_module_specs.py index e82b6638f0b..1c19b02f7b5 100755 --- a/megatron/core/models/gpt/moe_module_specs.py +++ b/megatron/core/models/gpt/moe_module_specs.py @@ -30,7 +30,6 @@ def get_moe_module_spec( use_te: Whether to use Transformer Engine. num_experts: Number of experts. moe_grouped_gemm: Whether to use grouped GEMM. - moe_use_legacy_grouped_gemm: Whether to use legacy grouped GEMM. """ if use_te is not None and use_te: backend: BackendSpecProvider = TESpecProvider() diff --git a/megatron/core/transformer/moe/experts.py b/megatron/core/transformer/moe/experts.py index 355b84e8150..b9099068720 100644 --- a/megatron/core/transformer/moe/experts.py +++ b/megatron/core/transformer/moe/experts.py @@ -6,7 +6,6 @@ from contextlib import nullcontext from copy import deepcopy from dataclasses import dataclass -from functools import partial from itertools import chain from math import ceil from typing import Optional, Protocol, Tuple @@ -26,12 +25,6 @@ from megatron.core.pipeline_parallel.fine_grained_activation_offload import ( FineGrainedActivationOffloadingInterface as off_interface, ) -from megatron.core.tensor_parallel.layers import ( - _initialize_affine_weight_cpu, - _initialize_affine_weight_gpu, - set_tensor_model_parallel_attributes, -) -from megatron.core.tensor_parallel.utils import divide from megatron.core.transformer.mlp import ( MLP, MLPSubmodules, @@ -83,469 +76,6 @@ logger = logging.getLogger(__name__) -class GroupedMLP(MegatronModule): - """An efficient implementation of the Experts layer using GroupedGEMM. - - Executes multiple experts in parallel to maximize computational efficiency. - """ - - # TODO(M4): breaking api, switched from pass in tp_group to pass in pg_collection. - def __init__( - self, - num_local_experts: int, - config: TransformerConfig, - pg_collection: Optional[ProcessGroupCollection] = None, - ): - super().__init__(config=config) - self.config: TransformerConfig = config - self.num_local_experts = num_local_experts - gg.assert_grouped_gemm_is_available() - assert ( - config.add_bias_linear == False - ), "bias not supported in Grouped GEMM yet, please set '--disable-bias-linear' instead." - assert ( - config.moe_latent_size is None - ), "MoE latent projection not supported in GroupedMLP yet." - - self.expert_parallel = config.expert_model_parallel_size > 1 - if self.config.gated_linear_unit: - if self.config.activation_func not in (F.silu, F.gelu): - raise ValueError("Activation function must be silu or gelu when using GroupedMLP.") - - @jit_fuser - def glu(x): - x = torch.chunk(x, 2, dim=-1) - return self.config.activation_func(x[0]) * x[1] - - self.activation_func = glu - else: - self.activation_func = self.config.activation_func - self.activation_recompute = ( - self.config.recompute_granularity == 'selective' - and "moe_act" in self.config.recompute_modules - ) - if self.activation_recompute and (self.config.fp8 or self.config.fp4): - raise ValueError( - "moe_act recompute for fp8 or fp4 cannot work with the legacy GroupedMLP." - ) - - @jit_fuser - def activation_func_with_probs(x, probs): - dtype = x.dtype - res = self.activation_func(x) * probs - return res.to(dtype) - - self.activation_func_with_probs = activation_func_with_probs - - self.ep_group = pg_collection.ep - # use pg_collection.expt_tp_group as tensor parallel group in this module. - self.tp_group = pg_collection.expt_tp - # use pg_collection.expt_dp_group as data parallel group in this module. - self.dp_group = pg_collection.expt_dp - # How many feature each rank holds for fc1 and fc2, respectively. - tp_size = self.tp_group.size() - tp_rank = self.tp_group.rank() - - fc1_output_size = self.config.moe_ffn_hidden_size * self.num_local_experts - if config.gated_linear_unit: - # Project to 4h. If using swiglu double the output width, - # see https://arxiv.org/pdf/2002.05202.pdf - fc1_output_size *= 2 - fc1_output_size_per_partition = divide(fc1_output_size, tp_size) - - fc2_input_size = self.config.moe_ffn_hidden_size * self.num_local_experts - fc2_input_size_per_partition = divide(fc2_input_size, tp_size) - - # Note: The current kernel implementations of grouped_gemm - # does not support transposition with CUTLASS grouped GEMM - # (https://github.com/fanshiqing/grouped_gemm/blob/main/csrc/grouped_gemm.cu#L355-L358) - # and as a result we avoid allocate the transpose of weights. - # Initialize weight. - if config.use_cpu_initialization: - self.weight1 = Parameter( - torch.empty( - self.config.hidden_size, - fc1_output_size_per_partition, - dtype=config.params_dtype, - ) - ) - self.weight2 = Parameter( - torch.empty( - fc2_input_size_per_partition, self.config.hidden_size, dtype=config.params_dtype - ) - ) - if config.perform_initialization: - _initialize_affine_weight_cpu( - self.weight1, - self.config.hidden_size, - fc1_output_size, - fc1_output_size_per_partition, - partition_dim=1, - init_method=config.init_method, - params_dtype=config.params_dtype, - rank=tp_rank, - world_size=tp_size, - ) - _initialize_affine_weight_cpu( - self.weight2, - fc2_input_size, - self.config.hidden_size, - fc2_input_size_per_partition, - partition_dim=0, - init_method=config.output_layer_init_method, - params_dtype=config.params_dtype, - rank=tp_rank, - world_size=tp_size, - ) - else: - # Ensure TP attrs are set even when not initializing - set_tensor_model_parallel_attributes( - tensor=self.weight1, is_parallel=True, dim=1, stride=1 - ) - set_tensor_model_parallel_attributes( - tensor=self.weight2, is_parallel=True, dim=0, stride=1 - ) - else: - self.weight1 = Parameter( - torch.empty( - self.config.hidden_size, - fc1_output_size_per_partition, - device=torch.cuda.current_device(), - dtype=config.params_dtype, - ) - ) - self.weight2 = Parameter( - torch.empty( - fc2_input_size_per_partition, - self.config.hidden_size, - device=torch.cuda.current_device(), - dtype=config.params_dtype, - ) - ) - if config.perform_initialization: - _initialize_affine_weight_gpu( - self.weight1, config.init_method, partition_dim=1, is_expert=True - ) - _initialize_affine_weight_gpu( - self.weight2, config.output_layer_init_method, partition_dim=0, is_expert=True - ) - else: - # Ensure TP attrs are set even when not initializing - set_tensor_model_parallel_attributes( - tensor=self.weight1, is_parallel=True, dim=1, stride=1 - ) - set_tensor_model_parallel_attributes( - tensor=self.weight2, is_parallel=True, dim=0, stride=1 - ) - setattr(self.weight1, 'allreduce', not self.expert_parallel) - setattr(self.weight2, 'allreduce', not self.expert_parallel) - - def remove_extra_states_check(self, incompatible_keys): - """ - Remove _extra_state from unexpected keys. - These keys are for dist ckpt compatibility with SequentialMLP. - """ - keys = deepcopy(incompatible_keys.unexpected_keys) - for key in keys: - if '_extra_state' in key: - incompatible_keys.unexpected_keys.remove(key) - - self.register_load_state_dict_post_hook(remove_extra_states_check) - - def forward( - self, - permuted_local_hidden_states: torch.Tensor, - tokens_per_expert: torch.Tensor, - permuted_probs: torch.Tensor, - ): - """Forward step of the GroupedMLP.""" - assert self.config.bf16, "Currently GroupedMLP for MoE only supports bf16." - if self.activation_recompute: - self.activation_checkpoint = tensor_parallel.CheckpointWithoutOutput() - - if self.config.moe_apply_probs_on_input: - assert ( - self.config.moe_router_topk == 1 - ), "`moe_apply_probs_on_input` only works with `moe_router_topk`=1." - original_dtype = permuted_local_hidden_states.dtype - permuted_local_hidden_states = ( - permuted_probs.unsqueeze(-1) * permuted_local_hidden_states - ) - permuted_local_hidden_states = permuted_local_hidden_states.to(original_dtype) - # Probs already applied, so reset to 1. - permuted_probs = torch.ones_like(permuted_probs) - - if permuted_local_hidden_states.nelement() != 0: - # Reshape the weights for the grouped GEMMs. - w1 = self.weight1.view(self.num_local_experts, self.config.hidden_size, -1) - w2 = self.weight2.view(self.num_local_experts, -1, self.config.hidden_size) - - fc1_output = gg.ops.gmm( - permuted_local_hidden_states, w1, tokens_per_expert, trans_b=False - ) - if self.activation_recompute: - intermediate_parallel = self.activation_checkpoint.checkpoint( - self.activation_func_with_probs, fc1_output, permuted_probs.unsqueeze(-1) - ) - fc2_output = gg.ops.gmm(intermediate_parallel, w2, tokens_per_expert, trans_b=False) - self.activation_checkpoint.discard_output_and_register_recompute(fc2_output) - else: - intermediate_parallel = self.activation_func_with_probs( - fc1_output, permuted_probs.unsqueeze(-1) - ) - fc2_output = gg.ops.gmm(intermediate_parallel, w2, tokens_per_expert, trans_b=False) - else: - # No token is allocated for local experts. - assert torch.count_nonzero(tokens_per_expert) == 0 - - # Make sure params of experts still have gradients even given zero tokens. - w1 = self.weight1.view(self.config.hidden_size, -1) - w2 = self.weight2.view(-1, self.config.hidden_size) - h = torch.matmul(permuted_local_hidden_states, w1) - if self.activation_recompute: - h = self.activation_checkpoint.checkpoint( - self.activation_func_with_probs, h, permuted_probs.unsqueeze(-1) - ) - fc2_output = torch.matmul(h, w2) - self.activation_checkpoint.discard_output_and_register_recompute(fc2_output) - else: - h = self.activation_func_with_probs(h, permuted_probs.unsqueeze(-1)) - fc2_output = torch.matmul(h, w2) - - return fc2_output, None - - def sharded_state_dict(self, prefix='', sharded_offsets=(), metadata=None): - """ - Maps local expert to global experts. - The sharded_state_dict for the weight parts are compatible with the SequentialMLP, - whereas the optimizer states are not due to the limitation from weight transposing. - That is, for finetuning scenario, the checkpoint is compatible with the SequentialMLP. - - When `singleton_local_shards` metadata flag is True, experts are broken down into - separate tensors and stored under separate global keys. Additionally, similarly to MLP, - layers with GLU activations are broken down into separate `w` and `v` tensors. - """ - singleton_local_shards = (metadata or {}).get('singleton_local_shards', False) - sharded_state_dict = {} - ep_size = self.ep_group.size() - ep_rank = self.ep_group.rank() - tp_size = self.tp_group.size() - tp_rank = self.tp_group.rank() - dp_rank = self.dp_group.rank() - num_global_experts = ep_size * self.num_local_experts - local_expert_indices_offset = ep_rank * self.num_local_experts - - prepend_axis_num = len(sharded_offsets) - replica_id = (0, 0, dp_rank) - - local_ffn_dim_size = ( - self.weight2.numel() // self.num_local_experts // self.config.hidden_size - ) - - def _break_into_individual_experts( - experts_ten: torch.Tensor, - key: str, - tp_offset: Tuple[int, int, int], - replica_id: ReplicaId, - ): - """Breaks experts into individual tensors and stores them under separate global keys""" - experts_state = [] - assert len(experts_ten) == self.num_local_experts, ( - experts_ten.shape, - self.num_local_experts, - ) - for local_expert_idx, expert_ten in enumerate(experts_ten): - global_expert_idx = local_expert_indices_offset + local_expert_idx - expert_key = key.replace( - f'{prefix}experts.', f'{prefix}experts.{global_expert_idx}.' - ) - experts_state.append( - ShardedTensor.from_rank_offsets( - expert_key, - expert_ten.contiguous(), - *sharded_offsets, - tp_offset, - replica_id=replica_id, - prepend_axis_num=prepend_axis_num, - ) - ) - return experts_state - - @torch.no_grad() - def sh_ten_build_fn( - key: str, - t: torch.Tensor, - replica_id: ReplicaId, - flattened_range: Optional[slice], - tp_axis: int, - with_glu: bool, - ): - # TODO: write a generic implementation to cover both cases with and without GLU - if tp_axis == 1: - # weight1 - if with_glu: - last_dim_size = local_ffn_dim_size * 2 - else: - last_dim_size = local_ffn_dim_size - real_shape = (self.num_local_experts, self.config.hidden_size, last_dim_size) - elif tp_axis == 0: - # weight2 - real_shape = (self.num_local_experts, local_ffn_dim_size, self.config.hidden_size) - assert with_glu == False - else: - raise ValueError("tp_axis should be 0 or 1.") - if flattened_range is None: - # weights - t = t.view(real_shape).transpose(-1, -2) - # change tp_axis due to the transposing - tp_axis = 1 - tp_axis - if with_glu: - assert tp_axis == 0, tp_axis - if singleton_local_shards: - w_tensor, v_tensor = torch.chunk(t, 2, -2) - w_key = f'{key}_w' - v_key = f'{key}_v' - sub_states = { - 'singleton_local_shards': LocalNonpersistentObject(True), - 'data': { - 'w': _break_into_individual_experts( - w_tensor, - w_key, - (prepend_axis_num, tp_rank, tp_size), - replica_id, - ), - 'v': _break_into_individual_experts( - v_tensor, - v_key, - (prepend_axis_num, tp_rank, tp_size), - replica_id, - ), - }, - } - else: - local_tensors = torch.chunk(t, 2, -2) - sub_states = [ - ShardedTensor.from_rank_offsets( - key, - local_tensors[0].contiguous(), - *sharded_offsets, - (prepend_axis_num, ep_rank, ep_size), - (prepend_axis_num + 1, tp_rank, tp_size * 2), - replica_id=replica_id, - prepend_axis_num=prepend_axis_num, - ), - ShardedTensor.from_rank_offsets( - key, - local_tensors[1].contiguous(), - *sharded_offsets, - (prepend_axis_num, ep_rank, ep_size), - (prepend_axis_num + 1, tp_size + tp_rank, tp_size * 2), - replica_id=replica_id, - prepend_axis_num=prepend_axis_num, - ), - ] - else: - if singleton_local_shards: - sub_states = { - 'singleton_local_shards': LocalNonpersistentObject(True), - 'data': _break_into_individual_experts( - t, key, (prepend_axis_num + tp_axis, tp_rank, tp_size), replica_id - ), - } - else: - sub_states = ShardedTensor.from_rank_offsets( - key, - t.contiguous(), - *sharded_offsets, - (prepend_axis_num, ep_rank, ep_size), - (prepend_axis_num + 1 + tp_axis, tp_rank, tp_size), - replica_id=replica_id, - prepend_axis_num=prepend_axis_num, - ) - return sub_states # pylint: disable=possibly-used-before-assignment - - @torch.no_grad() - def sh_ten_merge_fn(sub_state_dict, tp_axis: int, with_glu: bool): - if tp_axis == 1: - # weight1 - weight_shape = (self.config.hidden_size, -1) - elif tp_axis == 0: - # weight2 - weight_shape = (-1, self.config.hidden_size) - assert with_glu == False - else: - raise ValueError("tp_axis should be 0 or 1.") - if isinstance(sub_state_dict, dict): - assert sub_state_dict['singleton_local_shards'] - if with_glu: - assert isinstance(sub_state_dict['data'], dict) - sub_state_dict = torch.cat( - ( - torch.stack(sub_state_dict['data']['w']), - torch.stack(sub_state_dict['data']['v']), - ), - dim=-2, - ) - else: - assert isinstance(sub_state_dict['data'], list) - sub_state_dict = torch.stack(sub_state_dict['data']) - else: - if with_glu: - sub_state_dict = torch.cat(sub_state_dict, -2) - return sub_state_dict.transpose(-1, -2).reshape(weight_shape) - - state_dict = self.state_dict(prefix='', keep_vars=True) - for name, tensor in state_dict.items(): - if name == 'weight1': - tp_axis = 1 - with_glu = self.config.gated_linear_unit - wkey = f'{prefix}experts.linear_fc1.weight' - else: - tp_axis = 0 - with_glu = False - wkey = f'{prefix}experts.linear_fc2.weight' - - this_replica_id = list(copy.deepcopy(replica_id)) - - sharded_state_dict[f'{prefix}{name}'] = ShardedTensorFactory( - wkey, - tensor, - partial(sh_ten_build_fn, tp_axis=tp_axis, with_glu=with_glu), - partial(sh_ten_merge_fn, tp_axis=tp_axis, with_glu=with_glu), - tuple(this_replica_id), - ) - - replica_id = (0, tp_rank, dp_rank) - # Add fake _extra_state to be compatible with SequentialMLP - for expert_local_idx in range(self.num_local_experts): - expert_global_idx = local_expert_indices_offset + expert_local_idx - if singleton_local_shards: - expert_sharded_offsets = sharded_offsets - else: - expert_sharded_offsets = ( - *sharded_offsets, - (len(sharded_offsets), expert_global_idx, num_global_experts), - ) - for mod in ['linear_fc1', 'linear_fc2']: - if singleton_local_shards: - expert_key = f'{prefix}experts.{expert_global_idx}.{mod}._extra_state' - else: - expert_key = f'{prefix}experts.{mod}._extra_state' - sharded_state_dict[f'{prefix}expert{expert_global_idx}.{mod}._extra_state'] = ( - make_sharded_object_for_checkpoint( - None, expert_key, expert_sharded_offsets, replica_id - ) - ) - - return sharded_state_dict - - def backward_dw(self): - """Performs backward pass for weight gradients in Experts. - Empty implementation for compatibility with SequentialMLP and TEGroupedMLP. - """ - pass - - class GroupedLinearFc1Interface(Protocol): """Interface for linear_fc1 module in TEGroupedMLP.""" diff --git a/pyproject.toml b/pyproject.toml index 16ec5210ca1..9ccafd4094e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -95,7 +95,6 @@ dev = [ "mamba-ssm~=2.2", "causal-conv1d~=1.5", "flash-linear-attention~=0.4.0", - "nv-grouped-gemm~=1.1", "megatron-energon[av_decode]~=6.0", "av", "flashinfer-python>=0.5.0,<0.7.0", @@ -118,7 +117,6 @@ lts = [ "opentelemetry-api~=1.33.1", "mamba-ssm~=2.2", "causal-conv1d~=1.5", - "nv-grouped-gemm~=1.1", "megatron-energon[av_decode]~=6.0", "av", "flashinfer-python>=0.5.0,<0.7.0", @@ -176,7 +174,6 @@ no_pypi_wheels = ["emerging_optimizers; python_version >= '3.12'", "fast-hadamar default-groups = ["linting", "build", "test"] no-build-isolation-package = [ "causal-conv1d", - "nv-grouped-gemm", "mamba-ssm", "transformer-engine", "transformer-engine-torch", diff --git a/tests/unit_tests/models/test_experimental_attention_variant_module_specs.py b/tests/unit_tests/models/test_experimental_attention_variant_module_specs.py index e3a589f1b97..9c76140d287 100644 --- a/tests/unit_tests/models/test_experimental_attention_variant_module_specs.py +++ b/tests/unit_tests/models/test_experimental_attention_variant_module_specs.py @@ -78,7 +78,6 @@ def _make_config(**overrides): moe_layer_freq=1, num_moe_experts=None, moe_grouped_gemm=False, - moe_use_legacy_grouped_gemm=False, use_te_activation_func=False, pipeline_model_parallel_size=1, pipeline_model_parallel_layout=None, diff --git a/tests/unit_tests/models/test_gpt_model.py b/tests/unit_tests/models/test_gpt_model.py index 336ff0552b0..b5f2ecb2203 100644 --- a/tests/unit_tests/models/test_gpt_model.py +++ b/tests/unit_tests/models/test_gpt_model.py @@ -469,7 +469,6 @@ def test_get_transformer_layer_spec_forwards_use_te_activation_func(): mock_args.qk_layernorm = False mock_args.multi_latent_attention = False mock_args.experimental_attention_variant = None - mock_args.moe_use_legacy_grouped_gemm = False mock_args.qk_l2_norm = False with ( diff --git a/tests/unit_tests/transformer/moe/test_paged_stashing.py b/tests/unit_tests/transformer/moe/test_paged_stashing.py index 262346d0609..7e12c65bfb5 100644 --- a/tests/unit_tests/transformer/moe/test_paged_stashing.py +++ b/tests/unit_tests/transformer/moe/test_paged_stashing.py @@ -239,7 +239,6 @@ def test_forward_backward_4_layers(self): moe_flex_dispatcher_backend="hybridep", test_dtype=torch.bfloat16, moe_grouped_gemm=True, - moe_use_legacy_grouped_gemm=False, moe_paged_stash=True, moe_expert_rank_capacity_factor=1.5, use_transformer_engine_op_fuser=True, @@ -329,7 +328,6 @@ def test_overload_factor_and_over_budget(self): moe_flex_dispatcher_backend="hybridep", test_dtype=torch.bfloat16, moe_grouped_gemm=True, - moe_use_legacy_grouped_gemm=False, moe_paged_stash=True, moe_expert_rank_capacity_factor=1.5, use_transformer_engine_op_fuser=True, diff --git a/uv.lock b/uv.lock index 1c7c2a30797..62ea93ec3ac 100644 --- a/uv.lock +++ b/uv.lock @@ -3187,7 +3187,6 @@ dev = [ { name = "mamba-ssm" }, { name = "megatron-energon", extra = ["av-decode"], marker = "extra == 'extra-13-megatron-core-dev'" }, { name = "multi-storage-client" }, - { name = "nv-grouped-gemm" }, { name = "nvidia-modelopt", marker = "(sys_platform != 'darwin' and extra == 'extra-13-megatron-core-dev') or (extra == 'extra-13-megatron-core-dev' and extra == 'extra-13-megatron-core-lts')" }, { name = "nvidia-resiliency-ext" }, { name = "nvtx" }, @@ -3213,7 +3212,6 @@ lts = [ { name = "mamba-ssm" }, { name = "megatron-energon", extra = ["av-decode"], marker = "extra == 'extra-13-megatron-core-lts'" }, { name = "multi-storage-client" }, - { name = "nv-grouped-gemm" }, { name = "nvtx" }, { name = "onnxscript", version = "0.6.2", source = { registry = "https://pypi.org/simple" } }, { name = "opentelemetry-api", version = "1.33.1", source = { registry = "https://pypi.org/simple" } }, @@ -3323,8 +3321,6 @@ requires-dist = [ { name = "multi-storage-client", marker = "extra == 'dev'", specifier = "~=0.27" }, { name = "multi-storage-client", marker = "extra == 'lts'", specifier = "~=0.27" }, { name = "numpy" }, - { name = "nv-grouped-gemm", marker = "extra == 'dev'", specifier = "~=1.1" }, - { name = "nv-grouped-gemm", marker = "extra == 'lts'", specifier = "~=1.1" }, { name = "nvidia-modelopt", extras = ["torch"], marker = "sys_platform != 'darwin' and extra == 'dev'" }, { name = "nvidia-resiliency-ext", marker = "extra == 'dev'", git = "https://github.com/NVIDIA/nvidia-resiliency-ext.git?rev=15a851565a4ce846c04431ecb0cf09903ab4837e" }, { name = "nvtx", marker = "extra == 'dev'", specifier = "~=0.2" }, @@ -4284,17 +4280,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/04/74/f4c001f4714c3ad9ce037e18cf2b9c64871a84951eaa0baf683a9ca9301c/numpy-2.4.4-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:f2cf083b324a467e1ab358c105f6cad5ea950f50524668a80c486ff1db24e119", size = 12509075, upload-time = "2026-03-29T13:21:57.644Z" }, ] -[[package]] -name = "nv-grouped-gemm" -version = "1.1.4.post8" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "absl-py" }, - { name = "numpy", version = "2.0.2", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version < '3.11' and extra == 'extra-13-megatron-core-lts') or extra == 'extra-13-megatron-core-dev'" }, - { name = "numpy", version = "2.4.4", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version >= '3.11' and extra == 'extra-13-megatron-core-lts') or (extra == 'extra-13-megatron-core-dev' and extra == 'extra-13-megatron-core-lts')" }, - { name = "torch", marker = "sys_platform == 'never'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/02/ad/046a097b63a96c1ba1d85f0031dbe7fcbdb33e6c445dfbaba2ffaefdd497/nv_grouped_gemm-1.1.4.post8.tar.gz", hash = "sha256:ab321693f0292cfd8a26dc7b6f14decd9eb00e209494de7218e4fad36191275d", size = 20821209, upload-time = "2025-12-17T02:22:38.432Z" } [[package]] name = "nvdlfw-inspect"