Kernels
github-actions[bot] commited on
Commit
678578a
·
1 Parent(s): 6943c45

Add built binary [ci skip]

Browse files
Files changed (27) hide show
  1. build/torch27-cxx11-cu118-x86_64-linux/optimizer/_ops.py +3 -3
  2. build/torch27-cxx11-cu118-x86_64-linux/optimizer/{_optimizer_37be0d0_dirty.abi3.so → _optimizer_6943c45_dirty.abi3.so} +1 -1
  3. build/torch27-cxx11-cu118-x86_64-linux/optimizer/muon.py +67 -20
  4. build/torch27-cxx11-cu126-x86_64-linux/optimizer/_ops.py +3 -3
  5. build/{torch28-cxx11-cu126-x86_64-linux/optimizer/_optimizer_37be0d0_dirty.abi3.so → torch27-cxx11-cu126-x86_64-linux/optimizer/_optimizer_6943c45_dirty.abi3.so} +1 -1
  6. build/torch27-cxx11-cu126-x86_64-linux/optimizer/muon.py +67 -20
  7. build/torch27-cxx11-cu128-x86_64-linux/optimizer/_ops.py +3 -3
  8. build/{torch28-cxx11-cu128-x86_64-linux/optimizer/_optimizer_37be0d0_dirty.abi3.so → torch27-cxx11-cu128-x86_64-linux/optimizer/_optimizer_6943c45_dirty.abi3.so} +1 -1
  9. build/torch27-cxx11-cu128-x86_64-linux/optimizer/muon.py +67 -20
  10. build/torch27-cxx11-rocm63-x86_64-linux/optimizer/_ops.py +3 -3
  11. build/torch27-cxx11-rocm63-x86_64-linux/optimizer/{_optimizer_37be0d0_dirty.abi3.so → _optimizer_6943c45_dirty.abi3.so} +1 -1
  12. build/torch27-cxx11-rocm63-x86_64-linux/optimizer/muon.py +67 -20
  13. build/torch28-cxx11-cu126-x86_64-linux/optimizer/_ops.py +3 -3
  14. build/{torch27-cxx11-cu126-x86_64-linux/optimizer/_optimizer_37be0d0_dirty.abi3.so → torch28-cxx11-cu126-x86_64-linux/optimizer/_optimizer_6943c45_dirty.abi3.so} +1 -1
  15. build/torch28-cxx11-cu126-x86_64-linux/optimizer/muon.py +67 -20
  16. build/torch28-cxx11-cu128-x86_64-linux/optimizer/_ops.py +3 -3
  17. build/{torch28-cxx11-cu129-x86_64-linux/optimizer/_optimizer_37be0d0_dirty.abi3.so → torch28-cxx11-cu128-x86_64-linux/optimizer/_optimizer_6943c45_dirty.abi3.so} +1 -1
  18. build/torch28-cxx11-cu128-x86_64-linux/optimizer/muon.py +67 -20
  19. build/torch28-cxx11-cu129-x86_64-linux/optimizer/_ops.py +3 -3
  20. build/{torch27-cxx11-cu128-x86_64-linux/optimizer/_optimizer_37be0d0_dirty.abi3.so → torch28-cxx11-cu129-x86_64-linux/optimizer/_optimizer_6943c45_dirty.abi3.so} +1 -1
  21. build/torch28-cxx11-cu129-x86_64-linux/optimizer/muon.py +67 -20
  22. build/torch28-cxx11-rocm63-x86_64-linux/optimizer/_ops.py +3 -3
  23. build/torch28-cxx11-rocm63-x86_64-linux/optimizer/{_optimizer_37be0d0_dirty.abi3.so → _optimizer_6943c45_dirty.abi3.so} +1 -1
  24. build/torch28-cxx11-rocm63-x86_64-linux/optimizer/muon.py +67 -20
  25. build/torch28-cxx11-rocm64-x86_64-linux/optimizer/_ops.py +3 -3
  26. build/torch28-cxx11-rocm64-x86_64-linux/optimizer/{_optimizer_37be0d0_dirty.abi3.so → _optimizer_6943c45_dirty.abi3.so} +1 -1
  27. build/torch28-cxx11-rocm64-x86_64-linux/optimizer/muon.py +67 -20
build/torch27-cxx11-cu118-x86_64-linux/optimizer/_ops.py CHANGED
@@ -1,9 +1,9 @@
1
  import torch
2
- from . import _optimizer_37be0d0_dirty
3
- ops = torch.ops._optimizer_37be0d0_dirty
4
 
5
  def add_op_namespace_prefix(op_name: str):
6
  """
7
  Prefix op by namespace.
8
  """
9
- return f"_optimizer_37be0d0_dirty::{op_name}"
 
1
  import torch
2
+ from . import _optimizer_6943c45_dirty
3
+ ops = torch.ops._optimizer_6943c45_dirty
4
 
5
  def add_op_namespace_prefix(op_name: str):
6
  """
7
  Prefix op by namespace.
8
  """
9
+ return f"_optimizer_6943c45_dirty::{op_name}"
build/torch27-cxx11-cu118-x86_64-linux/optimizer/{_optimizer_37be0d0_dirty.abi3.so → _optimizer_6943c45_dirty.abi3.so} RENAMED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:c75f1e3401cc6e4ad02a674aadda11b11a28c366ad71fc11d1525ac66ca661de
3
  size 1787368
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:939122c6c19779ad52d51d68a870c547d59b40d57f71464f8c85904078863c45
3
  size 1787368
build/torch27-cxx11-cu118-x86_64-linux/optimizer/muon.py CHANGED
@@ -73,7 +73,7 @@ class _muon_state:
73
  qk_clip_state = None
74
 
75
 
76
- def split_elems_for_src(param, state, src_rank, num_ranks) -> int:
77
  rows = param.shape[0]
78
  cols = int(param.numel() // rows)
79
  base, rem = divmod(rows, num_ranks)
@@ -83,6 +83,10 @@ def split_elems_for_src(param, state, src_rank, num_ranks) -> int:
83
 
84
  @torch.no_grad()
85
  def _alloc_gathered_grad(params, param_to_state, rank, compute_stream):
 
 
 
 
86
  with torch.cuda.stream(compute_stream):
87
  for p in params:
88
  state = param_to_state[id(p)]
@@ -102,13 +106,17 @@ def _alloc_gathered_grad(params, param_to_state, rank, compute_stream):
102
  @torch.no_grad()
103
  def _all2all_gather(params, param_to_state, rank, comm_stream, none_grad,
104
  alloc_event):
 
 
 
105
  with torch.cuda.stream(comm_stream):
106
  process_group = param_to_state[id(params[0])].process_group
107
  num_ranks = dist.get_world_size(group=process_group)
108
 
109
- # Calculate sending tensors
110
  per_dst = [[] for _ in range(num_ranks)]
111
  send_counts = [0] * num_ranks
 
112
  for p in params:
113
  state = param_to_state[id(p)]
114
  dst = state.worker_rank
@@ -125,15 +133,16 @@ def _all2all_gather(params, param_to_state, rank, comm_stream, none_grad,
125
  for v in per_dst), "all params should be sharded to all devices"
126
 
127
  send_buf = torch.cat([torch.cat(v, dim=0) for v in per_dst], dim=0)
128
- owner_params = [
129
  p for p in params if param_to_state[id(p)].worker_rank == rank
130
  ]
131
 
132
- # Calculate receiving tensors
133
  recv_counts = [0] * num_ranks
 
134
  for src in range(num_ranks):
135
  total = 0
136
- for p in owner_params:
137
  state = param_to_state[id(p)]
138
  assert state.worker_rank == rank
139
  total += split_elems_for_src(p, state, src, num_ranks)
@@ -141,6 +150,8 @@ def _all2all_gather(params, param_to_state, rank, comm_stream, none_grad,
141
 
142
  recv_total = sum(recv_counts)
143
  recv_buf = torch.empty(recv_total, dtype=COMM_DTYPE, device="cuda")
 
 
144
  dist.all_to_all_single(
145
  recv_buf,
146
  send_buf,
@@ -165,14 +176,14 @@ def _all2all_gather(params, param_to_state, rank, comm_stream, none_grad,
165
  comm_stream.wait_event(alloc_event)
166
 
167
  off = 0
168
- write_offsets = {id(p): 0 for p in owner_params}
169
  for src in range(num_ranks):
170
  if recv_counts[src] == 0:
171
  continue
172
 
173
  block = recv_counts[src]
174
  inner_off = 0
175
- for p in owner_params:
176
  state = param_to_state[id(p)]
177
  assert state.worker_rank == rank
178
  n = split_elems_for_src(p, state, src, num_ranks)
@@ -222,6 +233,10 @@ def _compute_u(p, state, steps, rank, compute_stream):
222
 
223
  @torch.no_grad()
224
  def _alloc_scattered_u(params, param_to_state, rank, compute_stream):
 
 
 
 
225
  with torch.cuda.stream(compute_stream):
226
  for p in params:
227
  state = param_to_state[id(p)]
@@ -234,18 +249,22 @@ def _alloc_scattered_u(params, param_to_state, rank, compute_stream):
234
 
235
 
236
  def _all2all_scatter(params, param_to_state, rank, comm_stream, alloc_event):
 
 
 
237
  with torch.cuda.stream(comm_stream):
238
  process_group = param_to_state[id(params[0])].process_group
239
  num_ranks = dist.get_world_size(group=process_group)
240
- owner_params = [
241
  p for p in params if param_to_state[id(p)].worker_rank == rank
242
  ]
243
 
 
244
  per_dst = [[] for _ in range(num_ranks)]
245
  send_counts = [0] * num_ranks
246
 
247
- if owner_params:
248
- for p in owner_params:
249
  state = param_to_state[id(p)]
250
  if state.compute_event is None:
251
  raise RuntimeError(
@@ -276,7 +295,9 @@ def _all2all_scatter(params, param_to_state, rank, comm_stream, alloc_event):
276
  # Even non-owner ranks must join the collective call
277
  send_buf = torch.empty(0, dtype=COMM_DTYPE, device="cuda")
278
 
 
279
  recv_counts = [0] * num_ranks
 
280
  for src in range(num_ranks):
281
  total = 0
282
  for p in params:
@@ -290,6 +311,7 @@ def _all2all_scatter(params, param_to_state, rank, comm_stream, alloc_event):
290
  assert recv_total > 0
291
  recv_buf = torch.empty(recv_total, dtype=COMM_DTYPE, device="cuda")
292
 
 
293
  dist.all_to_all_single(
294
  recv_buf,
295
  send_buf,
@@ -298,6 +320,21 @@ def _all2all_scatter(params, param_to_state, rank, comm_stream, alloc_event):
298
  group=process_group,
299
  )
300
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
301
  comm_stream.wait_event(alloc_event)
302
 
303
  off = 0
@@ -479,6 +516,11 @@ class Muon(torch.optim.Optimizer):
479
  "head_dim": 128,
480
  "threshold": 100
481
  }
 
 
 
 
 
482
  """
483
 
484
  def __init__(self,
@@ -497,7 +539,8 @@ class Muon(torch.optim.Optimizer):
497
  "k_indices": [],
498
  "head_dim": 128,
499
  "threshold": 100
500
- }):
 
501
  defaults = dict(
502
  lr=lr,
503
  weight_decay=weight_decay,
@@ -521,15 +564,13 @@ class Muon(torch.optim.Optimizer):
521
 
522
  super().__init__(params, defaults)
523
 
524
- if dist.is_initialized():
525
- self.rank = dist.get_rank()
526
- else:
527
- self.rank = None
528
 
529
  self.comm_stream = torch.cuda.Stream()
530
  self.compute_stream = torch.cuda.Stream()
531
  self.debug = debug
532
  self.clip_config = clip_config
 
533
 
534
  def _calc_flops(self, G, steps):
535
  assert len(G.shape) == 2
@@ -602,7 +643,11 @@ class Muon(torch.optim.Optimizer):
602
  if mesh is None:
603
  mesh = p.device_mesh
604
  shard_mesh, process_group = self.get_shard_mesh(p, self.rank)
605
- self.rank = dist.get_rank(group=process_group)
 
 
 
 
606
  elif mesh != p.device_mesh:
607
  raise ValueError("All parameters must be on the same mesh.")
608
 
@@ -743,6 +788,8 @@ class Muon(torch.optim.Optimizer):
743
  param_to_state, ordered_params = self.init_state_and_assign_params(
744
  names, params, group, qk_logits)
745
 
 
 
746
  def enqueue_all2all_gather(start_idx, chunk_size):
747
  target_params = ordered_params[start_idx:start_idx + chunk_size]
748
  if target_params:
@@ -781,16 +828,16 @@ class Muon(torch.optim.Optimizer):
781
  # Wait grad update
782
  self.comm_stream.wait_stream(torch.cuda.current_stream())
783
 
784
- PRE_STEP = 5
785
- for i in range(0, PRE_STEP):
786
  enqueue_all2all_gather(i * chunk_size, chunk_size)
787
  enqueue_computes(i * chunk_size, chunk_size)
788
 
789
  for i in range(0, len(params) + chunk_size - 1, chunk_size):
790
  enqueue_all2all_scatter(i, chunk_size)
791
- enqueue_all2all_gather(i + PRE_STEP * chunk_size, chunk_size)
792
  enqueue_update_param(i, chunk_size)
793
- enqueue_computes(i + PRE_STEP * chunk_size, chunk_size)
794
 
795
  # Wait the last update_param to finish
796
  torch.cuda.current_stream().wait_stream(self.compute_stream)
 
73
  qk_clip_state = None
74
 
75
 
76
+ def split_elems_for_src(param, src_rank, num_ranks) -> int:
77
  rows = param.shape[0]
78
  cols = int(param.numel() // rows)
79
  base, rem = divmod(rows, num_ranks)
 
83
 
84
  @torch.no_grad()
85
  def _alloc_gathered_grad(params, param_to_state, rank, compute_stream):
86
+ """
87
+ Pre-allocate gathered_grad buffer on compute_stream
88
+ before launching all2all gather
89
+ """
90
  with torch.cuda.stream(compute_stream):
91
  for p in params:
92
  state = param_to_state[id(p)]
 
106
  @torch.no_grad()
107
  def _all2all_gather(params, param_to_state, rank, comm_stream, none_grad,
108
  alloc_event):
109
+ """
110
+ All2all gathers shards so each owner rank reconstructs its full gradient
111
+ """
112
  with torch.cuda.stream(comm_stream):
113
  process_group = param_to_state[id(params[0])].process_group
114
  num_ranks = dist.get_world_size(group=process_group)
115
 
116
+ # Construct sending buffers
117
  per_dst = [[] for _ in range(num_ranks)]
118
  send_counts = [0] * num_ranks
119
+
120
  for p in params:
121
  state = param_to_state[id(p)]
122
  dst = state.worker_rank
 
133
  for v in per_dst), "all params should be sharded to all devices"
134
 
135
  send_buf = torch.cat([torch.cat(v, dim=0) for v in per_dst], dim=0)
136
+ owned_params = [
137
  p for p in params if param_to_state[id(p)].worker_rank == rank
138
  ]
139
 
140
+ # Compute receive sizes and allocate receiving buffers
141
  recv_counts = [0] * num_ranks
142
+
143
  for src in range(num_ranks):
144
  total = 0
145
+ for p in owned_params:
146
  state = param_to_state[id(p)]
147
  assert state.worker_rank == rank
148
  total += split_elems_for_src(p, state, src, num_ranks)
 
150
 
151
  recv_total = sum(recv_counts)
152
  recv_buf = torch.empty(recv_total, dtype=COMM_DTYPE, device="cuda")
153
+
154
+ #All2All
155
  dist.all_to_all_single(
156
  recv_buf,
157
  send_buf,
 
176
  comm_stream.wait_event(alloc_event)
177
 
178
  off = 0
179
+ write_offsets = {id(p): 0 for p in owned_params}
180
  for src in range(num_ranks):
181
  if recv_counts[src] == 0:
182
  continue
183
 
184
  block = recv_counts[src]
185
  inner_off = 0
186
+ for p in owned_params:
187
  state = param_to_state[id(p)]
188
  assert state.worker_rank == rank
189
  n = split_elems_for_src(p, state, src, num_ranks)
 
233
 
234
  @torch.no_grad()
235
  def _alloc_scattered_u(params, param_to_state, rank, compute_stream):
236
+ """
237
+ Pre-allocate scattered_u buffer on compute_stream
238
+ before launching all2all gather
239
+ """
240
  with torch.cuda.stream(compute_stream):
241
  for p in params:
242
  state = param_to_state[id(p)]
 
249
 
250
 
251
  def _all2all_scatter(params, param_to_state, rank, comm_stream, alloc_event):
252
+ """
253
+ All2all scatters full gradients to all ranks
254
+ """
255
  with torch.cuda.stream(comm_stream):
256
  process_group = param_to_state[id(params[0])].process_group
257
  num_ranks = dist.get_world_size(group=process_group)
258
+ owned_params = [
259
  p for p in params if param_to_state[id(p)].worker_rank == rank
260
  ]
261
 
262
+ # Construct sending buffer
263
  per_dst = [[] for _ in range(num_ranks)]
264
  send_counts = [0] * num_ranks
265
 
266
+ if owned_params:
267
+ for p in owned_params:
268
  state = param_to_state[id(p)]
269
  if state.compute_event is None:
270
  raise RuntimeError(
 
295
  # Even non-owner ranks must join the collective call
296
  send_buf = torch.empty(0, dtype=COMM_DTYPE, device="cuda")
297
 
298
+ # Compute receive sizes and allocate receiving buffers
299
  recv_counts = [0] * num_ranks
300
+
301
  for src in range(num_ranks):
302
  total = 0
303
  for p in params:
 
311
  assert recv_total > 0
312
  recv_buf = torch.empty(recv_total, dtype=COMM_DTYPE, device="cuda")
313
 
314
+ #All2All
315
  dist.all_to_all_single(
316
  recv_buf,
317
  send_buf,
 
320
  group=process_group,
321
  )
322
 
323
+ # Copy to pre-allocated scattered_u buffer from the received buffer
324
+ #
325
+ # recv_buf (num ranks = 3, local_rank = 0)
326
+ #
327
+ # From rank 0 From rank 1 From rank 2
328
+ # | p1_0, p2_0, p3_0 | p4_0 | p5_0, p6_0 |
329
+ #
330
+ # Outer loop:
331
+ # rank 0 -> rank 1 -> rank2
332
+ #
333
+ # Inner loop:
334
+ # src(0) : p1_0 -> p2_0 -> p3_0
335
+ # src(1) : p4_0
336
+ # src(2) : p5_0 -> p6_0
337
+
338
  comm_stream.wait_event(alloc_event)
339
 
340
  off = 0
 
516
  "head_dim": 128,
517
  "threshold": 100
518
  }
519
+ overlap_step : How many all2all gather, compute operations are launched in advance
520
+ before the corresponding all2all scatter steps begin.
521
+ A higher overlap_step increases memory usage but can improve
522
+ performance by overlapping communication.
523
+ Parallel muon only.
524
  """
525
 
526
  def __init__(self,
 
539
  "k_indices": [],
540
  "head_dim": 128,
541
  "threshold": 100
542
+ },
543
+ overlap_step=5):
544
  defaults = dict(
545
  lr=lr,
546
  weight_decay=weight_decay,
 
564
 
565
  super().__init__(params, defaults)
566
 
567
+ self.rank = None
 
 
 
568
 
569
  self.comm_stream = torch.cuda.Stream()
570
  self.compute_stream = torch.cuda.Stream()
571
  self.debug = debug
572
  self.clip_config = clip_config
573
+ self.overlap_step = overlap_step
574
 
575
  def _calc_flops(self, G, steps):
576
  assert len(G.shape) == 2
 
643
  if mesh is None:
644
  mesh = p.device_mesh
645
  shard_mesh, process_group = self.get_shard_mesh(p, self.rank)
646
+ local_rank = dist.get_rank(group=process_group)
647
+ if self.rank is None:
648
+ self.rank = dist.get_rank(group=process_group)
649
+ else:
650
+ assert self.rank == local_rank
651
  elif mesh != p.device_mesh:
652
  raise ValueError("All parameters must be on the same mesh.")
653
 
 
788
  param_to_state, ordered_params = self.init_state_and_assign_params(
789
  names, params, group, qk_logits)
790
 
791
+ assert self.rank is not None
792
+
793
  def enqueue_all2all_gather(start_idx, chunk_size):
794
  target_params = ordered_params[start_idx:start_idx + chunk_size]
795
  if target_params:
 
828
  # Wait grad update
829
  self.comm_stream.wait_stream(torch.cuda.current_stream())
830
 
831
+ overlap_step = self.overlap_step
832
+ for i in range(0, overlap_step):
833
  enqueue_all2all_gather(i * chunk_size, chunk_size)
834
  enqueue_computes(i * chunk_size, chunk_size)
835
 
836
  for i in range(0, len(params) + chunk_size - 1, chunk_size):
837
  enqueue_all2all_scatter(i, chunk_size)
838
+ enqueue_all2all_gather(i + overlap_step * chunk_size, chunk_size)
839
  enqueue_update_param(i, chunk_size)
840
+ enqueue_computes(i + overlap_step * chunk_size, chunk_size)
841
 
842
  # Wait the last update_param to finish
843
  torch.cuda.current_stream().wait_stream(self.compute_stream)
build/torch27-cxx11-cu126-x86_64-linux/optimizer/_ops.py CHANGED
@@ -1,9 +1,9 @@
1
  import torch
2
- from . import _optimizer_37be0d0_dirty
3
- ops = torch.ops._optimizer_37be0d0_dirty
4
 
5
  def add_op_namespace_prefix(op_name: str):
6
  """
7
  Prefix op by namespace.
8
  """
9
- return f"_optimizer_37be0d0_dirty::{op_name}"
 
1
  import torch
2
+ from . import _optimizer_6943c45_dirty
3
+ ops = torch.ops._optimizer_6943c45_dirty
4
 
5
  def add_op_namespace_prefix(op_name: str):
6
  """
7
  Prefix op by namespace.
8
  """
9
+ return f"_optimizer_6943c45_dirty::{op_name}"
build/{torch28-cxx11-cu126-x86_64-linux/optimizer/_optimizer_37be0d0_dirty.abi3.so → torch27-cxx11-cu126-x86_64-linux/optimizer/_optimizer_6943c45_dirty.abi3.so} RENAMED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:10fdf4bbdc0ceb7b6c1504145ea53f837ac237422c43e3b74b12aec789c49dac
3
  size 1824256
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:10905a024d5fa31fe31b8370747790b2f0ce60d06881831efb7cc07e1c5e5436
3
  size 1824256
build/torch27-cxx11-cu126-x86_64-linux/optimizer/muon.py CHANGED
@@ -73,7 +73,7 @@ class _muon_state:
73
  qk_clip_state = None
74
 
75
 
76
- def split_elems_for_src(param, state, src_rank, num_ranks) -> int:
77
  rows = param.shape[0]
78
  cols = int(param.numel() // rows)
79
  base, rem = divmod(rows, num_ranks)
@@ -83,6 +83,10 @@ def split_elems_for_src(param, state, src_rank, num_ranks) -> int:
83
 
84
  @torch.no_grad()
85
  def _alloc_gathered_grad(params, param_to_state, rank, compute_stream):
 
 
 
 
86
  with torch.cuda.stream(compute_stream):
87
  for p in params:
88
  state = param_to_state[id(p)]
@@ -102,13 +106,17 @@ def _alloc_gathered_grad(params, param_to_state, rank, compute_stream):
102
  @torch.no_grad()
103
  def _all2all_gather(params, param_to_state, rank, comm_stream, none_grad,
104
  alloc_event):
 
 
 
105
  with torch.cuda.stream(comm_stream):
106
  process_group = param_to_state[id(params[0])].process_group
107
  num_ranks = dist.get_world_size(group=process_group)
108
 
109
- # Calculate sending tensors
110
  per_dst = [[] for _ in range(num_ranks)]
111
  send_counts = [0] * num_ranks
 
112
  for p in params:
113
  state = param_to_state[id(p)]
114
  dst = state.worker_rank
@@ -125,15 +133,16 @@ def _all2all_gather(params, param_to_state, rank, comm_stream, none_grad,
125
  for v in per_dst), "all params should be sharded to all devices"
126
 
127
  send_buf = torch.cat([torch.cat(v, dim=0) for v in per_dst], dim=0)
128
- owner_params = [
129
  p for p in params if param_to_state[id(p)].worker_rank == rank
130
  ]
131
 
132
- # Calculate receiving tensors
133
  recv_counts = [0] * num_ranks
 
134
  for src in range(num_ranks):
135
  total = 0
136
- for p in owner_params:
137
  state = param_to_state[id(p)]
138
  assert state.worker_rank == rank
139
  total += split_elems_for_src(p, state, src, num_ranks)
@@ -141,6 +150,8 @@ def _all2all_gather(params, param_to_state, rank, comm_stream, none_grad,
141
 
142
  recv_total = sum(recv_counts)
143
  recv_buf = torch.empty(recv_total, dtype=COMM_DTYPE, device="cuda")
 
 
144
  dist.all_to_all_single(
145
  recv_buf,
146
  send_buf,
@@ -165,14 +176,14 @@ def _all2all_gather(params, param_to_state, rank, comm_stream, none_grad,
165
  comm_stream.wait_event(alloc_event)
166
 
167
  off = 0
168
- write_offsets = {id(p): 0 for p in owner_params}
169
  for src in range(num_ranks):
170
  if recv_counts[src] == 0:
171
  continue
172
 
173
  block = recv_counts[src]
174
  inner_off = 0
175
- for p in owner_params:
176
  state = param_to_state[id(p)]
177
  assert state.worker_rank == rank
178
  n = split_elems_for_src(p, state, src, num_ranks)
@@ -222,6 +233,10 @@ def _compute_u(p, state, steps, rank, compute_stream):
222
 
223
  @torch.no_grad()
224
  def _alloc_scattered_u(params, param_to_state, rank, compute_stream):
 
 
 
 
225
  with torch.cuda.stream(compute_stream):
226
  for p in params:
227
  state = param_to_state[id(p)]
@@ -234,18 +249,22 @@ def _alloc_scattered_u(params, param_to_state, rank, compute_stream):
234
 
235
 
236
  def _all2all_scatter(params, param_to_state, rank, comm_stream, alloc_event):
 
 
 
237
  with torch.cuda.stream(comm_stream):
238
  process_group = param_to_state[id(params[0])].process_group
239
  num_ranks = dist.get_world_size(group=process_group)
240
- owner_params = [
241
  p for p in params if param_to_state[id(p)].worker_rank == rank
242
  ]
243
 
 
244
  per_dst = [[] for _ in range(num_ranks)]
245
  send_counts = [0] * num_ranks
246
 
247
- if owner_params:
248
- for p in owner_params:
249
  state = param_to_state[id(p)]
250
  if state.compute_event is None:
251
  raise RuntimeError(
@@ -276,7 +295,9 @@ def _all2all_scatter(params, param_to_state, rank, comm_stream, alloc_event):
276
  # Even non-owner ranks must join the collective call
277
  send_buf = torch.empty(0, dtype=COMM_DTYPE, device="cuda")
278
 
 
279
  recv_counts = [0] * num_ranks
 
280
  for src in range(num_ranks):
281
  total = 0
282
  for p in params:
@@ -290,6 +311,7 @@ def _all2all_scatter(params, param_to_state, rank, comm_stream, alloc_event):
290
  assert recv_total > 0
291
  recv_buf = torch.empty(recv_total, dtype=COMM_DTYPE, device="cuda")
292
 
 
293
  dist.all_to_all_single(
294
  recv_buf,
295
  send_buf,
@@ -298,6 +320,21 @@ def _all2all_scatter(params, param_to_state, rank, comm_stream, alloc_event):
298
  group=process_group,
299
  )
300
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
301
  comm_stream.wait_event(alloc_event)
302
 
303
  off = 0
@@ -479,6 +516,11 @@ class Muon(torch.optim.Optimizer):
479
  "head_dim": 128,
480
  "threshold": 100
481
  }
 
 
 
 
 
482
  """
483
 
484
  def __init__(self,
@@ -497,7 +539,8 @@ class Muon(torch.optim.Optimizer):
497
  "k_indices": [],
498
  "head_dim": 128,
499
  "threshold": 100
500
- }):
 
501
  defaults = dict(
502
  lr=lr,
503
  weight_decay=weight_decay,
@@ -521,15 +564,13 @@ class Muon(torch.optim.Optimizer):
521
 
522
  super().__init__(params, defaults)
523
 
524
- if dist.is_initialized():
525
- self.rank = dist.get_rank()
526
- else:
527
- self.rank = None
528
 
529
  self.comm_stream = torch.cuda.Stream()
530
  self.compute_stream = torch.cuda.Stream()
531
  self.debug = debug
532
  self.clip_config = clip_config
 
533
 
534
  def _calc_flops(self, G, steps):
535
  assert len(G.shape) == 2
@@ -602,7 +643,11 @@ class Muon(torch.optim.Optimizer):
602
  if mesh is None:
603
  mesh = p.device_mesh
604
  shard_mesh, process_group = self.get_shard_mesh(p, self.rank)
605
- self.rank = dist.get_rank(group=process_group)
 
 
 
 
606
  elif mesh != p.device_mesh:
607
  raise ValueError("All parameters must be on the same mesh.")
608
 
@@ -743,6 +788,8 @@ class Muon(torch.optim.Optimizer):
743
  param_to_state, ordered_params = self.init_state_and_assign_params(
744
  names, params, group, qk_logits)
745
 
 
 
746
  def enqueue_all2all_gather(start_idx, chunk_size):
747
  target_params = ordered_params[start_idx:start_idx + chunk_size]
748
  if target_params:
@@ -781,16 +828,16 @@ class Muon(torch.optim.Optimizer):
781
  # Wait grad update
782
  self.comm_stream.wait_stream(torch.cuda.current_stream())
783
 
784
- PRE_STEP = 5
785
- for i in range(0, PRE_STEP):
786
  enqueue_all2all_gather(i * chunk_size, chunk_size)
787
  enqueue_computes(i * chunk_size, chunk_size)
788
 
789
  for i in range(0, len(params) + chunk_size - 1, chunk_size):
790
  enqueue_all2all_scatter(i, chunk_size)
791
- enqueue_all2all_gather(i + PRE_STEP * chunk_size, chunk_size)
792
  enqueue_update_param(i, chunk_size)
793
- enqueue_computes(i + PRE_STEP * chunk_size, chunk_size)
794
 
795
  # Wait the last update_param to finish
796
  torch.cuda.current_stream().wait_stream(self.compute_stream)
 
73
  qk_clip_state = None
74
 
75
 
76
+ def split_elems_for_src(param, src_rank, num_ranks) -> int:
77
  rows = param.shape[0]
78
  cols = int(param.numel() // rows)
79
  base, rem = divmod(rows, num_ranks)
 
83
 
84
  @torch.no_grad()
85
  def _alloc_gathered_grad(params, param_to_state, rank, compute_stream):
86
+ """
87
+ Pre-allocate gathered_grad buffer on compute_stream
88
+ before launching all2all gather
89
+ """
90
  with torch.cuda.stream(compute_stream):
91
  for p in params:
92
  state = param_to_state[id(p)]
 
106
  @torch.no_grad()
107
  def _all2all_gather(params, param_to_state, rank, comm_stream, none_grad,
108
  alloc_event):
109
+ """
110
+ All2all gathers shards so each owner rank reconstructs its full gradient
111
+ """
112
  with torch.cuda.stream(comm_stream):
113
  process_group = param_to_state[id(params[0])].process_group
114
  num_ranks = dist.get_world_size(group=process_group)
115
 
116
+ # Construct sending buffers
117
  per_dst = [[] for _ in range(num_ranks)]
118
  send_counts = [0] * num_ranks
119
+
120
  for p in params:
121
  state = param_to_state[id(p)]
122
  dst = state.worker_rank
 
133
  for v in per_dst), "all params should be sharded to all devices"
134
 
135
  send_buf = torch.cat([torch.cat(v, dim=0) for v in per_dst], dim=0)
136
+ owned_params = [
137
  p for p in params if param_to_state[id(p)].worker_rank == rank
138
  ]
139
 
140
+ # Compute receive sizes and allocate receiving buffers
141
  recv_counts = [0] * num_ranks
142
+
143
  for src in range(num_ranks):
144
  total = 0
145
+ for p in owned_params:
146
  state = param_to_state[id(p)]
147
  assert state.worker_rank == rank
148
  total += split_elems_for_src(p, state, src, num_ranks)
 
150
 
151
  recv_total = sum(recv_counts)
152
  recv_buf = torch.empty(recv_total, dtype=COMM_DTYPE, device="cuda")
153
+
154
+ #All2All
155
  dist.all_to_all_single(
156
  recv_buf,
157
  send_buf,
 
176
  comm_stream.wait_event(alloc_event)
177
 
178
  off = 0
179
+ write_offsets = {id(p): 0 for p in owned_params}
180
  for src in range(num_ranks):
181
  if recv_counts[src] == 0:
182
  continue
183
 
184
  block = recv_counts[src]
185
  inner_off = 0
186
+ for p in owned_params:
187
  state = param_to_state[id(p)]
188
  assert state.worker_rank == rank
189
  n = split_elems_for_src(p, state, src, num_ranks)
 
233
 
234
  @torch.no_grad()
235
  def _alloc_scattered_u(params, param_to_state, rank, compute_stream):
236
+ """
237
+ Pre-allocate scattered_u buffer on compute_stream
238
+ before launching all2all gather
239
+ """
240
  with torch.cuda.stream(compute_stream):
241
  for p in params:
242
  state = param_to_state[id(p)]
 
249
 
250
 
251
  def _all2all_scatter(params, param_to_state, rank, comm_stream, alloc_event):
252
+ """
253
+ All2all scatters full gradients to all ranks
254
+ """
255
  with torch.cuda.stream(comm_stream):
256
  process_group = param_to_state[id(params[0])].process_group
257
  num_ranks = dist.get_world_size(group=process_group)
258
+ owned_params = [
259
  p for p in params if param_to_state[id(p)].worker_rank == rank
260
  ]
261
 
262
+ # Construct sending buffer
263
  per_dst = [[] for _ in range(num_ranks)]
264
  send_counts = [0] * num_ranks
265
 
266
+ if owned_params:
267
+ for p in owned_params:
268
  state = param_to_state[id(p)]
269
  if state.compute_event is None:
270
  raise RuntimeError(
 
295
  # Even non-owner ranks must join the collective call
296
  send_buf = torch.empty(0, dtype=COMM_DTYPE, device="cuda")
297
 
298
+ # Compute receive sizes and allocate receiving buffers
299
  recv_counts = [0] * num_ranks
300
+
301
  for src in range(num_ranks):
302
  total = 0
303
  for p in params:
 
311
  assert recv_total > 0
312
  recv_buf = torch.empty(recv_total, dtype=COMM_DTYPE, device="cuda")
313
 
314
+ #All2All
315
  dist.all_to_all_single(
316
  recv_buf,
317
  send_buf,
 
320
  group=process_group,
321
  )
322
 
323
+ # Copy to pre-allocated scattered_u buffer from the received buffer
324
+ #
325
+ # recv_buf (num ranks = 3, local_rank = 0)
326
+ #
327
+ # From rank 0 From rank 1 From rank 2
328
+ # | p1_0, p2_0, p3_0 | p4_0 | p5_0, p6_0 |
329
+ #
330
+ # Outer loop:
331
+ # rank 0 -> rank 1 -> rank2
332
+ #
333
+ # Inner loop:
334
+ # src(0) : p1_0 -> p2_0 -> p3_0
335
+ # src(1) : p4_0
336
+ # src(2) : p5_0 -> p6_0
337
+
338
  comm_stream.wait_event(alloc_event)
339
 
340
  off = 0
 
516
  "head_dim": 128,
517
  "threshold": 100
518
  }
519
+ overlap_step : How many all2all gather, compute operations are launched in advance
520
+ before the corresponding all2all scatter steps begin.
521
+ A higher overlap_step increases memory usage but can improve
522
+ performance by overlapping communication.
523
+ Parallel muon only.
524
  """
525
 
526
  def __init__(self,
 
539
  "k_indices": [],
540
  "head_dim": 128,
541
  "threshold": 100
542
+ },
543
+ overlap_step=5):
544
  defaults = dict(
545
  lr=lr,
546
  weight_decay=weight_decay,
 
564
 
565
  super().__init__(params, defaults)
566
 
567
+ self.rank = None
 
 
 
568
 
569
  self.comm_stream = torch.cuda.Stream()
570
  self.compute_stream = torch.cuda.Stream()
571
  self.debug = debug
572
  self.clip_config = clip_config
573
+ self.overlap_step = overlap_step
574
 
575
  def _calc_flops(self, G, steps):
576
  assert len(G.shape) == 2
 
643
  if mesh is None:
644
  mesh = p.device_mesh
645
  shard_mesh, process_group = self.get_shard_mesh(p, self.rank)
646
+ local_rank = dist.get_rank(group=process_group)
647
+ if self.rank is None:
648
+ self.rank = dist.get_rank(group=process_group)
649
+ else:
650
+ assert self.rank == local_rank
651
  elif mesh != p.device_mesh:
652
  raise ValueError("All parameters must be on the same mesh.")
653
 
 
788
  param_to_state, ordered_params = self.init_state_and_assign_params(
789
  names, params, group, qk_logits)
790
 
791
+ assert self.rank is not None
792
+
793
  def enqueue_all2all_gather(start_idx, chunk_size):
794
  target_params = ordered_params[start_idx:start_idx + chunk_size]
795
  if target_params:
 
828
  # Wait grad update
829
  self.comm_stream.wait_stream(torch.cuda.current_stream())
830
 
831
+ overlap_step = self.overlap_step
832
+ for i in range(0, overlap_step):
833
  enqueue_all2all_gather(i * chunk_size, chunk_size)
834
  enqueue_computes(i * chunk_size, chunk_size)
835
 
836
  for i in range(0, len(params) + chunk_size - 1, chunk_size):
837
  enqueue_all2all_scatter(i, chunk_size)
838
+ enqueue_all2all_gather(i + overlap_step * chunk_size, chunk_size)
839
  enqueue_update_param(i, chunk_size)
840
+ enqueue_computes(i + overlap_step * chunk_size, chunk_size)
841
 
842
  # Wait the last update_param to finish
843
  torch.cuda.current_stream().wait_stream(self.compute_stream)
build/torch27-cxx11-cu128-x86_64-linux/optimizer/_ops.py CHANGED
@@ -1,9 +1,9 @@
1
  import torch
2
- from . import _optimizer_37be0d0_dirty
3
- ops = torch.ops._optimizer_37be0d0_dirty
4
 
5
  def add_op_namespace_prefix(op_name: str):
6
  """
7
  Prefix op by namespace.
8
  """
9
- return f"_optimizer_37be0d0_dirty::{op_name}"
 
1
  import torch
2
+ from . import _optimizer_6943c45_dirty
3
+ ops = torch.ops._optimizer_6943c45_dirty
4
 
5
  def add_op_namespace_prefix(op_name: str):
6
  """
7
  Prefix op by namespace.
8
  """
9
+ return f"_optimizer_6943c45_dirty::{op_name}"
build/{torch28-cxx11-cu128-x86_64-linux/optimizer/_optimizer_37be0d0_dirty.abi3.so → torch27-cxx11-cu128-x86_64-linux/optimizer/_optimizer_6943c45_dirty.abi3.so} RENAMED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:af40fc0276d4e4c0e3e0908a6574ccbd06233f5ef2618160daaffd19a068ab3b
3
  size 1883344
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:058aa5ff9f1e974cb5b52e4a7af074cef2092c457b5498356fc0fbdd86adf5f3
3
  size 1883344
build/torch27-cxx11-cu128-x86_64-linux/optimizer/muon.py CHANGED
@@ -73,7 +73,7 @@ class _muon_state:
73
  qk_clip_state = None
74
 
75
 
76
- def split_elems_for_src(param, state, src_rank, num_ranks) -> int:
77
  rows = param.shape[0]
78
  cols = int(param.numel() // rows)
79
  base, rem = divmod(rows, num_ranks)
@@ -83,6 +83,10 @@ def split_elems_for_src(param, state, src_rank, num_ranks) -> int:
83
 
84
  @torch.no_grad()
85
  def _alloc_gathered_grad(params, param_to_state, rank, compute_stream):
 
 
 
 
86
  with torch.cuda.stream(compute_stream):
87
  for p in params:
88
  state = param_to_state[id(p)]
@@ -102,13 +106,17 @@ def _alloc_gathered_grad(params, param_to_state, rank, compute_stream):
102
  @torch.no_grad()
103
  def _all2all_gather(params, param_to_state, rank, comm_stream, none_grad,
104
  alloc_event):
 
 
 
105
  with torch.cuda.stream(comm_stream):
106
  process_group = param_to_state[id(params[0])].process_group
107
  num_ranks = dist.get_world_size(group=process_group)
108
 
109
- # Calculate sending tensors
110
  per_dst = [[] for _ in range(num_ranks)]
111
  send_counts = [0] * num_ranks
 
112
  for p in params:
113
  state = param_to_state[id(p)]
114
  dst = state.worker_rank
@@ -125,15 +133,16 @@ def _all2all_gather(params, param_to_state, rank, comm_stream, none_grad,
125
  for v in per_dst), "all params should be sharded to all devices"
126
 
127
  send_buf = torch.cat([torch.cat(v, dim=0) for v in per_dst], dim=0)
128
- owner_params = [
129
  p for p in params if param_to_state[id(p)].worker_rank == rank
130
  ]
131
 
132
- # Calculate receiving tensors
133
  recv_counts = [0] * num_ranks
 
134
  for src in range(num_ranks):
135
  total = 0
136
- for p in owner_params:
137
  state = param_to_state[id(p)]
138
  assert state.worker_rank == rank
139
  total += split_elems_for_src(p, state, src, num_ranks)
@@ -141,6 +150,8 @@ def _all2all_gather(params, param_to_state, rank, comm_stream, none_grad,
141
 
142
  recv_total = sum(recv_counts)
143
  recv_buf = torch.empty(recv_total, dtype=COMM_DTYPE, device="cuda")
 
 
144
  dist.all_to_all_single(
145
  recv_buf,
146
  send_buf,
@@ -165,14 +176,14 @@ def _all2all_gather(params, param_to_state, rank, comm_stream, none_grad,
165
  comm_stream.wait_event(alloc_event)
166
 
167
  off = 0
168
- write_offsets = {id(p): 0 for p in owner_params}
169
  for src in range(num_ranks):
170
  if recv_counts[src] == 0:
171
  continue
172
 
173
  block = recv_counts[src]
174
  inner_off = 0
175
- for p in owner_params:
176
  state = param_to_state[id(p)]
177
  assert state.worker_rank == rank
178
  n = split_elems_for_src(p, state, src, num_ranks)
@@ -222,6 +233,10 @@ def _compute_u(p, state, steps, rank, compute_stream):
222
 
223
  @torch.no_grad()
224
  def _alloc_scattered_u(params, param_to_state, rank, compute_stream):
 
 
 
 
225
  with torch.cuda.stream(compute_stream):
226
  for p in params:
227
  state = param_to_state[id(p)]
@@ -234,18 +249,22 @@ def _alloc_scattered_u(params, param_to_state, rank, compute_stream):
234
 
235
 
236
  def _all2all_scatter(params, param_to_state, rank, comm_stream, alloc_event):
 
 
 
237
  with torch.cuda.stream(comm_stream):
238
  process_group = param_to_state[id(params[0])].process_group
239
  num_ranks = dist.get_world_size(group=process_group)
240
- owner_params = [
241
  p for p in params if param_to_state[id(p)].worker_rank == rank
242
  ]
243
 
 
244
  per_dst = [[] for _ in range(num_ranks)]
245
  send_counts = [0] * num_ranks
246
 
247
- if owner_params:
248
- for p in owner_params:
249
  state = param_to_state[id(p)]
250
  if state.compute_event is None:
251
  raise RuntimeError(
@@ -276,7 +295,9 @@ def _all2all_scatter(params, param_to_state, rank, comm_stream, alloc_event):
276
  # Even non-owner ranks must join the collective call
277
  send_buf = torch.empty(0, dtype=COMM_DTYPE, device="cuda")
278
 
 
279
  recv_counts = [0] * num_ranks
 
280
  for src in range(num_ranks):
281
  total = 0
282
  for p in params:
@@ -290,6 +311,7 @@ def _all2all_scatter(params, param_to_state, rank, comm_stream, alloc_event):
290
  assert recv_total > 0
291
  recv_buf = torch.empty(recv_total, dtype=COMM_DTYPE, device="cuda")
292
 
 
293
  dist.all_to_all_single(
294
  recv_buf,
295
  send_buf,
@@ -298,6 +320,21 @@ def _all2all_scatter(params, param_to_state, rank, comm_stream, alloc_event):
298
  group=process_group,
299
  )
300
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
301
  comm_stream.wait_event(alloc_event)
302
 
303
  off = 0
@@ -479,6 +516,11 @@ class Muon(torch.optim.Optimizer):
479
  "head_dim": 128,
480
  "threshold": 100
481
  }
 
 
 
 
 
482
  """
483
 
484
  def __init__(self,
@@ -497,7 +539,8 @@ class Muon(torch.optim.Optimizer):
497
  "k_indices": [],
498
  "head_dim": 128,
499
  "threshold": 100
500
- }):
 
501
  defaults = dict(
502
  lr=lr,
503
  weight_decay=weight_decay,
@@ -521,15 +564,13 @@ class Muon(torch.optim.Optimizer):
521
 
522
  super().__init__(params, defaults)
523
 
524
- if dist.is_initialized():
525
- self.rank = dist.get_rank()
526
- else:
527
- self.rank = None
528
 
529
  self.comm_stream = torch.cuda.Stream()
530
  self.compute_stream = torch.cuda.Stream()
531
  self.debug = debug
532
  self.clip_config = clip_config
 
533
 
534
  def _calc_flops(self, G, steps):
535
  assert len(G.shape) == 2
@@ -602,7 +643,11 @@ class Muon(torch.optim.Optimizer):
602
  if mesh is None:
603
  mesh = p.device_mesh
604
  shard_mesh, process_group = self.get_shard_mesh(p, self.rank)
605
- self.rank = dist.get_rank(group=process_group)
 
 
 
 
606
  elif mesh != p.device_mesh:
607
  raise ValueError("All parameters must be on the same mesh.")
608
 
@@ -743,6 +788,8 @@ class Muon(torch.optim.Optimizer):
743
  param_to_state, ordered_params = self.init_state_and_assign_params(
744
  names, params, group, qk_logits)
745
 
 
 
746
  def enqueue_all2all_gather(start_idx, chunk_size):
747
  target_params = ordered_params[start_idx:start_idx + chunk_size]
748
  if target_params:
@@ -781,16 +828,16 @@ class Muon(torch.optim.Optimizer):
781
  # Wait grad update
782
  self.comm_stream.wait_stream(torch.cuda.current_stream())
783
 
784
- PRE_STEP = 5
785
- for i in range(0, PRE_STEP):
786
  enqueue_all2all_gather(i * chunk_size, chunk_size)
787
  enqueue_computes(i * chunk_size, chunk_size)
788
 
789
  for i in range(0, len(params) + chunk_size - 1, chunk_size):
790
  enqueue_all2all_scatter(i, chunk_size)
791
- enqueue_all2all_gather(i + PRE_STEP * chunk_size, chunk_size)
792
  enqueue_update_param(i, chunk_size)
793
- enqueue_computes(i + PRE_STEP * chunk_size, chunk_size)
794
 
795
  # Wait the last update_param to finish
796
  torch.cuda.current_stream().wait_stream(self.compute_stream)
 
73
  qk_clip_state = None
74
 
75
 
76
+ def split_elems_for_src(param, src_rank, num_ranks) -> int:
77
  rows = param.shape[0]
78
  cols = int(param.numel() // rows)
79
  base, rem = divmod(rows, num_ranks)
 
83
 
84
  @torch.no_grad()
85
  def _alloc_gathered_grad(params, param_to_state, rank, compute_stream):
86
+ """
87
+ Pre-allocate gathered_grad buffer on compute_stream
88
+ before launching all2all gather
89
+ """
90
  with torch.cuda.stream(compute_stream):
91
  for p in params:
92
  state = param_to_state[id(p)]
 
106
  @torch.no_grad()
107
  def _all2all_gather(params, param_to_state, rank, comm_stream, none_grad,
108
  alloc_event):
109
+ """
110
+ All2all gathers shards so each owner rank reconstructs its full gradient
111
+ """
112
  with torch.cuda.stream(comm_stream):
113
  process_group = param_to_state[id(params[0])].process_group
114
  num_ranks = dist.get_world_size(group=process_group)
115
 
116
+ # Construct sending buffers
117
  per_dst = [[] for _ in range(num_ranks)]
118
  send_counts = [0] * num_ranks
119
+
120
  for p in params:
121
  state = param_to_state[id(p)]
122
  dst = state.worker_rank
 
133
  for v in per_dst), "all params should be sharded to all devices"
134
 
135
  send_buf = torch.cat([torch.cat(v, dim=0) for v in per_dst], dim=0)
136
+ owned_params = [
137
  p for p in params if param_to_state[id(p)].worker_rank == rank
138
  ]
139
 
140
+ # Compute receive sizes and allocate receiving buffers
141
  recv_counts = [0] * num_ranks
142
+
143
  for src in range(num_ranks):
144
  total = 0
145
+ for p in owned_params:
146
  state = param_to_state[id(p)]
147
  assert state.worker_rank == rank
148
  total += split_elems_for_src(p, state, src, num_ranks)
 
150
 
151
  recv_total = sum(recv_counts)
152
  recv_buf = torch.empty(recv_total, dtype=COMM_DTYPE, device="cuda")
153
+
154
+ #All2All
155
  dist.all_to_all_single(
156
  recv_buf,
157
  send_buf,
 
176
  comm_stream.wait_event(alloc_event)
177
 
178
  off = 0
179
+ write_offsets = {id(p): 0 for p in owned_params}
180
  for src in range(num_ranks):
181
  if recv_counts[src] == 0:
182
  continue
183
 
184
  block = recv_counts[src]
185
  inner_off = 0
186
+ for p in owned_params:
187
  state = param_to_state[id(p)]
188
  assert state.worker_rank == rank
189
  n = split_elems_for_src(p, state, src, num_ranks)
 
233
 
234
  @torch.no_grad()
235
  def _alloc_scattered_u(params, param_to_state, rank, compute_stream):
236
+ """
237
+ Pre-allocate scattered_u buffer on compute_stream
238
+ before launching all2all gather
239
+ """
240
  with torch.cuda.stream(compute_stream):
241
  for p in params:
242
  state = param_to_state[id(p)]
 
249
 
250
 
251
  def _all2all_scatter(params, param_to_state, rank, comm_stream, alloc_event):
252
+ """
253
+ All2all scatters full gradients to all ranks
254
+ """
255
  with torch.cuda.stream(comm_stream):
256
  process_group = param_to_state[id(params[0])].process_group
257
  num_ranks = dist.get_world_size(group=process_group)
258
+ owned_params = [
259
  p for p in params if param_to_state[id(p)].worker_rank == rank
260
  ]
261
 
262
+ # Construct sending buffer
263
  per_dst = [[] for _ in range(num_ranks)]
264
  send_counts = [0] * num_ranks
265
 
266
+ if owned_params:
267
+ for p in owned_params:
268
  state = param_to_state[id(p)]
269
  if state.compute_event is None:
270
  raise RuntimeError(
 
295
  # Even non-owner ranks must join the collective call
296
  send_buf = torch.empty(0, dtype=COMM_DTYPE, device="cuda")
297
 
298
+ # Compute receive sizes and allocate receiving buffers
299
  recv_counts = [0] * num_ranks
300
+
301
  for src in range(num_ranks):
302
  total = 0
303
  for p in params:
 
311
  assert recv_total > 0
312
  recv_buf = torch.empty(recv_total, dtype=COMM_DTYPE, device="cuda")
313
 
314
+ #All2All
315
  dist.all_to_all_single(
316
  recv_buf,
317
  send_buf,
 
320
  group=process_group,
321
  )
322
 
323
+ # Copy to pre-allocated scattered_u buffer from the received buffer
324
+ #
325
+ # recv_buf (num ranks = 3, local_rank = 0)
326
+ #
327
+ # From rank 0 From rank 1 From rank 2
328
+ # | p1_0, p2_0, p3_0 | p4_0 | p5_0, p6_0 |
329
+ #
330
+ # Outer loop:
331
+ # rank 0 -> rank 1 -> rank2
332
+ #
333
+ # Inner loop:
334
+ # src(0) : p1_0 -> p2_0 -> p3_0
335
+ # src(1) : p4_0
336
+ # src(2) : p5_0 -> p6_0
337
+
338
  comm_stream.wait_event(alloc_event)
339
 
340
  off = 0
 
516
  "head_dim": 128,
517
  "threshold": 100
518
  }
519
+ overlap_step : How many all2all gather, compute operations are launched in advance
520
+ before the corresponding all2all scatter steps begin.
521
+ A higher overlap_step increases memory usage but can improve
522
+ performance by overlapping communication.
523
+ Parallel muon only.
524
  """
525
 
526
  def __init__(self,
 
539
  "k_indices": [],
540
  "head_dim": 128,
541
  "threshold": 100
542
+ },
543
+ overlap_step=5):
544
  defaults = dict(
545
  lr=lr,
546
  weight_decay=weight_decay,
 
564
 
565
  super().__init__(params, defaults)
566
 
567
+ self.rank = None
 
 
 
568
 
569
  self.comm_stream = torch.cuda.Stream()
570
  self.compute_stream = torch.cuda.Stream()
571
  self.debug = debug
572
  self.clip_config = clip_config
573
+ self.overlap_step = overlap_step
574
 
575
  def _calc_flops(self, G, steps):
576
  assert len(G.shape) == 2
 
643
  if mesh is None:
644
  mesh = p.device_mesh
645
  shard_mesh, process_group = self.get_shard_mesh(p, self.rank)
646
+ local_rank = dist.get_rank(group=process_group)
647
+ if self.rank is None:
648
+ self.rank = dist.get_rank(group=process_group)
649
+ else:
650
+ assert self.rank == local_rank
651
  elif mesh != p.device_mesh:
652
  raise ValueError("All parameters must be on the same mesh.")
653
 
 
788
  param_to_state, ordered_params = self.init_state_and_assign_params(
789
  names, params, group, qk_logits)
790
 
791
+ assert self.rank is not None
792
+
793
  def enqueue_all2all_gather(start_idx, chunk_size):
794
  target_params = ordered_params[start_idx:start_idx + chunk_size]
795
  if target_params:
 
828
  # Wait grad update
829
  self.comm_stream.wait_stream(torch.cuda.current_stream())
830
 
831
+ overlap_step = self.overlap_step
832
+ for i in range(0, overlap_step):
833
  enqueue_all2all_gather(i * chunk_size, chunk_size)
834
  enqueue_computes(i * chunk_size, chunk_size)
835
 
836
  for i in range(0, len(params) + chunk_size - 1, chunk_size):
837
  enqueue_all2all_scatter(i, chunk_size)
838
+ enqueue_all2all_gather(i + overlap_step * chunk_size, chunk_size)
839
  enqueue_update_param(i, chunk_size)
840
+ enqueue_computes(i + overlap_step * chunk_size, chunk_size)
841
 
842
  # Wait the last update_param to finish
843
  torch.cuda.current_stream().wait_stream(self.compute_stream)
build/torch27-cxx11-rocm63-x86_64-linux/optimizer/_ops.py CHANGED
@@ -1,9 +1,9 @@
1
  import torch
2
- from . import _optimizer_37be0d0_dirty
3
- ops = torch.ops._optimizer_37be0d0_dirty
4
 
5
  def add_op_namespace_prefix(op_name: str):
6
  """
7
  Prefix op by namespace.
8
  """
9
- return f"_optimizer_37be0d0_dirty::{op_name}"
 
1
  import torch
2
+ from . import _optimizer_6943c45_dirty
3
+ ops = torch.ops._optimizer_6943c45_dirty
4
 
5
  def add_op_namespace_prefix(op_name: str):
6
  """
7
  Prefix op by namespace.
8
  """
9
+ return f"_optimizer_6943c45_dirty::{op_name}"
build/torch27-cxx11-rocm63-x86_64-linux/optimizer/{_optimizer_37be0d0_dirty.abi3.so → _optimizer_6943c45_dirty.abi3.so} RENAMED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:8f968917ca40eb2ff9b121ea44889d0446a388432a57a01ff8d102ff59695b8a
3
  size 1749776
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:f63251067a8472a98f754fc603e51a85b44fb51777a40d229af67b173f2a7b2c
3
  size 1749776
build/torch27-cxx11-rocm63-x86_64-linux/optimizer/muon.py CHANGED
@@ -73,7 +73,7 @@ class _muon_state:
73
  qk_clip_state = None
74
 
75
 
76
- def split_elems_for_src(param, state, src_rank, num_ranks) -> int:
77
  rows = param.shape[0]
78
  cols = int(param.numel() // rows)
79
  base, rem = divmod(rows, num_ranks)
@@ -83,6 +83,10 @@ def split_elems_for_src(param, state, src_rank, num_ranks) -> int:
83
 
84
  @torch.no_grad()
85
  def _alloc_gathered_grad(params, param_to_state, rank, compute_stream):
 
 
 
 
86
  with torch.cuda.stream(compute_stream):
87
  for p in params:
88
  state = param_to_state[id(p)]
@@ -102,13 +106,17 @@ def _alloc_gathered_grad(params, param_to_state, rank, compute_stream):
102
  @torch.no_grad()
103
  def _all2all_gather(params, param_to_state, rank, comm_stream, none_grad,
104
  alloc_event):
 
 
 
105
  with torch.cuda.stream(comm_stream):
106
  process_group = param_to_state[id(params[0])].process_group
107
  num_ranks = dist.get_world_size(group=process_group)
108
 
109
- # Calculate sending tensors
110
  per_dst = [[] for _ in range(num_ranks)]
111
  send_counts = [0] * num_ranks
 
112
  for p in params:
113
  state = param_to_state[id(p)]
114
  dst = state.worker_rank
@@ -125,15 +133,16 @@ def _all2all_gather(params, param_to_state, rank, comm_stream, none_grad,
125
  for v in per_dst), "all params should be sharded to all devices"
126
 
127
  send_buf = torch.cat([torch.cat(v, dim=0) for v in per_dst], dim=0)
128
- owner_params = [
129
  p for p in params if param_to_state[id(p)].worker_rank == rank
130
  ]
131
 
132
- # Calculate receiving tensors
133
  recv_counts = [0] * num_ranks
 
134
  for src in range(num_ranks):
135
  total = 0
136
- for p in owner_params:
137
  state = param_to_state[id(p)]
138
  assert state.worker_rank == rank
139
  total += split_elems_for_src(p, state, src, num_ranks)
@@ -141,6 +150,8 @@ def _all2all_gather(params, param_to_state, rank, comm_stream, none_grad,
141
 
142
  recv_total = sum(recv_counts)
143
  recv_buf = torch.empty(recv_total, dtype=COMM_DTYPE, device="cuda")
 
 
144
  dist.all_to_all_single(
145
  recv_buf,
146
  send_buf,
@@ -165,14 +176,14 @@ def _all2all_gather(params, param_to_state, rank, comm_stream, none_grad,
165
  comm_stream.wait_event(alloc_event)
166
 
167
  off = 0
168
- write_offsets = {id(p): 0 for p in owner_params}
169
  for src in range(num_ranks):
170
  if recv_counts[src] == 0:
171
  continue
172
 
173
  block = recv_counts[src]
174
  inner_off = 0
175
- for p in owner_params:
176
  state = param_to_state[id(p)]
177
  assert state.worker_rank == rank
178
  n = split_elems_for_src(p, state, src, num_ranks)
@@ -222,6 +233,10 @@ def _compute_u(p, state, steps, rank, compute_stream):
222
 
223
  @torch.no_grad()
224
  def _alloc_scattered_u(params, param_to_state, rank, compute_stream):
 
 
 
 
225
  with torch.cuda.stream(compute_stream):
226
  for p in params:
227
  state = param_to_state[id(p)]
@@ -234,18 +249,22 @@ def _alloc_scattered_u(params, param_to_state, rank, compute_stream):
234
 
235
 
236
  def _all2all_scatter(params, param_to_state, rank, comm_stream, alloc_event):
 
 
 
237
  with torch.cuda.stream(comm_stream):
238
  process_group = param_to_state[id(params[0])].process_group
239
  num_ranks = dist.get_world_size(group=process_group)
240
- owner_params = [
241
  p for p in params if param_to_state[id(p)].worker_rank == rank
242
  ]
243
 
 
244
  per_dst = [[] for _ in range(num_ranks)]
245
  send_counts = [0] * num_ranks
246
 
247
- if owner_params:
248
- for p in owner_params:
249
  state = param_to_state[id(p)]
250
  if state.compute_event is None:
251
  raise RuntimeError(
@@ -276,7 +295,9 @@ def _all2all_scatter(params, param_to_state, rank, comm_stream, alloc_event):
276
  # Even non-owner ranks must join the collective call
277
  send_buf = torch.empty(0, dtype=COMM_DTYPE, device="cuda")
278
 
 
279
  recv_counts = [0] * num_ranks
 
280
  for src in range(num_ranks):
281
  total = 0
282
  for p in params:
@@ -290,6 +311,7 @@ def _all2all_scatter(params, param_to_state, rank, comm_stream, alloc_event):
290
  assert recv_total > 0
291
  recv_buf = torch.empty(recv_total, dtype=COMM_DTYPE, device="cuda")
292
 
 
293
  dist.all_to_all_single(
294
  recv_buf,
295
  send_buf,
@@ -298,6 +320,21 @@ def _all2all_scatter(params, param_to_state, rank, comm_stream, alloc_event):
298
  group=process_group,
299
  )
300
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
301
  comm_stream.wait_event(alloc_event)
302
 
303
  off = 0
@@ -479,6 +516,11 @@ class Muon(torch.optim.Optimizer):
479
  "head_dim": 128,
480
  "threshold": 100
481
  }
 
 
 
 
 
482
  """
483
 
484
  def __init__(self,
@@ -497,7 +539,8 @@ class Muon(torch.optim.Optimizer):
497
  "k_indices": [],
498
  "head_dim": 128,
499
  "threshold": 100
500
- }):
 
501
  defaults = dict(
502
  lr=lr,
503
  weight_decay=weight_decay,
@@ -521,15 +564,13 @@ class Muon(torch.optim.Optimizer):
521
 
522
  super().__init__(params, defaults)
523
 
524
- if dist.is_initialized():
525
- self.rank = dist.get_rank()
526
- else:
527
- self.rank = None
528
 
529
  self.comm_stream = torch.cuda.Stream()
530
  self.compute_stream = torch.cuda.Stream()
531
  self.debug = debug
532
  self.clip_config = clip_config
 
533
 
534
  def _calc_flops(self, G, steps):
535
  assert len(G.shape) == 2
@@ -602,7 +643,11 @@ class Muon(torch.optim.Optimizer):
602
  if mesh is None:
603
  mesh = p.device_mesh
604
  shard_mesh, process_group = self.get_shard_mesh(p, self.rank)
605
- self.rank = dist.get_rank(group=process_group)
 
 
 
 
606
  elif mesh != p.device_mesh:
607
  raise ValueError("All parameters must be on the same mesh.")
608
 
@@ -743,6 +788,8 @@ class Muon(torch.optim.Optimizer):
743
  param_to_state, ordered_params = self.init_state_and_assign_params(
744
  names, params, group, qk_logits)
745
 
 
 
746
  def enqueue_all2all_gather(start_idx, chunk_size):
747
  target_params = ordered_params[start_idx:start_idx + chunk_size]
748
  if target_params:
@@ -781,16 +828,16 @@ class Muon(torch.optim.Optimizer):
781
  # Wait grad update
782
  self.comm_stream.wait_stream(torch.cuda.current_stream())
783
 
784
- PRE_STEP = 5
785
- for i in range(0, PRE_STEP):
786
  enqueue_all2all_gather(i * chunk_size, chunk_size)
787
  enqueue_computes(i * chunk_size, chunk_size)
788
 
789
  for i in range(0, len(params) + chunk_size - 1, chunk_size):
790
  enqueue_all2all_scatter(i, chunk_size)
791
- enqueue_all2all_gather(i + PRE_STEP * chunk_size, chunk_size)
792
  enqueue_update_param(i, chunk_size)
793
- enqueue_computes(i + PRE_STEP * chunk_size, chunk_size)
794
 
795
  # Wait the last update_param to finish
796
  torch.cuda.current_stream().wait_stream(self.compute_stream)
 
73
  qk_clip_state = None
74
 
75
 
76
+ def split_elems_for_src(param, src_rank, num_ranks) -> int:
77
  rows = param.shape[0]
78
  cols = int(param.numel() // rows)
79
  base, rem = divmod(rows, num_ranks)
 
83
 
84
  @torch.no_grad()
85
  def _alloc_gathered_grad(params, param_to_state, rank, compute_stream):
86
+ """
87
+ Pre-allocate gathered_grad buffer on compute_stream
88
+ before launching all2all gather
89
+ """
90
  with torch.cuda.stream(compute_stream):
91
  for p in params:
92
  state = param_to_state[id(p)]
 
106
  @torch.no_grad()
107
  def _all2all_gather(params, param_to_state, rank, comm_stream, none_grad,
108
  alloc_event):
109
+ """
110
+ All2all gathers shards so each owner rank reconstructs its full gradient
111
+ """
112
  with torch.cuda.stream(comm_stream):
113
  process_group = param_to_state[id(params[0])].process_group
114
  num_ranks = dist.get_world_size(group=process_group)
115
 
116
+ # Construct sending buffers
117
  per_dst = [[] for _ in range(num_ranks)]
118
  send_counts = [0] * num_ranks
119
+
120
  for p in params:
121
  state = param_to_state[id(p)]
122
  dst = state.worker_rank
 
133
  for v in per_dst), "all params should be sharded to all devices"
134
 
135
  send_buf = torch.cat([torch.cat(v, dim=0) for v in per_dst], dim=0)
136
+ owned_params = [
137
  p for p in params if param_to_state[id(p)].worker_rank == rank
138
  ]
139
 
140
+ # Compute receive sizes and allocate receiving buffers
141
  recv_counts = [0] * num_ranks
142
+
143
  for src in range(num_ranks):
144
  total = 0
145
+ for p in owned_params:
146
  state = param_to_state[id(p)]
147
  assert state.worker_rank == rank
148
  total += split_elems_for_src(p, state, src, num_ranks)
 
150
 
151
  recv_total = sum(recv_counts)
152
  recv_buf = torch.empty(recv_total, dtype=COMM_DTYPE, device="cuda")
153
+
154
+ #All2All
155
  dist.all_to_all_single(
156
  recv_buf,
157
  send_buf,
 
176
  comm_stream.wait_event(alloc_event)
177
 
178
  off = 0
179
+ write_offsets = {id(p): 0 for p in owned_params}
180
  for src in range(num_ranks):
181
  if recv_counts[src] == 0:
182
  continue
183
 
184
  block = recv_counts[src]
185
  inner_off = 0
186
+ for p in owned_params:
187
  state = param_to_state[id(p)]
188
  assert state.worker_rank == rank
189
  n = split_elems_for_src(p, state, src, num_ranks)
 
233
 
234
  @torch.no_grad()
235
  def _alloc_scattered_u(params, param_to_state, rank, compute_stream):
236
+ """
237
+ Pre-allocate scattered_u buffer on compute_stream
238
+ before launching all2all gather
239
+ """
240
  with torch.cuda.stream(compute_stream):
241
  for p in params:
242
  state = param_to_state[id(p)]
 
249
 
250
 
251
  def _all2all_scatter(params, param_to_state, rank, comm_stream, alloc_event):
252
+ """
253
+ All2all scatters full gradients to all ranks
254
+ """
255
  with torch.cuda.stream(comm_stream):
256
  process_group = param_to_state[id(params[0])].process_group
257
  num_ranks = dist.get_world_size(group=process_group)
258
+ owned_params = [
259
  p for p in params if param_to_state[id(p)].worker_rank == rank
260
  ]
261
 
262
+ # Construct sending buffer
263
  per_dst = [[] for _ in range(num_ranks)]
264
  send_counts = [0] * num_ranks
265
 
266
+ if owned_params:
267
+ for p in owned_params:
268
  state = param_to_state[id(p)]
269
  if state.compute_event is None:
270
  raise RuntimeError(
 
295
  # Even non-owner ranks must join the collective call
296
  send_buf = torch.empty(0, dtype=COMM_DTYPE, device="cuda")
297
 
298
+ # Compute receive sizes and allocate receiving buffers
299
  recv_counts = [0] * num_ranks
300
+
301
  for src in range(num_ranks):
302
  total = 0
303
  for p in params:
 
311
  assert recv_total > 0
312
  recv_buf = torch.empty(recv_total, dtype=COMM_DTYPE, device="cuda")
313
 
314
+ #All2All
315
  dist.all_to_all_single(
316
  recv_buf,
317
  send_buf,
 
320
  group=process_group,
321
  )
322
 
323
+ # Copy to pre-allocated scattered_u buffer from the received buffer
324
+ #
325
+ # recv_buf (num ranks = 3, local_rank = 0)
326
+ #
327
+ # From rank 0 From rank 1 From rank 2
328
+ # | p1_0, p2_0, p3_0 | p4_0 | p5_0, p6_0 |
329
+ #
330
+ # Outer loop:
331
+ # rank 0 -> rank 1 -> rank2
332
+ #
333
+ # Inner loop:
334
+ # src(0) : p1_0 -> p2_0 -> p3_0
335
+ # src(1) : p4_0
336
+ # src(2) : p5_0 -> p6_0
337
+
338
  comm_stream.wait_event(alloc_event)
339
 
340
  off = 0
 
516
  "head_dim": 128,
517
  "threshold": 100
518
  }
519
+ overlap_step : How many all2all gather, compute operations are launched in advance
520
+ before the corresponding all2all scatter steps begin.
521
+ A higher overlap_step increases memory usage but can improve
522
+ performance by overlapping communication.
523
+ Parallel muon only.
524
  """
525
 
526
  def __init__(self,
 
539
  "k_indices": [],
540
  "head_dim": 128,
541
  "threshold": 100
542
+ },
543
+ overlap_step=5):
544
  defaults = dict(
545
  lr=lr,
546
  weight_decay=weight_decay,
 
564
 
565
  super().__init__(params, defaults)
566
 
567
+ self.rank = None
 
 
 
568
 
569
  self.comm_stream = torch.cuda.Stream()
570
  self.compute_stream = torch.cuda.Stream()
571
  self.debug = debug
572
  self.clip_config = clip_config
573
+ self.overlap_step = overlap_step
574
 
575
  def _calc_flops(self, G, steps):
576
  assert len(G.shape) == 2
 
643
  if mesh is None:
644
  mesh = p.device_mesh
645
  shard_mesh, process_group = self.get_shard_mesh(p, self.rank)
646
+ local_rank = dist.get_rank(group=process_group)
647
+ if self.rank is None:
648
+ self.rank = dist.get_rank(group=process_group)
649
+ else:
650
+ assert self.rank == local_rank
651
  elif mesh != p.device_mesh:
652
  raise ValueError("All parameters must be on the same mesh.")
653
 
 
788
  param_to_state, ordered_params = self.init_state_and_assign_params(
789
  names, params, group, qk_logits)
790
 
791
+ assert self.rank is not None
792
+
793
  def enqueue_all2all_gather(start_idx, chunk_size):
794
  target_params = ordered_params[start_idx:start_idx + chunk_size]
795
  if target_params:
 
828
  # Wait grad update
829
  self.comm_stream.wait_stream(torch.cuda.current_stream())
830
 
831
+ overlap_step = self.overlap_step
832
+ for i in range(0, overlap_step):
833
  enqueue_all2all_gather(i * chunk_size, chunk_size)
834
  enqueue_computes(i * chunk_size, chunk_size)
835
 
836
  for i in range(0, len(params) + chunk_size - 1, chunk_size):
837
  enqueue_all2all_scatter(i, chunk_size)
838
+ enqueue_all2all_gather(i + overlap_step * chunk_size, chunk_size)
839
  enqueue_update_param(i, chunk_size)
840
+ enqueue_computes(i + overlap_step * chunk_size, chunk_size)
841
 
842
  # Wait the last update_param to finish
843
  torch.cuda.current_stream().wait_stream(self.compute_stream)
build/torch28-cxx11-cu126-x86_64-linux/optimizer/_ops.py CHANGED
@@ -1,9 +1,9 @@
1
  import torch
2
- from . import _optimizer_37be0d0_dirty
3
- ops = torch.ops._optimizer_37be0d0_dirty
4
 
5
  def add_op_namespace_prefix(op_name: str):
6
  """
7
  Prefix op by namespace.
8
  """
9
- return f"_optimizer_37be0d0_dirty::{op_name}"
 
1
  import torch
2
+ from . import _optimizer_6943c45_dirty
3
+ ops = torch.ops._optimizer_6943c45_dirty
4
 
5
  def add_op_namespace_prefix(op_name: str):
6
  """
7
  Prefix op by namespace.
8
  """
9
+ return f"_optimizer_6943c45_dirty::{op_name}"
build/{torch27-cxx11-cu126-x86_64-linux/optimizer/_optimizer_37be0d0_dirty.abi3.so → torch28-cxx11-cu126-x86_64-linux/optimizer/_optimizer_6943c45_dirty.abi3.so} RENAMED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:10fdf4bbdc0ceb7b6c1504145ea53f837ac237422c43e3b74b12aec789c49dac
3
  size 1824256
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:10905a024d5fa31fe31b8370747790b2f0ce60d06881831efb7cc07e1c5e5436
3
  size 1824256
build/torch28-cxx11-cu126-x86_64-linux/optimizer/muon.py CHANGED
@@ -73,7 +73,7 @@ class _muon_state:
73
  qk_clip_state = None
74
 
75
 
76
- def split_elems_for_src(param, state, src_rank, num_ranks) -> int:
77
  rows = param.shape[0]
78
  cols = int(param.numel() // rows)
79
  base, rem = divmod(rows, num_ranks)
@@ -83,6 +83,10 @@ def split_elems_for_src(param, state, src_rank, num_ranks) -> int:
83
 
84
  @torch.no_grad()
85
  def _alloc_gathered_grad(params, param_to_state, rank, compute_stream):
 
 
 
 
86
  with torch.cuda.stream(compute_stream):
87
  for p in params:
88
  state = param_to_state[id(p)]
@@ -102,13 +106,17 @@ def _alloc_gathered_grad(params, param_to_state, rank, compute_stream):
102
  @torch.no_grad()
103
  def _all2all_gather(params, param_to_state, rank, comm_stream, none_grad,
104
  alloc_event):
 
 
 
105
  with torch.cuda.stream(comm_stream):
106
  process_group = param_to_state[id(params[0])].process_group
107
  num_ranks = dist.get_world_size(group=process_group)
108
 
109
- # Calculate sending tensors
110
  per_dst = [[] for _ in range(num_ranks)]
111
  send_counts = [0] * num_ranks
 
112
  for p in params:
113
  state = param_to_state[id(p)]
114
  dst = state.worker_rank
@@ -125,15 +133,16 @@ def _all2all_gather(params, param_to_state, rank, comm_stream, none_grad,
125
  for v in per_dst), "all params should be sharded to all devices"
126
 
127
  send_buf = torch.cat([torch.cat(v, dim=0) for v in per_dst], dim=0)
128
- owner_params = [
129
  p for p in params if param_to_state[id(p)].worker_rank == rank
130
  ]
131
 
132
- # Calculate receiving tensors
133
  recv_counts = [0] * num_ranks
 
134
  for src in range(num_ranks):
135
  total = 0
136
- for p in owner_params:
137
  state = param_to_state[id(p)]
138
  assert state.worker_rank == rank
139
  total += split_elems_for_src(p, state, src, num_ranks)
@@ -141,6 +150,8 @@ def _all2all_gather(params, param_to_state, rank, comm_stream, none_grad,
141
 
142
  recv_total = sum(recv_counts)
143
  recv_buf = torch.empty(recv_total, dtype=COMM_DTYPE, device="cuda")
 
 
144
  dist.all_to_all_single(
145
  recv_buf,
146
  send_buf,
@@ -165,14 +176,14 @@ def _all2all_gather(params, param_to_state, rank, comm_stream, none_grad,
165
  comm_stream.wait_event(alloc_event)
166
 
167
  off = 0
168
- write_offsets = {id(p): 0 for p in owner_params}
169
  for src in range(num_ranks):
170
  if recv_counts[src] == 0:
171
  continue
172
 
173
  block = recv_counts[src]
174
  inner_off = 0
175
- for p in owner_params:
176
  state = param_to_state[id(p)]
177
  assert state.worker_rank == rank
178
  n = split_elems_for_src(p, state, src, num_ranks)
@@ -222,6 +233,10 @@ def _compute_u(p, state, steps, rank, compute_stream):
222
 
223
  @torch.no_grad()
224
  def _alloc_scattered_u(params, param_to_state, rank, compute_stream):
 
 
 
 
225
  with torch.cuda.stream(compute_stream):
226
  for p in params:
227
  state = param_to_state[id(p)]
@@ -234,18 +249,22 @@ def _alloc_scattered_u(params, param_to_state, rank, compute_stream):
234
 
235
 
236
  def _all2all_scatter(params, param_to_state, rank, comm_stream, alloc_event):
 
 
 
237
  with torch.cuda.stream(comm_stream):
238
  process_group = param_to_state[id(params[0])].process_group
239
  num_ranks = dist.get_world_size(group=process_group)
240
- owner_params = [
241
  p for p in params if param_to_state[id(p)].worker_rank == rank
242
  ]
243
 
 
244
  per_dst = [[] for _ in range(num_ranks)]
245
  send_counts = [0] * num_ranks
246
 
247
- if owner_params:
248
- for p in owner_params:
249
  state = param_to_state[id(p)]
250
  if state.compute_event is None:
251
  raise RuntimeError(
@@ -276,7 +295,9 @@ def _all2all_scatter(params, param_to_state, rank, comm_stream, alloc_event):
276
  # Even non-owner ranks must join the collective call
277
  send_buf = torch.empty(0, dtype=COMM_DTYPE, device="cuda")
278
 
 
279
  recv_counts = [0] * num_ranks
 
280
  for src in range(num_ranks):
281
  total = 0
282
  for p in params:
@@ -290,6 +311,7 @@ def _all2all_scatter(params, param_to_state, rank, comm_stream, alloc_event):
290
  assert recv_total > 0
291
  recv_buf = torch.empty(recv_total, dtype=COMM_DTYPE, device="cuda")
292
 
 
293
  dist.all_to_all_single(
294
  recv_buf,
295
  send_buf,
@@ -298,6 +320,21 @@ def _all2all_scatter(params, param_to_state, rank, comm_stream, alloc_event):
298
  group=process_group,
299
  )
300
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
301
  comm_stream.wait_event(alloc_event)
302
 
303
  off = 0
@@ -479,6 +516,11 @@ class Muon(torch.optim.Optimizer):
479
  "head_dim": 128,
480
  "threshold": 100
481
  }
 
 
 
 
 
482
  """
483
 
484
  def __init__(self,
@@ -497,7 +539,8 @@ class Muon(torch.optim.Optimizer):
497
  "k_indices": [],
498
  "head_dim": 128,
499
  "threshold": 100
500
- }):
 
501
  defaults = dict(
502
  lr=lr,
503
  weight_decay=weight_decay,
@@ -521,15 +564,13 @@ class Muon(torch.optim.Optimizer):
521
 
522
  super().__init__(params, defaults)
523
 
524
- if dist.is_initialized():
525
- self.rank = dist.get_rank()
526
- else:
527
- self.rank = None
528
 
529
  self.comm_stream = torch.cuda.Stream()
530
  self.compute_stream = torch.cuda.Stream()
531
  self.debug = debug
532
  self.clip_config = clip_config
 
533
 
534
  def _calc_flops(self, G, steps):
535
  assert len(G.shape) == 2
@@ -602,7 +643,11 @@ class Muon(torch.optim.Optimizer):
602
  if mesh is None:
603
  mesh = p.device_mesh
604
  shard_mesh, process_group = self.get_shard_mesh(p, self.rank)
605
- self.rank = dist.get_rank(group=process_group)
 
 
 
 
606
  elif mesh != p.device_mesh:
607
  raise ValueError("All parameters must be on the same mesh.")
608
 
@@ -743,6 +788,8 @@ class Muon(torch.optim.Optimizer):
743
  param_to_state, ordered_params = self.init_state_and_assign_params(
744
  names, params, group, qk_logits)
745
 
 
 
746
  def enqueue_all2all_gather(start_idx, chunk_size):
747
  target_params = ordered_params[start_idx:start_idx + chunk_size]
748
  if target_params:
@@ -781,16 +828,16 @@ class Muon(torch.optim.Optimizer):
781
  # Wait grad update
782
  self.comm_stream.wait_stream(torch.cuda.current_stream())
783
 
784
- PRE_STEP = 5
785
- for i in range(0, PRE_STEP):
786
  enqueue_all2all_gather(i * chunk_size, chunk_size)
787
  enqueue_computes(i * chunk_size, chunk_size)
788
 
789
  for i in range(0, len(params) + chunk_size - 1, chunk_size):
790
  enqueue_all2all_scatter(i, chunk_size)
791
- enqueue_all2all_gather(i + PRE_STEP * chunk_size, chunk_size)
792
  enqueue_update_param(i, chunk_size)
793
- enqueue_computes(i + PRE_STEP * chunk_size, chunk_size)
794
 
795
  # Wait the last update_param to finish
796
  torch.cuda.current_stream().wait_stream(self.compute_stream)
 
73
  qk_clip_state = None
74
 
75
 
76
+ def split_elems_for_src(param, src_rank, num_ranks) -> int:
77
  rows = param.shape[0]
78
  cols = int(param.numel() // rows)
79
  base, rem = divmod(rows, num_ranks)
 
83
 
84
  @torch.no_grad()
85
  def _alloc_gathered_grad(params, param_to_state, rank, compute_stream):
86
+ """
87
+ Pre-allocate gathered_grad buffer on compute_stream
88
+ before launching all2all gather
89
+ """
90
  with torch.cuda.stream(compute_stream):
91
  for p in params:
92
  state = param_to_state[id(p)]
 
106
  @torch.no_grad()
107
  def _all2all_gather(params, param_to_state, rank, comm_stream, none_grad,
108
  alloc_event):
109
+ """
110
+ All2all gathers shards so each owner rank reconstructs its full gradient
111
+ """
112
  with torch.cuda.stream(comm_stream):
113
  process_group = param_to_state[id(params[0])].process_group
114
  num_ranks = dist.get_world_size(group=process_group)
115
 
116
+ # Construct sending buffers
117
  per_dst = [[] for _ in range(num_ranks)]
118
  send_counts = [0] * num_ranks
119
+
120
  for p in params:
121
  state = param_to_state[id(p)]
122
  dst = state.worker_rank
 
133
  for v in per_dst), "all params should be sharded to all devices"
134
 
135
  send_buf = torch.cat([torch.cat(v, dim=0) for v in per_dst], dim=0)
136
+ owned_params = [
137
  p for p in params if param_to_state[id(p)].worker_rank == rank
138
  ]
139
 
140
+ # Compute receive sizes and allocate receiving buffers
141
  recv_counts = [0] * num_ranks
142
+
143
  for src in range(num_ranks):
144
  total = 0
145
+ for p in owned_params:
146
  state = param_to_state[id(p)]
147
  assert state.worker_rank == rank
148
  total += split_elems_for_src(p, state, src, num_ranks)
 
150
 
151
  recv_total = sum(recv_counts)
152
  recv_buf = torch.empty(recv_total, dtype=COMM_DTYPE, device="cuda")
153
+
154
+ #All2All
155
  dist.all_to_all_single(
156
  recv_buf,
157
  send_buf,
 
176
  comm_stream.wait_event(alloc_event)
177
 
178
  off = 0
179
+ write_offsets = {id(p): 0 for p in owned_params}
180
  for src in range(num_ranks):
181
  if recv_counts[src] == 0:
182
  continue
183
 
184
  block = recv_counts[src]
185
  inner_off = 0
186
+ for p in owned_params:
187
  state = param_to_state[id(p)]
188
  assert state.worker_rank == rank
189
  n = split_elems_for_src(p, state, src, num_ranks)
 
233
 
234
  @torch.no_grad()
235
  def _alloc_scattered_u(params, param_to_state, rank, compute_stream):
236
+ """
237
+ Pre-allocate scattered_u buffer on compute_stream
238
+ before launching all2all gather
239
+ """
240
  with torch.cuda.stream(compute_stream):
241
  for p in params:
242
  state = param_to_state[id(p)]
 
249
 
250
 
251
  def _all2all_scatter(params, param_to_state, rank, comm_stream, alloc_event):
252
+ """
253
+ All2all scatters full gradients to all ranks
254
+ """
255
  with torch.cuda.stream(comm_stream):
256
  process_group = param_to_state[id(params[0])].process_group
257
  num_ranks = dist.get_world_size(group=process_group)
258
+ owned_params = [
259
  p for p in params if param_to_state[id(p)].worker_rank == rank
260
  ]
261
 
262
+ # Construct sending buffer
263
  per_dst = [[] for _ in range(num_ranks)]
264
  send_counts = [0] * num_ranks
265
 
266
+ if owned_params:
267
+ for p in owned_params:
268
  state = param_to_state[id(p)]
269
  if state.compute_event is None:
270
  raise RuntimeError(
 
295
  # Even non-owner ranks must join the collective call
296
  send_buf = torch.empty(0, dtype=COMM_DTYPE, device="cuda")
297
 
298
+ # Compute receive sizes and allocate receiving buffers
299
  recv_counts = [0] * num_ranks
300
+
301
  for src in range(num_ranks):
302
  total = 0
303
  for p in params:
 
311
  assert recv_total > 0
312
  recv_buf = torch.empty(recv_total, dtype=COMM_DTYPE, device="cuda")
313
 
314
+ #All2All
315
  dist.all_to_all_single(
316
  recv_buf,
317
  send_buf,
 
320
  group=process_group,
321
  )
322
 
323
+ # Copy to pre-allocated scattered_u buffer from the received buffer
324
+ #
325
+ # recv_buf (num ranks = 3, local_rank = 0)
326
+ #
327
+ # From rank 0 From rank 1 From rank 2
328
+ # | p1_0, p2_0, p3_0 | p4_0 | p5_0, p6_0 |
329
+ #
330
+ # Outer loop:
331
+ # rank 0 -> rank 1 -> rank2
332
+ #
333
+ # Inner loop:
334
+ # src(0) : p1_0 -> p2_0 -> p3_0
335
+ # src(1) : p4_0
336
+ # src(2) : p5_0 -> p6_0
337
+
338
  comm_stream.wait_event(alloc_event)
339
 
340
  off = 0
 
516
  "head_dim": 128,
517
  "threshold": 100
518
  }
519
+ overlap_step : How many all2all gather, compute operations are launched in advance
520
+ before the corresponding all2all scatter steps begin.
521
+ A higher overlap_step increases memory usage but can improve
522
+ performance by overlapping communication.
523
+ Parallel muon only.
524
  """
525
 
526
  def __init__(self,
 
539
  "k_indices": [],
540
  "head_dim": 128,
541
  "threshold": 100
542
+ },
543
+ overlap_step=5):
544
  defaults = dict(
545
  lr=lr,
546
  weight_decay=weight_decay,
 
564
 
565
  super().__init__(params, defaults)
566
 
567
+ self.rank = None
 
 
 
568
 
569
  self.comm_stream = torch.cuda.Stream()
570
  self.compute_stream = torch.cuda.Stream()
571
  self.debug = debug
572
  self.clip_config = clip_config
573
+ self.overlap_step = overlap_step
574
 
575
  def _calc_flops(self, G, steps):
576
  assert len(G.shape) == 2
 
643
  if mesh is None:
644
  mesh = p.device_mesh
645
  shard_mesh, process_group = self.get_shard_mesh(p, self.rank)
646
+ local_rank = dist.get_rank(group=process_group)
647
+ if self.rank is None:
648
+ self.rank = dist.get_rank(group=process_group)
649
+ else:
650
+ assert self.rank == local_rank
651
  elif mesh != p.device_mesh:
652
  raise ValueError("All parameters must be on the same mesh.")
653
 
 
788
  param_to_state, ordered_params = self.init_state_and_assign_params(
789
  names, params, group, qk_logits)
790
 
791
+ assert self.rank is not None
792
+
793
  def enqueue_all2all_gather(start_idx, chunk_size):
794
  target_params = ordered_params[start_idx:start_idx + chunk_size]
795
  if target_params:
 
828
  # Wait grad update
829
  self.comm_stream.wait_stream(torch.cuda.current_stream())
830
 
831
+ overlap_step = self.overlap_step
832
+ for i in range(0, overlap_step):
833
  enqueue_all2all_gather(i * chunk_size, chunk_size)
834
  enqueue_computes(i * chunk_size, chunk_size)
835
 
836
  for i in range(0, len(params) + chunk_size - 1, chunk_size):
837
  enqueue_all2all_scatter(i, chunk_size)
838
+ enqueue_all2all_gather(i + overlap_step * chunk_size, chunk_size)
839
  enqueue_update_param(i, chunk_size)
840
+ enqueue_computes(i + overlap_step * chunk_size, chunk_size)
841
 
842
  # Wait the last update_param to finish
843
  torch.cuda.current_stream().wait_stream(self.compute_stream)
build/torch28-cxx11-cu128-x86_64-linux/optimizer/_ops.py CHANGED
@@ -1,9 +1,9 @@
1
  import torch
2
- from . import _optimizer_37be0d0_dirty
3
- ops = torch.ops._optimizer_37be0d0_dirty
4
 
5
  def add_op_namespace_prefix(op_name: str):
6
  """
7
  Prefix op by namespace.
8
  """
9
- return f"_optimizer_37be0d0_dirty::{op_name}"
 
1
  import torch
2
+ from . import _optimizer_6943c45_dirty
3
+ ops = torch.ops._optimizer_6943c45_dirty
4
 
5
  def add_op_namespace_prefix(op_name: str):
6
  """
7
  Prefix op by namespace.
8
  """
9
+ return f"_optimizer_6943c45_dirty::{op_name}"
build/{torch28-cxx11-cu129-x86_64-linux/optimizer/_optimizer_37be0d0_dirty.abi3.so → torch28-cxx11-cu128-x86_64-linux/optimizer/_optimizer_6943c45_dirty.abi3.so} RENAMED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:4789f8aba6b8d3ff6557b8d44b657551469ddd8857b1e315eb29b09a4c86da1a
3
  size 1883344
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:058aa5ff9f1e974cb5b52e4a7af074cef2092c457b5498356fc0fbdd86adf5f3
3
  size 1883344
build/torch28-cxx11-cu128-x86_64-linux/optimizer/muon.py CHANGED
@@ -73,7 +73,7 @@ class _muon_state:
73
  qk_clip_state = None
74
 
75
 
76
- def split_elems_for_src(param, state, src_rank, num_ranks) -> int:
77
  rows = param.shape[0]
78
  cols = int(param.numel() // rows)
79
  base, rem = divmod(rows, num_ranks)
@@ -83,6 +83,10 @@ def split_elems_for_src(param, state, src_rank, num_ranks) -> int:
83
 
84
  @torch.no_grad()
85
  def _alloc_gathered_grad(params, param_to_state, rank, compute_stream):
 
 
 
 
86
  with torch.cuda.stream(compute_stream):
87
  for p in params:
88
  state = param_to_state[id(p)]
@@ -102,13 +106,17 @@ def _alloc_gathered_grad(params, param_to_state, rank, compute_stream):
102
  @torch.no_grad()
103
  def _all2all_gather(params, param_to_state, rank, comm_stream, none_grad,
104
  alloc_event):
 
 
 
105
  with torch.cuda.stream(comm_stream):
106
  process_group = param_to_state[id(params[0])].process_group
107
  num_ranks = dist.get_world_size(group=process_group)
108
 
109
- # Calculate sending tensors
110
  per_dst = [[] for _ in range(num_ranks)]
111
  send_counts = [0] * num_ranks
 
112
  for p in params:
113
  state = param_to_state[id(p)]
114
  dst = state.worker_rank
@@ -125,15 +133,16 @@ def _all2all_gather(params, param_to_state, rank, comm_stream, none_grad,
125
  for v in per_dst), "all params should be sharded to all devices"
126
 
127
  send_buf = torch.cat([torch.cat(v, dim=0) for v in per_dst], dim=0)
128
- owner_params = [
129
  p for p in params if param_to_state[id(p)].worker_rank == rank
130
  ]
131
 
132
- # Calculate receiving tensors
133
  recv_counts = [0] * num_ranks
 
134
  for src in range(num_ranks):
135
  total = 0
136
- for p in owner_params:
137
  state = param_to_state[id(p)]
138
  assert state.worker_rank == rank
139
  total += split_elems_for_src(p, state, src, num_ranks)
@@ -141,6 +150,8 @@ def _all2all_gather(params, param_to_state, rank, comm_stream, none_grad,
141
 
142
  recv_total = sum(recv_counts)
143
  recv_buf = torch.empty(recv_total, dtype=COMM_DTYPE, device="cuda")
 
 
144
  dist.all_to_all_single(
145
  recv_buf,
146
  send_buf,
@@ -165,14 +176,14 @@ def _all2all_gather(params, param_to_state, rank, comm_stream, none_grad,
165
  comm_stream.wait_event(alloc_event)
166
 
167
  off = 0
168
- write_offsets = {id(p): 0 for p in owner_params}
169
  for src in range(num_ranks):
170
  if recv_counts[src] == 0:
171
  continue
172
 
173
  block = recv_counts[src]
174
  inner_off = 0
175
- for p in owner_params:
176
  state = param_to_state[id(p)]
177
  assert state.worker_rank == rank
178
  n = split_elems_for_src(p, state, src, num_ranks)
@@ -222,6 +233,10 @@ def _compute_u(p, state, steps, rank, compute_stream):
222
 
223
  @torch.no_grad()
224
  def _alloc_scattered_u(params, param_to_state, rank, compute_stream):
 
 
 
 
225
  with torch.cuda.stream(compute_stream):
226
  for p in params:
227
  state = param_to_state[id(p)]
@@ -234,18 +249,22 @@ def _alloc_scattered_u(params, param_to_state, rank, compute_stream):
234
 
235
 
236
  def _all2all_scatter(params, param_to_state, rank, comm_stream, alloc_event):
 
 
 
237
  with torch.cuda.stream(comm_stream):
238
  process_group = param_to_state[id(params[0])].process_group
239
  num_ranks = dist.get_world_size(group=process_group)
240
- owner_params = [
241
  p for p in params if param_to_state[id(p)].worker_rank == rank
242
  ]
243
 
 
244
  per_dst = [[] for _ in range(num_ranks)]
245
  send_counts = [0] * num_ranks
246
 
247
- if owner_params:
248
- for p in owner_params:
249
  state = param_to_state[id(p)]
250
  if state.compute_event is None:
251
  raise RuntimeError(
@@ -276,7 +295,9 @@ def _all2all_scatter(params, param_to_state, rank, comm_stream, alloc_event):
276
  # Even non-owner ranks must join the collective call
277
  send_buf = torch.empty(0, dtype=COMM_DTYPE, device="cuda")
278
 
 
279
  recv_counts = [0] * num_ranks
 
280
  for src in range(num_ranks):
281
  total = 0
282
  for p in params:
@@ -290,6 +311,7 @@ def _all2all_scatter(params, param_to_state, rank, comm_stream, alloc_event):
290
  assert recv_total > 0
291
  recv_buf = torch.empty(recv_total, dtype=COMM_DTYPE, device="cuda")
292
 
 
293
  dist.all_to_all_single(
294
  recv_buf,
295
  send_buf,
@@ -298,6 +320,21 @@ def _all2all_scatter(params, param_to_state, rank, comm_stream, alloc_event):
298
  group=process_group,
299
  )
300
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
301
  comm_stream.wait_event(alloc_event)
302
 
303
  off = 0
@@ -479,6 +516,11 @@ class Muon(torch.optim.Optimizer):
479
  "head_dim": 128,
480
  "threshold": 100
481
  }
 
 
 
 
 
482
  """
483
 
484
  def __init__(self,
@@ -497,7 +539,8 @@ class Muon(torch.optim.Optimizer):
497
  "k_indices": [],
498
  "head_dim": 128,
499
  "threshold": 100
500
- }):
 
501
  defaults = dict(
502
  lr=lr,
503
  weight_decay=weight_decay,
@@ -521,15 +564,13 @@ class Muon(torch.optim.Optimizer):
521
 
522
  super().__init__(params, defaults)
523
 
524
- if dist.is_initialized():
525
- self.rank = dist.get_rank()
526
- else:
527
- self.rank = None
528
 
529
  self.comm_stream = torch.cuda.Stream()
530
  self.compute_stream = torch.cuda.Stream()
531
  self.debug = debug
532
  self.clip_config = clip_config
 
533
 
534
  def _calc_flops(self, G, steps):
535
  assert len(G.shape) == 2
@@ -602,7 +643,11 @@ class Muon(torch.optim.Optimizer):
602
  if mesh is None:
603
  mesh = p.device_mesh
604
  shard_mesh, process_group = self.get_shard_mesh(p, self.rank)
605
- self.rank = dist.get_rank(group=process_group)
 
 
 
 
606
  elif mesh != p.device_mesh:
607
  raise ValueError("All parameters must be on the same mesh.")
608
 
@@ -743,6 +788,8 @@ class Muon(torch.optim.Optimizer):
743
  param_to_state, ordered_params = self.init_state_and_assign_params(
744
  names, params, group, qk_logits)
745
 
 
 
746
  def enqueue_all2all_gather(start_idx, chunk_size):
747
  target_params = ordered_params[start_idx:start_idx + chunk_size]
748
  if target_params:
@@ -781,16 +828,16 @@ class Muon(torch.optim.Optimizer):
781
  # Wait grad update
782
  self.comm_stream.wait_stream(torch.cuda.current_stream())
783
 
784
- PRE_STEP = 5
785
- for i in range(0, PRE_STEP):
786
  enqueue_all2all_gather(i * chunk_size, chunk_size)
787
  enqueue_computes(i * chunk_size, chunk_size)
788
 
789
  for i in range(0, len(params) + chunk_size - 1, chunk_size):
790
  enqueue_all2all_scatter(i, chunk_size)
791
- enqueue_all2all_gather(i + PRE_STEP * chunk_size, chunk_size)
792
  enqueue_update_param(i, chunk_size)
793
- enqueue_computes(i + PRE_STEP * chunk_size, chunk_size)
794
 
795
  # Wait the last update_param to finish
796
  torch.cuda.current_stream().wait_stream(self.compute_stream)
 
73
  qk_clip_state = None
74
 
75
 
76
+ def split_elems_for_src(param, src_rank, num_ranks) -> int:
77
  rows = param.shape[0]
78
  cols = int(param.numel() // rows)
79
  base, rem = divmod(rows, num_ranks)
 
83
 
84
  @torch.no_grad()
85
  def _alloc_gathered_grad(params, param_to_state, rank, compute_stream):
86
+ """
87
+ Pre-allocate gathered_grad buffer on compute_stream
88
+ before launching all2all gather
89
+ """
90
  with torch.cuda.stream(compute_stream):
91
  for p in params:
92
  state = param_to_state[id(p)]
 
106
  @torch.no_grad()
107
  def _all2all_gather(params, param_to_state, rank, comm_stream, none_grad,
108
  alloc_event):
109
+ """
110
+ All2all gathers shards so each owner rank reconstructs its full gradient
111
+ """
112
  with torch.cuda.stream(comm_stream):
113
  process_group = param_to_state[id(params[0])].process_group
114
  num_ranks = dist.get_world_size(group=process_group)
115
 
116
+ # Construct sending buffers
117
  per_dst = [[] for _ in range(num_ranks)]
118
  send_counts = [0] * num_ranks
119
+
120
  for p in params:
121
  state = param_to_state[id(p)]
122
  dst = state.worker_rank
 
133
  for v in per_dst), "all params should be sharded to all devices"
134
 
135
  send_buf = torch.cat([torch.cat(v, dim=0) for v in per_dst], dim=0)
136
+ owned_params = [
137
  p for p in params if param_to_state[id(p)].worker_rank == rank
138
  ]
139
 
140
+ # Compute receive sizes and allocate receiving buffers
141
  recv_counts = [0] * num_ranks
142
+
143
  for src in range(num_ranks):
144
  total = 0
145
+ for p in owned_params:
146
  state = param_to_state[id(p)]
147
  assert state.worker_rank == rank
148
  total += split_elems_for_src(p, state, src, num_ranks)
 
150
 
151
  recv_total = sum(recv_counts)
152
  recv_buf = torch.empty(recv_total, dtype=COMM_DTYPE, device="cuda")
153
+
154
+ #All2All
155
  dist.all_to_all_single(
156
  recv_buf,
157
  send_buf,
 
176
  comm_stream.wait_event(alloc_event)
177
 
178
  off = 0
179
+ write_offsets = {id(p): 0 for p in owned_params}
180
  for src in range(num_ranks):
181
  if recv_counts[src] == 0:
182
  continue
183
 
184
  block = recv_counts[src]
185
  inner_off = 0
186
+ for p in owned_params:
187
  state = param_to_state[id(p)]
188
  assert state.worker_rank == rank
189
  n = split_elems_for_src(p, state, src, num_ranks)
 
233
 
234
  @torch.no_grad()
235
  def _alloc_scattered_u(params, param_to_state, rank, compute_stream):
236
+ """
237
+ Pre-allocate scattered_u buffer on compute_stream
238
+ before launching all2all gather
239
+ """
240
  with torch.cuda.stream(compute_stream):
241
  for p in params:
242
  state = param_to_state[id(p)]
 
249
 
250
 
251
  def _all2all_scatter(params, param_to_state, rank, comm_stream, alloc_event):
252
+ """
253
+ All2all scatters full gradients to all ranks
254
+ """
255
  with torch.cuda.stream(comm_stream):
256
  process_group = param_to_state[id(params[0])].process_group
257
  num_ranks = dist.get_world_size(group=process_group)
258
+ owned_params = [
259
  p for p in params if param_to_state[id(p)].worker_rank == rank
260
  ]
261
 
262
+ # Construct sending buffer
263
  per_dst = [[] for _ in range(num_ranks)]
264
  send_counts = [0] * num_ranks
265
 
266
+ if owned_params:
267
+ for p in owned_params:
268
  state = param_to_state[id(p)]
269
  if state.compute_event is None:
270
  raise RuntimeError(
 
295
  # Even non-owner ranks must join the collective call
296
  send_buf = torch.empty(0, dtype=COMM_DTYPE, device="cuda")
297
 
298
+ # Compute receive sizes and allocate receiving buffers
299
  recv_counts = [0] * num_ranks
300
+
301
  for src in range(num_ranks):
302
  total = 0
303
  for p in params:
 
311
  assert recv_total > 0
312
  recv_buf = torch.empty(recv_total, dtype=COMM_DTYPE, device="cuda")
313
 
314
+ #All2All
315
  dist.all_to_all_single(
316
  recv_buf,
317
  send_buf,
 
320
  group=process_group,
321
  )
322
 
323
+ # Copy to pre-allocated scattered_u buffer from the received buffer
324
+ #
325
+ # recv_buf (num ranks = 3, local_rank = 0)
326
+ #
327
+ # From rank 0 From rank 1 From rank 2
328
+ # | p1_0, p2_0, p3_0 | p4_0 | p5_0, p6_0 |
329
+ #
330
+ # Outer loop:
331
+ # rank 0 -> rank 1 -> rank2
332
+ #
333
+ # Inner loop:
334
+ # src(0) : p1_0 -> p2_0 -> p3_0
335
+ # src(1) : p4_0
336
+ # src(2) : p5_0 -> p6_0
337
+
338
  comm_stream.wait_event(alloc_event)
339
 
340
  off = 0
 
516
  "head_dim": 128,
517
  "threshold": 100
518
  }
519
+ overlap_step : How many all2all gather, compute operations are launched in advance
520
+ before the corresponding all2all scatter steps begin.
521
+ A higher overlap_step increases memory usage but can improve
522
+ performance by overlapping communication.
523
+ Parallel muon only.
524
  """
525
 
526
  def __init__(self,
 
539
  "k_indices": [],
540
  "head_dim": 128,
541
  "threshold": 100
542
+ },
543
+ overlap_step=5):
544
  defaults = dict(
545
  lr=lr,
546
  weight_decay=weight_decay,
 
564
 
565
  super().__init__(params, defaults)
566
 
567
+ self.rank = None
 
 
 
568
 
569
  self.comm_stream = torch.cuda.Stream()
570
  self.compute_stream = torch.cuda.Stream()
571
  self.debug = debug
572
  self.clip_config = clip_config
573
+ self.overlap_step = overlap_step
574
 
575
  def _calc_flops(self, G, steps):
576
  assert len(G.shape) == 2
 
643
  if mesh is None:
644
  mesh = p.device_mesh
645
  shard_mesh, process_group = self.get_shard_mesh(p, self.rank)
646
+ local_rank = dist.get_rank(group=process_group)
647
+ if self.rank is None:
648
+ self.rank = dist.get_rank(group=process_group)
649
+ else:
650
+ assert self.rank == local_rank
651
  elif mesh != p.device_mesh:
652
  raise ValueError("All parameters must be on the same mesh.")
653
 
 
788
  param_to_state, ordered_params = self.init_state_and_assign_params(
789
  names, params, group, qk_logits)
790
 
791
+ assert self.rank is not None
792
+
793
  def enqueue_all2all_gather(start_idx, chunk_size):
794
  target_params = ordered_params[start_idx:start_idx + chunk_size]
795
  if target_params:
 
828
  # Wait grad update
829
  self.comm_stream.wait_stream(torch.cuda.current_stream())
830
 
831
+ overlap_step = self.overlap_step
832
+ for i in range(0, overlap_step):
833
  enqueue_all2all_gather(i * chunk_size, chunk_size)
834
  enqueue_computes(i * chunk_size, chunk_size)
835
 
836
  for i in range(0, len(params) + chunk_size - 1, chunk_size):
837
  enqueue_all2all_scatter(i, chunk_size)
838
+ enqueue_all2all_gather(i + overlap_step * chunk_size, chunk_size)
839
  enqueue_update_param(i, chunk_size)
840
+ enqueue_computes(i + overlap_step * chunk_size, chunk_size)
841
 
842
  # Wait the last update_param to finish
843
  torch.cuda.current_stream().wait_stream(self.compute_stream)
build/torch28-cxx11-cu129-x86_64-linux/optimizer/_ops.py CHANGED
@@ -1,9 +1,9 @@
1
  import torch
2
- from . import _optimizer_37be0d0_dirty
3
- ops = torch.ops._optimizer_37be0d0_dirty
4
 
5
  def add_op_namespace_prefix(op_name: str):
6
  """
7
  Prefix op by namespace.
8
  """
9
- return f"_optimizer_37be0d0_dirty::{op_name}"
 
1
  import torch
2
+ from . import _optimizer_6943c45_dirty
3
+ ops = torch.ops._optimizer_6943c45_dirty
4
 
5
  def add_op_namespace_prefix(op_name: str):
6
  """
7
  Prefix op by namespace.
8
  """
9
+ return f"_optimizer_6943c45_dirty::{op_name}"
build/{torch27-cxx11-cu128-x86_64-linux/optimizer/_optimizer_37be0d0_dirty.abi3.so → torch28-cxx11-cu129-x86_64-linux/optimizer/_optimizer_6943c45_dirty.abi3.so} RENAMED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:af40fc0276d4e4c0e3e0908a6574ccbd06233f5ef2618160daaffd19a068ab3b
3
  size 1883344
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:6fc3515c8f7a60854606e596524c768196bd424219ff9fe80d1c69bfe2803bcd
3
  size 1883344
build/torch28-cxx11-cu129-x86_64-linux/optimizer/muon.py CHANGED
@@ -73,7 +73,7 @@ class _muon_state:
73
  qk_clip_state = None
74
 
75
 
76
- def split_elems_for_src(param, state, src_rank, num_ranks) -> int:
77
  rows = param.shape[0]
78
  cols = int(param.numel() // rows)
79
  base, rem = divmod(rows, num_ranks)
@@ -83,6 +83,10 @@ def split_elems_for_src(param, state, src_rank, num_ranks) -> int:
83
 
84
  @torch.no_grad()
85
  def _alloc_gathered_grad(params, param_to_state, rank, compute_stream):
 
 
 
 
86
  with torch.cuda.stream(compute_stream):
87
  for p in params:
88
  state = param_to_state[id(p)]
@@ -102,13 +106,17 @@ def _alloc_gathered_grad(params, param_to_state, rank, compute_stream):
102
  @torch.no_grad()
103
  def _all2all_gather(params, param_to_state, rank, comm_stream, none_grad,
104
  alloc_event):
 
 
 
105
  with torch.cuda.stream(comm_stream):
106
  process_group = param_to_state[id(params[0])].process_group
107
  num_ranks = dist.get_world_size(group=process_group)
108
 
109
- # Calculate sending tensors
110
  per_dst = [[] for _ in range(num_ranks)]
111
  send_counts = [0] * num_ranks
 
112
  for p in params:
113
  state = param_to_state[id(p)]
114
  dst = state.worker_rank
@@ -125,15 +133,16 @@ def _all2all_gather(params, param_to_state, rank, comm_stream, none_grad,
125
  for v in per_dst), "all params should be sharded to all devices"
126
 
127
  send_buf = torch.cat([torch.cat(v, dim=0) for v in per_dst], dim=0)
128
- owner_params = [
129
  p for p in params if param_to_state[id(p)].worker_rank == rank
130
  ]
131
 
132
- # Calculate receiving tensors
133
  recv_counts = [0] * num_ranks
 
134
  for src in range(num_ranks):
135
  total = 0
136
- for p in owner_params:
137
  state = param_to_state[id(p)]
138
  assert state.worker_rank == rank
139
  total += split_elems_for_src(p, state, src, num_ranks)
@@ -141,6 +150,8 @@ def _all2all_gather(params, param_to_state, rank, comm_stream, none_grad,
141
 
142
  recv_total = sum(recv_counts)
143
  recv_buf = torch.empty(recv_total, dtype=COMM_DTYPE, device="cuda")
 
 
144
  dist.all_to_all_single(
145
  recv_buf,
146
  send_buf,
@@ -165,14 +176,14 @@ def _all2all_gather(params, param_to_state, rank, comm_stream, none_grad,
165
  comm_stream.wait_event(alloc_event)
166
 
167
  off = 0
168
- write_offsets = {id(p): 0 for p in owner_params}
169
  for src in range(num_ranks):
170
  if recv_counts[src] == 0:
171
  continue
172
 
173
  block = recv_counts[src]
174
  inner_off = 0
175
- for p in owner_params:
176
  state = param_to_state[id(p)]
177
  assert state.worker_rank == rank
178
  n = split_elems_for_src(p, state, src, num_ranks)
@@ -222,6 +233,10 @@ def _compute_u(p, state, steps, rank, compute_stream):
222
 
223
  @torch.no_grad()
224
  def _alloc_scattered_u(params, param_to_state, rank, compute_stream):
 
 
 
 
225
  with torch.cuda.stream(compute_stream):
226
  for p in params:
227
  state = param_to_state[id(p)]
@@ -234,18 +249,22 @@ def _alloc_scattered_u(params, param_to_state, rank, compute_stream):
234
 
235
 
236
  def _all2all_scatter(params, param_to_state, rank, comm_stream, alloc_event):
 
 
 
237
  with torch.cuda.stream(comm_stream):
238
  process_group = param_to_state[id(params[0])].process_group
239
  num_ranks = dist.get_world_size(group=process_group)
240
- owner_params = [
241
  p for p in params if param_to_state[id(p)].worker_rank == rank
242
  ]
243
 
 
244
  per_dst = [[] for _ in range(num_ranks)]
245
  send_counts = [0] * num_ranks
246
 
247
- if owner_params:
248
- for p in owner_params:
249
  state = param_to_state[id(p)]
250
  if state.compute_event is None:
251
  raise RuntimeError(
@@ -276,7 +295,9 @@ def _all2all_scatter(params, param_to_state, rank, comm_stream, alloc_event):
276
  # Even non-owner ranks must join the collective call
277
  send_buf = torch.empty(0, dtype=COMM_DTYPE, device="cuda")
278
 
 
279
  recv_counts = [0] * num_ranks
 
280
  for src in range(num_ranks):
281
  total = 0
282
  for p in params:
@@ -290,6 +311,7 @@ def _all2all_scatter(params, param_to_state, rank, comm_stream, alloc_event):
290
  assert recv_total > 0
291
  recv_buf = torch.empty(recv_total, dtype=COMM_DTYPE, device="cuda")
292
 
 
293
  dist.all_to_all_single(
294
  recv_buf,
295
  send_buf,
@@ -298,6 +320,21 @@ def _all2all_scatter(params, param_to_state, rank, comm_stream, alloc_event):
298
  group=process_group,
299
  )
300
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
301
  comm_stream.wait_event(alloc_event)
302
 
303
  off = 0
@@ -479,6 +516,11 @@ class Muon(torch.optim.Optimizer):
479
  "head_dim": 128,
480
  "threshold": 100
481
  }
 
 
 
 
 
482
  """
483
 
484
  def __init__(self,
@@ -497,7 +539,8 @@ class Muon(torch.optim.Optimizer):
497
  "k_indices": [],
498
  "head_dim": 128,
499
  "threshold": 100
500
- }):
 
501
  defaults = dict(
502
  lr=lr,
503
  weight_decay=weight_decay,
@@ -521,15 +564,13 @@ class Muon(torch.optim.Optimizer):
521
 
522
  super().__init__(params, defaults)
523
 
524
- if dist.is_initialized():
525
- self.rank = dist.get_rank()
526
- else:
527
- self.rank = None
528
 
529
  self.comm_stream = torch.cuda.Stream()
530
  self.compute_stream = torch.cuda.Stream()
531
  self.debug = debug
532
  self.clip_config = clip_config
 
533
 
534
  def _calc_flops(self, G, steps):
535
  assert len(G.shape) == 2
@@ -602,7 +643,11 @@ class Muon(torch.optim.Optimizer):
602
  if mesh is None:
603
  mesh = p.device_mesh
604
  shard_mesh, process_group = self.get_shard_mesh(p, self.rank)
605
- self.rank = dist.get_rank(group=process_group)
 
 
 
 
606
  elif mesh != p.device_mesh:
607
  raise ValueError("All parameters must be on the same mesh.")
608
 
@@ -743,6 +788,8 @@ class Muon(torch.optim.Optimizer):
743
  param_to_state, ordered_params = self.init_state_and_assign_params(
744
  names, params, group, qk_logits)
745
 
 
 
746
  def enqueue_all2all_gather(start_idx, chunk_size):
747
  target_params = ordered_params[start_idx:start_idx + chunk_size]
748
  if target_params:
@@ -781,16 +828,16 @@ class Muon(torch.optim.Optimizer):
781
  # Wait grad update
782
  self.comm_stream.wait_stream(torch.cuda.current_stream())
783
 
784
- PRE_STEP = 5
785
- for i in range(0, PRE_STEP):
786
  enqueue_all2all_gather(i * chunk_size, chunk_size)
787
  enqueue_computes(i * chunk_size, chunk_size)
788
 
789
  for i in range(0, len(params) + chunk_size - 1, chunk_size):
790
  enqueue_all2all_scatter(i, chunk_size)
791
- enqueue_all2all_gather(i + PRE_STEP * chunk_size, chunk_size)
792
  enqueue_update_param(i, chunk_size)
793
- enqueue_computes(i + PRE_STEP * chunk_size, chunk_size)
794
 
795
  # Wait the last update_param to finish
796
  torch.cuda.current_stream().wait_stream(self.compute_stream)
 
73
  qk_clip_state = None
74
 
75
 
76
+ def split_elems_for_src(param, src_rank, num_ranks) -> int:
77
  rows = param.shape[0]
78
  cols = int(param.numel() // rows)
79
  base, rem = divmod(rows, num_ranks)
 
83
 
84
  @torch.no_grad()
85
  def _alloc_gathered_grad(params, param_to_state, rank, compute_stream):
86
+ """
87
+ Pre-allocate gathered_grad buffer on compute_stream
88
+ before launching all2all gather
89
+ """
90
  with torch.cuda.stream(compute_stream):
91
  for p in params:
92
  state = param_to_state[id(p)]
 
106
  @torch.no_grad()
107
  def _all2all_gather(params, param_to_state, rank, comm_stream, none_grad,
108
  alloc_event):
109
+ """
110
+ All2all gathers shards so each owner rank reconstructs its full gradient
111
+ """
112
  with torch.cuda.stream(comm_stream):
113
  process_group = param_to_state[id(params[0])].process_group
114
  num_ranks = dist.get_world_size(group=process_group)
115
 
116
+ # Construct sending buffers
117
  per_dst = [[] for _ in range(num_ranks)]
118
  send_counts = [0] * num_ranks
119
+
120
  for p in params:
121
  state = param_to_state[id(p)]
122
  dst = state.worker_rank
 
133
  for v in per_dst), "all params should be sharded to all devices"
134
 
135
  send_buf = torch.cat([torch.cat(v, dim=0) for v in per_dst], dim=0)
136
+ owned_params = [
137
  p for p in params if param_to_state[id(p)].worker_rank == rank
138
  ]
139
 
140
+ # Compute receive sizes and allocate receiving buffers
141
  recv_counts = [0] * num_ranks
142
+
143
  for src in range(num_ranks):
144
  total = 0
145
+ for p in owned_params:
146
  state = param_to_state[id(p)]
147
  assert state.worker_rank == rank
148
  total += split_elems_for_src(p, state, src, num_ranks)
 
150
 
151
  recv_total = sum(recv_counts)
152
  recv_buf = torch.empty(recv_total, dtype=COMM_DTYPE, device="cuda")
153
+
154
+ #All2All
155
  dist.all_to_all_single(
156
  recv_buf,
157
  send_buf,
 
176
  comm_stream.wait_event(alloc_event)
177
 
178
  off = 0
179
+ write_offsets = {id(p): 0 for p in owned_params}
180
  for src in range(num_ranks):
181
  if recv_counts[src] == 0:
182
  continue
183
 
184
  block = recv_counts[src]
185
  inner_off = 0
186
+ for p in owned_params:
187
  state = param_to_state[id(p)]
188
  assert state.worker_rank == rank
189
  n = split_elems_for_src(p, state, src, num_ranks)
 
233
 
234
  @torch.no_grad()
235
  def _alloc_scattered_u(params, param_to_state, rank, compute_stream):
236
+ """
237
+ Pre-allocate scattered_u buffer on compute_stream
238
+ before launching all2all gather
239
+ """
240
  with torch.cuda.stream(compute_stream):
241
  for p in params:
242
  state = param_to_state[id(p)]
 
249
 
250
 
251
  def _all2all_scatter(params, param_to_state, rank, comm_stream, alloc_event):
252
+ """
253
+ All2all scatters full gradients to all ranks
254
+ """
255
  with torch.cuda.stream(comm_stream):
256
  process_group = param_to_state[id(params[0])].process_group
257
  num_ranks = dist.get_world_size(group=process_group)
258
+ owned_params = [
259
  p for p in params if param_to_state[id(p)].worker_rank == rank
260
  ]
261
 
262
+ # Construct sending buffer
263
  per_dst = [[] for _ in range(num_ranks)]
264
  send_counts = [0] * num_ranks
265
 
266
+ if owned_params:
267
+ for p in owned_params:
268
  state = param_to_state[id(p)]
269
  if state.compute_event is None:
270
  raise RuntimeError(
 
295
  # Even non-owner ranks must join the collective call
296
  send_buf = torch.empty(0, dtype=COMM_DTYPE, device="cuda")
297
 
298
+ # Compute receive sizes and allocate receiving buffers
299
  recv_counts = [0] * num_ranks
300
+
301
  for src in range(num_ranks):
302
  total = 0
303
  for p in params:
 
311
  assert recv_total > 0
312
  recv_buf = torch.empty(recv_total, dtype=COMM_DTYPE, device="cuda")
313
 
314
+ #All2All
315
  dist.all_to_all_single(
316
  recv_buf,
317
  send_buf,
 
320
  group=process_group,
321
  )
322
 
323
+ # Copy to pre-allocated scattered_u buffer from the received buffer
324
+ #
325
+ # recv_buf (num ranks = 3, local_rank = 0)
326
+ #
327
+ # From rank 0 From rank 1 From rank 2
328
+ # | p1_0, p2_0, p3_0 | p4_0 | p5_0, p6_0 |
329
+ #
330
+ # Outer loop:
331
+ # rank 0 -> rank 1 -> rank2
332
+ #
333
+ # Inner loop:
334
+ # src(0) : p1_0 -> p2_0 -> p3_0
335
+ # src(1) : p4_0
336
+ # src(2) : p5_0 -> p6_0
337
+
338
  comm_stream.wait_event(alloc_event)
339
 
340
  off = 0
 
516
  "head_dim": 128,
517
  "threshold": 100
518
  }
519
+ overlap_step : How many all2all gather, compute operations are launched in advance
520
+ before the corresponding all2all scatter steps begin.
521
+ A higher overlap_step increases memory usage but can improve
522
+ performance by overlapping communication.
523
+ Parallel muon only.
524
  """
525
 
526
  def __init__(self,
 
539
  "k_indices": [],
540
  "head_dim": 128,
541
  "threshold": 100
542
+ },
543
+ overlap_step=5):
544
  defaults = dict(
545
  lr=lr,
546
  weight_decay=weight_decay,
 
564
 
565
  super().__init__(params, defaults)
566
 
567
+ self.rank = None
 
 
 
568
 
569
  self.comm_stream = torch.cuda.Stream()
570
  self.compute_stream = torch.cuda.Stream()
571
  self.debug = debug
572
  self.clip_config = clip_config
573
+ self.overlap_step = overlap_step
574
 
575
  def _calc_flops(self, G, steps):
576
  assert len(G.shape) == 2
 
643
  if mesh is None:
644
  mesh = p.device_mesh
645
  shard_mesh, process_group = self.get_shard_mesh(p, self.rank)
646
+ local_rank = dist.get_rank(group=process_group)
647
+ if self.rank is None:
648
+ self.rank = dist.get_rank(group=process_group)
649
+ else:
650
+ assert self.rank == local_rank
651
  elif mesh != p.device_mesh:
652
  raise ValueError("All parameters must be on the same mesh.")
653
 
 
788
  param_to_state, ordered_params = self.init_state_and_assign_params(
789
  names, params, group, qk_logits)
790
 
791
+ assert self.rank is not None
792
+
793
  def enqueue_all2all_gather(start_idx, chunk_size):
794
  target_params = ordered_params[start_idx:start_idx + chunk_size]
795
  if target_params:
 
828
  # Wait grad update
829
  self.comm_stream.wait_stream(torch.cuda.current_stream())
830
 
831
+ overlap_step = self.overlap_step
832
+ for i in range(0, overlap_step):
833
  enqueue_all2all_gather(i * chunk_size, chunk_size)
834
  enqueue_computes(i * chunk_size, chunk_size)
835
 
836
  for i in range(0, len(params) + chunk_size - 1, chunk_size):
837
  enqueue_all2all_scatter(i, chunk_size)
838
+ enqueue_all2all_gather(i + overlap_step * chunk_size, chunk_size)
839
  enqueue_update_param(i, chunk_size)
840
+ enqueue_computes(i + overlap_step * chunk_size, chunk_size)
841
 
842
  # Wait the last update_param to finish
843
  torch.cuda.current_stream().wait_stream(self.compute_stream)
build/torch28-cxx11-rocm63-x86_64-linux/optimizer/_ops.py CHANGED
@@ -1,9 +1,9 @@
1
  import torch
2
- from . import _optimizer_37be0d0_dirty
3
- ops = torch.ops._optimizer_37be0d0_dirty
4
 
5
  def add_op_namespace_prefix(op_name: str):
6
  """
7
  Prefix op by namespace.
8
  """
9
- return f"_optimizer_37be0d0_dirty::{op_name}"
 
1
  import torch
2
+ from . import _optimizer_6943c45_dirty
3
+ ops = torch.ops._optimizer_6943c45_dirty
4
 
5
  def add_op_namespace_prefix(op_name: str):
6
  """
7
  Prefix op by namespace.
8
  """
9
+ return f"_optimizer_6943c45_dirty::{op_name}"
build/torch28-cxx11-rocm63-x86_64-linux/optimizer/{_optimizer_37be0d0_dirty.abi3.so → _optimizer_6943c45_dirty.abi3.so} RENAMED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:0319a66c40de59e7e9216cf5c76962bb152cbab063a3993058400a27eeb13cc8
3
  size 1749936
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:d572269f12f1092080e5efeb914e5cb18bbe491d3561ab077016eaec2be7fe55
3
  size 1749936
build/torch28-cxx11-rocm63-x86_64-linux/optimizer/muon.py CHANGED
@@ -73,7 +73,7 @@ class _muon_state:
73
  qk_clip_state = None
74
 
75
 
76
- def split_elems_for_src(param, state, src_rank, num_ranks) -> int:
77
  rows = param.shape[0]
78
  cols = int(param.numel() // rows)
79
  base, rem = divmod(rows, num_ranks)
@@ -83,6 +83,10 @@ def split_elems_for_src(param, state, src_rank, num_ranks) -> int:
83
 
84
  @torch.no_grad()
85
  def _alloc_gathered_grad(params, param_to_state, rank, compute_stream):
 
 
 
 
86
  with torch.cuda.stream(compute_stream):
87
  for p in params:
88
  state = param_to_state[id(p)]
@@ -102,13 +106,17 @@ def _alloc_gathered_grad(params, param_to_state, rank, compute_stream):
102
  @torch.no_grad()
103
  def _all2all_gather(params, param_to_state, rank, comm_stream, none_grad,
104
  alloc_event):
 
 
 
105
  with torch.cuda.stream(comm_stream):
106
  process_group = param_to_state[id(params[0])].process_group
107
  num_ranks = dist.get_world_size(group=process_group)
108
 
109
- # Calculate sending tensors
110
  per_dst = [[] for _ in range(num_ranks)]
111
  send_counts = [0] * num_ranks
 
112
  for p in params:
113
  state = param_to_state[id(p)]
114
  dst = state.worker_rank
@@ -125,15 +133,16 @@ def _all2all_gather(params, param_to_state, rank, comm_stream, none_grad,
125
  for v in per_dst), "all params should be sharded to all devices"
126
 
127
  send_buf = torch.cat([torch.cat(v, dim=0) for v in per_dst], dim=0)
128
- owner_params = [
129
  p for p in params if param_to_state[id(p)].worker_rank == rank
130
  ]
131
 
132
- # Calculate receiving tensors
133
  recv_counts = [0] * num_ranks
 
134
  for src in range(num_ranks):
135
  total = 0
136
- for p in owner_params:
137
  state = param_to_state[id(p)]
138
  assert state.worker_rank == rank
139
  total += split_elems_for_src(p, state, src, num_ranks)
@@ -141,6 +150,8 @@ def _all2all_gather(params, param_to_state, rank, comm_stream, none_grad,
141
 
142
  recv_total = sum(recv_counts)
143
  recv_buf = torch.empty(recv_total, dtype=COMM_DTYPE, device="cuda")
 
 
144
  dist.all_to_all_single(
145
  recv_buf,
146
  send_buf,
@@ -165,14 +176,14 @@ def _all2all_gather(params, param_to_state, rank, comm_stream, none_grad,
165
  comm_stream.wait_event(alloc_event)
166
 
167
  off = 0
168
- write_offsets = {id(p): 0 for p in owner_params}
169
  for src in range(num_ranks):
170
  if recv_counts[src] == 0:
171
  continue
172
 
173
  block = recv_counts[src]
174
  inner_off = 0
175
- for p in owner_params:
176
  state = param_to_state[id(p)]
177
  assert state.worker_rank == rank
178
  n = split_elems_for_src(p, state, src, num_ranks)
@@ -222,6 +233,10 @@ def _compute_u(p, state, steps, rank, compute_stream):
222
 
223
  @torch.no_grad()
224
  def _alloc_scattered_u(params, param_to_state, rank, compute_stream):
 
 
 
 
225
  with torch.cuda.stream(compute_stream):
226
  for p in params:
227
  state = param_to_state[id(p)]
@@ -234,18 +249,22 @@ def _alloc_scattered_u(params, param_to_state, rank, compute_stream):
234
 
235
 
236
  def _all2all_scatter(params, param_to_state, rank, comm_stream, alloc_event):
 
 
 
237
  with torch.cuda.stream(comm_stream):
238
  process_group = param_to_state[id(params[0])].process_group
239
  num_ranks = dist.get_world_size(group=process_group)
240
- owner_params = [
241
  p for p in params if param_to_state[id(p)].worker_rank == rank
242
  ]
243
 
 
244
  per_dst = [[] for _ in range(num_ranks)]
245
  send_counts = [0] * num_ranks
246
 
247
- if owner_params:
248
- for p in owner_params:
249
  state = param_to_state[id(p)]
250
  if state.compute_event is None:
251
  raise RuntimeError(
@@ -276,7 +295,9 @@ def _all2all_scatter(params, param_to_state, rank, comm_stream, alloc_event):
276
  # Even non-owner ranks must join the collective call
277
  send_buf = torch.empty(0, dtype=COMM_DTYPE, device="cuda")
278
 
 
279
  recv_counts = [0] * num_ranks
 
280
  for src in range(num_ranks):
281
  total = 0
282
  for p in params:
@@ -290,6 +311,7 @@ def _all2all_scatter(params, param_to_state, rank, comm_stream, alloc_event):
290
  assert recv_total > 0
291
  recv_buf = torch.empty(recv_total, dtype=COMM_DTYPE, device="cuda")
292
 
 
293
  dist.all_to_all_single(
294
  recv_buf,
295
  send_buf,
@@ -298,6 +320,21 @@ def _all2all_scatter(params, param_to_state, rank, comm_stream, alloc_event):
298
  group=process_group,
299
  )
300
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
301
  comm_stream.wait_event(alloc_event)
302
 
303
  off = 0
@@ -479,6 +516,11 @@ class Muon(torch.optim.Optimizer):
479
  "head_dim": 128,
480
  "threshold": 100
481
  }
 
 
 
 
 
482
  """
483
 
484
  def __init__(self,
@@ -497,7 +539,8 @@ class Muon(torch.optim.Optimizer):
497
  "k_indices": [],
498
  "head_dim": 128,
499
  "threshold": 100
500
- }):
 
501
  defaults = dict(
502
  lr=lr,
503
  weight_decay=weight_decay,
@@ -521,15 +564,13 @@ class Muon(torch.optim.Optimizer):
521
 
522
  super().__init__(params, defaults)
523
 
524
- if dist.is_initialized():
525
- self.rank = dist.get_rank()
526
- else:
527
- self.rank = None
528
 
529
  self.comm_stream = torch.cuda.Stream()
530
  self.compute_stream = torch.cuda.Stream()
531
  self.debug = debug
532
  self.clip_config = clip_config
 
533
 
534
  def _calc_flops(self, G, steps):
535
  assert len(G.shape) == 2
@@ -602,7 +643,11 @@ class Muon(torch.optim.Optimizer):
602
  if mesh is None:
603
  mesh = p.device_mesh
604
  shard_mesh, process_group = self.get_shard_mesh(p, self.rank)
605
- self.rank = dist.get_rank(group=process_group)
 
 
 
 
606
  elif mesh != p.device_mesh:
607
  raise ValueError("All parameters must be on the same mesh.")
608
 
@@ -743,6 +788,8 @@ class Muon(torch.optim.Optimizer):
743
  param_to_state, ordered_params = self.init_state_and_assign_params(
744
  names, params, group, qk_logits)
745
 
 
 
746
  def enqueue_all2all_gather(start_idx, chunk_size):
747
  target_params = ordered_params[start_idx:start_idx + chunk_size]
748
  if target_params:
@@ -781,16 +828,16 @@ class Muon(torch.optim.Optimizer):
781
  # Wait grad update
782
  self.comm_stream.wait_stream(torch.cuda.current_stream())
783
 
784
- PRE_STEP = 5
785
- for i in range(0, PRE_STEP):
786
  enqueue_all2all_gather(i * chunk_size, chunk_size)
787
  enqueue_computes(i * chunk_size, chunk_size)
788
 
789
  for i in range(0, len(params) + chunk_size - 1, chunk_size):
790
  enqueue_all2all_scatter(i, chunk_size)
791
- enqueue_all2all_gather(i + PRE_STEP * chunk_size, chunk_size)
792
  enqueue_update_param(i, chunk_size)
793
- enqueue_computes(i + PRE_STEP * chunk_size, chunk_size)
794
 
795
  # Wait the last update_param to finish
796
  torch.cuda.current_stream().wait_stream(self.compute_stream)
 
73
  qk_clip_state = None
74
 
75
 
76
+ def split_elems_for_src(param, src_rank, num_ranks) -> int:
77
  rows = param.shape[0]
78
  cols = int(param.numel() // rows)
79
  base, rem = divmod(rows, num_ranks)
 
83
 
84
  @torch.no_grad()
85
  def _alloc_gathered_grad(params, param_to_state, rank, compute_stream):
86
+ """
87
+ Pre-allocate gathered_grad buffer on compute_stream
88
+ before launching all2all gather
89
+ """
90
  with torch.cuda.stream(compute_stream):
91
  for p in params:
92
  state = param_to_state[id(p)]
 
106
  @torch.no_grad()
107
  def _all2all_gather(params, param_to_state, rank, comm_stream, none_grad,
108
  alloc_event):
109
+ """
110
+ All2all gathers shards so each owner rank reconstructs its full gradient
111
+ """
112
  with torch.cuda.stream(comm_stream):
113
  process_group = param_to_state[id(params[0])].process_group
114
  num_ranks = dist.get_world_size(group=process_group)
115
 
116
+ # Construct sending buffers
117
  per_dst = [[] for _ in range(num_ranks)]
118
  send_counts = [0] * num_ranks
119
+
120
  for p in params:
121
  state = param_to_state[id(p)]
122
  dst = state.worker_rank
 
133
  for v in per_dst), "all params should be sharded to all devices"
134
 
135
  send_buf = torch.cat([torch.cat(v, dim=0) for v in per_dst], dim=0)
136
+ owned_params = [
137
  p for p in params if param_to_state[id(p)].worker_rank == rank
138
  ]
139
 
140
+ # Compute receive sizes and allocate receiving buffers
141
  recv_counts = [0] * num_ranks
142
+
143
  for src in range(num_ranks):
144
  total = 0
145
+ for p in owned_params:
146
  state = param_to_state[id(p)]
147
  assert state.worker_rank == rank
148
  total += split_elems_for_src(p, state, src, num_ranks)
 
150
 
151
  recv_total = sum(recv_counts)
152
  recv_buf = torch.empty(recv_total, dtype=COMM_DTYPE, device="cuda")
153
+
154
+ #All2All
155
  dist.all_to_all_single(
156
  recv_buf,
157
  send_buf,
 
176
  comm_stream.wait_event(alloc_event)
177
 
178
  off = 0
179
+ write_offsets = {id(p): 0 for p in owned_params}
180
  for src in range(num_ranks):
181
  if recv_counts[src] == 0:
182
  continue
183
 
184
  block = recv_counts[src]
185
  inner_off = 0
186
+ for p in owned_params:
187
  state = param_to_state[id(p)]
188
  assert state.worker_rank == rank
189
  n = split_elems_for_src(p, state, src, num_ranks)
 
233
 
234
  @torch.no_grad()
235
  def _alloc_scattered_u(params, param_to_state, rank, compute_stream):
236
+ """
237
+ Pre-allocate scattered_u buffer on compute_stream
238
+ before launching all2all gather
239
+ """
240
  with torch.cuda.stream(compute_stream):
241
  for p in params:
242
  state = param_to_state[id(p)]
 
249
 
250
 
251
  def _all2all_scatter(params, param_to_state, rank, comm_stream, alloc_event):
252
+ """
253
+ All2all scatters full gradients to all ranks
254
+ """
255
  with torch.cuda.stream(comm_stream):
256
  process_group = param_to_state[id(params[0])].process_group
257
  num_ranks = dist.get_world_size(group=process_group)
258
+ owned_params = [
259
  p for p in params if param_to_state[id(p)].worker_rank == rank
260
  ]
261
 
262
+ # Construct sending buffer
263
  per_dst = [[] for _ in range(num_ranks)]
264
  send_counts = [0] * num_ranks
265
 
266
+ if owned_params:
267
+ for p in owned_params:
268
  state = param_to_state[id(p)]
269
  if state.compute_event is None:
270
  raise RuntimeError(
 
295
  # Even non-owner ranks must join the collective call
296
  send_buf = torch.empty(0, dtype=COMM_DTYPE, device="cuda")
297
 
298
+ # Compute receive sizes and allocate receiving buffers
299
  recv_counts = [0] * num_ranks
300
+
301
  for src in range(num_ranks):
302
  total = 0
303
  for p in params:
 
311
  assert recv_total > 0
312
  recv_buf = torch.empty(recv_total, dtype=COMM_DTYPE, device="cuda")
313
 
314
+ #All2All
315
  dist.all_to_all_single(
316
  recv_buf,
317
  send_buf,
 
320
  group=process_group,
321
  )
322
 
323
+ # Copy to pre-allocated scattered_u buffer from the received buffer
324
+ #
325
+ # recv_buf (num ranks = 3, local_rank = 0)
326
+ #
327
+ # From rank 0 From rank 1 From rank 2
328
+ # | p1_0, p2_0, p3_0 | p4_0 | p5_0, p6_0 |
329
+ #
330
+ # Outer loop:
331
+ # rank 0 -> rank 1 -> rank2
332
+ #
333
+ # Inner loop:
334
+ # src(0) : p1_0 -> p2_0 -> p3_0
335
+ # src(1) : p4_0
336
+ # src(2) : p5_0 -> p6_0
337
+
338
  comm_stream.wait_event(alloc_event)
339
 
340
  off = 0
 
516
  "head_dim": 128,
517
  "threshold": 100
518
  }
519
+ overlap_step : How many all2all gather, compute operations are launched in advance
520
+ before the corresponding all2all scatter steps begin.
521
+ A higher overlap_step increases memory usage but can improve
522
+ performance by overlapping communication.
523
+ Parallel muon only.
524
  """
525
 
526
  def __init__(self,
 
539
  "k_indices": [],
540
  "head_dim": 128,
541
  "threshold": 100
542
+ },
543
+ overlap_step=5):
544
  defaults = dict(
545
  lr=lr,
546
  weight_decay=weight_decay,
 
564
 
565
  super().__init__(params, defaults)
566
 
567
+ self.rank = None
 
 
 
568
 
569
  self.comm_stream = torch.cuda.Stream()
570
  self.compute_stream = torch.cuda.Stream()
571
  self.debug = debug
572
  self.clip_config = clip_config
573
+ self.overlap_step = overlap_step
574
 
575
  def _calc_flops(self, G, steps):
576
  assert len(G.shape) == 2
 
643
  if mesh is None:
644
  mesh = p.device_mesh
645
  shard_mesh, process_group = self.get_shard_mesh(p, self.rank)
646
+ local_rank = dist.get_rank(group=process_group)
647
+ if self.rank is None:
648
+ self.rank = dist.get_rank(group=process_group)
649
+ else:
650
+ assert self.rank == local_rank
651
  elif mesh != p.device_mesh:
652
  raise ValueError("All parameters must be on the same mesh.")
653
 
 
788
  param_to_state, ordered_params = self.init_state_and_assign_params(
789
  names, params, group, qk_logits)
790
 
791
+ assert self.rank is not None
792
+
793
  def enqueue_all2all_gather(start_idx, chunk_size):
794
  target_params = ordered_params[start_idx:start_idx + chunk_size]
795
  if target_params:
 
828
  # Wait grad update
829
  self.comm_stream.wait_stream(torch.cuda.current_stream())
830
 
831
+ overlap_step = self.overlap_step
832
+ for i in range(0, overlap_step):
833
  enqueue_all2all_gather(i * chunk_size, chunk_size)
834
  enqueue_computes(i * chunk_size, chunk_size)
835
 
836
  for i in range(0, len(params) + chunk_size - 1, chunk_size):
837
  enqueue_all2all_scatter(i, chunk_size)
838
+ enqueue_all2all_gather(i + overlap_step * chunk_size, chunk_size)
839
  enqueue_update_param(i, chunk_size)
840
+ enqueue_computes(i + overlap_step * chunk_size, chunk_size)
841
 
842
  # Wait the last update_param to finish
843
  torch.cuda.current_stream().wait_stream(self.compute_stream)
build/torch28-cxx11-rocm64-x86_64-linux/optimizer/_ops.py CHANGED
@@ -1,9 +1,9 @@
1
  import torch
2
- from . import _optimizer_37be0d0_dirty
3
- ops = torch.ops._optimizer_37be0d0_dirty
4
 
5
  def add_op_namespace_prefix(op_name: str):
6
  """
7
  Prefix op by namespace.
8
  """
9
- return f"_optimizer_37be0d0_dirty::{op_name}"
 
1
  import torch
2
+ from . import _optimizer_6943c45_dirty
3
+ ops = torch.ops._optimizer_6943c45_dirty
4
 
5
  def add_op_namespace_prefix(op_name: str):
6
  """
7
  Prefix op by namespace.
8
  """
9
+ return f"_optimizer_6943c45_dirty::{op_name}"
build/torch28-cxx11-rocm64-x86_64-linux/optimizer/{_optimizer_37be0d0_dirty.abi3.so → _optimizer_6943c45_dirty.abi3.so} RENAMED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:88f4b7caa9e13481a51ec93422477854ab460b2197c6b469ebe6d6cb8f81ddf5
3
  size 1750024
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:76ab2b9f9b47115d3ec6fbef5863bd80f3673a95ddf404ae03d8e516c3e3167a
3
  size 1750024
build/torch28-cxx11-rocm64-x86_64-linux/optimizer/muon.py CHANGED
@@ -73,7 +73,7 @@ class _muon_state:
73
  qk_clip_state = None
74
 
75
 
76
- def split_elems_for_src(param, state, src_rank, num_ranks) -> int:
77
  rows = param.shape[0]
78
  cols = int(param.numel() // rows)
79
  base, rem = divmod(rows, num_ranks)
@@ -83,6 +83,10 @@ def split_elems_for_src(param, state, src_rank, num_ranks) -> int:
83
 
84
  @torch.no_grad()
85
  def _alloc_gathered_grad(params, param_to_state, rank, compute_stream):
 
 
 
 
86
  with torch.cuda.stream(compute_stream):
87
  for p in params:
88
  state = param_to_state[id(p)]
@@ -102,13 +106,17 @@ def _alloc_gathered_grad(params, param_to_state, rank, compute_stream):
102
  @torch.no_grad()
103
  def _all2all_gather(params, param_to_state, rank, comm_stream, none_grad,
104
  alloc_event):
 
 
 
105
  with torch.cuda.stream(comm_stream):
106
  process_group = param_to_state[id(params[0])].process_group
107
  num_ranks = dist.get_world_size(group=process_group)
108
 
109
- # Calculate sending tensors
110
  per_dst = [[] for _ in range(num_ranks)]
111
  send_counts = [0] * num_ranks
 
112
  for p in params:
113
  state = param_to_state[id(p)]
114
  dst = state.worker_rank
@@ -125,15 +133,16 @@ def _all2all_gather(params, param_to_state, rank, comm_stream, none_grad,
125
  for v in per_dst), "all params should be sharded to all devices"
126
 
127
  send_buf = torch.cat([torch.cat(v, dim=0) for v in per_dst], dim=0)
128
- owner_params = [
129
  p for p in params if param_to_state[id(p)].worker_rank == rank
130
  ]
131
 
132
- # Calculate receiving tensors
133
  recv_counts = [0] * num_ranks
 
134
  for src in range(num_ranks):
135
  total = 0
136
- for p in owner_params:
137
  state = param_to_state[id(p)]
138
  assert state.worker_rank == rank
139
  total += split_elems_for_src(p, state, src, num_ranks)
@@ -141,6 +150,8 @@ def _all2all_gather(params, param_to_state, rank, comm_stream, none_grad,
141
 
142
  recv_total = sum(recv_counts)
143
  recv_buf = torch.empty(recv_total, dtype=COMM_DTYPE, device="cuda")
 
 
144
  dist.all_to_all_single(
145
  recv_buf,
146
  send_buf,
@@ -165,14 +176,14 @@ def _all2all_gather(params, param_to_state, rank, comm_stream, none_grad,
165
  comm_stream.wait_event(alloc_event)
166
 
167
  off = 0
168
- write_offsets = {id(p): 0 for p in owner_params}
169
  for src in range(num_ranks):
170
  if recv_counts[src] == 0:
171
  continue
172
 
173
  block = recv_counts[src]
174
  inner_off = 0
175
- for p in owner_params:
176
  state = param_to_state[id(p)]
177
  assert state.worker_rank == rank
178
  n = split_elems_for_src(p, state, src, num_ranks)
@@ -222,6 +233,10 @@ def _compute_u(p, state, steps, rank, compute_stream):
222
 
223
  @torch.no_grad()
224
  def _alloc_scattered_u(params, param_to_state, rank, compute_stream):
 
 
 
 
225
  with torch.cuda.stream(compute_stream):
226
  for p in params:
227
  state = param_to_state[id(p)]
@@ -234,18 +249,22 @@ def _alloc_scattered_u(params, param_to_state, rank, compute_stream):
234
 
235
 
236
  def _all2all_scatter(params, param_to_state, rank, comm_stream, alloc_event):
 
 
 
237
  with torch.cuda.stream(comm_stream):
238
  process_group = param_to_state[id(params[0])].process_group
239
  num_ranks = dist.get_world_size(group=process_group)
240
- owner_params = [
241
  p for p in params if param_to_state[id(p)].worker_rank == rank
242
  ]
243
 
 
244
  per_dst = [[] for _ in range(num_ranks)]
245
  send_counts = [0] * num_ranks
246
 
247
- if owner_params:
248
- for p in owner_params:
249
  state = param_to_state[id(p)]
250
  if state.compute_event is None:
251
  raise RuntimeError(
@@ -276,7 +295,9 @@ def _all2all_scatter(params, param_to_state, rank, comm_stream, alloc_event):
276
  # Even non-owner ranks must join the collective call
277
  send_buf = torch.empty(0, dtype=COMM_DTYPE, device="cuda")
278
 
 
279
  recv_counts = [0] * num_ranks
 
280
  for src in range(num_ranks):
281
  total = 0
282
  for p in params:
@@ -290,6 +311,7 @@ def _all2all_scatter(params, param_to_state, rank, comm_stream, alloc_event):
290
  assert recv_total > 0
291
  recv_buf = torch.empty(recv_total, dtype=COMM_DTYPE, device="cuda")
292
 
 
293
  dist.all_to_all_single(
294
  recv_buf,
295
  send_buf,
@@ -298,6 +320,21 @@ def _all2all_scatter(params, param_to_state, rank, comm_stream, alloc_event):
298
  group=process_group,
299
  )
300
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
301
  comm_stream.wait_event(alloc_event)
302
 
303
  off = 0
@@ -479,6 +516,11 @@ class Muon(torch.optim.Optimizer):
479
  "head_dim": 128,
480
  "threshold": 100
481
  }
 
 
 
 
 
482
  """
483
 
484
  def __init__(self,
@@ -497,7 +539,8 @@ class Muon(torch.optim.Optimizer):
497
  "k_indices": [],
498
  "head_dim": 128,
499
  "threshold": 100
500
- }):
 
501
  defaults = dict(
502
  lr=lr,
503
  weight_decay=weight_decay,
@@ -521,15 +564,13 @@ class Muon(torch.optim.Optimizer):
521
 
522
  super().__init__(params, defaults)
523
 
524
- if dist.is_initialized():
525
- self.rank = dist.get_rank()
526
- else:
527
- self.rank = None
528
 
529
  self.comm_stream = torch.cuda.Stream()
530
  self.compute_stream = torch.cuda.Stream()
531
  self.debug = debug
532
  self.clip_config = clip_config
 
533
 
534
  def _calc_flops(self, G, steps):
535
  assert len(G.shape) == 2
@@ -602,7 +643,11 @@ class Muon(torch.optim.Optimizer):
602
  if mesh is None:
603
  mesh = p.device_mesh
604
  shard_mesh, process_group = self.get_shard_mesh(p, self.rank)
605
- self.rank = dist.get_rank(group=process_group)
 
 
 
 
606
  elif mesh != p.device_mesh:
607
  raise ValueError("All parameters must be on the same mesh.")
608
 
@@ -743,6 +788,8 @@ class Muon(torch.optim.Optimizer):
743
  param_to_state, ordered_params = self.init_state_and_assign_params(
744
  names, params, group, qk_logits)
745
 
 
 
746
  def enqueue_all2all_gather(start_idx, chunk_size):
747
  target_params = ordered_params[start_idx:start_idx + chunk_size]
748
  if target_params:
@@ -781,16 +828,16 @@ class Muon(torch.optim.Optimizer):
781
  # Wait grad update
782
  self.comm_stream.wait_stream(torch.cuda.current_stream())
783
 
784
- PRE_STEP = 5
785
- for i in range(0, PRE_STEP):
786
  enqueue_all2all_gather(i * chunk_size, chunk_size)
787
  enqueue_computes(i * chunk_size, chunk_size)
788
 
789
  for i in range(0, len(params) + chunk_size - 1, chunk_size):
790
  enqueue_all2all_scatter(i, chunk_size)
791
- enqueue_all2all_gather(i + PRE_STEP * chunk_size, chunk_size)
792
  enqueue_update_param(i, chunk_size)
793
- enqueue_computes(i + PRE_STEP * chunk_size, chunk_size)
794
 
795
  # Wait the last update_param to finish
796
  torch.cuda.current_stream().wait_stream(self.compute_stream)
 
73
  qk_clip_state = None
74
 
75
 
76
+ def split_elems_for_src(param, src_rank, num_ranks) -> int:
77
  rows = param.shape[0]
78
  cols = int(param.numel() // rows)
79
  base, rem = divmod(rows, num_ranks)
 
83
 
84
  @torch.no_grad()
85
  def _alloc_gathered_grad(params, param_to_state, rank, compute_stream):
86
+ """
87
+ Pre-allocate gathered_grad buffer on compute_stream
88
+ before launching all2all gather
89
+ """
90
  with torch.cuda.stream(compute_stream):
91
  for p in params:
92
  state = param_to_state[id(p)]
 
106
  @torch.no_grad()
107
  def _all2all_gather(params, param_to_state, rank, comm_stream, none_grad,
108
  alloc_event):
109
+ """
110
+ All2all gathers shards so each owner rank reconstructs its full gradient
111
+ """
112
  with torch.cuda.stream(comm_stream):
113
  process_group = param_to_state[id(params[0])].process_group
114
  num_ranks = dist.get_world_size(group=process_group)
115
 
116
+ # Construct sending buffers
117
  per_dst = [[] for _ in range(num_ranks)]
118
  send_counts = [0] * num_ranks
119
+
120
  for p in params:
121
  state = param_to_state[id(p)]
122
  dst = state.worker_rank
 
133
  for v in per_dst), "all params should be sharded to all devices"
134
 
135
  send_buf = torch.cat([torch.cat(v, dim=0) for v in per_dst], dim=0)
136
+ owned_params = [
137
  p for p in params if param_to_state[id(p)].worker_rank == rank
138
  ]
139
 
140
+ # Compute receive sizes and allocate receiving buffers
141
  recv_counts = [0] * num_ranks
142
+
143
  for src in range(num_ranks):
144
  total = 0
145
+ for p in owned_params:
146
  state = param_to_state[id(p)]
147
  assert state.worker_rank == rank
148
  total += split_elems_for_src(p, state, src, num_ranks)
 
150
 
151
  recv_total = sum(recv_counts)
152
  recv_buf = torch.empty(recv_total, dtype=COMM_DTYPE, device="cuda")
153
+
154
+ #All2All
155
  dist.all_to_all_single(
156
  recv_buf,
157
  send_buf,
 
176
  comm_stream.wait_event(alloc_event)
177
 
178
  off = 0
179
+ write_offsets = {id(p): 0 for p in owned_params}
180
  for src in range(num_ranks):
181
  if recv_counts[src] == 0:
182
  continue
183
 
184
  block = recv_counts[src]
185
  inner_off = 0
186
+ for p in owned_params:
187
  state = param_to_state[id(p)]
188
  assert state.worker_rank == rank
189
  n = split_elems_for_src(p, state, src, num_ranks)
 
233
 
234
  @torch.no_grad()
235
  def _alloc_scattered_u(params, param_to_state, rank, compute_stream):
236
+ """
237
+ Pre-allocate scattered_u buffer on compute_stream
238
+ before launching all2all gather
239
+ """
240
  with torch.cuda.stream(compute_stream):
241
  for p in params:
242
  state = param_to_state[id(p)]
 
249
 
250
 
251
  def _all2all_scatter(params, param_to_state, rank, comm_stream, alloc_event):
252
+ """
253
+ All2all scatters full gradients to all ranks
254
+ """
255
  with torch.cuda.stream(comm_stream):
256
  process_group = param_to_state[id(params[0])].process_group
257
  num_ranks = dist.get_world_size(group=process_group)
258
+ owned_params = [
259
  p for p in params if param_to_state[id(p)].worker_rank == rank
260
  ]
261
 
262
+ # Construct sending buffer
263
  per_dst = [[] for _ in range(num_ranks)]
264
  send_counts = [0] * num_ranks
265
 
266
+ if owned_params:
267
+ for p in owned_params:
268
  state = param_to_state[id(p)]
269
  if state.compute_event is None:
270
  raise RuntimeError(
 
295
  # Even non-owner ranks must join the collective call
296
  send_buf = torch.empty(0, dtype=COMM_DTYPE, device="cuda")
297
 
298
+ # Compute receive sizes and allocate receiving buffers
299
  recv_counts = [0] * num_ranks
300
+
301
  for src in range(num_ranks):
302
  total = 0
303
  for p in params:
 
311
  assert recv_total > 0
312
  recv_buf = torch.empty(recv_total, dtype=COMM_DTYPE, device="cuda")
313
 
314
+ #All2All
315
  dist.all_to_all_single(
316
  recv_buf,
317
  send_buf,
 
320
  group=process_group,
321
  )
322
 
323
+ # Copy to pre-allocated scattered_u buffer from the received buffer
324
+ #
325
+ # recv_buf (num ranks = 3, local_rank = 0)
326
+ #
327
+ # From rank 0 From rank 1 From rank 2
328
+ # | p1_0, p2_0, p3_0 | p4_0 | p5_0, p6_0 |
329
+ #
330
+ # Outer loop:
331
+ # rank 0 -> rank 1 -> rank2
332
+ #
333
+ # Inner loop:
334
+ # src(0) : p1_0 -> p2_0 -> p3_0
335
+ # src(1) : p4_0
336
+ # src(2) : p5_0 -> p6_0
337
+
338
  comm_stream.wait_event(alloc_event)
339
 
340
  off = 0
 
516
  "head_dim": 128,
517
  "threshold": 100
518
  }
519
+ overlap_step : How many all2all gather, compute operations are launched in advance
520
+ before the corresponding all2all scatter steps begin.
521
+ A higher overlap_step increases memory usage but can improve
522
+ performance by overlapping communication.
523
+ Parallel muon only.
524
  """
525
 
526
  def __init__(self,
 
539
  "k_indices": [],
540
  "head_dim": 128,
541
  "threshold": 100
542
+ },
543
+ overlap_step=5):
544
  defaults = dict(
545
  lr=lr,
546
  weight_decay=weight_decay,
 
564
 
565
  super().__init__(params, defaults)
566
 
567
+ self.rank = None
 
 
 
568
 
569
  self.comm_stream = torch.cuda.Stream()
570
  self.compute_stream = torch.cuda.Stream()
571
  self.debug = debug
572
  self.clip_config = clip_config
573
+ self.overlap_step = overlap_step
574
 
575
  def _calc_flops(self, G, steps):
576
  assert len(G.shape) == 2
 
643
  if mesh is None:
644
  mesh = p.device_mesh
645
  shard_mesh, process_group = self.get_shard_mesh(p, self.rank)
646
+ local_rank = dist.get_rank(group=process_group)
647
+ if self.rank is None:
648
+ self.rank = dist.get_rank(group=process_group)
649
+ else:
650
+ assert self.rank == local_rank
651
  elif mesh != p.device_mesh:
652
  raise ValueError("All parameters must be on the same mesh.")
653
 
 
788
  param_to_state, ordered_params = self.init_state_and_assign_params(
789
  names, params, group, qk_logits)
790
 
791
+ assert self.rank is not None
792
+
793
  def enqueue_all2all_gather(start_idx, chunk_size):
794
  target_params = ordered_params[start_idx:start_idx + chunk_size]
795
  if target_params:
 
828
  # Wait grad update
829
  self.comm_stream.wait_stream(torch.cuda.current_stream())
830
 
831
+ overlap_step = self.overlap_step
832
+ for i in range(0, overlap_step):
833
  enqueue_all2all_gather(i * chunk_size, chunk_size)
834
  enqueue_computes(i * chunk_size, chunk_size)
835
 
836
  for i in range(0, len(params) + chunk_size - 1, chunk_size):
837
  enqueue_all2all_scatter(i, chunk_size)
838
+ enqueue_all2all_gather(i + overlap_step * chunk_size, chunk_size)
839
  enqueue_update_param(i, chunk_size)
840
+ enqueue_computes(i + overlap_step * chunk_size, chunk_size)
841
 
842
  # Wait the last update_param to finish
843
  torch.cuda.current_stream().wait_stream(self.compute_stream)