Evaluation
T2 — Spatial-temporal multiscale prediction. 3D MERFISH (500-gene panel) · predicts expression + 3D coordinates.
Scoring
These metrics should reflect what a virtual embryo is for: predicting in silico what an embryo does that is otherwise only knowable by running the experiment. Each answers one biological question; how the questions combine into a single leaderboard number is set out at the end of this section.
Eight metrics rank Task 2, in four questions weighted 25% each: expression change, cell-state distribution, tissue shape and growth scale, and local spatial organisation. Geometry therefore carries a full quarter of the score on its own — matching every expression marginal buys none of it. Each setting and each held-out stage is scored separately.
Notation
pred_X, true_X and ref_X are [n_cells, n_genes] log-normalised expression matrices — the submission, the held-out target, and the reference the change is measured against (the preceding stage for Tasks 1 and 2, the matched wild type for Task 3). An overbar denotes the pseudobulk, the mean over cells, a vector of length n_genes. pred_C and true_C are [n_cells, 3] coordinate matrices, Tasks 2 and 3 only.
Two properties hold by construction across the whole panel. A submission chooses its own coordinate frame — every spatial term is invariant to translation and rotation, and outside the stated laterality gap to reflection. And a submission chooses its own cell count: nothing requires n_pred = n_true, and where a count difference would otherwise confound a comparison both clouds are first subsampled to a shared size. No submission ever carries cell-type labels; every metric that needs a type uses a frozen probe q(·) trained once on the real target and applied identically to every entry.
Expression change
25% of the scoreWhich genes moved, and in which direction.
Differential Expression Score (DES)
common/core_metrics.py::de_score, de_genes, _signed_overlapThe differential expression score evaluates how accurately a model recovers the genes that development, or a knockout, actually moved. A differential-expression call is the readout most single-cell experiments are run for and the input to everything downstream, so a model that cannot reproduce it has not reproduced the finding, whatever else it got right.
First, the truth declares its own DE genes. For each gene we test the target against the reference with a two-sided Mann-Whitney U test, control the false discovery rate with the Benjamini-Hochberg procedure at α = 0.05, and apply an effect-size floor that removes changes too small to mean anything biologically:
and split that set by direction into up- and down-regulated genes:
Next, the prediction is given no say in how many genes it names. It is asked for exactly n_u = |U_true| up-genes and n_d = |D_true| down-genes, chosen by its own log fold change, so that naming a thousand genes to catch fifty cannot help:
We then match the two sets sign for sign and normalise to the size of the true set:
Finally, that overlap is scored against a measured null rather than against zero. Highly-expressed genes are mechanically easier to call differentially expressed, and they overlap substantially with the genes that really are developmental DEGs — so a submission that has learned nothing except which genes are highly expressed scored 0.61 on a naive overlap, against 0.17 for the best real baseline. The null is the same construction applied to a prediction that knows only the reference’s own expression level, in both directions, since scaling the reference down games the score as readily as scaling it up:
0 means no better than knowing gene expression level alone, 1 means the truth’s own DE call was recovered exactly, and a negative score means the prediction is pointing the wrong genes in the wrong direction.
Directional Concordance Score (DCS)
common/core_metrics.py::de_directionThe directional concordance score measures whether a model moved genes in the direction the real embryo moves them, across the whole transcriptome rather than only the called set. Where DES asks which genes changed, this asks whether the change went the right way — so a model that has the shape of the response right but its magnitude wrong still scores.
First, we take the predicted and observed log fold changes against the reference, and rank-transform both along with the reference’s own expression profile:
Next, letting C be the 3 × 3 Pearson correlation matrix of those three rank vectors, we take the partial correlation of predicted against observed change, controlling for reference expression level:
That control is not a refinement, it is the metric. A real developmental or perturbation response is itself correlated with how highly a gene is already expressed, because highly-expressed genes tend to be the ones under active regulation at that stage. A plain correlation therefore pays a submission for reproducing a relationship that carries no model signal at all: submitting 0.99× the reference scored 0.31 before the control was added. Partialling the reference out leaves only the agreement its own expression level cannot already explain.
A no-change prediction returns 0, as does the degenerate case where the prediction’s entire signal is collinear with reference expression level and there is nothing left to credit.
Cell-state distribution
25% of the scoreThe predicted population against the observed one, including the covariance structure marginals cannot see.
Maximum Mean Discrepancy (MMD)
common/core_metrics.py::mmd_unbiasedMaximum mean discrepancy measures whether the predicted population of cells is the same population as the observed one — the right cell states in the right proportions. A stage of development is a mixture of progenitors, differentiating cells and terminal types all at once, not one average cell, and this is the term that holds a submission to that.
First, both the prediction and the target — up to 2000 cells each — are projected into a 30-component PCA basis fitted on the target alone, so that a submission cannot bend the space it is scored in to its own advantage.
Next, for each of five RBF kernel bandwidths γ_s = s · γ₀ with s ∈ {0.25, 0.5, 1, 2, 4}, spread around the target’s own median-heuristic bandwidth γ₀, we compute the squared discrepancy between the two sets of cells:
Finally, we average over the five bandwidths, so the score sees both coarse population shifts and fine within-population structure rather than committing to one length scale:
Dropping the kernel diagonal — the i ≠ i′ and j ≠ j′ conditions — makes this an unbiased estimator. The biased version put a perfect prediction at roughly 2/n rather than 0, a finite-sample artefact that a naive rescaling then mistook for the attainable ceiling.
Co-expression Structure Score (CSS)
common/core_metrics.py::variogram_scoreThe co-expression structure score measures whether genes that move together in the real embryo still move together in the prediction. A cell-fate programme is a set of co-regulated genes — a transcription factor and its targets rising in step — and this is the only term in the panel that constrains it. Every other expression metric here is a function of per-gene marginals or lives in a PCA space, so a submission can get every gene’s individual distribution exactly right while scrambling which genes co-vary with which, and pass all of them.
First, we sample 20,000 random gene pairs (i, j) with i ≠ j. For each pair, in each dataset, we take the geostatistical variogram at p = 0.5 — applied across gene pairs instead of spatial lags:
Finally, the score is the mean squared difference between the predicted and observed variograms over those pairs — a direct measurement of whether pairwise gene-gene covariance structure survived the prediction:
0 for a perfect match.
Tissue shape and growth scale
25% of the scoreRotation-invariant form and size. Geometry carries its own weight — matching every marginal does not buy it.
The shape terms first canonicalise each point cloud, so that embryos imaged in independent, arbitrary frames are comparable at all. C is the coordinate matrix, V the cloud’s own PCA rotation:
That centres translation, aligns rotation to the principal axes, and rescales by the rotation-invariant RMS radius — leaving only shape, with size handled by its own term. PCA fixes each axis but not its sign, so the terms optimise over the four sign flips with determinant +1, proper rotations only. This does not silently credit a mirror image, but neither can it detect one: laterality is a stated blind spot.
Shape Distribution Distance (SDD)
common/shape_metrics.py::d2_distanceThe shape distribution distance measures whether the predicted tissue has the right form. An embryo is a shape, and a model that produces the right cells in the wrong arrangement has not modelled morphogenesis — but comparing two embryos imaged in independent, arbitrary frames needs a descriptor that does not depend on the frame at all.
First, for each point cloud we sample 2 × 10⁵ random point pairs and normalise their distance by that cloud’s own RMS radius, giving the distribution of how far apart pairs of cells inside the tissue tend to be, relative to its own size:
Finally, the score is the earth-mover’s distance between those two empirical distributions:
0 means the same shape.
Because it only ever uses distances within a single cloud, this term needs no registration step, no shared frame, and no cell correspondence between prediction and target in order to be defined — so it carries zero registration risk. It was measured to be monotone in true developmental distance, robust to a 16-fold cell-count difference, and to rank a real morphological prediction above a featureless blob rather than tying with one.
Occupancy Dice Score (ODS)
common/shape_metrics.py::occupancy_diceThe occupancy Dice score measures whether the predicted tissue occupies the same region of space as the real one — the volumetric counterpart to the shape distribution above, which compares form but not the space it fills.
First, both clouds are canonicalised — centred, PCA-aligned and rescaled by RMS radius — and voxelised on the same fixed 16³ grid spanning [−3, 3] RMS radii, giving the set of occupied voxels:
Finally, we take the Dice overlap of those two sets, maximised over the four sign flips with determinant +1 — proper rotations only, since PCA fixes each axis but not its sign:
1 means an identical occupied region. The voxel edge is also reported in units of the truth’s median nearest-neighbour spacing — read the Dice value only when that ratio is comfortably above ~10, since below it the grid is resolving individual cells rather than tissue.
Restricting to proper rotations means the score does not silently credit a mirror image — but neither can it detect one. Laterality is a stated blind spot of every shape term here: a mirrored embryo scores identically to a correct one.
Tissue Scale Ratio (TSR)
common/shape_metrics.py::scale_log_ratioThe tissue scale ratio measures growth: whether the embryo or organ has reached the right physical size at the target stage. Getting the form right at the wrong scale is a different failure from getting the form wrong, and development is as much about how much tissue there is as about how it is arranged.
Size is taken as the root-mean-square distance of cells from their centroid — rotation-invariant by construction, unlike a bounding-box extent — and the score is the signed log of the ratio between prediction and target:
0 is the correct size; positive means the model grew the tissue too much, negative too little.
Local spatial organisation
25% of the scoreWhether each cell sits among the right neighbours — the term that actually exercises the joint expression-and-position submission.
Neighborhood Fidelity Score (NFS)
T2/metrics.py::neighborhood_mmd, _knn_neighborhood_pbThe neighborhood fidelity score measures whether each cell sits among the right neighbours. Tissue identity is local: what makes a region cardiac outflow tract is not only which genes its cells express but which other cells they are next to, since signalling, boundaries and niches are all defined at the scale of a neighbourhood. This is the term that actually exercises the joint expression-and-position submission Tasks 2 and 3 ask for, rather than scoring expression and shape as two unrelated things.
First, for every cell we take its spatial-neighbourhood pseudobulk — the mean expression of its 15 nearest neighbours in space:
Finally, we compare the two resulting sets of neighbourhood profiles with the same unbiased multi-kernel discrepancy defined above:
Because this compares the distributions of neighbourhood-averaged profiles, it never assumes that predicted cell i is true cell i — it is coupling-independent by construction, so a submission is not required to reproduce any particular cell-to-cell correspondence with the target.
Overall score
Everything above measures one question. This is how they become the number on the leaderboard.
Per-metric skill
A raw metric value is not comparable across tasks, or even across metrics — some are bounded correlations, some are unbounded distances. Each one is therefore rescaled against two published anchors: a floor model (copy_last for Tasks 1 and 2, wt_identity for Task 3) and the attainable ceiling (half the held-out target scored against its other, disjoint half — deliberately not the target resubmitted verbatim, which no honest generative model can reach).
Let d(m) be a metric’s distance from the ceiling, and d_floor the floor’s own distance from the ceiling — one fixed “floor-unit” per metric:
The rescaling is hyperbolic rather than linear, which bounds the result to (0, 1] by construction instead of by clipping:
At the ceiling, d = 0 and skill = 1. At the floor, d = d_floor and skill = 0.5 — the floor sits at the midpoint of the scale, not at zero. As a model gets arbitrarily worse, skill approaches zero asymptotically without ever reaching it, so two very different degrees of failure stay numerically distinct instead of both flattening onto the same value. A model that beats the ceiling is clipped to exactly 1, since the ceiling is a half-versus-half estimate rather than a true optimum.
An earlier linear ratio was unbounded below, so a model well past the floor could read as −500% skill. Fixing it at the root rather than clipping afterwards matters: clipping would have collapsed every failure past the floor onto an identical flat zero, throwing away real information.
Two rules attach here. A metric whose ideal value is 0 rather than an extreme — a signed log ratio or log slope — is scored on its absolute value first, as a lower-is-better term. And a metric that is declared but comes back missing or NaN counts as skill 0, the worst case on this scale, never quietly dropped from the average; otherwise a model would be judged on an easier subset of questions than its competitors.
Combining the questions
Turning the panel into a single ranking has to keep the metric count from doubling as a weight. Task 2’s shape question happens to need three distance functions; averaging every metric flat would silently give “is the shape right” three times the say of “did you get the change right”, for no reason other than that shape is harder to capture in one number.
So metrics are combined by an explicit within-group weight that sums to 1, and groups by an explicit group weight that also sums to 1:
Because every skill(m) already lies in (0, 1], every weighted average of them — within a group, and again across groups — is automatically in (0, 100] on the printed scale. No clipping appears anywhere in the aggregation. A task score of 50 reads as “exactly matches the floor” on every task; above 50 is real improvement, below 50 real regression, and the scale never runs out of room in either direction.
Task 2 in full
The weights that apply to this task, as declared in the scoring table.
| Question | Weight | Metrics |
|---|---|---|
| Expression change | 25% | DES (0.50), DCS (0.50) |
| Cell-state distribution | 25% | MMD (0.60), CSS (0.40) |
| Tissue shape and growth scale | 25% | SDD (0.33), ODS (0.33), TSR (0.33) |
| Local spatial organisation | 25% | NFS |