Skip to content

support loading fit checkpoints in JacobianLens.load() - #1574

Open
priyanka25aug wants to merge 4 commits into
TransformerLensOrg:devfrom
priyanka25aug:jonah-review-1539
Open

support loading fit checkpoints in JacobianLens.load()#1574
priyanka25aug wants to merge 4 commits into
TransformerLensOrg:devfrom
priyanka25aug:jonah-review-1539

Conversation

@priyanka25aug

Copy link
Copy Markdown

What this does

Extends JacobianLens.load() to accept fit checkpoints (files saved by the fitting pipeline with a jacobian_sum key) in addition to the existing artifact format (files with a J key).

The conversion lives in a new _from_checkpoint_payload() classmethod:

  • Divides the running Jacobian sums by n_prompts to recover the per-prompt mean
  • Harvests safe scalar provenance keys (model_name, model_revision, corpus) from the flat payload namespace into metadata
  • Strips fit-reserved keys (transformer_lens_fit, transformer_lens_version, model_system, etc.) so they don't leak into the converted lens
  • Drops tensor-valued metadata fields that can't survive weights_only=True reload, recording their names and shapes in dropped_fields for transparency
  • Sets converted_from: "jacobian_lens_checkpoint" so merge() naturally refuses to mix converted and natively TL-fitted lenses (provenance keys differ)

Raises ValueError with a clear message if the file has neither key, or if n_prompts <= 0. Tuned-lens support deferred.

Files changed

  • transformer_lens/tools/analysis/jacobian_lens.py — new _FIT_RESERVED_KEYS and _CHECKPOINT_FLAT_PROVENANCE frozensets; updated load(); new _from_checkpoint_payload()
  • tests/unit/tools/test_jacobian_lens_import.py — unit tests on synthetic fixtures covering artifact regression, checkpoint round-trip, dtype preservation, n_prompts=0 guard, tensor field dropping, fit-key stripping, and merge provenance rejection; no model/oracle dependency
  • docs/source/content/jacobian_lens_fitting.md — "Importing an existing lens" section added

Type of change

  • New feature (non-breaking change which adds functionality)
  • This change requires a documentation update

Checklist

  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • I have not rewritten tests relating to key interfaces which would affect backward compatibility

Testing

uv run pytest tests/unit/tools/test_jacobian_lens_import.py -v

@priyanka25aug

Copy link
Copy Markdown
Author

Hi @jlarson4 — all format, type, docstring, and benchmark checks are passing. The remaining long-running jobs (compatibility across Python 3.10/3.11/3.12 and full coverage) are still in progress but looking clean so far.

Would you mind taking a look when you get a chance? Happy to make any changes based on your feedback.

@jlarson4 jlarson4 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @priyanka25aug! Thanks for taking this on. Checkpoint import is a genuinely useful capability, and the conversion math, artifact-path safety, and merge sentinel are all done right.

A couple comments below that we should address before merging

Comment thread transformer_lens/tools/analysis/jacobian_lens.py Outdated
Comment thread transformer_lens/tools/analysis/jacobian_lens.py
Comment thread tests/unit/tools/test_jacobian_lens_import.py
Comment thread docs/source/content/jacobian_lens_fitting.md Outdated
…, fix tuned-lens note

- Remove "target_layer" from _FIT_RESERVED_KEYS so it survives checkpoint
  conversion and validate_model() can refuse non-final-target lenses
- Add test_load_checkpoint_mirrors_fit_payload_schema: fixture matches the
  exact keys fit() produces so format drift causes a test failure
- Fix tuned-lens note: it is the Jacobian artifact format that has no bias
  slot, not the tuned-lens format; tuned-lens translators are affine (weight + bias)
@priyanka25aug

priyanka25aug commented Aug 4, 2026

Copy link
Copy Markdown
Author

@jlarson4 All four of your review comments have been addressed in 08738f86 and 7aec2e7b:

  1. target_layer preservation — removed from _FIT_RESERVED_KEYS so it survives checkpoint conversion and validate_model() correctly raises for non-final-target checkpoints.
    1. Reference fixture — added test_load_checkpoint_mirrors_fit_payload_schema using the exact payload layout fit() produces, including flat provenance keys and nested fit-reserved metadata, with assertions that verify target_layer is preserved and fit-reserved keys are stripped.
    1. Tuned-lens note — corrected the direction: tuned-lens translators are affine (weight + bias), the Jacobian artifact format has no bias slot to receive the translation component.
    1. n_done key_from_checkpoint_payload now reads payload.get("n_done", payload.get("n_prompts", 0)), preferring n_done (the key the reference writer emits) with n_prompts as a fallback so genuine checkpoints aren't silently rejected.
      All threads are resolved. Could you please re-review and merge when you're happy? Thank you!

Real checkpoint writers (reference package) store the prompt count as
n_done, not n_prompts. Prefer n_done with n_prompts as fallback so
genuine checkpoints are not rejected with n_prompts=0.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NiwNUm3YFj9yAuSBuGDnd8
@jlarson4

jlarson4 commented Aug 4, 2026

Copy link
Copy Markdown
Collaborator

@priyanka25aug There is a CI failure that needs it be addressed still it looks like. The failure is an indicator of the remaining bug. n_done was one of three keys the reference writer disagrees with us about. Real checkpoints also carry no d_model (derivable from any jacobian_sum matrix's shape) and put target_layer at the top level rather than inside a nested metadata dict. With only the count fixed, a genuine checkpoint still cannot load, it just fails one line later with an unhandled KeyError. Worth opening write_checkpoint() (jlens/fitting.py:315-327 in anthropics/jacobian-lens@581d398) and working from its six keys directly rather than from my comments one at a time.

If the intent was a TransformerLens checkpoint format rather than the reference one, say so and we'll take the other fork: that would mean teaching fit() to write it (checkpoint_path / checkpoint_every, resumable), because nothing in either codebase emits the documented layout. The PR docstring describes the running-sum file "written during or after a fitting run", which reads as the reference format, so that is what I was assuming.

Suggested order:

  1. Derive d_model from a jacobian_sum matrix's shape rather than requiring the key, and harvest top-level target_layer alongside the flat provenance keys.
  2. Then make one fixture the verbatim six-key payload and assert both that it loads and that a checkpoint recording a non-final target_layer is refused by validate_model().
  3. test_load_checkpoint_with_zero_n_prompts_raises needs a decision rather than a patch: its jacobian_sum is empty, so it can never load however the schema lands. Give it a matrix and let it assert the round trip, and test the non-positive-count guard on its own synthetic file. Whichever error the empty-sums case raises, it should name the empty sums, rather than using n_prompts=0 or a bare KeyError.
  4. Update the docs schema table to the real key set – as written it documents n_prompts/d_model as required, which sends readers off to hand-build files.
  5. Small doc gap from 08738f86: the "Metadata handling" section still says keys written by fit() "are not carried over ... (transformer_lens_fit, transformer_lens_version, model_system, hook_convention, etc.)". target_layer is now a deliberate exception and documented in the code comment, but not the doc.

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.

2 participants