Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions baseline/experiments/mnist_mlp3_tangent_rg/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -890,3 +890,48 @@ index. It includes an expected-versus-observed method coverage audit and a
dedicated FC1/FC2 ECS plot whose marker positions are slightly offset for
visibility when full-row and detX fits coincide; the underlying epoch values
are never changed. Report generation does not recompute any Jacobian.

For the complete notebook-free state/flow/local-response experiment, run:

```bash
bash baseline/experiments/mnist_mlp3_tangent_rg/scripts/run_short100_complete_rg_analysis.sh
```

This command executes three scientifically distinct analyses before rebuilding
the static HTML report:

1. **Weight-state quotient representatives.** On FC1 and FC2, it fixes the
midpoint ECS rank from the independently recorded `clip_xmax`/detX audit,
chooses the rectangular-diagonal canonical section of the two-sided
`O(m) x O(n)` orbit, and materializes three declared representatives:
midpoint truncation, the nonlinear Gram counterterm
`lambda -> max(lambda-tau,0)` scanned at
`tau/lambda_boundary in {0.25,0.50,0.75}`, and an
epoch-10-anchor-frozen Feshbach/Schur downfolding with ridge ratio `1e-2`.
Every materialized `W'` is passed through WeightWatcher both raw and with
`fix_fingers=clip_xmax`; this phase writes
`weight_quotient_weightwatcher_fits.csv`, `weight_quotient_spectra.csv`, and
`weight_quotient_operators.csv`.
2. **Between-checkpoint RG flow.** Consecutive 10-epoch checkpoints produce
generalized-Gram radial rates, Procrustes-aligned transfer-core rates,
midpoint-ECS top-k Grassmann rates, and relative-polar tilt rates. These are
finite secant/transfer observables and are explicitly never labelled as the
optimizer Jacobian `D beta(W)`. The complete amplitudes and power-law fits
are written to `two_checkpoint_flow_*.csv`.
For the centered log-singular quotient coordinate it also compares the
observed secant `[R(W1)-R(W0)]/delta_s` with the true local map-Jacobian
prediction `D R_W0[W1-W0]/delta_s`, saving relative error and cosine in
`two_checkpoint_jacobian_transport.csv`.
3. **Single-checkpoint Jacobians.** In addition to the centered log-singular
radial and exact ECS-cover derivatives, the reduced CLI evaluates the
gap-aware projector, trace-free log Gram, trace-free ridge resolvent, and
Feshbach trace-free log derivatives on the detX shell for FC1 and FC2.
Square FC2 is handled by the same right-singular top-k Grassmann geometry as
wide FC1.

The single-checkpoint Feshbach map is an intentional collapse control. In the
checkpoint's own SVD frame the P-Q Gram coupling is exactly zero, so its shell
downfolding contribution vanishes at first order. The state-level Feshbach map
avoids that triviality by freezing P/Q from the independent epoch-10 anchor.
Neither construction is presented as the unique quotient of an unknown sum of
Muon updates; they are falsifiable, fully specified quotient hypotheses.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#!/usr/bin/env bash

# Complete notebook-free analysis: single-checkpoint Jacobians, transformed
# weight quotient representatives, finite between-checkpoint RG flow, and the
# static shareable HTML report.

set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)"
OUTPUT_ROOT="${RG_MNIST_REDUCED_JACOBIAN_OUTPUT_ROOT:-/private/tmp/rg-mnist-mlp3-short100-jacobians-reduced}"

export RG_MNIST_REDUCED_JACOBIAN_OUTPUT_ROOT="${OUTPUT_ROOT}"

bash "${SCRIPT_DIR}/run_short100_jacobians_reduced.sh" "$@"

python -u "${SCRIPT_DIR}/run_short100_quotient_flow_cli.py" \
--run-root "${RG_MNIST_TANGENT_ROOT:-/private/tmp/rg-mnist-mlp3-short100-runs}" \
--cache-root "${RG_MNIST_TANGENT_CHECKPOINT_CACHE_ROOT:-/private/tmp/rg-mnist-mlp3-short100-checkpoints}" \
--output-root "${OUTPUT_ROOT}"

bash "${SCRIPT_DIR}/build_short100_jacobian_report.sh"
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,12 @@
"centered_log_singular_radial_pullback",
"finite_muon_ns5_pullback",
)
EXTENDED_DETX_METHODS = (
"gap_aware_projector_detx_shell_pullback",
"trace_free_log_gram_detx_shell_pullback",
"gram_ridge_resolvent_detx_shell_zratio_0p50_pullback",
"feshbach_trace_free_log_detx_shell_pullback",
)


class MaxInfoFilter(logging.Filter):
Expand Down Expand Up @@ -440,6 +446,78 @@ def ecs_fit_amplitudes(record: Any, *, compress_groups: bool) -> tuple[np.ndarra
}


def extended_detx_jacobian_spectra(
weight: np.ndarray,
singular_values: np.ndarray,
*,
retained_rank: int,
outer_rank: int,
rcond: float,
) -> dict[str, tuple[np.ndarray, Any, dict[str, Any]]]:
"""Exact additional Jacobians on the independently audited detX shell.

The resolvent is the differentiable ridge/noise-control analogue. The
Feshbach derivative is retained even though its shell term must collapse
at first order in the checkpoint SVD gauge; that collapse is a scientific
control, not silently interpreted as nontrivial downfolding.
"""
from rg_baselines.tangent_rg import ecs_jacobians

k = int(retained_rank)
q = int(outer_rank)
boundary_scale = float(singular_values[k - 1] ** 2)
resolvent_z = 0.50 * boundary_scale
shell_floor = float(singular_values[q - 1] ** 2)
feshbach_z = 0.50 * shell_floor
records = {
"gap_aware_projector_detx_shell_pullback": (
ecs_jacobians.gap_aware_projector_spectrum(
weight, retained_rank=k, outer_rank=q, rcond=rcond,
precomputed_singular_values=singular_values,
),
{"jacobian_family": "gap_aware_projector", "retained_rank": k, "outer_rank": q},
),
"trace_free_log_gram_detx_shell_pullback": (
ecs_jacobians.outer_trace_free_log_gram_spectrum(
weight, outer_rank=q, rcond=rcond,
precomputed_singular_values=singular_values,
),
{"jacobian_family": "trace_free_log_gram", "retained_rank": k, "outer_rank": q},
),
"gram_ridge_resolvent_detx_shell_zratio_0p50_pullback": (
ecs_jacobians.outer_resolvent_spectrum(
weight, outer_rank=q, z=resolvent_z, trace_free=True,
rcond=rcond, precomputed_singular_values=singular_values,
),
{
"jacobian_family": "trace_free_gram_ridge_resolvent",
"retained_rank": k, "outer_rank": q,
"resolvent_z": resolvent_z,
"resolvent_z_boundary_ratio": 0.50,
},
),
"feshbach_trace_free_log_detx_shell_pullback": (
ecs_jacobians.feshbach_trace_free_log_spectrum(
weight, retained_rank=k, outer_rank=q, z=feshbach_z, rcond=rcond,
),
{
"jacobian_family": "feshbach_trace_free_log_effective_core",
"retained_rank": k, "outer_rank": q,
"feshbach_z": feshbach_z,
"first_order_shell_downfolding_active": False,
},
),
}
return {
method: (
np.asarray(record.singular_amplitudes, dtype=float),
record,
metadata,
)
for method, (record, metadata) in records.items()
}


def safe_slug(text: str) -> str:
return "".join(char if char.isalnum() or char in "-_" else "_" for char in text)

Expand Down Expand Up @@ -527,7 +605,20 @@ def build_parser() -> argparse.ArgumentParser:
parser.add_argument("--minimum-tail", type=int, default=8)
parser.add_argument("--ns-steps", type=int, default=5)
parser.add_argument("--ns-eps", type=float, default=1e-7)
parser.add_argument(
"--ecs-rcond", type=float, default=1e-9,
help="relative numerical-rank and differentiability tolerance for ECS maps",
)
parser.add_argument("--skip-ecs", action="store_true")
parser.add_argument(
"--extended-ecs-jacobians",
action=argparse.BooleanOptionalAction,
default=False,
help=(
"add gap-aware, trace-free log-Gram, ridge-resolvent, and "
"Feshbach exact Jacobians on each requested layer's detX shell"
),
)
parser.add_argument(
"--compress-ecs-groups",
action=argparse.BooleanOptionalAction,
Expand Down Expand Up @@ -646,6 +737,8 @@ def run(args: argparse.Namespace) -> int:
"ecs_grassmann_cartan_cover_full_row_shell_pullback",
"ecs_grassmann_cartan_cover_detx_shell_pullback",
})
if args.extended_ecs_jacobians:
expected_methods.update(EXTENDED_DETX_METHODS)
spectrum_data_available = expected_methods.issubset(observed_methods)
if args.resume and completed_before and spectrum_data_available:
completed += 1
Expand Down Expand Up @@ -702,7 +795,9 @@ def same_unit(row: dict[str, Any]) -> bool:
if not args.skip_ecs and layer in ecs_layers:
from rg_baselines.tangent_rg import single_checkpoint

numerical_rank = int(np.count_nonzero(singular > args.ns_eps * singular[0]))
numerical_rank = int(
np.count_nonzero(singular > args.ecs_rcond * singular[0])
)
ecs_rank_records = exact_ecs_ranks(
identity["seed_dir"], optimizer, seed, int(ref.epoch),
int(ref.global_step), layer, numerical_rank,
Expand All @@ -722,7 +817,7 @@ def same_unit(row: dict[str, Any]) -> bool:
)
for method, k, q, rank_metadata in ecs_rank_records:
cover = single_checkpoint.ecs_grassmann_cover_analytic_spectrum(
weight, retained_rank=k, outer_rank=q, rcond=args.ns_eps,
weight, retained_rank=k, outer_rank=q, rcond=args.ecs_rcond,
precomputed_singular_values=singular,
)
amplitudes, compression_metadata = ecs_fit_amplitudes(
Expand All @@ -739,6 +834,35 @@ def same_unit(row: dict[str, Any]) -> bool:
method, k, q, len(amplitudes), int(cover.derivative_rank),
args.compress_ecs_groups,
)
if (
args.extended_ecs_jacobians
and method
== "ecs_grassmann_cartan_cover_detx_shell_pullback"
):
for extended_method, (
extended_amplitudes,
extended_record,
extended_metadata,
) in extended_detx_jacobian_spectra(
weight,
singular,
retained_rank=k,
outer_rank=q,
rcond=args.ecs_rcond,
).items():
method_factories[extended_method] = (
extended_amplitudes,
extended_record,
)
method_metadata[extended_method] = {
**rank_metadata,
**extended_metadata,
"ecs_shell_variant": "detx_shell",
}
logger.info(
"EXTENDED JACOBIAN method=%s k=%d q=%d n_amplitudes=%d",
extended_method, k, q, len(extended_amplitudes),
)

base = {
"optimizer": optimizer,
Expand Down Expand Up @@ -838,6 +962,7 @@ def same_unit(row: dict[str, Any]) -> bool:
not args.skip_ecs and layer in ecs_layers
),
"ecs_layers_requested": ",".join(ecs_layers),
"extended_ecs_jacobians": bool(args.extended_ecs_jacobians),
"completed_at_utc": utc_now(),
})
atomic_csv(completion_path, completion_rows)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export RG_MNIST_JACOBIAN_CLI_OUTPUT_ROOT="${RG_MNIST_REDUCED_JACOBIAN_OUTPUT_ROO
exec bash "${SCRIPT_DIR}/run_short100_jacobians_cli.sh" \
--methods centered_log_singular_radial_pullback \
--ecs-layers fc1.weight,fc2.weight \
--extended-ecs-jacobians \
--compress-ecs-groups \
--top-k 0 \
"$@"
Loading
Loading