"""Core model parts to implement during the model-structure stage. The functions and classes here intentionally start as skeletons. Course lessons will ask the learner to fill them in and align behavior with model/model_minimind.py. """ from __future__ import annotations import torch from torch import nn import torch.nn.functional as F from transformers.activations import ACT2FN def rotate_half(x: torch.Tensor) -> torch.Tensor: """TODO: implement RoPE half-rotation. Align with: model/model_minimind.py::apply_rotary_pos_emb.rotate_half """ raise NotImplementedError("Implement in the RoPE lesson.") def apply_rope( q: torch.Tensor, k: torch.Tensor, cos: torch.Tensor, sin: torch.Tensor, unsqueeze_dim: int = 1, ) -> tuple[torch.Tensor, torch.Tensor]: """TODO: apply RoPE to q and k. Align with: model/model_minimind.py::apply_rotary_pos_emb """ raise NotImplementedError("Implement in the RoPE lesson.") class RMSNorm(nn.Module): """TODO: implement RMSNorm. Align with: model/model_minimind.py::RMSNorm """ def __init__(self, dim: int, eps: float = 1e-6): super().__init__() self.dim = dim self.eps = eps self.weight = nn.Parameter(torch.ones(dim)) def forward(self, x: torch.Tensor) -> torch.Tensor: raise NotImplementedError("Implement in the RMSNorm lesson.") class Attention(nn.Module): """TODO: implement a minimal MiniMind attention module. Align with: model/model_minimind.py::Attention """ def __init__( self, hidden_size: int, num_attention_heads: int, num_key_value_heads: int, head_dim: int, dropout: float = 0.0, rms_norm_eps: float = 1e-6, ): super().__init__() self.hidden_size = hidden_size self.num_attention_heads = num_attention_heads self.num_key_value_heads = num_key_value_heads self.head_dim = head_dim self.dropout = dropout self.rms_norm_eps = rms_norm_eps def forward( self, x: torch.Tensor, position_embeddings: tuple[torch.Tensor, torch.Tensor], past_key_value: tuple[torch.Tensor, torch.Tensor] | None = None, use_cache: bool = False, attention_mask: torch.Tensor | None = None, ) -> tuple[torch.Tensor, tuple[torch.Tensor, torch.Tensor] | None]: raise NotImplementedError("Implement across the Attention/RoPE/KV cache lessons.") class FeedForward(nn.Module): """TODO: implement dense FFN. Align with: model/model_minimind.py::FeedForward """ def __init__(self, hidden_size: int, intermediate_size: int, hidden_act: str = "silu"): super().__init__() self.hidden_size = hidden_size self.intermediate_size = intermediate_size self.hidden_act = hidden_act self.gate_proj=nn.Linear(self.hidden_size,self.intermediate_size,bias=False) self.up_proj=nn.Linear(self.hidden_size,self.intermediate_size,bias=False) self.down_proj=nn.Linear(self.intermediate_size,self.hidden_size,bias=False) self.act_fn=ACT2FN[hidden_act] def forward(self, x: torch.Tensor) -> torch.Tensor: return self.down_proj(self.act_fn(self.gate_proj(x))*self.up_proj(x)) class MOEFeedForward(nn.Module): """TODO: implement a minimal MiniMind MoE FFN. Align with: model/model_minimind.py::MOEFeedForward """ def __init__( self, hidden_size: int, intermediate_size: int, num_experts: int = 4, num_experts_per_tok: int = 1, hidden_act: str = "silu", norm_topk_prob: bool = True, router_aux_loss_coef: float = 5e-4, ): super().__init__() self.hidden_size = hidden_size self.intermediate_size = intermediate_size self.num_experts = num_experts self.num_experts_per_tok = num_experts_per_tok self.hidden_act = hidden_act self.norm_topk_prob = norm_topk_prob self.router_aux_loss_coef = router_aux_loss_coef self.aux_loss = torch.zeros(()) self.gate=nn.Linear(self.hidden_size,self.num_experts,bias=False) self.experts=nn.ModuleList(FeedForward(self.hidden_size,self.intermediate_size) for _ in range(self.num_experts)) def forward(self, x: torch.Tensor) -> torch.Tensor: batch_size,seq_len,hidden_size=x.shape x_flat=x.view(-1,hidden_size) scores=F.softmax(self.gate(x_flat),dim=-1) topk_weight,topk_idx=torch.topk(scores,k=self.num_experts_per_tok,dim=-1,sorted=False)#[B*S,num_experts_per_tok] if self.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()#选出带有这个expert的每个token的id weight=topk_weight[mask].view(-1,1)#取出这些token对应的expert的权重 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.router_aux_loss_coef > 0: load=F.one_hot(topk_idx,self.num_experts).float()#[B*S,num_experts_per_tok,self.num_experts] load=load.mean(0)#[num_experts_per_tok,self.num_experts] self.aux_loss=(load*scores.mean(dim=0)).sum()*self.router_aux_loss_coef*self.num_experts else: self.aux_loss = scores.new_zeros(1).squeeze()#创建一个 shape = [1] 的全 0 tensor return y.view(batch_size,seq_len,hidden_size) raise NotImplementedError("Implement in the MoE lesson.")