Upload extensions_built_in/diffusion_models/hidream/src/models/moe.py with huggingface_hub
Browse files
extensions_built_in/diffusion_models/hidream/src/models/moe.py
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import math
|
| 2 |
+
import torch
|
| 3 |
+
from torch import nn
|
| 4 |
+
import torch.nn.functional as F
|
| 5 |
+
from .attention import FeedForwardSwiGLU
|
| 6 |
+
from torch.distributed.nn.functional import all_gather
|
| 7 |
+
|
| 8 |
+
_LOAD_BALANCING_LOSS = []
|
| 9 |
+
def save_load_balancing_loss(loss):
|
| 10 |
+
global _LOAD_BALANCING_LOSS
|
| 11 |
+
_LOAD_BALANCING_LOSS.append(loss)
|
| 12 |
+
|
| 13 |
+
def clear_load_balancing_loss():
|
| 14 |
+
global _LOAD_BALANCING_LOSS
|
| 15 |
+
_LOAD_BALANCING_LOSS.clear()
|
| 16 |
+
|
| 17 |
+
def get_load_balancing_loss():
|
| 18 |
+
global _LOAD_BALANCING_LOSS
|
| 19 |
+
return _LOAD_BALANCING_LOSS
|
| 20 |
+
|
| 21 |
+
def batched_load_balancing_loss():
|
| 22 |
+
aux_losses_arr = get_load_balancing_loss()
|
| 23 |
+
alpha = aux_losses_arr[0][-1]
|
| 24 |
+
Pi = torch.stack([ent[1] for ent in aux_losses_arr], dim=0)
|
| 25 |
+
fi = torch.stack([ent[2] for ent in aux_losses_arr], dim=0)
|
| 26 |
+
|
| 27 |
+
fi_list = all_gather(fi)
|
| 28 |
+
fi = torch.stack(fi_list, 0).mean(0)
|
| 29 |
+
|
| 30 |
+
aux_loss = (Pi * fi).sum(-1).mean() * alpha
|
| 31 |
+
return aux_loss
|
| 32 |
+
|
| 33 |
+
# Modified from https://github.com/deepseek-ai/DeepSeek-V3/blob/main/inference/model.py
|
| 34 |
+
class MoEGate(nn.Module):
|
| 35 |
+
def __init__(self, embed_dim, num_routed_experts=4, num_activated_experts=2, aux_loss_alpha=0.01):
|
| 36 |
+
super().__init__()
|
| 37 |
+
self.top_k = num_activated_experts
|
| 38 |
+
self.n_routed_experts = num_routed_experts
|
| 39 |
+
|
| 40 |
+
self.scoring_func = 'softmax'
|
| 41 |
+
self.alpha = aux_loss_alpha
|
| 42 |
+
self.seq_aux = False
|
| 43 |
+
|
| 44 |
+
# topk selection algorithm
|
| 45 |
+
self.norm_topk_prob = False
|
| 46 |
+
self.gating_dim = embed_dim
|
| 47 |
+
self.weight = nn.Parameter(torch.empty((self.n_routed_experts, self.gating_dim)))
|
| 48 |
+
self.reset_parameters()
|
| 49 |
+
|
| 50 |
+
def reset_parameters(self) -> None:
|
| 51 |
+
import torch.nn.init as init
|
| 52 |
+
init.kaiming_uniform_(self.weight, a=math.sqrt(5))
|
| 53 |
+
|
| 54 |
+
def forward(self, hidden_states):
|
| 55 |
+
bsz, seq_len, h = hidden_states.shape
|
| 56 |
+
# print(bsz, seq_len, h)
|
| 57 |
+
### compute gating score
|
| 58 |
+
hidden_states = hidden_states.view(-1, h)
|
| 59 |
+
logits = F.linear(hidden_states, self.weight, None)
|
| 60 |
+
if self.scoring_func == 'softmax':
|
| 61 |
+
scores = logits.softmax(dim=-1)
|
| 62 |
+
else:
|
| 63 |
+
raise NotImplementedError(f'insupportable scoring function for MoE gating: {self.scoring_func}')
|
| 64 |
+
|
| 65 |
+
### select top-k experts
|
| 66 |
+
topk_weight, topk_idx = torch.topk(scores, k=self.top_k, dim=-1, sorted=False)
|
| 67 |
+
|
| 68 |
+
### norm gate to sum 1
|
| 69 |
+
if self.top_k > 1 and self.norm_topk_prob:
|
| 70 |
+
denominator = topk_weight.sum(dim=-1, keepdim=True) + 1e-20
|
| 71 |
+
topk_weight = topk_weight / denominator
|
| 72 |
+
# this was in original and memory leaks, not needed
|
| 73 |
+
|
| 74 |
+
# ### expert-level computation auxiliary loss
|
| 75 |
+
# if self.training and self.alpha > 0.0:
|
| 76 |
+
# scores_for_aux = scores
|
| 77 |
+
# aux_topk = self.top_k
|
| 78 |
+
# # always compute aux loss based on the naive greedy topk method
|
| 79 |
+
# topk_idx_for_aux_loss = topk_idx.view(bsz, -1)
|
| 80 |
+
# if self.seq_aux:
|
| 81 |
+
# scores_for_seq_aux = scores_for_aux.view(bsz, seq_len, -1)
|
| 82 |
+
# ce = torch.zeros(bsz, self.n_routed_experts, device=hidden_states.device)
|
| 83 |
+
# ce.scatter_add_(1, topk_idx_for_aux_loss, torch.ones(bsz, seq_len * aux_topk, device=hidden_states.device)).div_(seq_len * aux_topk / self.n_routed_experts)
|
| 84 |
+
# aux_loss = (ce * scores_for_seq_aux.mean(dim = 1)).sum(dim = 1).mean() * self.alpha
|
| 85 |
+
# else:
|
| 86 |
+
# mask_ce = F.one_hot(topk_idx_for_aux_loss.view(-1), num_classes=self.n_routed_experts)
|
| 87 |
+
# ce = mask_ce.float().mean(0)
|
| 88 |
+
|
| 89 |
+
# Pi = scores_for_aux.mean(0)
|
| 90 |
+
# fi = ce * self.n_routed_experts
|
| 91 |
+
# aux_loss = (Pi * fi).sum() * self.alpha
|
| 92 |
+
# save_load_balancing_loss((aux_loss, Pi, fi, self.alpha))
|
| 93 |
+
# else:
|
| 94 |
+
aux_loss = None
|
| 95 |
+
return topk_idx, topk_weight, aux_loss
|
| 96 |
+
|
| 97 |
+
# Modified from https://github.com/deepseek-ai/DeepSeek-V3/blob/main/inference/model.py
|
| 98 |
+
class MOEFeedForwardSwiGLU(nn.Module):
|
| 99 |
+
def __init__(
|
| 100 |
+
self,
|
| 101 |
+
dim: int,
|
| 102 |
+
hidden_dim: int,
|
| 103 |
+
num_routed_experts: int,
|
| 104 |
+
num_activated_experts: int,
|
| 105 |
+
):
|
| 106 |
+
super().__init__()
|
| 107 |
+
self.shared_experts = FeedForwardSwiGLU(dim, hidden_dim // 2)
|
| 108 |
+
self.experts = nn.ModuleList([FeedForwardSwiGLU(dim, hidden_dim) for i in range(num_routed_experts)])
|
| 109 |
+
self.gate = MoEGate(
|
| 110 |
+
embed_dim = dim,
|
| 111 |
+
num_routed_experts = num_routed_experts,
|
| 112 |
+
num_activated_experts = num_activated_experts
|
| 113 |
+
)
|
| 114 |
+
self.num_activated_experts = num_activated_experts
|
| 115 |
+
|
| 116 |
+
def forward(self, x):
|
| 117 |
+
wtype = x.dtype
|
| 118 |
+
identity = x
|
| 119 |
+
orig_shape = x.shape
|
| 120 |
+
topk_idx, topk_weight, aux_loss = self.gate(x)
|
| 121 |
+
x = x.view(-1, x.shape[-1])
|
| 122 |
+
flat_topk_idx = topk_idx.view(-1)
|
| 123 |
+
y = self.moe_infer(x, flat_topk_idx, topk_weight.view(-1, 1)).view(*orig_shape)
|
| 124 |
+
# this was in original and memory leaks, not needed
|
| 125 |
+
# if self.training:
|
| 126 |
+
# x = x.repeat_interleave(self.num_activated_experts, dim=0)
|
| 127 |
+
# y = torch.empty_like(x, dtype=wtype)
|
| 128 |
+
# for i, expert in enumerate(self.experts):
|
| 129 |
+
# y[flat_topk_idx == i] = expert(x[flat_topk_idx == i]).to(dtype=wtype)
|
| 130 |
+
# y = (y.view(*topk_weight.shape, -1) * topk_weight.unsqueeze(-1)).sum(dim=1)
|
| 131 |
+
# y = y.view(*orig_shape).to(dtype=wtype)
|
| 132 |
+
# #y = AddAuxiliaryLoss.apply(y, aux_loss)
|
| 133 |
+
# else:
|
| 134 |
+
# y = self.moe_infer(x, flat_topk_idx, topk_weight.view(-1, 1)).view(*orig_shape)
|
| 135 |
+
y = y + self.shared_experts(identity)
|
| 136 |
+
return y
|
| 137 |
+
|
| 138 |
+
# @torch.no_grad()
|
| 139 |
+
def moe_infer(self, x, flat_expert_indices, flat_expert_weights):
|
| 140 |
+
expert_cache = torch.zeros_like(x)
|
| 141 |
+
idxs = flat_expert_indices.argsort()
|
| 142 |
+
tokens_per_expert = flat_expert_indices.bincount().cpu().numpy().cumsum(0)
|
| 143 |
+
token_idxs = idxs // self.num_activated_experts
|
| 144 |
+
for i, end_idx in enumerate(tokens_per_expert):
|
| 145 |
+
start_idx = 0 if i == 0 else tokens_per_expert[i-1]
|
| 146 |
+
if start_idx == end_idx:
|
| 147 |
+
continue
|
| 148 |
+
expert = self.experts[i]
|
| 149 |
+
exp_token_idx = token_idxs[start_idx:end_idx]
|
| 150 |
+
expert_tokens = x[exp_token_idx]
|
| 151 |
+
expert_out = expert(expert_tokens)
|
| 152 |
+
expert_out.mul_(flat_expert_weights[idxs[start_idx:end_idx]])
|
| 153 |
+
|
| 154 |
+
# for fp16 and other dtype
|
| 155 |
+
expert_cache = expert_cache.to(expert_out.dtype)
|
| 156 |
+
expert_cache.scatter_reduce_(0, exp_token_idx.view(-1, 1).repeat(1, x.shape[-1]), expert_out, reduce='sum')
|
| 157 |
+
return expert_cache
|