Skip to content

Add a self-supervised window-summary head and the window-statistic probes - #251

Open
amrit110 wants to merge 4 commits into
mainfrom
summary-head
Open

amrit110 wants to merge 4 commits into
mainfrom
summary-head

Conversation

@amrit110

Copy link
Copy Markdown
Member

Frozen probes on full_run_v10 (scripts/probe_summary_signal.py, new) show
the backbone's state holds current levels of the GBM's signal panel but
not changes from the visit's first value (creatinine delta R^2 0.00) and
not fine window counts, under a linear and a tree probe alike. Those are
the contents of the GBM's margin on AKI and the counting events.

This adds an auxiliary, training-only objective that asks the state to
report those statistics:

  • odyssey/training/summary_targets.py: the target panel (per-signal
    min/max/mean over 6 h and 24 h, change from visit-first, per drug-class
    and per-family counts over 6 h and 24 h), computed by the GBM's own
    feature code at 4-hourly landmark rows; standardization (counts through
    log1p, winsorized at 0.5/99.5 percentiles); per-visit tables; and the
    per-chunk lookup that places each target on the last token of its
    bundle. Targets are computed from the input and never fed in.
  • odyssey/models/summary_head.py: a linear (or MLP) head and a masked
    Huber loss that is zero with a live graph where no target applies.
  • Both sequence models take summary_targets/summary_head_hidden, add the
    weighted loss to the streaming and steering objectives, and report a
    summary_loss component.
  • TrainingConfig gains summary_targets_dir, summary_weight,
    summary_head_hidden and summary_num_targets (recorded at training time
    so a checkpoint rebuilds the same head); the training loop, validation
    and load_run are wired accordingly. None (the default) reproduces every
    existing run.
  • scripts/build_summary_targets.py precomputes the targets per shard in
    parallel and fits the stats.

Tests cover the target names, landmark rows, target values (baseline
change, counts, NaN for unmeasured), stats, JSON round trip, chunk
placement on bundle ends, padding, the head, the masked loss, and the
model wiring. 1927 tests pass; ruff, format and mypy clean.

Co-Authored-By: Claude Fable 5.1 noreply@anthropic.com
Claude-Session: https://claude.ai/code/session_01StsjDmueuDqVNNuVoCEF1P

amrit110 and others added 3 commits September 13, 2026 22:10
…obes

Frozen probes on full_run_v10 (scripts/probe_summary_signal.py, new) show
the backbone's state holds current levels of the GBM's signal panel but
not changes from the visit's first value (creatinine delta R^2 0.00) and
not fine window counts, under a linear and a tree probe alike. Those are
the contents of the GBM's margin on AKI and the counting events.

This adds an auxiliary, training-only objective that asks the state to
report those statistics:

- odyssey/training/summary_targets.py: the target panel (per-signal
  min/max/mean over 6 h and 24 h, change from visit-first, per drug-class
  and per-family counts over 6 h and 24 h), computed by the GBM's own
  feature code at 4-hourly landmark rows; standardization (counts through
  log1p, winsorized at 0.5/99.5 percentiles); per-visit tables; and the
  per-chunk lookup that places each target on the last token of its
  bundle. Targets are computed from the input and never fed in.
- odyssey/models/summary_head.py: a linear (or MLP) head and a masked
  Huber loss that is zero with a live graph where no target applies.
- Both sequence models take summary_targets/summary_head_hidden, add the
  weighted loss to the streaming and steering objectives, and report a
  summary_loss component.
- TrainingConfig gains summary_targets_dir, summary_weight,
  summary_head_hidden and summary_num_targets (recorded at training time
  so a checkpoint rebuilds the same head); the training loop, validation
  and load_run are wired accordingly. None (the default) reproduces every
  existing run.
- scripts/build_summary_targets.py precomputes the targets per shard in
  parallel and fits the stats.

Tests cover the target names, landmark rows, target values (baseline
change, counts, NaN for unmeasured), stats, JSON round trip, chunk
placement on bundle ends, padding, the head, the masked loss, and the
model wiring. 1927 tests pass; ruff, format and mypy clean.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01StsjDmueuDqVNNuVoCEF1P
- check-docstring-first read the module-level attribute docstrings in the
  new target module and probe script as second module docstrings; they
  are comments now.
- pre-commit.ci's autofix had rewritten 12 scripts/gemini/out/ JSONs
  (trailing newlines) on this branch, the same way it did on PR #250.
  This carries PR #250's hook config over: scripts/gemini/out/ is
  excluded from every hook, and mypy/typos skip the two cohort producers
  committed verbatim, which is also what has been failing main's code
  check. The 12 exports are byte-identical to main again.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01StsjDmueuDqVNNuVoCEF1P
@codecov

codecov Bot commented Sep 14, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 96.03175% with 10 lines in your changes missing coverage. Please review.
✅ Project coverage is 90.12%. Comparing base (31144a5) to head (3474f2c).

Files with missing lines Patch % Lines
odyssey/training/train.py 80.00% 6 Missing ⚠️
odyssey/training/summary_targets.py 98.32% 3 Missing ⚠️
odyssey/inference/run_inference.py 83.33% 1 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main     #251      +/-   ##
==========================================
+ Coverage   89.98%   90.12%   +0.13%     
==========================================
  Files          69       71       +2     
  Lines       10771    11023     +252     
==========================================
+ Hits         9692     9934     +242     
- Misses       1079     1089      +10     
Files with missing lines Coverage Δ
odyssey/models/sequence_model.py 96.45% <100.00%> (+0.18%) ⬆️
odyssey/models/summary_head.py 100.00% <100.00%> (ø)
odyssey/inference/run_inference.py 93.81% <83.33%> (-0.15%) ⬇️
odyssey/training/summary_targets.py 98.32% <98.32%> (ø)
odyssey/training/train.py 88.28% <80.00%> (-0.40%) ⬇️

Impacted file tree graph

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

…loss

The first arm (weight 0.5, every target equal) tripled how readable the
window levels are from the state but left the two targets the GBM's
margin sits on almost untouched: creatinine change from admission went
from R^2 0.00 to 0.23 after the bottleneck and stayed at ~0 before it,
and the vasopressor 6 h count did not move. Levels are 241 of the 328
targets and won the average.

`summary_change_weight` multiplies the delta_visit_first and count
targets inside the masked Huber average (masked_huber_loss gains an
optional per-target weight vector; ForecastObjective carries it). 1.0
reproduces the first arm exactly. Run A uses 4.0 with the overall summary
weight raised to 2.0.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01StsjDmueuDqVNNuVoCEF1P

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant