adv-optm 2.6.1.dev3__tar.gz → 2.6.2.dev2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. {adv_optm-2.6.1.dev3 → adv_optm-2.6.2.dev2}/PKG-INFO +1 -1
  2. {adv_optm-2.6.1.dev3 → adv_optm-2.6.2.dev2}/adv_optm/__init__.py +1 -1
  3. {adv_optm-2.6.1.dev3 → adv_optm-2.6.2.dev2}/adv_optm/optim/AdaMuon_adv.py +1 -2
  4. {adv_optm-2.6.1.dev3 → adv_optm-2.6.2.dev2}/adv_optm/optim/AdamW_adv.py +1 -2
  5. {adv_optm-2.6.1.dev3 → adv_optm-2.6.2.dev2}/adv_optm/optim/Adopt_adv.py +3 -3
  6. {adv_optm-2.6.1.dev3 → adv_optm-2.6.2.dev2}/adv_optm/optim/Lion_adv.py +0 -2
  7. {adv_optm-2.6.1.dev3 → adv_optm-2.6.2.dev2}/adv_optm/optim/Muon_adv.py +1 -2
  8. {adv_optm-2.6.1.dev3 → adv_optm-2.6.2.dev2}/adv_optm/optim/Prodigy_adv.py +1 -2
  9. {adv_optm-2.6.1.dev3 → adv_optm-2.6.2.dev2}/adv_optm/optim/SignSGD_adv.py +0 -2
  10. {adv_optm-2.6.1.dev3 → adv_optm-2.6.2.dev2}/adv_optm/optim/SinkSGD_adv.py +25 -10
  11. {adv_optm-2.6.1.dev3 → adv_optm-2.6.2.dev2}/adv_optm/util/param_update.py +27 -33
  12. {adv_optm-2.6.1.dev3 → adv_optm-2.6.2.dev2}/adv_optm/util/scaled_optm.py +1 -20
  13. adv_optm-2.6.2.dev2/adv_optm/util/sinkhorn.py +275 -0
  14. {adv_optm-2.6.1.dev3 → adv_optm-2.6.2.dev2}/adv_optm.egg-info/PKG-INFO +1 -1
  15. {adv_optm-2.6.1.dev3 → adv_optm-2.6.2.dev2}/setup.py +1 -1
  16. adv_optm-2.6.1.dev3/adv_optm/util/sinkhorn.py +0 -126
  17. {adv_optm-2.6.1.dev3 → adv_optm-2.6.2.dev2}/LICENSE +0 -0
  18. {adv_optm-2.6.1.dev3 → adv_optm-2.6.2.dev2}/README.md +0 -0
  19. {adv_optm-2.6.1.dev3 → adv_optm-2.6.2.dev2}/adv_optm/optim/__init__.py +0 -0
  20. {adv_optm-2.6.1.dev3 → adv_optm-2.6.2.dev2}/adv_optm/util/Kourkoutas.py +0 -0
  21. {adv_optm-2.6.1.dev3 → adv_optm-2.6.2.dev2}/adv_optm/util/Muon_AuxAdam.py +0 -0
  22. {adv_optm-2.6.1.dev3 → adv_optm-2.6.2.dev2}/adv_optm/util/Muon_util.py +0 -0
  23. {adv_optm-2.6.1.dev3 → adv_optm-2.6.2.dev2}/adv_optm/util/OrthoGrad.py +0 -0
  24. {adv_optm-2.6.1.dev3 → adv_optm-2.6.2.dev2}/adv_optm/util/__init__.py +0 -0
  25. {adv_optm-2.6.1.dev3 → adv_optm-2.6.2.dev2}/adv_optm/util/centered_decay.py +0 -0
  26. {adv_optm-2.6.1.dev3 → adv_optm-2.6.2.dev2}/adv_optm/util/factorization_util.py +0 -0
  27. {adv_optm-2.6.1.dev3 → adv_optm-2.6.2.dev2}/adv_optm/util/lion_k.py +0 -0
  28. {adv_optm-2.6.1.dev3 → adv_optm-2.6.2.dev2}/adv_optm/util/signed_util.py +0 -0
  29. {adv_optm-2.6.1.dev3 → adv_optm-2.6.2.dev2}/adv_optm/util/state_util.py +0 -0
  30. {adv_optm-2.6.1.dev3 → adv_optm-2.6.2.dev2}/adv_optm/util/update_util.py +0 -0
  31. {adv_optm-2.6.1.dev3 → adv_optm-2.6.2.dev2}/adv_optm.egg-info/SOURCES.txt +0 -0
  32. {adv_optm-2.6.1.dev3 → adv_optm-2.6.2.dev2}/adv_optm.egg-info/dependency_links.txt +0 -0
  33. {adv_optm-2.6.1.dev3 → adv_optm-2.6.2.dev2}/adv_optm.egg-info/requires.txt +0 -0
  34. {adv_optm-2.6.1.dev3 → adv_optm-2.6.2.dev2}/adv_optm.egg-info/top_level.txt +0 -0
  35. {adv_optm-2.6.1.dev3 → adv_optm-2.6.2.dev2}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: adv_optm
3
- Version: 2.6.1.dev3
3
+ Version: 2.6.2.dev2
4
4
  Summary: A family of highly efficient, lightweight yet powerful optimizers.
5
5
  Home-page: https://github.com/Koratahiu/Advanced_Optimizers
6
6
  Author: Koratahiu
@@ -20,4 +20,4 @@ __all__ = [
20
20
  "SinkSGD_adv",
21
21
  ]
22
22
 
23
- __version__ = "2.6.1.dev3"
23
+ __version__ = "2.6.2.dev2"
@@ -137,7 +137,6 @@ class AdaMuon_adv(torch.optim.Optimizer):
137
137
  # Decoupled/cautious weight decay
138
138
  weight_decay: float = 0,
139
139
  cautious_wd: bool = False,
140
- scaled_wd: bool = False,
141
140
  # Nesterov momentum
142
141
  nesterov: bool = True,
143
142
  nesterov_coef: float | None = None,
@@ -228,7 +227,7 @@ class AdaMuon_adv(torch.optim.Optimizer):
228
227
 
229
228
  defaults = {
230
229
  "lr": lr, "betas": betas, "weight_decay": weight_decay, "cautious_wd": cautious_wd,
231
- "eps": eps, "rms_rescaling": rms_rescaling, "ns_steps": ns_steps, "scaled_wd": scaled_wd,
230
+ "eps": eps, "rms_rescaling": rms_rescaling, "ns_steps": ns_steps,
232
231
  "ns_eps": ns_eps, "ns_coeffs": ns_coeffs, "nnmf_factor": nnmf_factor,
233
232
  "vector_reshape": vector_reshape,
234
233
  "nesterov":nesterov, "nesterov_coef": nesterov_coef, "use_atan2":use_atan2,
@@ -98,7 +98,6 @@ class AdamW_adv(torch.optim.Optimizer):
98
98
  weight_decay: float = 0.0,
99
99
  fisher_wd: bool = False,
100
100
  cautious_wd: bool = False,
101
- scaled_wd: bool = False,
102
101
  # Adam's Bias Correction
103
102
  use_bias_correction: bool = True,
104
103
  # Stochastic Rounding for BF16
@@ -157,7 +156,7 @@ class AdamW_adv(torch.optim.Optimizer):
157
156
 
158
157
  defaults = {
159
158
  "lr": lr, "betas": betas, "eps": eps, "weight_decay": weight_decay,
160
- "fisher_wd": fisher_wd, "cautious_wd": cautious_wd, "scaled_wd": scaled_wd,
159
+ "fisher_wd": fisher_wd, "cautious_wd": cautious_wd,
161
160
  "use_atan2": use_atan2, "nesterov": nesterov, "nesterov_coef": nesterov_coef,
162
161
  "normed_momentum": normed_momentum,
163
162
  "orthogonal_gradient": orthogonal_gradient, "use_bias_correction": use_bias_correction,
@@ -101,7 +101,6 @@ class Adopt_adv(torch.optim.Optimizer):
101
101
  weight_decay: float = 0.0,
102
102
  fisher_wd: bool = False,
103
103
  cautious_wd: bool = False,
104
- scaled_wd: bool = False,
105
104
  # ADOPT clipping
106
105
  clip_lambda: Optional[Callable[[int], float]] = lambda step: step**0.25,
107
106
  # Adam_atan2 (scale invariant)
@@ -158,7 +157,7 @@ class Adopt_adv(torch.optim.Optimizer):
158
157
  state_precision = "factored"
159
158
 
160
159
  defaults = {
161
- "lr": lr, "betas": betas, "eps": eps, "weight_decay": weight_decay, "scaled_wd": scaled_wd,
160
+ "lr": lr, "betas": betas, "eps": eps, "weight_decay": weight_decay,
162
161
  "fisher_wd": fisher_wd, "cautious_wd": cautious_wd, "orthogonal_gradient": orthogonal_gradient,
163
162
  "nesterov": nesterov, "nesterov_coef": nesterov_coef,
164
163
  "kourkoutas_beta": kourkoutas_beta, "beta2_min": beta2_min, "ema_alpha": ema_alpha,
@@ -315,7 +314,8 @@ class Adopt_adv(torch.optim.Optimizer):
315
314
  # The first step is for initialization only (skip when use_atan2 as it's scale invariant).
316
315
  if state['step'] == 0 and not (self.use_atan2 or group.get('spectral_normalization', False)):
317
316
  state['step'] += 1
318
- self.kourkoutas_helper.accumulate_gradient_sq_norm(p, grad)
317
+ if group.get('kourkoutas_beta', False):
318
+ self.kourkoutas_helper.accumulate_gradient_sq_norm(p, grad)
319
319
  return
320
320
 
321
321
  random_int_tensor = None
@@ -64,7 +64,6 @@ class Lion_adv(torch.optim.Optimizer):
64
64
  # Decoupled/cautious weight decay
65
65
  weight_decay: float = 0.0,
66
66
  cautious_wd: bool = False,
67
- scaled_wd: bool = False,
68
67
  # Stochastic Rounding for BF16
69
68
  stochastic_rounding: bool = True,
70
69
  # OrthoGrad
@@ -97,7 +96,6 @@ class Lion_adv(torch.optim.Optimizer):
97
96
  betas=betas,
98
97
  weight_decay=weight_decay,
99
98
  cautious_wd=cautious_wd,
100
- scaled_wd=scaled_wd,
101
99
  vector_reshape=vector_reshape,
102
100
  orthogonal_gradient=orthogonal_gradient,
103
101
  kappa_p=kappa_p,
@@ -111,7 +111,6 @@ class Muon_adv(torch.optim.Optimizer):
111
111
  # Decoupled/cautious weight decay
112
112
  weight_decay: float = 0.0,
113
113
  cautious_wd: bool = False,
114
- scaled_wd: bool = False,
115
114
  # Nesterov momentum
116
115
  nesterov: bool = True,
117
116
  nesterov_coef: float | None = None,
@@ -202,7 +201,7 @@ class Muon_adv(torch.optim.Optimizer):
202
201
  defaults = {
203
202
  "lr": lr, "beta1": beta1, "weight_decay": weight_decay, "cautious_wd": cautious_wd,
204
203
  "nesterov": nesterov, "nesterov_coef": nesterov_coef, "ns_steps": ns_steps, "ns_eps": ns_eps,
205
- "ns_coeffs": ns_coeffs, "nnmf_factor": nnmf_factor, "scaled_wd": scaled_wd,
204
+ "ns_coeffs": ns_coeffs, "nnmf_factor": nnmf_factor,
206
205
  "vector_reshape": vector_reshape, "rms_rescaling": rms_rescaling,
207
206
  "orthogonal_gradient": orthogonal_gradient,
208
207
  'compiled_optimizer': compiled_optimizer,
@@ -115,7 +115,6 @@ class Prodigy_adv(torch.optim.Optimizer):
115
115
  weight_decay: float = 0.0,
116
116
  fisher_wd: bool = False,
117
117
  cautious_wd: bool = False,
118
- scaled_wd: bool = False,
119
118
  # Stochastic Rounding for BF16
120
119
  stochastic_rounding: bool = True,
121
120
  # Adam_atan2 (scale invariant)
@@ -182,7 +181,7 @@ class Prodigy_adv(torch.optim.Optimizer):
182
181
 
183
182
  defaults = {
184
183
  "lr": lr, "betas": betas, "eps": eps, "weight_decay": weight_decay,
185
- "fisher_wd": fisher_wd, "cautious_wd": cautious_wd, "scaled_wd": scaled_wd,
184
+ "fisher_wd": fisher_wd, "cautious_wd": cautious_wd,
186
185
  "use_atan2": use_atan2,
187
186
  "orthogonal_gradient": orthogonal_gradient,
188
187
  "compiled_optimizer": compiled_optimizer,
@@ -59,7 +59,6 @@ class SignSGD_adv(torch.optim.Optimizer):
59
59
  # weight decay features
60
60
  geometric_wd: bool = False,
61
61
  cautious_wd: bool = False,
62
- scaled_wd: bool = False,
63
62
  # Stochastic Rounding for BF16
64
63
  stochastic_rounding: bool = True,
65
64
  # OrthoGrad
@@ -109,7 +108,6 @@ class SignSGD_adv(torch.optim.Optimizer):
109
108
  momentum=momentum,
110
109
  weight_decay=weight_decay,
111
110
  cautious_wd=cautious_wd,
112
- scaled_wd=scaled_wd,
113
111
  geometric_wd=geometric_wd,
114
112
  vector_reshape=vector_reshape,
115
113
  orthogonal_gradient=orthogonal_gradient,
@@ -8,7 +8,7 @@ from ..util.OrthoGrad import _orthogonalize_gradient
8
8
  from ..util.scaled_optm import scale_update, is_spectral, init_spectral_norm
9
9
  from ..util.centered_decay import _init_anchor, dequantize_anchor
10
10
  from ..util.state_util import init_state_tensor, get_state, set_state, upcast_grad_for_precision
11
- from ..util.sinkhorn import apply_sr_sinkhorn, get_sinkhorn_wd_scaler
11
+ from ..util.sinkhorn import apply_sr_sinkhorn, get_sinkhorn_wd_scaler, apply_oft_sinkhorn, apply_spectral_oft_sinkhorn
12
12
  from ..util.signed_util import get_signsgd_wd_target
13
13
 
14
14
  class SinkSGD_adv(torch.optim.Optimizer):
@@ -56,6 +56,8 @@ class SinkSGD_adv(torch.optim.Optimizer):
56
56
  # Sinkhorn Iterative Normalization
57
57
  sinkhorn_iterations: int = 5,
58
58
  orthogonal_sinkhorn: bool = False,
59
+ # OFT-specific Sinkhorn (symmetric)
60
+ skew_sinkoft: bool = False,
59
61
  # Normalization then Momentum
60
62
  normed_momentum: bool = False,
61
63
  # SNR Precondition (requires normed_momentum)
@@ -66,7 +68,6 @@ class SinkSGD_adv(torch.optim.Optimizer):
66
68
  # weight decay features
67
69
  geometric_wd: bool = False,
68
70
  cautious_wd: bool = False,
69
- scaled_wd: bool = False,
70
71
  # Stochastic Rounding for BF16
71
72
  stochastic_rounding: bool = True,
72
73
  # OrthoGrad
@@ -104,11 +105,11 @@ class SinkSGD_adv(torch.optim.Optimizer):
104
105
  defaults = {
105
106
  "lr": lr, "momentum": momentum,
106
107
  "weight_decay": weight_decay, "nesterov": nesterov, "nesterov_coef": nesterov_coef, "normed_momentum": normed_momentum, "snr_cond": snr_cond,
107
- "geometric_wd": geometric_wd, "cautious_wd": cautious_wd, "scaled_wd": scaled_wd,
108
+ "geometric_wd": geometric_wd, "cautious_wd": cautious_wd,
108
109
  "orthogonal_gradient": orthogonal_gradient,
109
110
  "compiled_optimizer": compiled_optimizer,
110
111
  "sinkhorn_iterations": sinkhorn_iterations,
111
- "orthogonal_sinkhorn": orthogonal_sinkhorn,
112
+ "orthogonal_sinkhorn": orthogonal_sinkhorn, "skew_sinkoft": skew_sinkoft,
112
113
  "spectral_normalization": spectral_normalization,
113
114
  "centered_wd": centered_wd, "centered_wd_mode": centered_wd_mode,
114
115
  "state_precision": state_precision,
@@ -237,6 +238,7 @@ class SinkSGD_adv(torch.optim.Optimizer):
237
238
  nesterov = group['nesterov']
238
239
  nesterov_coef = group.get('nesterov_coef', None)
239
240
  snr_cond = group.get('snr_cond', False)
241
+ oft_sym = group.get('skew_sinkoft', False) and getattr(p, '_is_oft', False)
240
242
 
241
243
  vt_row = None
242
244
  vt_col = None
@@ -249,9 +251,12 @@ class SinkSGD_adv(torch.optim.Optimizer):
249
251
  grad = _orthogonalize_gradient(p, grad, group["orthogonal_gradient"])
250
252
 
251
253
  if normed_mt:
254
+ # Sinkhorn iterative normalization
252
255
  if not is_vector:
253
- # Sinkhorn iterative normalization
254
- grad = apply_sr_sinkhorn(grad, iters=sinkhorn_iterations, p=p, ortho_project=orthogonal_sinkhorn)
256
+ if not oft_sym:
257
+ grad = apply_sr_sinkhorn(grad, iters=sinkhorn_iterations, p=p, ortho_project=orthogonal_sinkhorn)
258
+ else:
259
+ grad = apply_oft_sinkhorn(grad, iters=sinkhorn_iterations, p=p, ortho_project=orthogonal_sinkhorn)
255
260
  else:
256
261
  # For vectors, apply sign operation
257
262
  grad = grad.sign_()
@@ -343,9 +348,15 @@ class SinkSGD_adv(torch.optim.Optimizer):
343
348
  update.atan2_(denom)
344
349
 
345
350
  if not group.get('normed_momentum', False):
351
+ # Sinkhorn iterative normalization
346
352
  if not is_vector:
347
- # Sinkhorn iterative normalization
348
- update = apply_sr_sinkhorn(update, iters=sinkhorn_iterations, p=p, ortho_project=orthogonal_sinkhorn)
353
+ if not oft_sym:
354
+ update = apply_sr_sinkhorn(update, iters=sinkhorn_iterations, p=p, ortho_project=orthogonal_sinkhorn)
355
+ else:
356
+ if group.get('spectral_normalization', False):
357
+ update = apply_spectral_oft_sinkhorn(p, update, iters=sinkhorn_iterations, lr=step_size, state=state, ortho_project=orthogonal_sinkhorn)
358
+ else:
359
+ update = apply_oft_sinkhorn(update, iters=sinkhorn_iterations, p=p, ortho_project=orthogonal_sinkhorn)
349
360
  else:
350
361
  # For vectors, apply sign operation
351
362
  update = update.sign_()
@@ -362,9 +373,13 @@ class SinkSGD_adv(torch.optim.Optimizer):
362
373
  del anchor
363
374
 
364
375
  update_scaling = step_size
365
- if group.get('spectral_normalization', False):
376
+
377
+ # If spectral normalization was already applied natively in the OFT sinkhorn, skip the scaling block
378
+ spectral_sinkhorn_applied = oft_sym and not normed_mt and group.get('spectral_normalization', False)
379
+
380
+ if group.get('spectral_normalization', False) and not spectral_sinkhorn_applied:
366
381
  update = scale_update(p, update, update_scaling, state=state)
367
- else:
382
+ elif not spectral_sinkhorn_applied:
368
383
  if snr_cond:
369
384
  update_scaling = update_scaling * (4/math.pi)
370
385
  update.mul_(update_scaling)
@@ -6,7 +6,7 @@ import torch.nn.functional as F
6
6
 
7
7
  from typing import Dict, Any
8
8
 
9
- from .scaled_optm import adjust_wds, scale_wd
9
+ from .scaled_optm import adjust_wds
10
10
  from .centered_decay import dequantize_anchor
11
11
 
12
12
  _generators: Dict[torch.device, torch.Generator] = {}
@@ -18,8 +18,8 @@ def _apply_weight_decay(
18
18
  p: Tensor,
19
19
  state: Dict[str, Any],
20
20
  group: Dict[str, Any],
21
- eff_wd: float | Tensor | None,
22
- eff_cwd: float | Tensor | None,
21
+ scaled_wd: float | Tensor | None,
22
+ scaled_cwd: float | Tensor | None,
23
23
  wd_target: Tensor | None = None,
24
24
  cwd_target: Tensor | None = None,
25
25
  ) -> None:
@@ -29,26 +29,26 @@ def _apply_weight_decay(
29
29
  cautious = group.get('cautious_wd', False)
30
30
 
31
31
  # Standard Weight Decay (pulls toward zero)
32
- if eff_wd is not None:
32
+ if scaled_wd is not None:
33
33
  if wd_target is None:
34
34
  wd_target = p_calc
35
35
  # Cautious Weight Decay: only decay if the update pushes in the same direction as the decay
36
36
  if cautious:
37
37
  mask = (update_calc * p_calc >= 0).to(p_calc.dtype)
38
- if isinstance(eff_wd, Tensor):
39
- p_calc.addcmul_(wd_target, mask * eff_wd, value=-1.0)
38
+ if isinstance(scaled_wd, Tensor):
39
+ p_calc.addcmul_(wd_target, mask * scaled_wd, value=-1.0)
40
40
  else:
41
- p_calc.addcmul_(wd_target, mask, value=-eff_wd)
41
+ p_calc.addcmul_(wd_target, mask, value=-scaled_wd)
42
42
  del mask
43
43
  else:
44
44
  # Standard decoupled weight decay
45
- if isinstance(eff_wd, Tensor):
46
- p_calc.addcmul_(wd_target, eff_wd, value=-1.0)
45
+ if isinstance(scaled_wd, Tensor):
46
+ p_calc.addcmul_(wd_target, scaled_wd, value=-1.0)
47
47
  else:
48
- p_calc.add_(wd_target, alpha=-eff_wd)
48
+ p_calc.add_(wd_target, alpha=-scaled_wd)
49
49
 
50
50
  # Centered Weight Decay (pulls toward anchor)
51
- if eff_cwd is not None and 'anchor_data' in state:
51
+ if scaled_cwd is not None and 'anchor_data' in state:
52
52
  if cwd_target is not None:
53
53
  decay_target = cwd_target
54
54
  else:
@@ -59,17 +59,17 @@ def _apply_weight_decay(
59
59
  if cautious:
60
60
  # Cautious Weight Decay: only decay if the update pushes in the same direction as the decay
61
61
  mask = (update_calc * decay_target >= 0).to(p_calc.dtype)
62
- if isinstance(eff_cwd, Tensor):
63
- p_calc.addcmul_(decay_target, mask * eff_cwd, value=-1.0)
62
+ if isinstance(scaled_cwd, Tensor):
63
+ p_calc.addcmul_(decay_target, mask * scaled_cwd, value=-1.0)
64
64
  else:
65
- p_calc.addcmul_(decay_target, mask, value=-eff_cwd)
65
+ p_calc.addcmul_(decay_target, mask, value=-scaled_cwd)
66
66
  del mask
67
67
  else:
68
68
  # Standard decoupled weight decay
69
- if isinstance(eff_cwd, Tensor):
70
- p_calc.addcmul_(decay_target, eff_cwd, value=-1.0)
69
+ if isinstance(scaled_cwd, Tensor):
70
+ p_calc.addcmul_(decay_target, scaled_cwd, value=-1.0)
71
71
  else:
72
- p_calc.add_(decay_target, alpha=-eff_cwd)
72
+ p_calc.add_(decay_target, alpha=-scaled_cwd)
73
73
 
74
74
  if cwd_target is None:
75
75
  del decay_target
@@ -105,24 +105,18 @@ def apply_parameter_update(
105
105
  wd = group["weight_decay"] if wd is None else wd
106
106
  cwd = group.get("centered_wd", 0.0)
107
107
  wd, cwd = adjust_wds(wd, cwd, p)
108
- scaled_wd = group.get("scaled_wd", False)
109
- decoupled = scaled_wd or decoupled
110
108
 
111
109
  # Calculate global decay factor for decoupled vs standard
112
110
  decay_factor = (lr / self._init_lr) if decoupled else lr
113
111
 
114
- eff_wd = (wd * decay_factor) if wd != 0 else None
115
- eff_cwd = (cwd * decay_factor) if cwd != 0 else None
116
-
117
- if scaled_wd:
118
- eff_wd = scale_wd(eff_wd, p, skip_vectors=True)
119
- eff_cwd = scale_wd(eff_cwd, p, skip_vectors=False)
112
+ scaled_wd = (wd * decay_factor) if wd != 0 else None
113
+ scaled_cwd = (cwd * decay_factor) if cwd != 0 else None
120
114
 
121
115
  if wd_scaler is not None:
122
- if eff_wd is not None:
123
- eff_wd = eff_wd * wd_scaler
124
- if eff_cwd is not None:
125
- eff_cwd = eff_cwd * wd_scaler
116
+ if scaled_wd is not None:
117
+ scaled_wd = scaled_wd * wd_scaler
118
+ if scaled_cwd is not None:
119
+ scaled_cwd = scaled_cwd * wd_scaler
126
120
 
127
121
  state = self.state[p]
128
122
 
@@ -135,8 +129,8 @@ def apply_parameter_update(
135
129
  cwd_t = cwd_target.float() if cwd_target is not None else None
136
130
 
137
131
  # Apply weight decay if needed
138
- if eff_wd is not None or eff_cwd is not None:
139
- _apply_weight_decay(p_fp32, update_fp32, p, state, group, eff_wd, eff_cwd, wd_t, cwd_t)
132
+ if scaled_wd is not None or scaled_cwd is not None:
133
+ _apply_weight_decay(p_fp32, update_fp32, p, state, group, scaled_wd, scaled_cwd, wd_t, cwd_t)
140
134
 
141
135
  # Apply main update
142
136
  p_fp32.add_(-update_fp32)
@@ -153,8 +147,8 @@ def apply_parameter_update(
153
147
 
154
148
  else:
155
149
  # Standard path for non-bfloat16 or without stochastic rounding
156
- if eff_wd is not None or eff_cwd is not None:
157
- _apply_weight_decay(p, update, p, state, group, eff_wd, eff_cwd, wd_target, cwd_target)
150
+ if scaled_wd is not None or scaled_cwd is not None:
151
+ _apply_weight_decay(p, update, p, state, group, scaled_wd, scaled_cwd, wd_target, cwd_target)
158
152
 
159
153
  # Apply main update
160
154
  p.add_(-update)
@@ -97,25 +97,6 @@ def adjust_wds(wd: float, cwd: float, p: torch.Tensor) -> tuple[float, float]:
97
97
  # Centered WD safely regularizes the delta without collapsing base feature variance.
98
98
  return wd, cwd
99
99
 
100
- def scale_wd(wd: float | None, p: torch.Tensor, skip_vectors: bool = False) -> float:
101
- """
102
- Scale-invariant, dimension-scaled weight decay.
103
- """
104
- if wd is None:
105
- return wd
106
- if getattr(p, '_is_oft', False):
107
- n_el = p.shape[-1]
108
- b = (1.0 + math.sqrt(1.0 + 8.0 * n_el)) / 2.0
109
- wd = (2 * wd) / (b - 1)
110
- return wd
111
-
112
- is_vector = p.ndim < 2 or getattr(p, '_is_dora_scale', False) or getattr(p, 'is_vector', False)
113
- if is_vector:
114
- return 0.0 if skip_vectors else wd
115
-
116
- if p.ndim >= 2:
117
- width = p.numel() // p.shape[0]
118
- return wd / width
119
100
 
120
101
  def is_spectral(p: torch.Tensor) -> bool:
121
102
  """Determines if a parameter should undergo spectral normalization updates."""
@@ -133,7 +114,7 @@ def init_spectral_norm(state: dict, p: torch.Tensor):
133
114
  if getattr(p, '_is_oft', False):
134
115
  n_el = p.shape[-1]
135
116
  b = int((1.0 + math.sqrt(1.0 + 8.0 * n_el)) / 2.0)
136
- _, _, _ = get_cached_structural_tensors(b, p.dtype, p.device)
117
+ get_cached_structural_tensors(b, p.device)
137
118
  gen = param_update.get_generator(p.device)
138
119
  batch_size = p.numel() // n_el
139
120
  # Initialize v (Right singular vector)
@@ -0,0 +1,275 @@
1
+ import math
2
+ import torch
3
+
4
+ from . import scaled_optm
5
+
6
+ def apply_sr_sinkhorn(update: torch.Tensor, iters: int = 5, p: torch.Tensor | None = None, ortho_project: bool = False) -> torch.Tensor:
7
+ """
8
+ Applies Square-Root Sinkhorn (SR-Sinkhorn) multi-normalization.
9
+ As described in 'Gradient Multi-Normalization for Efficient LLM Training'.
10
+
11
+ This technique normalizes a 2D matrix alternatively by its row-wise L2 norm
12
+ and column-wise L2 norm, driving it toward a fixed point that uniformly
13
+ distributes update magnitudes.
14
+ """
15
+ original_shape = update.shape
16
+ original_dtype = update.dtype
17
+ update = update.float()
18
+
19
+ # 1D Vector Case
20
+ if update.dim() == 1:
21
+ if ortho_project:
22
+ p_float = p.float()
23
+ p_norm_sq = torch.dot(p_float, p_float).add_(1e-30)
24
+ proj = torch.dot(p_float, update) / p_norm_sq
25
+ update.sub_(p_float * proj)
26
+ norm = update.norm(p=2).clamp_min_(1e-12)
27
+ return update.mul_(math.sqrt(update.numel()) / norm).view(original_shape).to(original_dtype)
28
+
29
+ # 2D+ Matrix Case
30
+ update_2d = update.view(update.shape[0], -1)
31
+
32
+ m, n = update_2d.shape
33
+
34
+ # Dynamically determine the order of normalization based on aspect ratio
35
+ # Normalizing the longer dimension first aids stability.
36
+ scale_cond = update_2d.shape[0] > update_2d.shape[1]
37
+ dim = 0 if scale_cond else 1
38
+
39
+
40
+ # Precompute scaling factors.
41
+ scale_first = math.sqrt(m if scale_cond else n)
42
+ scale_second = math.sqrt(n if scale_cond else m)
43
+
44
+ if ortho_project:
45
+ param_2d = p.float().view(p.shape[0], -1)
46
+ p_norm_sq_dim = torch.sum(param_2d * param_2d, dim=dim, keepdim=True).add_(1e-30)
47
+ p_norm_sq_adim = torch.sum(param_2d * param_2d, dim=1-dim, keepdim=True).add_(1e-30)
48
+
49
+ # In-place alternating Sinkhorn normalization steps
50
+ for _ in range(iters):
51
+ # First normalization step
52
+ # Stability floor: equivalent to a single-element vector norm lower bound (lb)
53
+ norm1_lb = 1 / math.sqrt(update_2d.shape[dim])
54
+ norm1 = update_2d.norm(p=2, dim=dim, keepdim=True).clamp_min_(norm1_lb)
55
+ update_2d.mul_(scale_first / norm1)
56
+ if ortho_project:
57
+ update_2d = ortho_normed(param_2d, update_2d, p_norm_sq_dim, dim, scale_first)
58
+
59
+ # Second normalization step
60
+ norm2_lb = 1 / math.sqrt(update_2d.shape[1-dim])
61
+ norm2 = update_2d.norm(p=2, dim=1-dim, keepdim=True).clamp_min_(norm2_lb)
62
+ update_2d.mul_(scale_second / norm2)
63
+ if ortho_project:
64
+ update_2d = ortho_normed(param_2d, update_2d, p_norm_sq_adim, 1-dim, scale_second)
65
+
66
+ return update_2d.view(original_shape).to(original_dtype)
67
+
68
+ def ortho_normed(p_2d, update_2d, p_norm_sq, dim, target_norm):
69
+ """
70
+ Projects the update to be orthogonal to p along 'dim' and restores the original norm.
71
+ """
72
+ # Project: g_orth = g - (p * <p, g> / ||p||^2)
73
+ dot_prod = torch.sum(p_2d * update_2d, dim=dim, keepdim=True)
74
+ proj = dot_prod / p_norm_sq
75
+
76
+ # In-place subtraction: update_2d = update_2d - (proj * p_2d)
77
+ update_2d.addcmul_(proj, p_2d, value=-1.0)
78
+
79
+ # Magnitude Preservation
80
+ norm_lb = 1 / math.sqrt(update_2d.shape[dim])
81
+ g_orth_norm = update_2d.norm(p=2, dim=dim, keepdim=True).clamp_min_(norm_lb)
82
+ scale_factor = target_norm / g_orth_norm
83
+ return update_2d.mul_(scale_factor)
84
+
85
+ def get_sinkhorn_wd_scaler(
86
+ p: torch.Tensor,
87
+ row_denom: torch.Tensor | None = None,
88
+ col_denom: torch.Tensor | None = None
89
+ ):
90
+ """
91
+ Computes a structural weight decay multiplier.
92
+ Penalizes parameters belonging to dominant rows/columns more heavily,
93
+ while protecting parameters in under-utilized/noisy rows/columns from decay.
94
+ """
95
+ if p.ndim < 2:
96
+ return 1.0
97
+
98
+ p_2d = p.view(p.shape[0], -1)
99
+
100
+ # Lower bounds based on the effective 2D shapes
101
+ row_lb = 1 / math.sqrt(p_2d.shape[1])
102
+ col_lb = 1 / math.sqrt(p_2d.shape[0])
103
+
104
+ # Get the norms
105
+ row_norms = torch.linalg.vector_norm(p_2d, ord=2, dim=1, keepdim=True).clamp_min_(row_lb)
106
+ col_norms = torch.linalg.vector_norm(p_2d, ord=2, dim=0, keepdim=True).clamp_min_(col_lb)
107
+
108
+ # Compute the structural scaler
109
+ row_factor = row_norms.sqrt_()
110
+ col_factor = col_norms.sqrt_()
111
+
112
+ if row_denom is not None and col_denom is not None:
113
+ # Reshape denominators to ensure safe in-place broadcasting
114
+ row_denom = row_denom.sqrt().view(p_2d.shape[0], 1)
115
+ col_denom = col_denom.sqrt().view(1, p_2d.shape[1])
116
+
117
+ # High denom (noise) -> smaller angle (protects weights)
118
+ # Low denom (confident) -> larger angle (decays weights)
119
+ row_factor.atan2_(row_denom)
120
+ col_factor.atan2_(col_denom)
121
+
122
+ # Outer product: merges the row and column confidences into a 2D matrix
123
+ wd_scaler = row_factor * col_factor
124
+
125
+ # Normalize the scaler so its mean is exactly 1.0
126
+ wd_scaler.div_(wd_scaler.mean().clamp_min_(1e-12))
127
+
128
+ return wd_scaler.view_as(p)
129
+
130
+ def apply_oft_sinkhorn(
131
+ update: torch.Tensor,
132
+ iters: int = 5,
133
+ p: torch.Tensor | None = None,
134
+ ortho_project: bool = False
135
+ ):
136
+ n_el = update.shape[-1]
137
+ block_size = int((1 + math.sqrt(1 + 8 * n_el)) / 2)
138
+ device, dtype = update.device, update.dtype
139
+ rows, cols = scaled_optm.get_cached_structural_tensors(block_size, device)
140
+ batch_size = update.shape[0]
141
+
142
+ # Initialize matrices
143
+ G = torch.zeros(batch_size, block_size, block_size, device=device, dtype=dtype)
144
+ batch_idx = torch.arange(batch_size, device=device)[:, None]
145
+
146
+ # Construct skew-symmetric gradient matrix G
147
+ G = G.index_put((batch_idx, rows, cols), update)
148
+ G = G - G.transpose(-2, -1)
149
+
150
+ # If OrthoGrad is enabled, construct the skew-symmetric parameter matrix Q
151
+ if ortho_project and p is not None:
152
+ Q = torch.zeros_like(G)
153
+ p_flat = p.view(batch_size, -1)
154
+ Q = Q.index_put((batch_idx, rows, cols), p_flat)
155
+ Q = Q - Q.transpose(-2, -1)
156
+ # Compute the squared Frobenius norm for each block (batch-wise)
157
+ Q_norm_sq = torch.sum(Q * Q, dim=(1, 2), keepdim=True).add_(1e-30)
158
+ # Theoretical norm of a Sinkhorn-normalized matrix to restore magnitude
159
+ target_norm = math.sqrt(block_size)
160
+
161
+ for _ in range(iters):
162
+ norms = torch.linalg.vector_norm(G, ord=2, dim=2, keepdim=True).clamp_min_(1e-12)
163
+ S = norms.sqrt_()
164
+ G.div_(S * S.mT)
165
+
166
+ # OrthoGrad step
167
+ if ortho_project and p is not None:
168
+ # Batch-wise Frobenius inner product
169
+ dot_prod = torch.sum(Q * G, dim=(1, 2), keepdim=True)
170
+ proj = dot_prod / Q_norm_sq
171
+ # Subtract projection
172
+ G.addcmul_(proj, Q, value=-1.0)
173
+ # Restore magnitude
174
+ g_orth_norm = torch.linalg.vector_norm(G, ord=2, dim=(1, 2), keepdim=True).clamp_min_(1e-12)
175
+ G.mul_(target_norm / g_orth_norm)
176
+
177
+ update.copy_(G[batch_idx, rows, cols])
178
+
179
+ # Global normalization
180
+ norm = torch.linalg.vector_norm(update).clamp_min_(1e-12)
181
+ target_norm_global = math.sqrt(update.numel())
182
+ update.mul_(target_norm_global / norm)
183
+
184
+ return update
185
+
186
+ @torch.no_grad()
187
+ def apply_spectral_oft_sinkhorn(
188
+ p: torch.Tensor,
189
+ update: torch.Tensor,
190
+ lr: float,
191
+ state: dict,
192
+ iters: int = 5,
193
+ ortho_project: bool = True
194
+ ) -> torch.Tensor:
195
+ """
196
+ Applies Spectral Normalization directly on the skew-symmetric gradient.
197
+ """
198
+ n_el = p.shape[-1]
199
+ block_size = int((1 + math.sqrt(1 + 8 * n_el)) / 2)
200
+ device, dtype = p.device, p.dtype
201
+ rows, cols = scaled_optm.get_cached_structural_tensors(block_size, device)
202
+
203
+ orig_shape = p.shape
204
+
205
+ # Align the scale of p with the forward pass
206
+ scale_factor = getattr(p, '_oft_scale_factor', 1.0)
207
+ batch_size = update.shape[0]
208
+
209
+ # Initialize matrices
210
+ G = torch.zeros(batch_size, block_size, block_size, device=device, dtype=dtype)
211
+ batch_idx = torch.arange(batch_size, device=device)[:, None]
212
+
213
+ # Construct skew-symmetric gradient matrix G
214
+ G = G.index_put((batch_idx, rows, cols), update)
215
+ G = G - G.transpose(-2, -1)
216
+
217
+ # If OrthoGrad is enabled, construct the skew-symmetric parameter matrix Q
218
+ if ortho_project and p is not None:
219
+ Q = torch.zeros_like(G)
220
+ p_flat = p.view(batch_size, -1)
221
+ Q = Q.index_put((batch_idx, rows, cols), p_flat)
222
+ Q = Q - Q.transpose(-2, -1)
223
+ # Compute the squared Frobenius norm for each block (batch-wise)
224
+ Q_norm_sq = torch.sum(Q * Q, dim=(1, 2), keepdim=True).add_(1e-30)
225
+ # Theoretical norm of a Sinkhorn-normalized matrix to restore magnitude
226
+ target_norm = math.sqrt(block_size)
227
+
228
+ for _ in range(iters):
229
+ norms = torch.linalg.vector_norm(G, ord=2, dim=2, keepdim=True).clamp_min_(1e-12)
230
+ S = norms.sqrt_()
231
+ G.div_(S * S.mT)
232
+
233
+ # OrthoGrad step
234
+ if ortho_project and p is not None:
235
+ # Batch-wise Frobenius inner product
236
+ dot_prod = torch.sum(Q * G, dim=(1, 2), keepdim=True)
237
+ proj = dot_prod / Q_norm_sq
238
+ # Subtract projection
239
+ G.addcmul_(proj, Q, value=-1.0)
240
+ # Restore magnitude
241
+ g_orth_norm = torch.linalg.vector_norm(G, ord=2, dim=(1, 2), keepdim=True).clamp_min_(1e-12)
242
+ G.mul_(target_norm / g_orth_norm)
243
+
244
+ update.copy_(G[batch_idx, rows, cols])
245
+
246
+ # Spectral Normalization on G
247
+ u_state = state['spectral_u'].unsqueeze(-1).to(dtype)
248
+ v_state = state['spectral_v'].unsqueeze(-1).to(dtype)
249
+ # Power Iteration step to estimate the largest singular value (sigma)
250
+ # Update v (Right Singular Vector)
251
+ v_raw = torch.bmm(G.mT, u_state)
252
+ v_norm = torch.linalg.vector_norm(v_raw, dim=1, keepdim=True)
253
+ candidate_v = v_raw / v_norm.clamp_min(1e-8)
254
+ next_v = torch.where(v_norm >= 1e-6, candidate_v, v_state)
255
+ # Update u (Left Singular Vector)
256
+ u_raw = torch.bmm(G, next_v)
257
+ u_norm = torch.linalg.vector_norm(u_raw, dim=1, keepdim=True)
258
+ candidate_u = u_raw / u_norm.clamp_min(1e-8)
259
+ next_u = torch.where(u_norm >= 1e-6, candidate_u, u_state)
260
+ state['spectral_v'].copy_(next_v.squeeze(-1))
261
+ state['spectral_u'].copy_(next_u.squeeze(-1))
262
+
263
+ # Estimate sigma (The spectral norm) for each block
264
+ sigma = torch.sum(next_u * u_raw, dim=1, keepdim=True)
265
+
266
+ # Squeeze out the last dimension so shape becomes (batch_size, 1)
267
+ sigma = sigma.squeeze(-1)
268
+
269
+ target_scale = 0.5 * scale_factor
270
+ spectral_eps = 1.0 / (2.0 * math.sqrt(block_size))
271
+
272
+ # Apply the clamp and scaling block-wise
273
+ scale = lr * (target_scale / sigma.clamp_min(spectral_eps))
274
+
275
+ return update.mul_(scale).view(orig_shape)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: adv_optm
3
- Version: 2.6.1.dev3
3
+ Version: 2.6.2.dev2
4
4
  Summary: A family of highly efficient, lightweight yet powerful optimizers.
5
5
  Home-page: https://github.com/Koratahiu/Advanced_Optimizers
6
6
  Author: Koratahiu
@@ -5,7 +5,7 @@ with open("README.md", "r", encoding="utf-8") as fh:
5
5
 
6
6
  setup(
7
7
  name="adv_optm",
8
- version="2.6.1.dev3",
8
+ version="2.6.2.dev2",
9
9
  author="Koratahiu",
10
10
  author_email="hiuhonor@gmail.com",
11
11
  license='Apache 2.0',
@@ -1,126 +0,0 @@
1
- import math
2
- import torch
3
-
4
- def apply_sr_sinkhorn(update: torch.Tensor, iters: int = 5, p: torch.Tensor | None = None, ortho_project: bool = False) -> torch.Tensor:
5
- """
6
- Applies Square-Root Sinkhorn (SR-Sinkhorn) multi-normalization.
7
- As described in 'Gradient Multi-Normalization for Efficient LLM Training'.
8
-
9
- This technique normalizes a 2D matrix alternatively by its row-wise L2 norm
10
- and column-wise L2 norm, driving it toward a fixed point that uniformly
11
- distributes update magnitudes.
12
- """
13
- original_shape = update.shape
14
- original_dtype = update.dtype
15
- update = update.float()
16
-
17
- # 1D Vector Case
18
- if update.dim() == 1:
19
- if ortho_project:
20
- p_float = p.float()
21
- p_norm_sq = torch.dot(p_float, p_float).add_(1e-30)
22
- proj = torch.dot(p_float, update) / p_norm_sq
23
- update.sub_(p_float * proj)
24
- norm = update.norm(p=2).clamp_min_(1e-12)
25
- return update.mul_(math.sqrt(update.numel()) / norm).view(original_shape).to(original_dtype)
26
-
27
- # 2D+ Matrix Case
28
- update_2d = update.view(update.shape[0], -1)
29
-
30
- m, n = update_2d.shape
31
-
32
- # Dynamically determine the order of normalization based on aspect ratio
33
- # Normalizing the longer dimension first aids stability.
34
- scale_cond = update_2d.shape[0] > update_2d.shape[1]
35
- dim = 0 if scale_cond else 1
36
-
37
-
38
- # Precompute scaling factors.
39
- scale_first = math.sqrt(m if scale_cond else n)
40
- scale_second = math.sqrt(n if scale_cond else m)
41
-
42
- if ortho_project:
43
- param_2d = p.float().view(p.shape[0], -1)
44
- p_norm_sq_dim = torch.sum(param_2d * param_2d, dim=dim, keepdim=True).add_(1e-30)
45
- p_norm_sq_adim = torch.sum(param_2d * param_2d, dim=1-dim, keepdim=True).add_(1e-30)
46
-
47
- # In-place alternating Sinkhorn normalization steps
48
- for _ in range(iters):
49
- # First normalization step
50
- # Stability floor: equivalent to a single-element vector norm lower bound (lb)
51
- norm1_lb = 1 / math.sqrt(update_2d.shape[dim])
52
- norm1 = update_2d.norm(p=2, dim=dim, keepdim=True).clamp_min_(norm1_lb)
53
- update_2d.mul_(scale_first / norm1)
54
- if ortho_project:
55
- update_2d = ortho_normed(param_2d, update_2d, p_norm_sq_dim, dim, scale_first)
56
-
57
- # Second normalization step
58
- norm2_lb = 1 / math.sqrt(update_2d.shape[1-dim])
59
- norm2 = update_2d.norm(p=2, dim=1-dim, keepdim=True).clamp_min_(norm2_lb)
60
- update_2d.mul_(scale_second / norm2)
61
- if ortho_project:
62
- update_2d = ortho_normed(param_2d, update_2d, p_norm_sq_adim, 1-dim, scale_second)
63
-
64
- return update_2d.view(original_shape).to(original_dtype)
65
-
66
- def ortho_normed(p_2d, update_2d, p_norm_sq, dim, target_norm):
67
- """
68
- Projects the update to be orthogonal to p along 'dim' and restores the original norm.
69
- """
70
- # Project: g_orth = g - (p * <p, g> / ||p||^2)
71
- dot_prod = torch.sum(p_2d * update_2d, dim=dim, keepdim=True)
72
- proj = dot_prod / p_norm_sq
73
-
74
- # In-place subtraction: update_2d = update_2d - (proj * p_2d)
75
- update_2d.addcmul_(proj, p_2d, value=-1.0)
76
-
77
- # Magnitude Preservation
78
- norm_lb = 1 / math.sqrt(update_2d.shape[dim])
79
- g_orth_norm = update_2d.norm(p=2, dim=dim, keepdim=True).clamp_min_(norm_lb)
80
- scale_factor = target_norm / g_orth_norm
81
- return update_2d.mul_(scale_factor)
82
-
83
- def get_sinkhorn_wd_scaler(
84
- p: torch.Tensor,
85
- row_denom: torch.Tensor | None = None,
86
- col_denom: torch.Tensor | None = None
87
- ):
88
- """
89
- Computes a structural weight decay multiplier.
90
- Penalizes parameters belonging to dominant rows/columns more heavily,
91
- while protecting parameters in under-utilized/noisy rows/columns from decay.
92
- """
93
- if p.ndim < 2:
94
- return 1.0
95
-
96
- p_2d = p.view(p.shape[0], -1)
97
-
98
- # Lower bounds based on the effective 2D shapes
99
- row_lb = 1 / math.sqrt(p_2d.shape[1])
100
- col_lb = 1 / math.sqrt(p_2d.shape[0])
101
-
102
- # Get the norms
103
- row_norms = torch.linalg.vector_norm(p_2d, ord=2, dim=1, keepdim=True).clamp_min_(row_lb)
104
- col_norms = torch.linalg.vector_norm(p_2d, ord=2, dim=0, keepdim=True).clamp_min_(col_lb)
105
-
106
- # Compute the structural scaler
107
- row_factor = row_norms.sqrt_()
108
- col_factor = col_norms.sqrt_()
109
-
110
- if row_denom is not None and col_denom is not None:
111
- # Reshape denominators to ensure safe in-place broadcasting
112
- row_denom = row_denom.sqrt().view(p_2d.shape[0], 1)
113
- col_denom = col_denom.sqrt().view(1, p_2d.shape[1])
114
-
115
- # High denom (noise) -> smaller angle (protects weights)
116
- # Low denom (confident) -> larger angle (decays weights)
117
- row_factor.atan2_(row_denom)
118
- col_factor.atan2_(col_denom)
119
-
120
- # Outer product: merges the row and column confidences into a 2D matrix
121
- wd_scaler = row_factor * col_factor
122
-
123
- # Normalize the scaler so its mean is exactly 1.0
124
- wd_scaler.div_(wd_scaler.mean().clamp_min_(1e-12))
125
-
126
- return wd_scaler.view_as(p)
File without changes
File without changes
File without changes