| """The reproductions, at a size CI can afford. |
| |
| A reproduction script that nobody runs between releases stops working quietly: |
| an API changes, a shape drifts, and the failure surfaces months later when |
| somebody tries to reproduce a number. These tests build every reproduction's |
| *model* and train it for a handful of steps on synthetic data of the right |
| shape, asserting only that the thing learns something. No downloads, no |
| accuracy claims — the numbers live in RESULTS.md and come from real runs. |
| |
| The synthetic stand-in is deliberate: PLAN.md's Phase 9 risk note says dataset |
| download flakiness must not be able to turn CI red. |
| """ |
|
|
| import sys |
| from pathlib import Path |
|
|
| import pytest |
| import torch |
| import torch.nn as nn |
|
|
| sys.path.insert(0, str(Path(__file__).resolve().parent.parent)) |
|
|
| repro = pytest.importorskip("examples.repro.image_nd") |
| from examples.repro import forecast_sparse, harness, image_nd, smnist |
|
|
|
|
| def fit(model, batches, lr=3e-3, steps=40): |
| """Train briefly; return (first loss, last loss).""" |
| opt = torch.optim.Adam(model.parameters(), lr=lr) |
| first = last = None |
| for i in range(steps): |
| x, y = batches[i % len(batches)] |
| loss = ( |
| nn.functional.mse_loss(model(x), y) |
| if y.dtype.is_floating_point |
| else (nn.functional.cross_entropy(model(x), y)) |
| ) |
| opt.zero_grad(set_to_none=True) |
| loss.backward() |
| opt.step() |
| first = float(loss.detach()) if i == 0 else first |
| last = float(loss.detach()) |
| return first, last |
|
|
|
|
| def test_the_sequence_classifier_learns(): |
| """sMNIST's model on a short synthetic sequence task: the class is decided |
| by an early token, so a model that cannot carry information forward fails.""" |
| torch.manual_seed(0) |
| model = smnist.SequenceClassifier(d_model=16, n_layers=2, n_classes=2, d_state=8) |
| x = torch.randn(16, 32, 1) |
| y = (x[:, 0, 0] > 0).long() |
| x[:, 0, 0] = 0.0 |
| x[:, 2, 0] = torch.where(y == 1, 3.0, -3.0) |
| first, last = fit(model, [(x, y)], steps=60) |
| assert last < first * 0.6, f"sequence classifier did not learn: {first:.3f} -> {last:.3f}" |
|
|
|
|
| @pytest.mark.parametrize("arch", ["mamba_nd", "s4d_nd", "lstm"]) |
| def test_every_image_model_builds_and_learns(arch): |
| torch.manual_seed(0) |
| model = image_nd.build_model(arch, (4, 4), 1, d_model=16, n_layers=2, n_classes=2) |
| x = torch.randn(16, 4, 4, 1) |
| y = (x[:, 0, 0, 0] > 0).long() |
| first, last = fit(model, [(x, y)], steps=50) |
| assert last < first * 0.8, f"{arch} did not learn: {first:.3f} -> {last:.3f}" |
|
|
|
|
| @pytest.mark.parametrize("arm", sorted(forecast_sparse.ARMS)) |
| def test_every_forecasting_arm_builds_and_learns(arm): |
| """Each arm differs in one thing; all four must at least run and improve, |
| or a comparison between them is comparing one working model to one broken |
| one.""" |
| torch.manual_seed(0) |
| keep = torch.ones(3, 4, dtype=torch.bool) |
| keep[0, 0] = keep[2, 3] = False |
| prep = {"shape": (3, 4), "names": ("station", "pollutant"), "keep": keep} |
| model = forecast_sparse.build_arm(arm, prep, d_model=16, n_layers=2) |
| x = torch.randn(4, 6, 3, 4, 1) |
| y = x[:, -1:] * 0.5 |
| first, last = fit(model, [(x, y)], steps=40) |
| assert last < first * 0.9, f"arm {arm} did not learn: {first:.4f} -> {last:.4f}" |
|
|
|
|
| def test_absent_cells_stay_absent_through_the_masked_arm(): |
| """The sparse arm's whole claim: values in absent cells cannot reach the |
| output. If this fails, the `masked` vs `zeros` comparison measures noise.""" |
| torch.manual_seed(0) |
| keep = torch.ones(3, 4, dtype=torch.bool) |
| keep[1, 2] = False |
| prep = {"shape": (3, 4), "names": ("station", "pollutant"), "keep": keep} |
| model = forecast_sparse.build_arm("masked", prep, d_model=8, n_layers=2).eval() |
| x = torch.randn(2, 5, 3, 4, 1) |
| mask = keep.reshape(1, 1, 3, 4, 1).float() |
| noisy = x.clone() |
| noisy[:, :, 1, 2] += 1e3 |
| with torch.no_grad(): |
| assert torch.equal(model(x * mask), model(noisy * mask)) |
|
|
|
|
| def test_the_ledger_row_names_its_own_metric(): |
| """A results row whose number has no name is a number nobody can check.""" |
| result = harness.Result( |
| config={"task": "t", "model": "m", "epochs": 1, "seed": 0}, |
| metric=0.9912, |
| metric_name="test_acc", |
| train_loss=0.01, |
| epochs_run=1, |
| seconds=60.0, |
| machine={"accelerator": "cpu"}, |
| history=[], |
| ) |
| assert "99.12%" in result.row() and "test_acc" in result.row() |
|
|