From eeb50b079dc2831947b09b174877fe454eaf387c Mon Sep 17 00:00:00 2001 From: YurenHao0426 Date: Wed, 22 Jul 2026 17:01:10 -0500 Subject: experiment: add dynamic neutral residual projection --- experiments/conv_local_smoke.py | 33 ++++++++++++++++++++++++++++ experiments/diagnose_kp_traffic_nonfinite.py | 10 +++++++-- 2 files changed, 41 insertions(+), 2 deletions(-) (limited to 'experiments') diff --git a/experiments/conv_local_smoke.py b/experiments/conv_local_smoke.py index dbae759..cdf1ad0 100644 --- a/experiments/conv_local_smoke.py +++ b/experiments/conv_local_smoke.py @@ -1003,6 +1003,26 @@ def kp_mixed_traffic_checks(): assert stable_fit["min_residual_soma_slope"] < -9e-4 assert stable_fit["max_applied_stability_margin"] >= 1e-3 + # A deliberately inaccurate slow predictor leaves an affine neutral mode. + # The fast controller must remove that mode using only paired neutral + # soma/traffic observations, without changing the predictor parameters or + # reading the task instruction during its coefficient fit. + frozen_before_projection = [value.clone() for value in + net.P_traffic + net.P_traffic_bias] + projected = net.mixed_apical_components( + instruction, forward["hiddens"], "innovation", + neutral_projection=True) + projection = projected["neutral_projection"] + projected_instruction_error = max(float((left - right).abs().max()) + for left, right in zip( + projected["innovation"], instruction)) + assert projected_instruction_error < 1e-14 + assert projection["post_projection_traffic_rms_ratio"] < 1e-14 + assert projection["max_absolute_post_projection_soma_slope"] < 1e-14 + assert projection["instruction_observations"] == 0 + assert all(torch.equal(before, after) for before, after in zip( + frozen_before_projection, net.P_traffic + net.P_traffic_bias)) + for slope, bias in zip(net.P_traffic, net.P_traffic_bias): slope.zero_() bias.zero_() @@ -1098,6 +1118,14 @@ def kp_mixed_traffic_checks(): assert all(not value.requires_grad for value in net.W + net.Q + net.P_traffic + net.P_traffic_bias + [net.W_out, net.R_out, net.b_out]) + projected_result = conv_kp_mixed_traffic_step( + net, x, y, ConvSDILConfig( + eta=1e-4, eta_output=1e-4, eta_P=0.1, momentum=0.0, + weight_decay=0.0, learn_A=False, learn_P=True), + step=2, rule="innovation", predictor_every=0, + neutral_projection=True) + assert math.isfinite(projected_result["loss"]) + assert projected_result["neutral_projection"] is not None assert net.mixed_elementwise_ops_per_example("matched") > ( net.mixed_elementwise_ops_per_example("raw")) return { @@ -1109,6 +1137,11 @@ def kp_mixed_traffic_checks(): "residual_traffic_rms_ratio"], "kp_traffic_closed_form_residual_slope": closed_form[ "max_absolute_residual_soma_slope"], + "kp_traffic_projected_instruction_error": projected_instruction_error, + "kp_traffic_projected_residual_ratio": projection[ + "post_projection_traffic_rms_ratio"], + "kp_traffic_projected_residual_slope": projection[ + "max_absolute_post_projection_soma_slope"], "kp_traffic_matched_norm_error": max(norm_errors), "kp_traffic_matched_direction_error": max(direction_errors), "kp_traffic_reciprocal_correlation_error": max(correlation_errors), diff --git a/experiments/diagnose_kp_traffic_nonfinite.py b/experiments/diagnose_kp_traffic_nonfinite.py index 7b7389f..d438e01 100644 --- a/experiments/diagnose_kp_traffic_nonfinite.py +++ b/experiments/diagnose_kp_traffic_nonfinite.py @@ -91,6 +91,7 @@ def main(): default="nlms20") parser.add_argument("--predictor_every", type=int, default=16) parser.add_argument("--stability_margin", type=float, default=0.0) + parser.add_argument("--neutral_projection", action="store_true") parser.add_argument("--device", default="cuda") parser.add_argument("--max_steps", type=int, default=352) parser.add_argument("--out", required=True) @@ -176,7 +177,8 @@ def main(): break result = conv_kp_mixed_traffic_step( net, x, y, config, step, args.rule, - predictor_every=args.predictor_every) + predictor_every=args.predictor_every, + neutral_projection=args.neutral_projection) state = network_state(net) bad = nonfinite_groups(state) for name, indices in bad.items(): @@ -210,6 +212,7 @@ def main(): "traffic_rms": result["traffic_rms"], "predictor_updated": result["did_predictor_update"], "predictor_mse": result["predictor_mse"], + "neutral_projection": result["neutral_projection"], "parameter_state": state, }) if active_bad or active_metric_names: @@ -226,13 +229,16 @@ def main(): if row["predictor_mse"] is not None: numeric.append(float(row["predictor_mse"])) output = { - "protocol": "kp_mixed_traffic_nonfinite_diagnosis_v1", + "protocol": ("kp_dynamic_neutral_projection_diagnosis_v1" + if args.neutral_projection + else "kp_mixed_traffic_nonfinite_diagnosis_v1"), "scope": "training_only_no_validation_or_test_evaluation", "provenance": provenance(), "rule": args.rule, "predictor_mode": args.predictor_mode, "predictor_every": args.predictor_every, "stability_margin": args.stability_margin, + "neutral_projection": args.neutral_projection, "max_steps": args.max_steps, "split": split, "traffic_calibration": calibration, -- cgit v1.2.3