v0.4.0 ↔ main model equivalence check (spike analysis) - #282
Open
Haddox wants to merge 3 commits into
Open
Conversation
…ts.png) Demonstrates that the manuscript 0.4.0 global-epistasis-with-shifts model and the current main formulation are one forward model in two coordinate systems, and that the transformation preserves the Huber loss. - check_equivalence_from_image.ipynb: self-contained notebook (auto-downloads the committed spike CSVs from the pinned SARS-CoV-2_spike_multidms commit; GE shape read from ge_fits.png). Three checks pass: (1) 0.4.0 and main per-condition Huber losses coincide (exactly as D_d -> 0); (2) predicted-vs-observed Pearson r matches func_score_corr.png (0.795 / 0.891 / 0.876); (3) main's functional_score_loss reproduces the main-form loss. - compute_equivalence.py / pick_example_variant.py: script form + real-variant walkthrough. - data/ (large CSVs) is gitignored and fetched at runtime. Refs #281 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Mirror the issue #281 wording into the notebook's worked-example cell: describe how each pipeline assembles the latent phenotype (Step 2) and clarify that Step 3 passes it through the sigmoid global-epistasis function. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
convert_040_to_main_params.py maps a fitted multidms 0.4.0 model to the full parameter set that initializes a `main` jaxmodels.Model at the same point in parameter space, and writes three CSVs (main_init_params/) that specify it: beta per (condition, mutation), per-condition beta0/logtheta, and the global scalars/structural choices (alpha, reference, Sigmoid GE, ...). Runs on spike replicate 2 (image-inferred GE shape) and verifies the CSVs round-trip: a Model rebuilt from them matches an in-memory Model's per-condition functional_score_loss to machine precision, and reproduces the func_score_corr.png correlations. Mirrors the converter into the notebook as a final cell. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This was referenced Aug 18, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a self-contained validation experiment (
experiments/v04-equivalence/) showing that themanuscript multidms 0.4.0 global-epistasis-with-shifts model and the current
main(PR #164) model are one forward model in two coordinate systems, and that the change of
variables preserves the Huber loss.
The map from a fitted 0.4.0 model to
main's parameters is:β_d = β + Δ_d— per-condition absolute effect vector (reference:Δ = 0 ⇒ β_ref = β)β0,d = β0 + α_d— fold the additive offset into the per-condition interceptα = θ_scale— the 0.4.0 sigmoid range becomesmain's output scaleWith these, both formulations evaluate the same latent phenotype
φ_d(v); the two Huber residualsdiffer only by a per-condition constant
D_d = θ_bias + θ_scale·σ(φ_wt,d), which vanishes when thefit places each homolog's wildtype at predicted score 0.
Dataset
The notebook evaluates the SARS-CoV-2 spike deep-mutational-scanning data from the manuscript
analysis (
matsengrp/SARS-CoV-2_spike_multidms@6c98b7b), the same fit reported in the paper:shared effect vector
βplus per-homolog shiftsΔ_d.mutations_df.csv(at the chosen shift-lasso4e-5); observed per-variant functional scores come fromtraining_functional_scores.csv(replicate 2), collapsing identical variants by mean to match the fit's
collapse_identical_variants="mean". These CSVs (~48 MB) are fetched at runtime from the pinnedcommit and are git-ignored.
Relationship to the two images
The committed CSVs give
βand the shifts, but not the sigmoid global-epistasis shapeparameters (no fitted pickle is available). We recover those from two diagnostic figures from the
0.4.0 spike fit:
ge_fits.png(global-epistasis curve: observed functional score vs. predicted latentφ,with the fitted sigmoid
g(φ) = θ_scale·σ(φ) + θ_biasand each homolog's wildtype marked). Fromit we read the shape parameters used to reconstruct the 0.4.0 model:
θ_scale ≈ 7.4(range),θ_bias ≈ −3.4(lower asymptote), andφ_wt ≈ −0.4(wildtype latent). Crucially, the wildtypelines sit on the
g(φ) = 0crossing, i.e.D_d ≈ 0— the condition that makes the loss identityexact.
func_score_corr.png(observed vs. predicted functional score, per homolog: Delta r ≈ 0.80,BA1 ≈ 0.86–0.90, BA2 ≈ 0.86–0.88). This is the validation target: recomputing predicted
functional scores from the reconstructed model should reproduce these correlations.
Both figures are included in the experiment folder for reference.
Key results
Huber loss preserved. With
θ_biascalibrated soD_d = 0, the 0.4.0 andmainper-condition Huber losses are identical to machine precision:
With the raw eyeballed
θ_bias = −3.4(D_d ≈ −0.43) the gap is still tiny (≤ 0.047 percondition) — confirming the losses coincide as
D_d → 0.Correlations match
func_score_corr.png. Recomputed predicted-vs-observed Pearson r(identical under both forms): Delta 0.795, Omicron_BA1 0.891, Omicron_BA2 0.876 —
matching the published ~0.80 / 0.86–0.90 / 0.86–0.88.
maincode-path agrees.jaxmodels.functional_score_lossreproduces the main-form loss forall three homologs.
Initializing a
mainmodel from the 0.4.0 fitBeyond validating the loss identity,
convert_040_to_main_params.pymaterializes the mappedparameters as CSVs, so a
mainjaxmodels.Modelcan be initialized at the exact point inparameter space implied by the 0.4.0 fit — no pkl, no re-fit. It applies the map above
(
β_d = β + Δ_d;β0,d = φ_wt,d − x_wt,d·β_d;α = θ_scale;logθ_d = 0;θ_biascalibrated soD_d = 0), runs it on the spike replicate-2 parameter set, and writes three CSVs tomain_init_params/that together fully specify aModel:main_params_beta.csv(condition, mutation, beta), 3 × 10,870 rowsModel.φ[c].βmain_params_latent.csvbeta0,logtheta,is_reference(+phi_wt,D_ddiagnostics)Model.φ[c].β0,Model.logθ[c]main_params_global.csvalpha=7.4,reference_condition=Omicron_BA1,global_epistasis=Sigmoid,output_activation=IdentityOutput,huber_delta=1.0, calibratedtheta_biasModel.α,Model.reference_condition, structural choicesThe script (and a mirrored notebook cell) then reads the CSVs back, rebuilds a
Model, andverifies it lands where intended: per-condition
functional_score_lossmatches an in-memory modelto machine precision (gaps ≤
5.6e-17) and correlations reproducefunc_score_corr.png(0.795 / 0.891 / 0.876). The per-condition
β0differ (−0.452 / −0.400 / −0.561) precisely becauseeach folds in that homolog's bundle term
−x_wt,d·β_d, placing all three wildtypes at the readφ_wt = −0.40.Contents
check_equivalence_from_image.ipynb— executed notebook with the three checks, a workedsingle-variant walkthrough, and the converter/round-trip cell.
convert_040_to_main_params.py— converts 0.4.0 parameters → themain-model init CSVs, with abuilt-in CSV round-trip verification.
main_init_params/{main_params_beta,main_params_latent,main_params_global}.csv— the emittedmain-model initialization parameters for spike replicate 2.compute_equivalence.py— script form of the loss-equivalence analysis.pick_example_variant.py— extracts the real-variant worked example..gitignore— excludes the fetcheddata/CSVs.ge_fits.png,func_score_corr.png— the reference figures.Closes #281.
🤖 Generated with Claude Code