@@ -80,10 +80,10 @@ class ConditionalFeedForward(nn.Module):
8080 def __init__ (self , args : ModelArgs ):
8181 super ().__init__ ()
8282 self .dim = args .dim
83- hidden_dim = args .hidden_dim
83+ hidden_dim = (
84+ args .moe_hidden_dim if args .moe_hidden_dim is not None else args .hidden_dim
85+ )
8486 if hidden_dim is None :
85- # If hidden_dim is not explicitly set in the ModelArgs,
86- # then calculate implicitly based on dim and also multiple of `args.multiple_of`
8787 multiple_of = args .multiple_of
8888 hidden_dim = 4 * self .dim
8989 hidden_dim = int (2 * hidden_dim / 3 )
@@ -95,9 +95,9 @@ def __init__(self, args: ModelArgs):
9595 self .num_experts = args .num_experts
9696
9797 def forward (self , x : torch .Tensor , expert_indices : torch .Tensor ) -> torch .Tensor :
98- w1_weights = self .w1 [expert_indices ].transpose (- 1 , - 2 ) # [T, A, D, D ]
99- w3_weights = self .w3 [expert_indices ].transpose (- 1 , - 2 ) # [T, A, D, D ]
100- w2_weights = self .w2 [expert_indices ] # [T, A, D , D]
98+ w1_weights = self .w1 [expert_indices ].transpose (- 1 , - 2 ) # [T, A, D, hidden ]
99+ w3_weights = self .w3 [expert_indices ].transpose (- 1 , - 2 ) # [T, A, D, hidden ]
100+ w2_weights = self .w2 [expert_indices ] # [T, A, hidden , D]
101101 x1 = F .silu (torch .einsum ("ti,taio -> tao" , x , w1_weights ))
102102 x3 = torch .einsum ("ti, taio -> tao" , x , w3_weights )
103103 expert_outs = torch .einsum ("tao, taoi -> tai" , (x1 * x3 ), w2_weights )
@@ -110,16 +110,67 @@ def __init__(self, config) -> None:
110110 self .gate = nn .Linear (config .dim , config .num_experts , bias = False )
111111 self .cond_ffn = ConditionalFeedForward (config )
112112 self .dim = config .dim
113+ self .num_activated_experts = config .num_activated_experts
114+ self .score_func = config .moe_score_func
115+ self .route_scale = config .moe_route_scale
116+ if self .score_func not in {"sigmoid" , "softmax" , "softmax_all" }:
117+ raise ValueError (
118+ f"Unsupported MoE routing score function: { self .score_func } "
119+ )
120+ if self .score_func != "sigmoid" and self .route_scale != 1.0 :
121+ raise ValueError ("MoE route scaling is only supported with sigmoid routing" )
122+ if not 0 < self .num_activated_experts <= config .num_experts :
123+ raise ValueError (
124+ "The number of activated experts must be between one and the "
125+ "total number of experts"
126+ )
127+ self .expert_bias : torch .Tensor | None
128+ # Citrine C3: initialize the buffer on the gate's device.
129+ self .register_buffer (
130+ "expert_bias" ,
131+ (
132+ self .gate .weight .new_zeros (config .num_experts )
133+ if config .moe_use_expert_bias
134+ else None
135+ ),
136+ )
137+ if config .moe_shared_expert_hidden_dim is not None :
138+ self .shared_expert = FeedForward (
139+ dim = config .dim , hidden_dim = config .moe_shared_expert_hidden_dim
140+ )
141+ else :
142+ self .shared_expert = None
143+
144+ def _route (self , x : torch .Tensor ) -> tuple [torch .Tensor , torch .Tensor ]:
145+ scores = self .gate (x ) # [T, E]
146+ if self .score_func == "sigmoid" :
147+ scores = scores .sigmoid ()
148+ elif self .score_func == "softmax_all" :
149+ scores = scores .softmax (dim = - 1 )
150+ scores_for_topk = (
151+ (scores + self .expert_bias ) if self .expert_bias is not None else scores
152+ )
153+ _ , expert_indices = torch .topk (
154+ scores_for_topk , self .num_activated_experts , dim = - 1
155+ )
156+ expert_weights = scores .gather (1 , expert_indices )
157+ if self .score_func == "sigmoid" :
158+ normalizer = expert_weights .sum (dim = - 1 , keepdim = True ).clamp_min (
159+ torch .finfo (expert_weights .dtype ).tiny
160+ )
161+ expert_weights = expert_weights / normalizer * self .route_scale
162+ elif self .score_func == "softmax" :
163+ expert_weights = expert_weights .softmax (dim = - 1 )
164+ return expert_weights , expert_indices
113165
114166 def forward (self , x : torch .Tensor ) -> torch .Tensor :
115167 x = x .view (- 1 , self .dim )
116- # T = num_tokens, E = num_experts, D = hidden dim, A = activated experts
117- # x: [T, D]
118- scores = self .gate (x ) # [T, E]
119- expert_weights , expert_indices = torch .topk (scores , 2 , dim = - 1 ) # [T, A], [T, A]
120- expert_weights = expert_weights .softmax (dim = - 1 ) # [T, A]
168+ expert_weights , expert_indices = self ._route (x )
121169 expert_outs = self .cond_ffn (x , expert_indices )
122- return torch .einsum ("tai,ta -> ti" , expert_outs , expert_weights )
170+ out = torch .einsum ("tai,ta -> ti" , expert_outs , expert_weights )
171+ if self .shared_expert is not None :
172+ out = out + self .shared_expert (x )
173+ return out
123174
124175
125176class TransformerBlock (nn .Module ):
0 commit comments