55
66import mlx .core as mx
77import mlx .nn as nn
8+ from mlx .nn .layers .distributed import shard_inplace , shard_linear , sum_gradients
89
910from .base import BaseModelArgs , create_attention_mask , scaled_dot_product_attention
1011from .switch_layers import SwitchGLU
@@ -118,8 +119,12 @@ def __init__(self, args: ModelArgs):
118119 args .hidden_size , args .intermediate_size , args .num_local_experts
119120 )
120121 self .e_score_correction_bias = mx .zeros ((args .num_local_experts ,))
122+ self .sharding_group = None
121123
122124 def __call__ (self , x : mx .array ) -> mx .array :
125+ if self .sharding_group is not None :
126+ x = sum_gradients (self .sharding_group )(x )
127+
123128 gates = self .gate (x .astype (mx .float32 ))
124129
125130 scores = mx .sigmoid (gates )
@@ -135,6 +140,10 @@ def __call__(self, x: mx.array) -> mx.array:
135140
136141 y = self .switch_mlp (x , inds )
137142 y = (y * scores [..., None ]).sum (axis = - 2 )
143+
144+ if self .sharding_group is not None :
145+ y = mx .distributed .all_sum (y , group = self .sharding_group )
146+
138147 return y
139148
140149
@@ -267,6 +276,53 @@ def dequant(weight, scale_inv):
267276
268277 return weights
269278
279+ def shard (self , group : Optional [mx .distributed .Group ] = None ):
280+ group = group or mx .distributed .init ()
281+ N = group .size ()
282+ rank = group .rank ()
283+ for layer in self .model .layers :
284+ # Shard the self attention
285+ layer .self_attn .q_proj = shard_linear (
286+ layer .self_attn .q_proj , "all-to-sharded" , group = group
287+ )
288+ layer .self_attn .k_proj = shard_linear (
289+ layer .self_attn .k_proj , "all-to-sharded" , group = group
290+ )
291+ layer .self_attn .v_proj = shard_linear (
292+ layer .self_attn .v_proj , "all-to-sharded" , group = group
293+ )
294+ layer .self_attn .o_proj = shard_linear (
295+ layer .self_attn .o_proj , "sharded-to-all" , group = group
296+ )
297+ if layer .self_attn .use_qk_norm :
298+ layer .self_attn .q_norm .weight = layer .self_attn .q_norm .weight .split (
299+ N , axis = - 1
300+ )[rank ]
301+ layer .self_attn .k_norm .weight = layer .self_attn .k_norm .weight .split (
302+ N , axis = - 1
303+ )[rank ]
304+
305+ layer .self_attn .num_attention_heads //= N
306+ layer .self_attn .num_key_value_heads //= N
307+
308+ # Shard the MLP
309+ shard_inplace (
310+ layer .block_sparse_moe .switch_mlp .gate_proj ,
311+ "all-to-sharded" ,
312+ group = group ,
313+ )
314+ shard_inplace (
315+ layer .block_sparse_moe .switch_mlp .down_proj ,
316+ "sharded-to-all" ,
317+ group = group ,
318+ )
319+ shard_inplace (
320+ layer .block_sparse_moe .switch_mlp .up_proj ,
321+ "all-to-sharded" ,
322+ group = group ,
323+ )
324+ layer .block_sparse_moe .sharding_group = group
325+
270326 @property
271327 def layers (self ):
272328 return self .model .layers
0 commit comments