| import torch |
| import torch.nn.functional as F |
| from torch import nn |
| from transformers.activations import ACT2FN |
|
|
|
|
| class FeedForward(nn.Module): |
| def __init__(self, config: "LMConfig", intermediate_size: int = None): |
| super().__init__() |
| intermediate_size = intermediate_size or config.intermediate_size |
| self.gate_proj = nn.Linear(config.hidden_size, intermediate_size, bias=False) |
| self.down_proj = nn.Linear(intermediate_size, config.hidden_size, bias=False) |
| self.up_proj = nn.Linear(config.hidden_size, intermediate_size, bias=False) |
| self.act_fn = ACT2FN[config.hidden_act] |
|
|
| def forward(self, x): |
| return self.down_proj(self.act_fn(self.gate_proj(x)) * self.up_proj(x)) |
|
|
|
|
| class MOEFeedForward(nn.Module): |
| def __init__(self, config: "LMConfig"): |
| super().__init__() |
| self.config = config |
| self.gate = nn.Linear(config.hidden_size, config.num_experts, bias=False) |
| self.experts = nn.ModuleList([FeedForward(config, intermediate_size=config.moe_intermediate_size) for _ in range(config.num_experts)]) |
| self.act_fn = ACT2FN[config.hidden_act] |
|
|
| def forward(self, x): |
| batch_size, seq_len, hidden_dim = x.shape |
| x_flat = x.view(-1, hidden_dim) |
| scores = F.softmax(self.gate(x_flat), dim=-1) |
| topk_weight, topk_idx = torch.topk(scores, k=self.config.num_experts_per_tok, dim=-1, sorted=False) |
| if self.config.norm_topk_prob: |
| topk_weight = topk_weight / (topk_weight.sum(dim=-1, keepdim=True) + 1e-20) |
| y = torch.zeros_like(x_flat) |
| for i, expert in enumerate(self.experts): |
| mask = (topk_idx == i) |
| if mask.any(): |
| token_idx = mask.any(dim=-1).nonzero().flatten() |
| weight = topk_weight[mask].view(-1, 1) |
| y.index_add_(0, token_idx, (expert(x_flat[token_idx]) * weight).to(y.dtype)) |
| elif self.training: |
| y[0, 0] += 0 * sum(p.sum() for p in expert.parameters()) |
| if self.training and self.config.router_aux_loss_coef > 0: |
| load = F.one_hot(topk_idx, self.config.num_experts).float().mean(0) |
| self.aux_loss = (load * scores.mean(0)).sum() * self.config.num_experts * self.config.router_aux_loss_coef |
| else: |
| self.aux_loss = scores.new_zeros(1).squeeze() |
| return y.view(batch_size, seq_len, hidden_dim) |
|
|