| from typing import Optional |
|
|
| import torch |
| import torch.nn as nn |
|
|
|
|
| class FeedForward(nn.Module): |
| def __init__( |
| self, |
| embedding_dim: int, |
| hidden_dim: int, |
| device: torch.device | None = None, |
| dtype: torch.dtype | None = None, |
| ): |
| factory_kwargs = dict(device=device, dtype=dtype) |
| super().__init__() |
|
|
| self.fc1 = nn.Linear(embedding_dim, hidden_dim, bias=False, **factory_kwargs) |
| self.fc2 = nn.Linear(embedding_dim, hidden_dim, bias=False, **factory_kwargs) |
| self.fc3 = nn.Linear(hidden_dim, embedding_dim, bias=False, **factory_kwargs) |
|
|
| def forward(self, x: torch.FloatTensor) -> torch.FloatTensor: |
| x_fc1 = self.fc1(x) |
| x_fc2 = self.fc2(x) |
|
|
| x = nn.functional.silu(x_fc1) * x_fc2 |
| x = self.fc3(x) |
| return x |
|
|
|
|
| class MoEFeedForward(nn.Module): |
| def __init__( |
| self, |
| embedding_dim: int, |
| hidden_dim: int, |
| num_experts_per_token: int, |
| num_experts: int, |
| device: torch.device | None = None, |
| dtype: torch.dtype | None = None, |
| ): |
| assert num_experts > 0, "num_experts should be greater than zero" |
| assert num_experts >= num_experts_per_token > 0, ( |
| "num_experts_per_token should be greater than zero and less than or equal to num_experts" |
| ) |
| super().__init__() |
| self.num_experts_per_token = num_experts_per_token |
| self.num_experts = num_experts |
| meta_device = torch.device("meta") |
|
|
| self.gate = nn.Linear( |
| embedding_dim, num_experts, bias=False, device=device, dtype=dtype |
| ) |
| self.ff = nn.ModuleList( |
| [ |
| FeedForward( |
| embedding_dim, |
| hidden_dim, |
| device=meta_device, |
| dtype=dtype, |
| ) |
| for _ in range(num_experts) |
| ] |
| ) |
|
|
| def forward(self, x: torch.FloatTensor) -> torch.Tensor: |
| scores = self.gate(x) |
| topk_scores, topk_indices = torch.topk( |
| scores, self.num_experts_per_token, dim=-1 |
| ) |
| topk_probs = torch.softmax(topk_scores, dim=-1) |
|
|
| expert_outputs = [] |
| for i in range(self.num_experts): |
| out = self.ff[i](x) |
| expert_outputs.append(out.unsqueeze(-2)) |
| expert_outputs = torch.cat(expert_outputs, dim=-2) |
|
|
| gating_probs = torch.zeros_like(scores) |
| for i in range(self.num_experts_per_token): |
| indices = topk_indices[..., i : i + 1] |
| prob = topk_probs[..., i : i + 1] |
| gating_probs.scatter_(dim=-1, index=indices, src=prob) |
| gating_probs = gating_probs.unsqueeze(-1) |
| y = (gating_probs * expert_outputs).sum(dim=-2) |
| return y |
|
|
|
|
| class RMSNorm(nn.Module): |
| def __init__( |
| self, |
| embedding_dim: int, |
| eps: float = 1e-6, |
| bias: int = False, |
| device: torch.device | None = None, |
| dtype: torch.dtype | None = None, |
| ): |
| factory_kwargs = dict(device=device, dtype=dtype) |
| super().__init__() |
| self.embedding_dim = embedding_dim |
| self.eps = eps |
| self.bias = bias |
| self.scale = nn.Parameter(torch.ones(embedding_dim, **factory_kwargs)) |
| self.shift = ( |
| nn.Parameter(torch.zeros(embedding_dim, **factory_kwargs)) if bias else None |
| ) |
| self.dtype = dtype |
|
|
| def extra_repr(self): |
| s = "embedding_dim=%r, eps=%r, bias=%r" % ( |
| self.embedding_dim, |
| self.eps, |
| self.bias, |
| ) |
| return s |
|
|
| def forward(self, x: torch.FloatTensor) -> torch.Tensor: |
| input_dtype = x.dtype |
|
|
| variance = x.to(self.dtype).pow(2).mean(dim=-1, keepdim=True) |
| norm_x = x * torch.rsqrt(variance + self.eps) |
| norm_x = norm_x * self.scale |
|
|
| if self.shift is not None: |
| norm_x = norm_x + self.shift |
|
|
| return norm_x.to(input_dtype) |
|
|
|
|
| def compute_rope_params( |
| head_dim: int, |
| theta_base: int = 10_000, |
| max_position_embeddings: int = 4096, |
| dtype: Optional[torch.dtype] = torch.float32, |
| device: Optional[torch.device] = None, |
| ) -> tuple[torch.Tensor, torch.Tensor]: |
| assert head_dim % 2 == 0, "Embedding dim (head_dim) must be even" |
|
|
| inv_freq = 1.0 / ( |
| theta_base |
| ** (torch.arange(0, head_dim, 2, dtype=torch.float32, device=device) / head_dim) |
| ) |
|
|
| positions = torch.arange( |
| max_position_embeddings, dtype=torch.float32, device=device |
| ) |
|
|
| angles = torch.outer(positions, inv_freq) |
| angles = torch.cat([angles, angles], dim=1) |
|
|
| cos = torch.cos(angles).to(dtype=dtype) |
| sin = torch.sin(angles).to(dtype=dtype) |
| return cos, sin |
|
|
|
|
| def apply_rope( |
| x: torch.Tensor, |
| cos: torch.Tensor, |
| sin: torch.Tensor, |
| offset: int = 0, |
| ) -> torch.Tensor: |
| assert x.dim() == 4, "expected tensor of dimension 4 (B, NH, S, H)" |
| _, _, seq_len, head_dim = x.shape |
| assert head_dim % 2 == 0, "head_dim must be even" |
|
|
| x1 = x[..., : head_dim // 2] |
| x2 = x[..., head_dim // 2 :] |
|
|
| |
| cos_sliced = cos[offset : offset + seq_len, :].unsqueeze(0).unsqueeze(0) |
| sin_sliced = sin[offset : offset + seq_len, :].unsqueeze(0).unsqueeze(0) |
|
|
| |
| rotated = torch.cat((-x2, x1), dim=-1) |
| x_rotated = (x * cos_sliced) + (rotated * sin_sliced) |
|
|
| return x_rotated.type_as(x) |
|
|