|
7 | 7 |
|
8 | 8 | import mlx.core as mx |
9 | 9 | import mlx.nn as nn |
| 10 | +from mlx.nn.layers.distributed import shard_inplace, shard_linear, sum_gradients |
10 | 11 |
|
11 | 12 | from .base import BaseModelArgs, create_attention_mask, scaled_dot_product_attention |
12 | 13 | from .pipeline import PipelineMixin |
@@ -205,13 +206,21 @@ def __init__(self, config: ModelArgs): |
205 | 206 | config=config, intermediate_size=intermediate_size |
206 | 207 | ) |
207 | 208 |
|
| 209 | + self.sharding_group = None |
| 210 | + |
208 | 211 | def __call__(self, x): |
| 212 | + if self.sharding_group is not None: |
| 213 | + x = sum_gradients(self.sharding_group)(x) |
| 214 | + |
209 | 215 | inds, scores = self.gate(x) |
210 | 216 | y = self.switch_mlp(x, inds) |
211 | 217 | y = (y * scores[..., None]).sum(axis=-2).astype(y.dtype) |
212 | 218 | if self.config.n_shared_experts is not None: |
213 | 219 | y = y + self.shared_experts(x) |
214 | 220 |
|
| 221 | + if self.sharding_group is not None: |
| 222 | + y = mx.distributed.all_sum(y, group=self.sharding_group) |
| 223 | + |
215 | 224 | return y |
216 | 225 |
|
217 | 226 |
|
@@ -252,10 +261,6 @@ def __init__(self, config: ModelArgs): |
252 | 261 | self.layers = [ |
253 | 262 | DecoderLayer(config, idx) for idx in range(config.num_hidden_layers) |
254 | 263 | ] |
255 | | - self.start_idx = 0 |
256 | | - self.end_idx = len(self.layers) |
257 | | - self.num_layers = self.end_idx |
258 | | - |
259 | 264 | self.norm = nn.RMSNorm(config.hidden_size, eps=config.rms_norm_eps) |
260 | 265 |
|
261 | 266 | def __call__( |
@@ -286,7 +291,8 @@ def __call__( |
286 | 291 | cache[-1].keys = mx.depends(cache[-1].keys, h) |
287 | 292 |
|
288 | 293 | # Broadcast h while keeping it in the graph |
289 | | - h = mx.distributed.all_gather(h)[: h.shape[0]] |
| 294 | + if pipeline_size > 1: |
| 295 | + h = mx.distributed.all_gather(h)[: h.shape[0]] |
290 | 296 |
|
291 | 297 | return self.norm(h) |
292 | 298 |
|
@@ -329,6 +335,61 @@ def sanitize(self, weights): |
329 | 335 | if not k.startswith(f"model.layers.{mpt_layer}") |
330 | 336 | } |
331 | 337 |
|
| 338 | + def shard(self, group: Optional[mx.distributed.Group] = None): |
| 339 | + group = group or mx.distributed.init() |
| 340 | + N = group.size() |
| 341 | + for layer in self.model.layers: |
| 342 | + # Shard the self attention |
| 343 | + layer.self_attn.q_proj = shard_linear( |
| 344 | + layer.self_attn.q_proj, "all-to-sharded", group=group |
| 345 | + ) |
| 346 | + layer.self_attn.k_proj = shard_linear( |
| 347 | + layer.self_attn.k_proj, "all-to-sharded", group=group |
| 348 | + ) |
| 349 | + layer.self_attn.v_proj = shard_linear( |
| 350 | + layer.self_attn.v_proj, "all-to-sharded", group=group |
| 351 | + ) |
| 352 | + layer.self_attn.o_proj = shard_linear( |
| 353 | + layer.self_attn.o_proj, "sharded-to-all", group=group |
| 354 | + ) |
| 355 | + layer.self_attn.n_heads //= N |
| 356 | + layer.self_attn.n_kv_heads //= N |
| 357 | + |
| 358 | + # Shard the MLP |
| 359 | + if isinstance(layer.mlp, MLP): |
| 360 | + layer.mlp.gate_proj = shard_linear( |
| 361 | + layer.mlp.gate_proj, "all-to-sharded", group=group |
| 362 | + ) |
| 363 | + layer.mlp.down_proj = shard_linear( |
| 364 | + layer.mlp.down_proj, "sharded-to-all", group=group |
| 365 | + ) |
| 366 | + layer.mlp.up_proj = shard_linear( |
| 367 | + layer.mlp.up_proj, "all-to-sharded", group=group |
| 368 | + ) |
| 369 | + |
| 370 | + # Shard the MoE. Shard in place since the MoE should be responsible |
| 371 | + # for aggregating the results. |
| 372 | + else: |
| 373 | + layer.mlp.sharding_group = group |
| 374 | + shard_inplace( |
| 375 | + layer.mlp.shared_experts.gate_proj, "all-to-sharded", group=group |
| 376 | + ) |
| 377 | + shard_inplace( |
| 378 | + layer.mlp.shared_experts.down_proj, "sharded-to-all", group=group |
| 379 | + ) |
| 380 | + shard_inplace( |
| 381 | + layer.mlp.shared_experts.up_proj, "all-to-sharded", group=group |
| 382 | + ) |
| 383 | + shard_inplace( |
| 384 | + layer.mlp.switch_mlp.gate_proj, "all-to-sharded", group=group |
| 385 | + ) |
| 386 | + shard_inplace( |
| 387 | + layer.mlp.switch_mlp.down_proj, "sharded-to-all", group=group |
| 388 | + ) |
| 389 | + shard_inplace( |
| 390 | + layer.mlp.switch_mlp.up_proj, "all-to-sharded", group=group |
| 391 | + ) |
| 392 | + |
332 | 393 | @property |
333 | 394 | def layers(self): |
334 | 395 | return self.model.pipeline_layers |
|
0 commit comments