diff options
Diffstat (limited to 'src/zbp_scaling/zbp/wp.py')
| -rw-r--r-- | src/zbp_scaling/zbp/wp.py | 28 |
1 files changed, 28 insertions, 0 deletions
diff --git a/src/zbp_scaling/zbp/wp.py b/src/zbp_scaling/zbp/wp.py new file mode 100644 index 0000000..ff2511d --- /dev/null +++ b/src/zbp_scaling/zbp/wp.py @@ -0,0 +1,28 @@ +"""Weight perturbation (parameter-space zeroth order) baseline: MeZO / CD-RGE / weight-space forward +gradient. All parameters are perturbed by eps*u (Rademacher), the loss is measured at +/- and the +gradient estimate is (1/n) sum_i u_i (L(theta+eps u_i) - L(theta-eps u_i)) / (2 eps). +2n forward passes of the whole network per step, no backward pass, variance ~ P/n with P = #params.""" +import torch + + +def wp_step(model, loss_fn, x, y, n, eps, gen): + params = [p for p in model.parameters() if p.requires_grad] + grads = [torch.zeros_like(p) for p in params] + with torch.no_grad(): + for i in range(n): + us = [(torch.randint(0, 2, p.shape, generator=gen, device=p.device).to(p.dtype) * 2 - 1) for p in params] + for p, u in zip(params, us): + p.add_(eps * u) + lp = loss_fn(model(x), y).item() + for p, u in zip(params, us): + p.sub_(2 * eps * u) + lm = loss_fn(model(x), y).item() + for p, u in zip(params, us): + p.add_(eps * u) + D = (lp - lm) / (2 * eps) + for g, u in zip(grads, us): + g.add_(u, alpha=D / n) + for p, g in zip(params, grads): + p.grad = g + loss = loss_fn(model(x), y) + return loss |
