← AHMAD BILAL / WRITING AI & RESEARCH
AI & RESEARCHDATASET BIASMEDICAL IMAGING

What my 92 was measuring

My TB screener measured 92 on the public benchmarks and 78 at a real hospital. I called the gap distribution shift. The audit found something less comfortable.

Ahmad BilalAug 2026~7 minAI & Research
FIG. 01 · THE LADDER One-bit bar chart of four AUROC scores stepping down: within-corpus 0.99, LOCO transfer 0.883, unseen cohort 0.569, random labels 0.53. A dashed rule marks the acquisition-only floor at 0.687, above the unseen-cohort bar.
Label-only probes on frozen embeddings, same encoders, four splits. The dither density is the value: the honest numbers dissolve. The dashed rule is a predictor that never saw a TB label, only the acquisition source.
0.990 0.569same evaluation family, split decides
0.687acquisition-only floor, no TB supervision
88.4%of composite “normals”, one hospital archive
92 78my screener, benchmark vs bedside

TB chest X-ray dataset bias is the reason a screening model can score above 0.95 on a public benchmark and stumble at a real clinic. The five most-used open TB corpora mix disease signal with acquisition signal: TB-positive and normal images entered them through different pipelines, so a model can pass the benchmark partly by recognizing the pipeline. In my audit of all five, the same evaluation family scored 0.990 under a random image split and 0.569 at a hospital cohort none of the corpora had seen.

In May I posted a hobby project. A TB screener built on two open medical-imaging encoders, Rad-DINO and TorchXRayVision, scored 92 on the public benchmarks and 78 on X-rays from a Pakistani hospital it had never seen. I called the gap distribution shift. Normal, expected, keep calibrating. Three months of auditing later, that answer looks too kind. Part of the 92 was never measuring tuberculosis at all.

01The build that started it

Tuberculosis killed an estimated 1.23 million people in 2024, and much of that is because we catch it late, after the treatment we already have can do less. An X-ray screener that runs in seconds is the obvious thing to build, which is why so many people have built one. Papers in this category routinely report AUROC above 0.95.

Mine was a weekend build that grew. Two frozen open encoders, a small trained head, and a product surface I spent more care on than the model: a quality gate that rejects non-chest images before scoring, a calibrated threshold instead of a raw probability, and a verdict card that prints the external field estimate first and the benchmark number second, labeled as an upper bound. There is a disagree button. A vision model drafts the radiology report but cannot change the verdict.

FIG. 02 · THE VERDICT CARD, RUNNING
Sixty-two seconds of the research preview. The card leads with 0.78, the estimate from a cohort the model never trained on, and labels the 0.92 benchmark number as an upper bound on someone else’s data. The agent trace on the right shows each stage with its provider and latency, and the verdict stays with the local validated head: the vision model drafts prose and never moves the number.

That surface reflected a suspicion more than a finding. On held-out folds of the public training corpora the model measured AUROC 0.92. On 3,008 images from a Pakistani hospital cohort it had never seen, 0.78. I designed the interface around the 0.78 because that is the number a clinic would actually get. What I could not yet say was where the other fourteen points had gone.

02Distribution shift was the kind explanation

“Scores drop on unseen data” is true and everyone nods. The world changes between training and deployment: different machines, different positioning, different patients. Collect local data, fine-tune, the gap narrows. That is what I wrote in May.

The audit says something less comfortable. I took the modeling out of the question entirely: no trained TB head, just label-only linear probes on frozen embeddings, the weakest reasonable reader of each dataset. Within a single corpus, the probes score 0.97 to 1.00. Hold out entire corpora and deduplicate the overlaps, and the same probes fall to 0.883. At the truly unseen cohort, 0.569. One evaluation family, one set of encoders. The split alone moves the score from nearly perfect to nearly chance. As the preprint puts it, evaluation design, not model quality, decides the number.

Distribution shift explains why a real signal degrades. It does not explain a number that was partly built out of something else. For that you have to look at how the datasets were assembled.

03Acquisition confounding, plainly

The pattern I audited for is class-conditional acquisition confounding: TB-positive and normal images entered the corpus through different pipelines, so the class label can be partly predicted from pipeline artifacts that have nothing to do with lungs. In the most widely used composite TB database, 88.4% of the “normal” images derive from one US research hospital’s archive, while all 700 TB-positive images come from dedicated TB collections. A model trained on that corpus does not need to find disease. Recognizing the hospital is enough to be mostly right.

Four receipts from the audit, each checkable in the released tool:

An acquisition-only predictor, a source classifier composed with per-source prevalence and given no image-level TB supervision of any kind, reaches AUROC 0.687 on the pooled benchmark. That is the real chance line for this data. Not 0.5.

Normals-only probes distinguish every pair of sources at 0.99 to 1.00. Healthy lungs everywhere look alike; the pipelines that photographed them do not.

A 24-dimension bundle of intensity statistics with no spatial content, no anatomy visible to it at all, orders the five corpora exactly as their documented provenance predicts.

And the controls hold: random labels score 0.48 to 0.58 throughout, and the results survive three unrelated frozen encoders, including one that has never seen a medical image.

One more, because it connects the statistics to the clinic. Films showing healed TB scars land in the TB-positive mode of the label-only probe with a median score of 0.9998. Confident scar false positives are a failure mode already documented for deployed TB screening tools. The confound and the clinical complaint line up.

04What to do before you trust a benchmark

None of this needed my datasets. If you are building or buying a model trained on any assembled corpus, medical or otherwise, the checks transfer as they are.

Ask where each class came from. If the positives and negatives never share an acquisition source, disease and pipeline are confounded by construction, and no amount of modeling on images alone can separate them. That question costs an email.

Run the acquisition-only null. Train a source classifier, compose it with per-source prevalence, and treat its score as your floor. A benchmark where the floor is 0.687 makes a 0.95 headline mean something very different.

Probe under leave-one-corpus-out with provenance dedup. Composite datasets recycle images from their sources; a random split quietly puts near-duplicates on both sides. Dedup first, then hold out whole corpora, and watch what survives.

Report the external number first. My verdict card prints 0.78 before 0.92 for the same reason the preprint leads with 0.569. The flattering number is an upper bound on someone else’s data. The honest one is an estimate of yours.

This failure lineage is documented. Zech and colleagues showed in 2018 that pneumonia models were detecting the hospital system. DeGrave, Janizek and Lee showed in 2021 that COVID-19 classifiers preferred shortcuts over signal. The TB corpora deserve the same scrutiny, and now there is an audit on record, with the tool, the provenance annotations and the source-matched splits released so you can point them at your own assembly. It is the same discipline I argue for in auditable AI research: a number you cannot trace is a number you cannot trust.

05Limits, stated plainly

All labels in the audit are radiographic. No clinical claims. The 0.78 external number is real signal; the audit does not say TB screening is fake, it says the benchmarks flatter it. An image-only modality has a ceiling regardless, because an X-ray shows patterns while only a lab test confirms the bacterium. And the composite database was reprocessed when it was assembled, so an image can no longer be traced back to its source from pixels alone. A copy cannot find its own original, and some questions about that corpus are now unanswerable.

The strongest objection I know: the 0.569 comes from one unseen cohort, and a single cohort can carry its own label problems. The controls constrain that reading, and the ladder does not depend on any single rung, but more truly external cohorts would settle it properly. If you run one, I want to see the number.

The audit is a solo preprint, on medRxiv and SSRN, separate from my product work; the rest of my research lives on the research page. If you screen on an assembled benchmark, here is my question: what is your acquisition-only floor? If you compute it and it beats 0.687, I would genuinely like to hear about it.

06References

07Further study

Branching by what you are actually trying to do next.

If you are about to trust a medical-imaging benchmark.

If you want to run the audit on your own corpus.

If you are building TB screening for a real setting.

If you want to argue with me. The sharpest version I can offer: the unseen cohort is one hospital, and its labels were not adjudicated for this study. If its ground truth is noisy, the 0.569 understates the transferable signal. The random-label controls and the three encoders bound how much of the ladder that concern can eat, but they do not bound it to zero. A second and third truly external cohort would. If you hold one, the audit tool will run on it.