Virtual Embryo Challenge
Submit

Reference rows

Every board carries a block of rows under Reference, not ranked. They are not entries and they do not compete: they are what the numbers above them are measured against. This page says what each one is.

All of them are scored by the same scorer, on the same split, as every submission: the floor and ceiling are not constants written into the site, they are measured on each board when its bundle is built.

The floor and the published baselines are runnable. the implementations open in a notebook. Each row also cites its source path below, which names where the code lives in our tree; the notebook is where you can read and execute it.

Open the baseline implementations in Colab

The floor

What a submission scores for changing nothing. Every score on the site is expressed relative to it: the floor is 50 by definition, and a model below 50 has done worse than not modelling at all. Which prediction counts as "nothing" depends on the task.

copy_last

T1T2

Predict the last observed stage, verbatim: every cell, unchanged.

How it is built

Returns the final training stage’s cells as the prediction. On Task 2 it carries that stage’s 3D coordinates across too, so the geometry is the previous embryo’s.

Why it is on the board

This is the floor: the score a model gets for changing nothing. It anchors the scale at 50, and it is not a weak opponent. Fitting a constant-velocity extrapolation off the evaluation stages lands below it on every setting. On the interpolation boards it is handicapped in a specific way worth knowing: the stage it copies is roughly 5.5× too small by volume, which the shape metrics penalise heavily.

T1/baselines.py::copy_last, T2/model.py::copy_last Run in Colab

wt_identity

T3

Predict the matched wild type. That is, that the mutation had no effect at all.

How it is built

Returns the target stage’s wild-type cells unchanged, keeping their coordinates.

Why it is on the board

Task 3’s floor. It is a strong one by construction: absolute expression barely moves after a knockout, so doing nothing already scores 0.956 absolute pseudobulk Pearson. That is exactly why the panel scores the wild-type-to-mutant change rather than the absolute state. Against this floor, absolute accuracy is not evidence of anything.

T3/model.py::wt_identity Run in Colab

The ceiling

What the data itself can support. Not a perfect model. An estimate of how much of the target is predictable at all, made by scoring the real answer against another sample of the same answer.

ceiling

T1T2T3

Half of the real held-out answer, scored against its other half.

How it is built

The target’s cells are split in two disjoint halves at a fixed seed. One half becomes the truth every submission is scored against; the other is submitted as a prediction.

Why it is on the board

It answers "how well can anything do here?": the ceiling is set by biological and sampling variation within the same embryo, not by an ideal model. Deliberately not the target resubmitted verbatim, which is a number no honest generative model could reach. Because it is an estimate from one half, a submission can beat it; the scale clips at 100.

bake.py, via common/core_metrics.py::split_half

Published baselines

Real methods, deliberately simple, published with their numbers. These are what a submission is actually trying to beat: each one is a specific assumption about development stated in one or two lines of code, and each is named in the competition proposal.

pseudobulk_shift

T1T2

Move each cell by its own cell type’s average change between the last two observed stages.

How it is built

For every cell type, take the difference of its mean expression between the last two training stages, Δ_c = mean(last|c) − mean(previous|c). Anchor on the real last-stage cells and add each cell’s own type’s Δ, clipped at zero. Types absent from the earlier stage stay where they are. On Task 2 the coordinates are again carried over unchanged.

Why it is on the board

The simplest thing that is not "do nothing": constant velocity, per cell type. It keeps within-type heterogeneity instead of collapsing to a mean, which is what makes it a fair reference rather than a straw man. It needs two visible stages to fit a difference, so it is absent from boards that have only one. Heart interpolation, for instance.

T1/baselines.py::pseudobulk_shift, T2/model.py::pseudobulk_shift Run in Colab

shift_transfer

T3

Assume every knockout produces the same transcriptional response, and copy the one you have seen.

How it is built

Measure the pseudobulk shift on the training knockout, Δ = pseudobulk(KO_train) − pseudobulk(WT_train), then add it to every cell of the target stage’s wild type, clipped at zero.

Why it is on the board

The paper’s named Task 3 baseline, and it encodes precisely the assumption the held-out perturbations exist to test: that knockouts share a common response. On the published references every model, this one included, gets the direction of the response wrong, so beating it is not a matter of a small architectural tweak.

T3/model.py::shift_transfer Run in Colab

gene_ko

T3

shift_transfer, plus the one thing about a knockout that is known with certainty.

How it is built

Runs shift_transfer, then sets the knocked-out gene’s expression to zero in every predicted cell.

Why it is on the board

Isolates how much of the score comes from the single fact that the perturbed gene is gone. The gap between this and shift_transfer is small, which is the point: knowing which gene was removed is not the same as knowing what its removal does.

T3/model.py::gene_ko Run in Colab

Adversarial controls

Predictions built to be wrong in one specific way, scored on every run and left on the board. They are how the metric panel is held honest: if a change to the scoring reopens a hole, the control that exploits it moves in public, on the leaderboard, instead of waiting to be found in an audit. A control scoring above the floor is a bug in the metrics, not a result.

ctrl_scale_ref

T1T2

The reference stage with every expression value doubled.

How it is built

ref_X × 2.0, cells and coordinates otherwise untouched.

Why it is on the board

A metric insensitive to overall scale would score this as well as the honest reference. It is kept on the board so that if a future change reopens that hole, the row moves in public.

bake.py

ctrl_shrink_ref

T1

The reference stage scaled by 0.99: a change small enough to be nothing.

How it is built

ref_X × 0.99.

Why it is on the board

The opposite test to ctrl_scale_ref: a metric that rewards any perturbation at all would score this above the floor for a change of one percent.

bake.py

ctrl_one_cell

T1

One average cell, repeated until it has the right cell count.

How it is built

The reference stage’s pseudobulk mean, tiled to the same number of cells.

Why it is on the board

Scores respectably on any metric that only compares means, and near zero on the two that compare populations. It is the row that shows why half of Task 1’s weight sits on distributional questions, and it is the trap named explicitly in the submission notes.

bake.py

ctrl_random_cube

T2

The right cells, scattered at random inside the target’s bounding box.

How it is built

Reference expression kept; coordinates redrawn uniformly at random between the true minimum and maximum along each axis.

Why it is on the board

A structureless cloud that merely fills the right volume. This is the control that caught a real hole: it beat the floor on the shape group at both interpolation boards, because copy_last is forced there onto a ~5.5× too small embryo while a right-extent blob is not penalised for size. The structure gate, shape credit multiplied by neighbourhood-structure skill, is what closed it.

bake.py

ctrl_squashed_ref

T2

The reference geometry stretched 4× along one axis and flattened to a quarter along another.

How it is built

Coordinates centred, multiplied by (4.0, 1.0, 0.25), then recentred. Expression untouched.

Why it is on the board

Preserves every local neighbourhood relationship while destroying the overall form. A shape metric that only looked at local structure would miss it entirely.

bake.py

ctrl_scale_wt

T3

The wild type with every expression value doubled.

How it is built

wt_X × 2.0.

Why it is on the board

The Task 3 analogue of ctrl_scale_ref: a large change in the wrong currency. The panel scores the change relative to wild type, so a uniform rescale should not read as a perturbation response.

bake.py

ctrl_shrink_wt

T3

The wild type scaled by 0.75.

How it is built

wt_X × 0.75.

Why it is on the board

A smaller uniform change in the same spirit. Enough to move most absolute measures, in a direction that has nothing to do with the knockout.

bake.py

ctrl_random_dir

T3

A response of exactly the right size, pointing in a random direction.

How it is built

A random Gaussian vector is rescaled to the same norm as the true wild-type-to-knockout shift, then added to the wild type and clipped at zero.

Why it is on the board

Separates magnitude from direction. Any metric that credits this is measuring only that something changed by about the right amount, which is why the panel scores the direction of the response explicitly, and why every published model getting that direction wrong is a finding rather than a rounding error.

bake.py

The scale these rows define. 50 at the floor, 100 at the ceiling, and how a metric is mapped onto it. Is derived on the evaluation page.