summaryrefslogtreecommitdiff
path: root/src/zbp_scaling/diagnostics.py
blob: 4fa37479f2c4cc813d95ec0a739eb4a305030346 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
"""Branch-gain profile rho_k and the NSR constant c(scale) = L * mean(rho) (THEORY.md T2/corollary).
Validation-only: uses the simulation autograd for exact J_F^T v."""
import torch
import torch.nn as nn
from .zbp import zbp_blocks, ZBPConfig


@torch.enable_grad()
def rho_profile(model, x, y):
    blocks = zbp_blocks(model)
    cfgs = [b.cfg for b in blocks]
    for b in blocks:
        b.cfg = b.cfg.replace(mode="exact")
        b.capture = True
    model.zero_grad(set_to_none=True)
    nn.functional.cross_entropy(model(x).flatten(0, 1), y.flatten()).backward()
    out = {}
    for b, c in zip(blocks, cfgs):
        b.cfg = c
        b.capture = False
        b.captured = None
    # rho via a recorded pass: |J_F^T v| / |v| per block from the Recorder
    from .zbp import Recorder
    for b in blocks:
        b.cfg = b.cfg.replace(mode="zero")
    with Recorder() as rec:
        model.zero_grad(set_to_none=True)
        nn.functional.cross_entropy(model(x).flatten(0, 1), y.flatten()).backward()
    for b, c in zip(blocks, cfgs):
        b.cfg = c
    model.zero_grad(set_to_none=True)
    rows = rec.summary()
    for name, r in rows.items():
        out[name] = (r["gnorm"] / max(r["vnorm"], 1e-30)) ** 2 if "vnorm" in r else None
    return out