Riel St. Amand
Galen

production

Galen

Production COVID-19 diagnostics at Gravity Diagnostics. A five-network ensemble read PCR curves in the browser, with zero reported errors across a million-plus diagnoses.

  • production ML
  • COVID-19
  • TensorFlow.js
  • ensemble
  • diagnostics

Galen was a production machine-learning system that read COVID-19 PCR amplification curves and returned a diagnosis. It was deployed at Gravity Diagnostics during the pandemic, from October 2020 to January 2021. Lab technicians ran it on live patient samples, and the answer mattered to the person whose swab it was.

The ensemble, and why it mirrors the assay

A single PCR run does not measure one thing. It amplifies several genetic targets in parallel, and the clinical protocol confirms a result across those targets rather than trusting any one of them. Galen was built to match that structure. It is an ensemble of five specialized networks, one per target, and each network does only its own job.

  1. MS2 — an internal control that confirms the sample and the run are valid.
  2. RNase P (RP) — a human gene control, present in any real patient sample.
  3. N — the nucleocapsid viral gene.
  4. ORF1ab — an open-reading-frame viral gene.
  5. S — the spike viral gene.

Three of those are viral targets and two are controls, the same split a lab tech reads by eye off the plate. The ensemble is the diagnostic protocol expressed as five classifiers. It spreads the viral call across three independent genes so that no single network's miss can carry a false negative on its own.

The decision logic is clinical, not a vote

The five networks do not take a majority vote. The system applies the gene combination rules a clinical lab already uses, with MS2 as the gate.

  1. Valid positive. MS2 present (the sample is real) and at least one viral gene of N, S, or ORF1ab detected. Result: DETECTED.
  2. Invalid sample. MS2 absent but viral genes detected, which means the control failed and the run cannot be trusted regardless of what the viral channels say. Result: INVALID, re-test.
  3. Valid negative. MS2 present and no viral gene detected. Result: NOT DETECTED.

The MS2 gate is the part that matters. A model that aggregates five probabilities will happily call a positive on a sample whose control had failed. Galen will not, because a degraded sample produces garbage on the viral channels and has to be thrown out rather than reported. The control is checked first, and the viral reads only count once the sample is known to be real. Requiring a viral hit across the N/S/ORF1ab set, rather than from one fixed gene, is the same redundancy a multi-gene PCR panel buys. A true infection lights up more than one target, and demanding at least one of three lowers the chance a single weak amplification curve drops a real positive.

What 175,000 hand-labeled samples bought

The models were trained on 175,000+ hand-labeled real-world PCR curves, drawn from actual patient samples and labeled by the lab technicians who read them for a living. The split was 80/20 train-test, stratified to hold the class balance across positive and negative cases and across all five targets, and randomized so the models could not learn anything from the order the data arrived in.

The point of that scale is coverage of the failure modes a production lab actually produces. The full spread of viral loads, sample quality, collection methods, and instrument conditions, not the clean curves a laboratory demo would show. The feedback loop with the techs fed edge cases back into the labels as they were found, the kind that never appear in idealized data. That coverage is what let the generalization hold when the system met a million real samples instead of a held-out fold.

Validation ran in production, in parallel

Galen was not signed off on a test set. It was validated in production, beside the people it was replacing. Its predictions ran alongside the human technicians' diagnoses for every sample, and the lab director, the person with medical sign-off, reviewed where the two disagreed.

The asymmetry is the result. The human technicians corrected their own initial diagnoses about 4% of the time. The ML system required no corrections across more than a million cases. This was the live deployment, with the lab director confirming zero corrections needed from the model over the validation phase. The bar for a diagnostic is agreement with ground truth when the stakes are real, and the model cleared the bar the humans missed.

Inference in the browser, no server

The whole system ran client-side. Each gene-specific model is a compact CNN-LSTM: a couple of Conv1D layers over the 40 PCR cycle points, a 50-unit LSTM for the temporal shape of the curve, dropout, and a sigmoid output, at roughly 50,000–60,000 parameters and about 160KB as a Keras H5 file, close to 630KB once converted to TensorFlow.js with its JSON metadata. That size was a deliberate choice over marginal accuracy from a larger network, because the models had to load and run in a browser on a lab workstation in under a second.

The React/TypeScript dashboard was the surface the techs actually used. It imported QuantStudio Excel files straight off the PCR instruments, the same .xlsx export the techs were already pulling for manual review, so supporting it added no new step to their day. The parser pulled the curve data for every well, normalized it, and fed it to the five TensorFlow.js models, which ran inference on all 384 samples of a plate in under a second with no server in the loop. Lab workstations had inconsistent network connectivity, so running everything in the browser took both the server dependency and the network latency off the table during high-volume runs.

Results came back as a color-coded plate map across 96- and 384-well layouts, each well painted with its detection status and gated by the MS2 quality check, with per-well PCR curve plots (Plotly.js) and the gene-by-gene reads behind every call. Export matched the format the lab's downstream patient-notification system already expected, so the output dropped into the existing workflow rather than forcing a new one. TypeScript earned its place here. In a medical application the type checker caught parsing and data-shape bugs during development that could otherwise have surfaced as a misread plate.

Code: Galen-COVID19 (the models, training pipeline, and ensemble architecture) and Galen-Front-End (the lab dashboard).