Skip to content

Commit d3a77e7

Browse files
committed
Switch back to non fused moe
Change-Id: If90f3f11f204a90d87418495fc78eb0773272d31
1 parent 673da7c commit d3a77e7

6 files changed

Lines changed: 46 additions & 183 deletions

File tree

optimum/habana/checkpoint_utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ def model_on_meta(config):
9494
"""
9595
Checks if load the model to meta.
9696
"""
97-
return config.model_type in ["bloom", "llama", "falcon", "qwen2"]
97+
return config.model_type in ["bloom", "llama", "falcon", "mixtral", "qwen2"]
9898

9999

100100
def get_optimized_model_name(config):

optimum/habana/transformers/modeling_utils.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@
4444
GaudiCodeGenForCausalLM,
4545
GaudiCohereDecoderLayer,
4646
GaudiCohereForCausalLM,
47-
GaudiDynamicMoeBlock,
4847
GaudiFalconAttention,
4948
GaudiFalconDecoderLayer,
5049
GaudiFalconForCausalLM,
@@ -189,6 +188,7 @@
189188
gaudi_MambaForCausalLM_prepare_inputs_for_generation,
190189
gaudi_MambaForCausalLM_update_model_kwargs_for_generation,
191190
gaudi_mistral_rmsnorm_forward,
191+
gaudi_mixtral_block_dynamic_moe_forward,
192192
gaudi_mixtral_block_sparse_moe_forward,
193193
gaudi_mixtral_rmsnorm_forward,
194194
gaudi_opt_attention_forward,
@@ -522,7 +522,9 @@ def adapt_transformers_to_gaudi():
522522
gaudi_mixtral_block_sparse_moe_forward
523523
)
524524
else:
525-
transformers.models.mixtral.modeling_mixtral.MixtralSparseMoeBlock = GaudiDynamicMoeBlock
525+
transformers.models.mixtral.modeling_mixtral.MixtralSparseMoeBlock.forward = (
526+
gaudi_mixtral_block_dynamic_moe_forward
527+
)
526528
transformers.models.mixtral.modeling_mixtral.MixtralDecoderLayer = GaudiMixtralDecoderLayer
527529
transformers.models.mixtral.modeling_mixtral.MixtralRMSNorm.forward = gaudi_mixtral_rmsnorm_forward
528530
transformers.models.mixtral.configuration_mixtral.MixtralConfig = MixtralConfig

optimum/habana/transformers/models/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@
142142
gaudi_mistral_rmsnorm_forward,
143143
)
144144
from .mixtral import (
145-
GaudiDynamicMoeBlock,
145+
gaudi_mixtral_block_dynamic_moe_forward,
146146
GaudiMixtralAttention,
147147
GaudiMixtralDecoderLayer,
148148
GaudiMixtralForCausalLM,

optimum/habana/transformers/models/mixtral/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from .configuration_mixtral import MixtralConfig
22
from .modeling_mixtral import (
3-
GaudiDynamicMoeBlock,
3+
gaudi_mixtral_block_dynamic_moe_forward,
44
GaudiMixtralAttention,
55
GaudiMixtralDecoderLayer,
66
GaudiMixtralForCausalLM,

optimum/habana/transformers/models/mixtral/modeling_mixtral.py

Lines changed: 39 additions & 172 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,7 @@
2222

2323
import contextlib
2424
import math
25-
import os
26-
from typing import Dict, List, Optional, OrderedDict, Tuple, Union
25+
from typing import List, Optional, Tuple, Union
2726

2827
import habana_frameworks.torch.core as htcore
2928
import torch
@@ -42,7 +41,6 @@
4241
MixtralDecoderLayer,
4342
MixtralForCausalLM,
4443
MixtralModel,
45-
MixtralSparseMoeBlock,
4644
apply_rotary_pos_emb,
4745
load_balancing_loss_func,
4846
)
@@ -451,35 +449,46 @@ def gaudi_mixtral_block_sparse_moe_forward(self, hidden_states: torch.Tensor) ->
451449
return final_hidden_states, router_logits
452450

453451

454-
class DynamicFusedMoE(nn.Module):
455-
"""DynamicFusedMoE layer for MoE models.
456-
Based on implementation from vllm:
457-
https://github.com/HabanaAI/vllm-fork/blob/84922944da5b65fa43bbdc465650911cbef9de72/vllm/hpu/ops.py#L282"""
458452

459-
def __init__(self, num_total_experts):
460-
super().__init__()
461-
self.num_total_experts = num_total_experts
453+
def gaudi_mixtral_block_dynamic_moe_forward(self, hidden_states: torch.Tensor) -> Tuple[torch.Tensor, torch.Tensor]:
454+
batch_size, sequence_length, hidden_dim = hidden_states.shape
455+
original_shape = hidden_states.shape
456+
hidden_states = hidden_states.view(-1, hidden_dim)
457+
# router_logits: (batch * sequence_length, n_experts)
458+
router_logits = self.gate(hidden_states)
462459

463-
def forward(
464-
self, hidden_states: torch.Tensor, w13: torch.Tensor, w2: torch.Tensor, score: torch.Tensor, topk: int
465-
) -> torch.Tensor:
466-
routing_weights, selected_experts = calculate_routing_tensors(score, topk, hidden_states.dtype)
467-
# pre-processing for custom op inputs
468-
experts_range = range(self.num_total_experts)
469-
w13_list = [w13[i, :, :].squeeze() for i in experts_range]
470-
w2_list = [w2[i, :, :].squeeze() for i in experts_range]
471-
final_hidden_states = torch.ops.hpu.mixture_of_experts(
472-
hidden_states=hidden_states,
473-
expert_routing_table=selected_experts,
474-
router_weights=routing_weights,
475-
w12=w13_list,
476-
w3=w2_list,
477-
permuted_weights=True,
478-
activation="silu",
479-
experts_min=0,
480-
experts_max=7,
481-
)
482-
return final_hidden_states.view(-1, hidden_states.shape[1])
460+
if is_deepspeed_available() and (not self.training):
461+
from deepspeed import comm as dist
462+
463+
if dist.is_initialized():
464+
output_tensors = [router_logits.clone() for _ in range(dist.get_world_size())]
465+
dist.all_gather(output_tensors, router_logits)
466+
router_logits = torch.cat(output_tensors, dim=1)
467+
468+
routing_weights, selected_experts = calculate_routing_tensors(router_logits, self.top_k, hidden_states.dtype)
469+
# pre-processing for custom op inputs
470+
w1_list = [expert.w1.weight for expert in self.experts]
471+
w2_list = [expert.w2.weight for expert in self.experts]
472+
w3_list = [expert.w3.weight for expert in self.experts]
473+
474+
final_hidden_states = torch.ops.hpu.mixture_of_experts(
475+
hidden_states=hidden_states,
476+
expert_routing_table=selected_experts,
477+
router_weights=routing_weights,
478+
w1=w1_list,
479+
w3=w2_list,
480+
w2=w3_list,
481+
permuted_weights=True,
482+
activation="silu",
483+
experts_min=0,
484+
experts_max=7,
485+
)
486+
if is_deepspeed_available() and (not self.training):
487+
from deepspeed import comm as dist
488+
if dist.is_initialized():
489+
490+
dist.all_reduce(final_hidden_states)
491+
return final_hidden_states.view(original_shape), router_logits
483492

484493

485494
def calculate_routing_tensors(
@@ -493,142 +502,6 @@ def calculate_routing_tensors(
493502
return routing_weights, selected_experts
494503

495504

496-
class FusedMoE(nn.Module):
497-
def __init__(
498-
self,
499-
config: MixtralConfig,
500-
tp_size: int = 1,
501-
params_dtype: Optional[torch.dtype] = None,
502-
):
503-
super().__init__()
504-
if params_dtype is None:
505-
params_dtype = torch.get_default_dtype()
506-
507-
self.top_k = config.num_experts_per_tok
508-
self.num_experts = config.num_local_experts
509-
self.tp_size = tp_size
510-
511-
self.intermediate_size = config.intermediate_size
512-
self.intermediate_size_per_partition = config.intermediate_size // self.tp_size
513-
self.hpu_fused_moe = DynamicFusedMoE(self.num_experts)
514-
515-
# Fused gate_up_proj (column parallel)
516-
self.w13_weight = nn.Parameter(
517-
torch.rand(
518-
self.num_experts,
519-
2 * self.intermediate_size_per_partition,
520-
config.hidden_size,
521-
dtype=params_dtype,
522-
).multiply(config.initializer_range)
523-
)
524-
# down_proj (row parallel)
525-
self.w2_weight = nn.Parameter(
526-
torch.rand(
527-
self.num_experts,
528-
config.hidden_size,
529-
self.intermediate_size_per_partition,
530-
dtype=params_dtype,
531-
).multiply(config.initializer_range)
532-
)
533-
534-
def forward(self, hidden_states: torch.Tensor, router_logits: torch.Tensor) -> torch.Tensor:
535-
final_hidden_states = self.hpu_fused_moe(
536-
hidden_states, self.w13_weight, self.w2_weight, router_logits, self.top_k
537-
)
538-
if self.tp_size > 1:
539-
from deepspeed import comm as dist
540-
541-
dist.all_reduce(final_hidden_states)
542-
return final_hidden_states
543-
544-
545-
class GaudiDynamicMoeBlock(MixtralSparseMoeBlock):
546-
def __init__(self, config: MixtralConfig):
547-
super().__init__(config)
548-
self.tp_size = 1
549-
if is_deepspeed_available():
550-
from deepspeed import comm as dist
551-
552-
if dist.is_initialized():
553-
self.tp_size = dist.get_world_size()
554-
self.intermediate_size_per_partition = config.intermediate_size // self.tp_size
555-
self.experts = FusedMoE(config, self.tp_size)
556-
557-
def forward(self, hidden_states: torch.Tensor) -> Tuple[torch.Tensor, torch.Tensor]:
558-
_, _, hidden_dim = hidden_states.shape
559-
orig_shape = hidden_states.shape
560-
561-
hidden_states = hidden_states.view(-1, hidden_dim)
562-
# router_logits: (batch * sequence_length, n_experts)
563-
router_logits = self.gate(hidden_states)
564-
if is_deepspeed_available() and (not self.training):
565-
from deepspeed import comm as dist
566-
567-
if dist.is_initialized():
568-
output_tensors = [router_logits.clone() for _ in range(dist.get_world_size())]
569-
dist.all_gather(output_tensors, router_logits)
570-
router_logits = torch.cat(output_tensors, dim=1)
571-
572-
final_hidden_states = self.experts(hidden_states, router_logits)
573-
return final_hidden_states.view(orig_shape), router_logits
574-
575-
def _load_from_state_dict(
576-
self,
577-
state_dict: OrderedDict[str, torch.Tensor],
578-
prefix: str,
579-
local_metadata: Dict[str, str],
580-
strict: bool,
581-
missing_keys: List[str],
582-
unexpected_keys: List[str],
583-
error_msgs: List[str],
584-
) -> None:
585-
gate_up = ["w1", "w3"]
586-
gate_down_up = ["w1", "w2", "w3"]
587-
params_dict = dict(self.experts.named_parameters())
588-
for name, loaded_weight in state_dict.items():
589-
if "rotary_emb.inv_freq" in name or not name.startswith(prefix) or name.endswith("gate.weight"):
590-
continue
591-
# normal flow, as using normal model
592-
if len(name.strip(prefix).split(".")) == 4:
593-
_, expert_id, weight_name, _ = name.strip(prefix).split(".")
594-
param_name = "w13_weight" if weight_name in gate_up else "w2_weight"
595-
shard_id = gate_down_up.index(weight_name)
596-
expert_id = int(expert_id)
597-
param_data = params_dict[param_name].data
598-
599-
tp_rank = 0
600-
if self.tp_size > 1:
601-
from deepspeed import comm as dist
602-
603-
tp_rank = dist.get_rank()
604-
605-
shard_size = self.intermediate_size_per_partition
606-
shard = slice(tp_rank * shard_size, (tp_rank + 1) * shard_size)
607-
608-
# w1, gate_proj case: Load into first shard of w13.
609-
if shard_id == 0:
610-
param_data[expert_id, 0:shard_size, :] = loaded_weight[shard, :]
611-
# w3, up_proj case: Load into second shard of w13.
612-
elif shard_id == 2:
613-
param_data[expert_id, shard_size : 2 * shard_size, :] = loaded_weight[shard, :]
614-
# w2, down_proj case: Load into only shard of w2.
615-
elif shard_id == 1:
616-
param_data[expert_id, :, :] = loaded_weight[:, shard]
617-
else:
618-
raise ValueError(f"Shard id must be in [0,1,2] but got {shard_id}")
619-
#flow prepared for tests
620-
elif len(name.strip(prefix).split(".")) == 2:
621-
if name.endswith("w13_weight"):
622-
self.experts.w13_weight.data = loaded_weight
623-
elif name.endswith("w2_weight"):
624-
self.experts.w2_weight.data = loaded_weight
625-
else:
626-
ValueError(f"Unexpected weight name: {name}")
627-
else:
628-
raise ValueError(f"Unexpected weight name: {name}")
629-
630-
631-
632505
class GaudiMixtralDecoderLayer(MixtralDecoderLayer):
633506
def __init__(self, config: MixtralConfig, layer_idx: int):
634507
super().__init__(config, layer_idx)
@@ -907,12 +780,6 @@ class GaudiMixtralForCausalLM(MixtralForCausalLM):
907780
- from step2 when enable KV cache, slice next_position_ids from position_ids base on the token_idx
908781
"""
909782

910-
# We don't want to raise an error for unitialized weights
911-
_keys_to_ignore_on_load_missing = [
912-
r"model.layers.\d+.block_sparse_moe.experts.w2_weight",
913-
r"model.layers.\d+.block_sparse_moe.experts.w13_weight",
914-
]
915-
916783
def allocate_kv_cache(self, batch_size, max_seq_len, inp_seq_len):
917784
self.model.allocate_kv_cache(batch_size, max_seq_len, inp_seq_len)
918785
self.kv_cache_len = max_seq_len

tests/transformers/tests/models/mixtral/test_modeling_mixtral.py

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -337,12 +337,6 @@ def test_retain_grad_hidden_states_attentions(self):
337337
@unittest.skip(reason="This test is not supported for Mixtral")
338338
def test_sample_generate_dict_output(self):
339339
pass
340-
341-
#TODO: @kwisniewski98 - Change saving scheme to be the same loading scheme
342-
@unittest.skip(reason="In most of the cases, Mixtral will have w1 w2 and w3 per each expert, so in that case we need expected missing, \
343-
but when we are loading checkpoint from saved model, it will be loaded as w13 and w2 and this causes this test to fail.")
344-
def test_model_weights_reload_no_missing_tied_weights(self):
345-
pass
346340

347341
# TODO (ydshieh): Check this. See https://app.circleci.com/pipelines/github/huggingface/transformers/79245/workflows/9490ef58-79c2-410d-8f51-e3495156cf9c/jobs/1012146
348342
def is_pipeline_test_to_skip(

0 commit comments

Comments
 (0)