Quazim0t0 Claude Opus 5.5 commited on
Commit
a28437c
·
1 Parent(s): 63780b7

Re-check FTZ/DAZ before every optimizer step (2026-10-20)

Browse files

pin_fp_mode ran once at start; a library imported mid-run can switch flush-to-zero /
denormals-are-zero back on. fit now checks before each opt.step, re-pins, and names the
rank and step. Verified: final parameter hashes unchanged vs 63780b7 on cuda+cpu and cpu+cpu.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Files changed (2) hide show
  1. daisychain/cluster.py +24 -0
  2. test_cluster_reductions.py +10 -0
daisychain/cluster.py CHANGED
@@ -42,6 +42,29 @@ def pin_fp_mode() -> None:
42
  torch.set_flush_denormal(False)
43
 
44
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
  def _cuda_usable() -> bool:
46
  """is_available() alone is not enough: with CUDA_VISIBLE_DEVICES set but EMPTY (a common way
47
  to say "CPU only") torch reports available=True and device_count()=0, and the node crashed
@@ -314,6 +337,7 @@ class DaisyCluster:
314
  loss.backward()
315
  capacity_weighted_allreduce_grads(model, w)
316
  check_finite_grads(model, s)
 
317
  if master is not None:
318
  with torch.no_grad():
319
  for mp, p in zip(master, params):
 
42
  torch.set_flush_denormal(False)
43
 
44
 
45
+ def fp_mode_ok() -> bool:
46
+ """True if this thread keeps subnormals: FTZ off (a normal*normal product may be subnormal)
47
+ and DAZ off (a subnormal input is read as itself)."""
48
+ ftz = torch.tensor([1e-20], dtype=torch.float32) * torch.tensor([1e-20], dtype=torch.float32)
49
+ daz = torch.tensor([1e-39], dtype=torch.float32) * 1.0
50
+ return float(ftz) != 0.0 and float(daz) != 0.0
51
+
52
+
53
+ def repin_fp_mode(step: int, rank: int) -> bool:
54
+ """Re-check the FP mode before an optimizer step; re-pin and say so if it was flipped.
55
+
56
+ pin_fp_mode runs once at start, but a library imported mid-run (a dataloader worker's
57
+ dependency, a fast-math extension) can switch FTZ/DAZ on afterwards. The emulator restores
58
+ MXCSR around EVERY guest call for this reason; here the replica hash would catch the fork
59
+ later with nothing naming the cause. Returns True if the mode had been flipped."""
60
+ if fp_mode_ok():
61
+ return False
62
+ pin_fp_mode()
63
+ print(" [fp] rank %d step %d: flush-to-zero/denormals-are-zero was switched ON since the "
64
+ "last step (a library changed MXCSR); re-pinned subnormals ON" % (rank, step), flush=True)
65
+ return True
66
+
67
+
68
  def _cuda_usable() -> bool:
69
  """is_available() alone is not enough: with CUDA_VISIBLE_DEVICES set but EMPTY (a common way
70
  to say "CPU only") torch reports available=True and device_count()=0, and the node crashed
 
337
  loss.backward()
338
  capacity_weighted_allreduce_grads(model, w)
339
  check_finite_grads(model, s)
340
+ repin_fp_mode(s, self.rank) # before the step: the update is where FTZ forks
341
  if master is not None:
342
  with torch.no_grad():
343
  for mp, p in zip(master, params):
test_cluster_reductions.py CHANGED
@@ -112,6 +112,16 @@ def main():
112
  caps, unit = plan_capacities([{"cores": 8, "capacity": 8.0}, {"cores": 8, "capacity": 150.0}])
113
  ck("old-format surveys (no unit) are classified, and mixed -> cores", caps == [8.0, 8.0], caps)
114
 
 
 
 
 
 
 
 
 
 
 
115
  print()
116
  if FAILURES:
117
  print("FAILED: %d" % len(FAILURES))
 
112
  caps, unit = plan_capacities([{"cores": 8, "capacity": 8.0}, {"cores": 8, "capacity": 150.0}])
113
  ck("old-format surveys (no unit) are classified, and mixed -> cores", caps == [8.0, 8.0], caps)
114
 
115
+ print("repin_fp_mode -- FTZ switched on mid-run is noticed and undone (2026-10-20)")
116
+ from daisychain.cluster import fp_mode_ok, pin_fp_mode, repin_fp_mode
117
+ pin_fp_mode()
118
+ ck("subnormals kept after pin_fp_mode", fp_mode_ok())
119
+ ck("no flip: repin reports nothing", repin_fp_mode(0, 0) is False)
120
+ torch.set_flush_denormal(True) # what a fast-math library does on load
121
+ ck("fp_mode_ok sees the flip", not fp_mode_ok())
122
+ ck("repin reports the flip", repin_fp_mode(7, 0) is True)
123
+ ck("...and subnormals are back", fp_mode_ok())
124
+
125
  print()
126
  if FAILURES:
127
  print("FAILED: %d" % len(FAILURES))