feat(aux-supervision): per-epoch aux observability in alpha_train (B6.5)
Smoke 1 at HEAD 21e7dfd63 showed BCE bit-identical to baseline
(asymmetric stop-grad isolation working) but zero aux signal in logs.
Adds:
- Per-epoch tracing 'aux snapshot' line with aux_huber_h{10,100,1000},
aux_dir_acc_h{10,100,1000}, stop_grad_aux_to_encoder
- AlphaTrainSummary JSON fields: final_aux_huber_ema_per_h,
final_aux_dir_acc_ema_per_h, final_stop_grad_aux_to_encoder
Reads PerceptionTrainer's pub fields directly (no accessor noise).
After re-running Smoke 1 we'll have empirical evidence whether aux is
learning on REAL ES MBP-10 data (vs the synthetic constant-direction
test where dir_acc trivially hits 1.0). This informs B7's gate threshold
design.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -239,6 +239,21 @@ struct AlphaTrainSummary {
|
||||
/// `--smoothness-base-lambda` is unset (default).
|
||||
#[serde(default)]
|
||||
final_smooth_loss_per_horizon: [f32; N_HORIZONS],
|
||||
/// Per-horizon Huber-loss EMA on the D-style aux supervision targets
|
||||
/// (Layer B). Stays at 0.0 if aux supervision is disabled. Tracks
|
||||
/// `PerceptionTrainer.aux_huber_ema_per_h` at the final epoch.
|
||||
#[serde(default)]
|
||||
final_aux_huber_ema_per_h: [f32; N_AUX_HORIZONS],
|
||||
/// Per-horizon directional accuracy EMA on the D-label sign (Layer B).
|
||||
/// > 0.85 with `aux_huber_ema < threshold` triggers the asymmetric
|
||||
/// stop-grad lift (`stop_grad_aux_to_encoder = false`).
|
||||
#[serde(default)]
|
||||
final_aux_dir_acc_ema_per_h: [f32; N_AUX_HORIZONS],
|
||||
/// Whether the asymmetric stop-grad was still active at the final epoch.
|
||||
/// `true` means aux trunk gradient never flowed back into the encoder
|
||||
/// (still "passive auditor" mode); `false` means the lift fired.
|
||||
#[serde(default)]
|
||||
final_stop_grad_aux_to_encoder: bool,
|
||||
}
|
||||
|
||||
/// Linear warmup then cosine decay to `lr_min`. `step_idx` is the
|
||||
@@ -636,6 +651,23 @@ fn main() -> Result<()> {
|
||||
tracing::warn!(epoch, error = %e, "isv snapshot failed (continuing)");
|
||||
}
|
||||
}
|
||||
|
||||
// SDD-3 Layer B6.5: aux supervision metrics per epoch (Layer B).
|
||||
// aux_huber_ema_per_h close to 0 = aux head learning; baseline
|
||||
// (predicting per-horizon mean of D-labels) is ~0.5-1.0. dir_acc
|
||||
// > 0.5 means aux predicts direction better than chance. Both
|
||||
// > thresholds trigger the asymmetric stop-grad lift (E3 design).
|
||||
tracing::info!(
|
||||
epoch,
|
||||
aux_huber_h10 = trainer.aux_huber_ema_per_h[0],
|
||||
aux_huber_h100 = trainer.aux_huber_ema_per_h[1],
|
||||
aux_huber_h1000 = trainer.aux_huber_ema_per_h[2],
|
||||
aux_dir_acc_h10 = trainer.aux_dir_acc_ema_per_h[0],
|
||||
aux_dir_acc_h100 = trainer.aux_dir_acc_ema_per_h[1],
|
||||
aux_dir_acc_h1000 = trainer.aux_dir_acc_ema_per_h[2],
|
||||
stop_grad_aux_to_encoder = trainer.stop_grad_aux_to_encoder,
|
||||
"aux snapshot"
|
||||
);
|
||||
final_val_loss = val_avg;
|
||||
final_val_auc = per_horizon_auc;
|
||||
n_val_seqs_consumed = val_loader.yielded();
|
||||
@@ -728,6 +760,9 @@ fn main() -> Result<()> {
|
||||
early_stopped,
|
||||
best_h1000_ckpt_path,
|
||||
final_smooth_loss_per_horizon: trainer.last_smoothness_loss_per_horizon(),
|
||||
final_aux_huber_ema_per_h: trainer.aux_huber_ema_per_h,
|
||||
final_aux_dir_acc_ema_per_h: trainer.aux_dir_acc_ema_per_h,
|
||||
final_stop_grad_aux_to_encoder: trainer.stop_grad_aux_to_encoder,
|
||||
};
|
||||
let summary_path = cli.out.join("alpha_train_summary.json");
|
||||
std::fs::write(&summary_path, serde_json::to_vec_pretty(&summary).context("serialize summary")?)
|
||||
|
||||
Reference in New Issue
Block a user