summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYurenHao0426 <Blackhao0426@gmail.com>2026-07-22 17:02:45 -0500
committerYurenHao0426 <Blackhao0426@gmail.com>2026-07-22 17:02:45 -0500
commit8b28522305612d6300f485e14046ae38d49af426 (patch)
tree8d6d656783cf4f248cdde1c748d5f282008ebb40
parenteeb50b079dc2831947b09b174877fe454eaf387c (diff)
protocol: freeze dynamic projection training gate
-rw-r--r--DYNAMIC_INNOVATION.md90
-rw-r--r--THEORY.md26
-rwxr-xr-xexperiments/analyze_kp_dynamic_projection.py172
-rwxr-xr-xexperiments/kp_dynamic_projection_development.py44
4 files changed, 332 insertions, 0 deletions
diff --git a/DYNAMIC_INNOVATION.md b/DYNAMIC_INNOVATION.md
new file mode 100644
index 0000000..19e39da
--- /dev/null
+++ b/DYNAMIC_INNOVATION.md
@@ -0,0 +1,90 @@
+# Dynamic neutral-projection development protocol
+
+## Claim boundary
+
+This is a new post-S0 development branch. It does not reinterpret or rescue
+MT-1: MT-1 remains failed, MT-2/MT-3 remain sealed, and the reviewer score
+remains 5/10. S0 ruled out extending a fixed one-sided predictor margin. The
+new question is whether a fast *local and instruction-off* projection can keep
+the multiplicative neutral-residual mode inside its two-sided stability window
+as somatic statistics change.
+
+The slow predictor is still fitted exactly once on the original 64-example
+neutral calibration prefix and is frozen during task learning. Before each
+task update, every cell receives a paired instruction-off observation of its
+current soma `h` and ordinary apical traffic `a0`. From the neutral residual
+
+```text
+e0 = a0 - (P h + b),
+```
+
+it forms the current-batch local affine projection
+
+```text
+q = Cov(e0, h) / Var(h),
+e_stable = (e0 - mean(e0)) - q (h - mean(h)).
+```
+
+The plasticity signal is `r = s + e_stable`. The coefficient fit sees zero
+task-instruction observations; it reads no label, loss, forward weight,
+feedback weight, or downstream state, and it does not modify the slow
+predictor. For the diagonal affine traffic used by frozen MT-1, the controller
+nulls the current empirical residual-coupling coefficient. With weight decay,
+the scalar homogeneous mode is therefore placed near `k=-lambda`, inside both
+Jury boundaries, instead of at a fixed negative coefficient whose product with
+an evolving covariance can cross the lower boundary.
+
+This controller requires one paired neutral apical microphase per task batch.
+Its elementwise work and observation count must be charged separately in any
+later endpoint comparison. It uses zero task-loss perturbation queries and no
+reverse-mode differentiation.
+
+## D0: mechanics (completed before task-data evaluation)
+
+The implementation must prove on synthetic float64 tensors that:
+
+- an inaccurate frozen slow predictor leaves a nonzero affine neutral mode;
+- fast projection reduces the post-projection neutral/traffic RMS ratio and
+ residual-soma slope below `1e-14` for diagonal affine traffic;
+- projected innovation equals clean instruction below `1e-14`;
+- the projection consumes zero instruction observations and leaves every slow
+ predictor parameter bitwise unchanged;
+- forward and reciprocal correlations remain independently computed; and
+- the extra elementwise work is exposed explicitly.
+
+These checks passed at clean revision `eeb50b0`.
+
+## D1: frozen training-prefix gate
+
+There is exactly one candidate and no hyperparameter grid. Keep the MT-1
+ResNet-20 architecture, CIFAR-10 45k training split, seed-0 initialization,
+four-to-one traffic intervention, augmentation, batch size 128, learning rate
+0.1, momentum 0.9, decay `1e-4`, and reciprocal KP path unchanged. Use a
+zero-margin closed-form slow predictor, freeze it, and apply the fast neutral
+projection on every one of the first 352 shuffled task minibatches. Restore
+the task-loader state after calibration. Do not evaluate validation or test
+examples.
+
+The candidate passes only if all conditions below hold:
+
+- every recorded loss, signal diagnostic, parameter, optimizer state,
+ BatchNorm statistic, and projection diagnostic remains finite for 352 steps;
+- maximum task minibatch loss is at most 10 and final-32 mean loss is at most
+ 2.5;
+- the used-signal/instruction RMS ratio stays within `1e-4` of one;
+- the maximum post-projection neutral/traffic RMS ratio is at most `1e-5`;
+- the maximum absolute post-projection residual-soma slope is at most `1e-5`;
+- every projection uses the current task batch's 72--128 local neutral
+ observations and exactly zero instruction observations;
+- maximum absolute forward and reciprocal-feedback weight is at most 10;
+- maximum absolute forward and reciprocal momentum is at most 50;
+- the 64-observation slow fit has zero stability margin, the slow predictor is
+ frozen during task training, initial traffic calibration is within `1e-5`
+ of ratio 4, and task-loader state restoration is exact; and
+- validation and test evaluation counts are both zero.
+
+A failure closes this paired-neutral projection branch without changing a
+threshold or adding a gain/clipping hyperparameter. A pass supplies no task
+accuracy claim and cannot change the reviewer score. It only authorizes a new,
+separately committed validation protocol with an explicit cost boundary.
+
diff --git a/THEORY.md b/THEORY.md
index f659d0f..b8416a3 100644
--- a/THEORY.md
+++ b/THEORY.md
@@ -571,6 +571,32 @@ transient loss and parameter growth. This is consistent with the two-sided
condition above: sign control is necessary but does not bound the evolving
gain `d c` or nonnormal deep-network transients.
+The post-S0 dynamic controller instead separates a slow neutral predictor from
+a fast instruction-off projection. On the current minibatch, let its neutral
+residual be `e0=a0-P h-b`. Each cell forms
+
+```text
+q_t = Cov_t(e0, h) / Var_t(h),
+e_perp = (e0 - mean_t(e0)) - q_t (h - mean_t(h)).
+```
+
+Only `s+e_perp` enters plasticity. The fit for `q_t` never observes `s`, so it
+cannot regress away a task instruction merely because that instruction is
+correlated with soma. For the diagonal affine traffic intervention,
+`e0=D h+c` and hence `e_perp=0` in exact arithmetic at every task state. The
+effective homogeneous coefficient is then `k=-lambda`, which satisfies both
+Jury bounds for the frozen positive learning rate, momentum below one, and
+small positive decay. Unlike a fixed negative margin, nulling `D` is invariant
+to changes in the nonnegative input-covariance eigenvalue `c`.
+
+This is an empirical local certificate for the intervention being tested, not
+a global stability theorem for a nonlinear ResNet. Finite-batch regression,
+roundoff, cross-layer nonnormality, and traffic outside the diagonal affine
+family remain possible failure modes. The separately frozen D1 training-prefix
+gate in `DYNAMIC_INNOVATION.md` therefore requires both the measured local
+certificate and bounded loss, parameter, optimizer, and BatchNorm trajectories
+before any validation endpoint can open.
+
### Intermittent feedback tracking can hide behind a final cosine
An idealized mirror event every `k` task updates uses
diff --git a/experiments/analyze_kp_dynamic_projection.py b/experiments/analyze_kp_dynamic_projection.py
new file mode 100755
index 0000000..f7cef08
--- /dev/null
+++ b/experiments/analyze_kp_dynamic_projection.py
@@ -0,0 +1,172 @@
+#!/usr/bin/env python3
+"""Audit the frozen D1 dynamic neutral-projection training prefix."""
+import argparse
+import json
+import math
+import os
+import statistics
+
+
+SPLIT_HASH = "8328b206a97c420e49e54e3eca4abe3274c4756b084355784ea3fb8059e4515b"
+
+
+def numeric_leaves(value):
+ if isinstance(value, bool) or value is None:
+ return
+ if isinstance(value, (int, float)):
+ yield float(value)
+ elif isinstance(value, dict):
+ for child in value.values():
+ yield from numeric_leaves(child)
+ elif isinstance(value, (list, tuple)):
+ for child in value:
+ yield from numeric_leaves(child)
+
+
+def main():
+ parser = argparse.ArgumentParser()
+ parser.add_argument(
+ "--input", default="results/kp_dynamic_projection/dynamic.json")
+ parser.add_argument(
+ "--out", default="results/kp_dynamic_projection_gate.json")
+ args = parser.parse_args()
+ with open(args.input) as handle:
+ record = json.load(handle)
+ expected = {
+ "protocol": "kp_dynamic_neutral_projection_diagnosis_v1",
+ "scope": "training_only_no_validation_or_test_evaluation",
+ "rule": "innovation",
+ "predictor_mode": "closed_form",
+ "predictor_every": 0,
+ "stability_margin": 0.0,
+ "neutral_projection": True,
+ "max_steps": 352,
+ "validation_evaluations": 0,
+ "test_evaluations": 0,
+ }
+ for key, value in expected.items():
+ if record.get(key) != value:
+ raise ValueError(f"D1 {key} drift")
+ if record["provenance"]["git_tracked_dirty"]:
+ raise ValueError("tracked-dirty D1 record")
+ if record["split"]["validation_index_sha256"] != SPLIT_HASH:
+ raise ValueError("D1 split drift")
+ trajectory = record["trajectory"]
+ if len(trajectory) != 352:
+ raise ValueError("D1 trajectory is incomplete")
+
+ losses = [float(row["batch_loss"]) for row in trajectory]
+ signal_ratios = [
+ float(row["teaching_rms"])
+ / max(float(row["instruction_rms"]), 1e-30)
+ for row in trajectory]
+ reports = [row["neutral_projection"] for row in trajectory]
+ if any(report is None for report in reports):
+ raise ValueError("D1 projection report is missing")
+ state_finite = all(
+ value["all_finite"]
+ for row in trajectory
+ for value in row["parameter_state"].values())
+ all_finite = all(math.isfinite(value)
+ for value in numeric_leaves(record))
+
+ def state_max(group):
+ return max(float(row["parameter_state"][group][
+ "max_abs_over_finite_tensors"]) for row in trajectory)
+
+ forward_weight_max = state_max("forward_weight")
+ feedback_weight_max = state_max("feedback_weight")
+ forward_momentum_max = state_max("forward_momentum")
+ feedback_momentum_max = state_max("feedback_momentum")
+ fit = record["predictor_warmup"]["closed_form_fit"]
+ ratio_errors = [abs(float(value) - 4.0) for value in
+ record["traffic_calibration"][
+ "realized_traffic_instruction_rms_ratio"]]
+ maximum_post_ratio = max(float(report[
+ "post_projection_traffic_rms_ratio"]) for report in reports)
+ maximum_post_slope = max(float(report[
+ "max_absolute_post_projection_soma_slope"]) for report in reports)
+ maximum_pre_ratio = max(float(report[
+ "pre_projection_traffic_rms_ratio"]) for report in reports)
+ maximum_correction_slope = max(float(report[
+ "max_absolute_correction_slope"]) for report in reports)
+ observation_counts = [int(report["observations"]) for report in reports]
+ instruction_observations = [
+ int(report["instruction_observations"]) for report in reports]
+
+ checks = {
+ "record_trajectory_and_state_finite": (
+ all_finite and state_finite
+ and record["first_any_nonfinite_step"] is None
+ and record["first_training_failure_step"] is None),
+ "maximum_batch_loss_at_most_10": max(losses) <= 10.0,
+ "final_32_mean_loss_at_most_2p5": (
+ statistics.mean(losses[-32:]) <= 2.5),
+ "used_instruction_rms_ratio_within_1e_minus_4": (
+ max(abs(value - 1.0) for value in signal_ratios) <= 1e-4),
+ "post_projection_traffic_ratio_at_most_1e_minus_5": (
+ maximum_post_ratio <= 1e-5),
+ "post_projection_soma_slope_at_most_1e_minus_5": (
+ maximum_post_slope <= 1e-5),
+ "paired_local_neutral_observations_only": (
+ min(observation_counts) >= 72
+ and max(observation_counts) <= 128
+ and max(instruction_observations) == 0),
+ "forward_and_feedback_weight_max_at_most_10": (
+ forward_weight_max <= 10.0 and feedback_weight_max <= 10.0),
+ "forward_and_feedback_momentum_max_at_most_50": (
+ forward_momentum_max <= 50.0
+ and feedback_momentum_max <= 50.0),
+ "zero_margin_64_observation_slow_fit": (
+ int(fit["observations"]) == 64
+ and float(fit["stability_margin"]) == 0.0),
+ "slow_predictor_frozen_during_task": all(
+ row["predictor_updated"] is False for row in trajectory),
+ "traffic_ratio_calibrated": max(ratio_errors) <= 1e-5,
+ "task_loader_state_restored": (
+ record["predictor_warmup"][
+ "task_loader_state_restored"] is True),
+ "no_held_out_evaluations": (
+ record["validation_evaluations"] == 0
+ and record["test_evaluations"] == 0),
+ }
+ passed = all(checks.values())
+ output = {
+ "protocol": "kp_dynamic_neutral_projection_training_prefix_v1",
+ "status": "passed" if passed else "failed",
+ "checks": checks,
+ "metrics": {
+ "maximum_batch_loss": max(losses),
+ "final_32_mean_loss": statistics.mean(losses[-32:]),
+ "maximum_used_instruction_rms_ratio_error": max(
+ abs(value - 1.0) for value in signal_ratios),
+ "maximum_pre_projection_traffic_rms_ratio": maximum_pre_ratio,
+ "maximum_post_projection_traffic_rms_ratio": maximum_post_ratio,
+ "maximum_post_projection_soma_slope": maximum_post_slope,
+ "maximum_correction_slope": maximum_correction_slope,
+ "minimum_projection_observations": min(observation_counts),
+ "maximum_projection_observations": max(observation_counts),
+ "maximum_forward_weight": forward_weight_max,
+ "maximum_feedback_weight": feedback_weight_max,
+ "maximum_forward_momentum": forward_momentum_max,
+ "maximum_feedback_momentum": feedback_momentum_max,
+ "maximum_initial_traffic_ratio_error": max(ratio_errors),
+ },
+ "source_commit": record["provenance"]["git_commit"],
+ "validation_evaluations": 0,
+ "test_evaluations": 0,
+ "review_score_before": 5,
+ "review_score_after": 5,
+ "score_change_rule": (
+ "training-only stability evidence cannot change the paper score"),
+ }
+ os.makedirs(os.path.dirname(os.path.abspath(args.out)), exist_ok=True)
+ with open(args.out, "w") as handle:
+ json.dump(output, handle, indent=2, sort_keys=True)
+ handle.write("\n")
+ print(json.dumps(output, indent=2))
+
+
+if __name__ == "__main__":
+ main()
+
diff --git a/experiments/kp_dynamic_projection_development.py b/experiments/kp_dynamic_projection_development.py
new file mode 100755
index 0000000..1a6be90
--- /dev/null
+++ b/experiments/kp_dynamic_projection_development.py
@@ -0,0 +1,44 @@
+#!/usr/bin/env python3
+"""Run the sole frozen D1 dynamic neutral-projection candidate."""
+import argparse
+import json
+import os
+import subprocess
+import sys
+
+
+def main():
+ parser = argparse.ArgumentParser()
+ parser.add_argument("--device", default="cuda")
+ parser.add_argument("--dry_run", action="store_true")
+ parser.add_argument(
+ "--s0_gate", default="results/kp_innovation_stability_gate.json")
+ parser.add_argument(
+ "--out", default="results/kp_dynamic_projection/dynamic.json")
+ args = parser.parse_args()
+ with open(args.s0_gate) as handle:
+ gate = json.load(handle)
+ if (gate.get("protocol") != "kp_stability_margin_training_prefix_v1"
+ or gate.get("status") != "failed_no_eligible_margin"):
+ raise ValueError("D1 requires the audited failed S0 gate")
+ command = [
+ sys.executable,
+ "experiments/diagnose_kp_traffic_nonfinite.py",
+ "--rule", "innovation",
+ "--predictor_mode", "closed_form",
+ "--predictor_every", "0",
+ "--stability_margin", "0",
+ "--neutral_projection",
+ "--device", args.device,
+ "--max_steps", "352",
+ "--out", args.out,
+ ]
+ print(" ".join(command), flush=True)
+ if not args.dry_run:
+ os.makedirs(os.path.dirname(os.path.abspath(args.out)), exist_ok=True)
+ subprocess.run(command, check=True)
+
+
+if __name__ == "__main__":
+ main()
+