SOlPHMdSY3 / code /claim5_stability.py
DineshAI's picture
Publish cumulative five-claim reproduction evidence
beea5e8 verified
Raw
History Blame Contribute Delete
9.61 kB
"""Paper-scale CPU reproduction of the critical-depth NTK experiment."""
import json
import time
import jax
jax.config.update("jax_platform_name", "cpu")
import jax.numpy as jnp
import numpy as np
WIDTH = 200
DEPTH = 30
N_NETWORKS = 1000
N_PROBES = 4
BATCH_SIZE = 4
SEED = 250811522
INPUTS = np.array(
[
[-0.9895229339599609, -0.5992491841316223],
[-0.17877478897571564, 2.253682851791382],
],
dtype=np.float32,
)
REGIMES = {"low": 0.25, "critical": 2.0, "high": 4.0}
def init_params(key, width: int, depth: int, c_w: float):
keys = jax.random.split(key, depth)
shapes = [(width, INPUTS.shape[1])] + [(width, width)] * (depth - 1)
return tuple(
jnp.sqrt(jnp.float32(c_w))
* jax.random.normal(layer_key, shape, dtype=jnp.float32)
for layer_key, shape in zip(keys, shapes, strict=True)
)
def forward_all_layers(params, inputs):
z = inputs
outputs = []
for layer, weights in enumerate(params):
activations = z if layer == 0 else jax.nn.relu(z)
z = activations @ weights.T / jnp.sqrt(jnp.float32(activations.shape[-1]))
outputs.append(z)
return jnp.stack(outputs)
def rademacher_tangent(key, params):
keys = jax.random.split(key, len(params))
return tuple(
jax.random.rademacher(tangent_key, weights.shape, dtype=jnp.float32)
for tangent_key, weights in zip(keys, params, strict=True)
)
def one_network(key, c_w: float, width: int, depth: int, probes: int):
parameter_key, probe_root = jax.random.split(key)
params = init_params(parameter_key, width, depth, c_w)
probe_keys = jax.random.split(probe_root, probes)
def one_probe(probe_key):
tangent = rademacher_tangent(probe_key, params)
_, directional = jax.jvp(
lambda p: forward_all_layers(p, jnp.asarray(INPUTS)),
(params,),
(tangent,),
)
theta_00 = jnp.mean(directional[:, 0] ** 2, axis=-1)
theta_01 = jnp.mean(directional[:, 0] * directional[:, 1], axis=-1)
theta_11 = jnp.mean(directional[:, 1] ** 2, axis=-1)
return jnp.stack((theta_00, theta_01, theta_11), axis=-1)
return jnp.mean(jax.vmap(one_probe)(probe_keys), axis=0)
def regression(x, y):
design = np.column_stack((np.ones_like(x), x))
intercept, slope = np.linalg.lstsq(design, y, rcond=None)[0]
fitted = intercept + slope * x
ss_res = float(np.sum((y - fitted) ** 2))
ss_tot = float(np.sum((y - np.mean(y)) ** 2))
return {
"intercept": float(intercept),
"slope": float(slope),
"r_squared": float(1.0 - ss_res / ss_tot) if ss_tot else 1.0,
}
def summarize(samples):
n = samples.shape[0]
mean = samples.mean(axis=0)
standard_deviation = samples.std(axis=0, ddof=1)
standard_error = standard_deviation / np.sqrt(n)
layers = np.arange(1, samples.shape[1] + 1, dtype=np.float64)
slopes = np.einsum("l,nlc->nc", layers, samples) / np.dot(layers, layers)
return {
"mean": mean.tolist(),
"standard_deviation": standard_deviation.tolist(),
"standard_error": standard_error.tolist(),
"per_network_through_origin_slopes": slopes.tolist(),
"through_origin_slope_mean": slopes.mean(axis=0).tolist(),
"through_origin_slope_standard_error": (
slopes.std(axis=0, ddof=1) / np.sqrt(n)
).tolist(),
}
def critical_checks(summary, low_summary, high_summary):
layers = np.arange(1, DEPTH + 1, dtype=np.float64)
observed = np.asarray(summary["mean"], dtype=np.float64)
standard_error = np.asarray(summary["standard_error"], dtype=np.float64)
expected_slope = float(np.dot(INPUTS[0], INPUTS[0]) / INPUTS.shape[1])
expected = expected_slope * layers
residual = observed[:, 0] - expected
safe_se = np.maximum(standard_error[:, 0], np.finfo(np.float64).eps)
slope_through_origin = float(summary["through_origin_slope_mean"][0])
slope_se = float(summary["through_origin_slope_standard_error"][0])
slope_z = abs(slope_through_origin - expected_slope) / max(slope_se, np.finfo(float).eps)
critical_diag_regression = regression(layers, observed[:, 0])
critical_offdiag_regression = regression(layers[9:], observed[9:, 1])
high = np.maximum(np.asarray(high_summary["mean"], dtype=np.float64)[:, 0], 1e-30)
high_log_regression = regression(layers[9:], np.log(high[9:]))
low = np.maximum(np.asarray(low_summary["mean"], dtype=np.float64)[:, 0], 1e-30)
low_log_regression = regression(layers[9:], np.log(low[9:]))
high_expected_residual = high - expected
high_se = np.maximum(
np.asarray(high_summary["standard_error"], dtype=np.float64)[:, 0],
np.finfo(np.float64).eps,
)
high_falsely_critical = bool(
abs(float(np.dot(layers, high, ) / np.dot(layers, layers)) - expected_slope)
/ max(float(np.sqrt(np.sum((layers * high_se) ** 2)) / np.dot(layers, layers)), np.finfo(float).eps)
<= 3.0
and np.max(np.abs(high_expected_residual) / np.maximum(expected, 1e-30)) <= 0.10
)
checks = {
"exact_paper_scale": WIDTH == 200 and DEPTH == 30 and N_NETWORKS == 1000,
"critical_slope_within_3_standard_errors": slope_z <= 3.0,
"critical_max_relative_deviation_at_most_10_percent": (
float(np.max(np.abs(residual) / expected)) <= 0.10
),
"critical_at_least_27_of_30_points_within_99pct_pointwise_ci": (
int(np.sum(np.abs(residual) <= 2.576 * safe_se)) >= 27
),
"critical_diagonal_linear_r_squared_at_least_0_995": (
critical_diag_regression["r_squared"] >= 0.995
),
"critical_offdiagonal_asymptotic_linear_r_squared_at_least_0_98": (
critical_offdiag_regression["r_squared"] >= 0.98
),
"high_variance_control_has_positive_exponential_log_slope": (
high_log_regression["slope"] >= 0.20
),
"low_variance_control_has_negative_exponential_log_slope": (
low_log_regression["slope"] <= -0.20
),
"high_variance_curve_rejected_by_critical_contract": not high_falsely_critical,
}
return {
"expected_critical_diagonal_slope": expected_slope,
"observed_critical_diagonal_slope_through_origin": slope_through_origin,
"observed_slope_standard_error": slope_se,
"observed_slope_z": float(slope_z),
"critical_max_relative_deviation": float(np.max(np.abs(residual) / expected)),
"critical_points_within_99pct_pointwise_ci": int(
np.sum(np.abs(residual) <= 2.576 * safe_se)
),
"critical_diagonal_regression": critical_diag_regression,
"critical_offdiagonal_regression_depths_10_to_30": critical_offdiag_regression,
"high_diagonal_log_regression_depths_10_to_30": high_log_regression,
"low_diagonal_log_regression_depths_10_to_30": low_log_regression,
"negative_control_high_falsely_accepted_as_critical": high_falsely_critical,
"checks": checks,
"passed": all(checks.values()),
}
def run_paper_scale():
started = time.perf_counter()
regime_summaries = {}
regime_seeds = {}
for regime_index, (name, c_w) in enumerate(REGIMES.items()):
seed = SEED + 100_000 * regime_index
regime_seeds[name] = seed
keys = jax.random.split(jax.random.PRNGKey(seed), N_NETWORKS)
batched = jax.jit(
jax.vmap(
lambda network_key: one_network(
network_key, c_w, WIDTH, DEPTH, N_PROBES
)
)
)
batches = []
regime_started = time.perf_counter()
for lower in range(0, N_NETWORKS, BATCH_SIZE):
upper = min(lower + BATCH_SIZE, N_NETWORKS)
batches.append(np.asarray(batched(keys[lower:upper])))
if upper % 100 == 0:
print(
f"CLAIM5_PROGRESS regime={name} networks={upper}/{N_NETWORKS} "
f"seconds={time.perf_counter() - regime_started:.1f}",
flush=True,
)
samples = np.concatenate(batches, axis=0).astype(np.float64)
regime_summaries[name] = summarize(samples)
regime_summaries[name]["runtime_seconds"] = time.perf_counter() - regime_started
verification = critical_checks(
regime_summaries["critical"],
regime_summaries["low"],
regime_summaries["high"],
)
return {
"claim": (
"At C_W=2, a bias-free width-200 ReLU MLP has linearly scaling "
"mean NTK through depth 30; away from C_W=2 it is exponentially unstable"
),
"estimator": (
"Appendix C output-channel trace average with unbiased Rademacher "
"Hutchinson parameter-space probes"
),
"inputs": INPUTS.tolist(),
"width": WIDTH,
"depth": DEPTH,
"network_initializations_per_regime": N_NETWORKS,
"hutchinson_probes_per_network": N_PROBES,
"regimes": REGIMES,
"seeds": regime_seeds,
"columns": ["theta_00", "theta_01", "theta_11"],
"layers": list(range(1, DEPTH + 1)),
"summaries": regime_summaries,
"verification": verification,
"runtime_seconds": time.perf_counter() - started,
"passed": verification["passed"],
}
def main():
result = run_paper_scale()
print(json.dumps(result, indent=2, sort_keys=True))
return 0 if result["passed"] else 1
if __name__ == "__main__":
raise SystemExit(main())