@@ -80,10 +80,12 @@ 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
85+ if args .moe_hidden_dim is not None
86+ else args .hidden_dim
87+ )
8488 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`
8789 multiple_of = args .multiple_of
8890 hidden_dim = 4 * self .dim
8991 hidden_dim = int (2 * hidden_dim / 3 )
@@ -95,9 +97,9 @@ def __init__(self, args: ModelArgs):
9597 self .num_experts = args .num_experts
9698
9799 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]
100+ w1_weights = self .w1 [expert_indices ].transpose (- 1 , - 2 ) # [T, A, D, hidden ]
101+ w3_weights = self .w3 [expert_indices ].transpose (- 1 , - 2 ) # [T, A, D, hidden ]
102+ w2_weights = self .w2 [expert_indices ] # [T, A, hidden , D]
101103 x1 = F .silu (torch .einsum ("ti,taio -> tao" , x , w1_weights ))
102104 x3 = torch .einsum ("ti, taio -> tao" , x , w3_weights )
103105 expert_outs = torch .einsum ("tao, taoi -> tai" , (x1 * x3 ), w2_weights )
@@ -110,16 +112,67 @@ def __init__(self, config) -> None:
110112 self .gate = nn .Linear (config .dim , config .num_experts , bias = False )
111113 self .cond_ffn = ConditionalFeedForward (config )
112114 self .dim = config .dim
115+ self .num_activated_experts = config .num_activated_experts
116+ self .score_func = config .moe_score_func
117+ self .route_scale = config .moe_route_scale
118+ if self .score_func not in {"sigmoid" , "softmax" , "softmax_all" }:
119+ raise ValueError (f"Unsupported MoE routing score function: { self .score_func } " )
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+ self .gate .weight .new_zeros (config .num_experts )
132+ if config .moe_use_expert_bias
133+ else None ,
134+ )
135+ if config .moe_shared_expert_hidden_dim is not None :
136+ self .shared_expert = FeedForward (
137+ dim = config .dim , hidden_dim = config .moe_shared_expert_hidden_dim
138+ )
139+ else :
140+ self .shared_expert = None
141+
142+ def _route (self , x : torch .Tensor ) -> tuple [torch .Tensor , torch .Tensor ]:
143+ scores = self .gate (x ) # [T, E]
144+ if self .score_func == "sigmoid" :
145+ scores = scores .sigmoid ()
146+ elif self .score_func == "softmax_all" :
147+ scores = scores .softmax (dim = - 1 )
148+ scores_for_topk = (
149+ (scores + self .expert_bias )
150+ if self .expert_bias is not None
151+ 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 = (
162+ expert_weights / normalizer * self .route_scale
163+ )
164+ elif self .score_func == "softmax" :
165+ expert_weights = expert_weights .softmax (dim = - 1 )
166+ return expert_weights , expert_indices
113167
114168 def forward (self , x : torch .Tensor ) -> torch .Tensor :
115169 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]
170+ expert_weights , expert_indices = self ._route (x )
121171 expert_outs = self .cond_ffn (x , expert_indices )
122- return torch .einsum ("tai,ta -> ti" , expert_outs , expert_weights )
172+ out = torch .einsum ("tai,ta -> ti" , expert_outs , expert_weights )
173+ if self .shared_expert is not None :
174+ out = out + self .shared_expert (x )
175+ return out
123176
124177
125178class TransformerBlock (nn .Module ):
0 commit comments