Reference implementation of the DBPM gating module from "Dynamic Bidirectional Pattern Memory: A Production-Scale Empirical Characterisation of Inference-Time Gating in Clinical NLP" (Lazem & Teahan, 2026). Preprint: arXiv (in preparation).
DBPM is an inference-time, gradient-free pattern memory that gates the outputs of a verifier-grounded clinical extraction pipeline. Per task it records both failures (a blocklist) and successes (a whitelist), propagates signal across tasks, weights evidence by source reliability, and forgets via real-time decay. The gate consults this memory to BLOCK, DOWNGRADE, or ALLOW each candidate, with no gradient updates to either the generator or the verifier.
The pipeline pairs a generator (Llama-3.3-70B) with a verifier (MMed-Llama-3.1-70B) over the 167,034 patient narratives of PMC-Patients. The paper characterises which gating signals actually make such a memory selective at production scale. Two results anchor it:
| Finding | Result |
|---|---|
| Natural verifier-fed design fails at scale | The relation-extraction channel persists 0 patterns despite 785,797 logged rejections, a structural consequence of decay outrunning reinforcement on a diffuse signal. |
| One signal source is selective | Of five tested question-answering gate signals, only the NER-coverage signal separates pass from fail: path lift 1.84 (95% CI [1.75, 1.93], p < 10⁻¹⁵), within a 1.52–1.84 band across four replications. |
The organising principle: a pre-generation gate is selective for verifier rejection only when its signal probes the same grounding question the verifier itself evaluates. A verifier-independent ontology predicate fills the empty relation channel where the verifier-fed signal could not.
The standalone DBPM gating module. The deployed worker gates three task channels at the candidate level, NER, RE, and QAR; the remaining task buckets carry reserved threshold entries but no consumer gate (see Mapping to the paper). The module implements:
- Bidirectional fail/success learning (blocklist and whitelist)
- Cross-task signal propagation (e.g. an RE hard-fail nudges NER severity)
- Three-tier gating (BLOCK / DOWNGRADE / ALLOW)
- Source-reliability weighting of evidence
- Real-time exponential decay (wall-clock half-life)
- The two verifier-independent predicates: the NER-coverage signal for the QA gate and the ontology-violation predicate for the RE channel
Note on naming. The paper refers to the mechanism as DBPM throughout; the code instantiates the class
BadPatternMemoryand the QA gate method isgate_qa, both retained as legacy identifiers. The paper's Appendix A.1 gives the full concept-to-identifier mapping.
The gating module only. The surrounding extraction pipeline (orchestration, model serving, the multi-stage extraction loop, the risk/intelligence layer, and the visualisation builder) is a separate system and is not included here. The cohort UID lists and aggregate counts permit reproduction of the reported gating numbers without the pipeline.
candidates verdicts
Generator ───────────────▶ DBPM gate ──────────────▶ Verifier
(Llama-3.3-70B) │ │ │ (MMed-Llama-3.1-70B)
│ │ └─ ALLOW ─▶ candidate passes unchanged
│ └──── DOWNGRADE ─▶ candidate passes, tagged
└──────── BLOCK ─▶ candidate dropped (verifier not called)
▲
│ consults
┌────────┴─────────┐
│ Blocklist B_j │ severity per signature
│ Whitelist W_j │ confidence per signature
└──────────────────┘
▲
verdict feedback (no gradient updates)
| Path | Contents |
|---|---|
dbpm.py |
Standalone DBPM gating module (the contribution); all numeric constants as class attributes |
example_usage.py |
End-to-end demo across the gated task channels |
run_ablation.sh |
Full-ON vs full-OFF ablation protocol (genericised; pipeline entry points are placeholders) |
graders/ |
Scripts that reproduce the reported lift, CI, and per-category numbers from released outputs |
cohorts/ |
Held-out and development cohort UID lists (index the public PMC-Patients corpus) |
results/ |
Aggregate gating-outcome counts (counts and rates only; no clinical text) |
requirements.txt |
Dependencies (filelock; numpy for one grader) |
CITATION.cff |
Citation metadata |
pip install -r requirements.txt # filelock (core); numpy (one grader)
python3 example_usage.py # end-to-end demo across the gated channels
python3 dbpm.py # built-in smoke testNo GPU required for the module or the graders; they run on any machine with Python 3.8+.
from dbpm import BadPatternMemory # the DBPM class (legacy name)
bpm = BadPatternMemory(path="bpm.json")
# learn from verifier outcomes
bpm.record("ner", {"pattern": "covid-19", "category": "Diagnosis"},
failure_type="success")
bpm.record("ner", {"pattern": "patient", "category": "Diagnosis",
"evidence_source": "verifier_mmed"}, failure_type="hard_fail")
bpm.save()
# gate future candidates
bpm.gate_ner("covid-19", "Diagnosis") # -> "ALLOW"
bpm.gate_relation("Symptom", "TREATS", "Diagnosis") # -> "DOWNGRADE" / "BLOCK"
bpm.gate_qa("treatment", difficulty=0.5, ner_categories={"diagnosis"})| Paper element | Code |
|---|---|
Algorithm 1 (memory update operator U) |
BadPatternMemory.record |
| Three-tier gate (Eq. 4) | gate_ner / gate_relation / gate_qa |
| Source-reliability weights (Table 3) | SOURCE_WEIGHTS + record |
| Real-time decay, wall-clock half-life (Eq. 5) | _time_decay |
| Cross-task propagation (§4.4) | record (cross-task path) |
| NER-coverage QA signal (the working gate, §4.8) | gate_qa coverage branch |
| Ontology-violation RE predicate (§4.7) | m3_ontology_violation |
The three gated tasks are NER, RE, and QAR. The summary channel has a reserved
threshold but no consumer gate; medication, temporal-event, risk, and visualisation
stages are outside the gating system (paper Appendix A.6).
All default ON; set any to 0 to disable. BPM_DISABLE=1 is the master switch.
| Flag | Controls |
|---|---|
BPM_ENABLE_CROSS_TASK |
cross-task signal propagation |
BPM_ENABLE_UNCERTAINTY |
uncertainty-weighted updates |
BPM_ENABLE_THREE_TIER |
the DOWNGRADE tier (off = BLOCK/ALLOW only) |
BPM_ENABLE_SOURCE_WEIGHTS |
source-reliability weighting |
BPM_DISABLE_M3 |
the RE ontology-violation channel |
M1_QA_GATE_HARD_BLOCK |
whether the QA gate may emit BLOCK (default 0, DOWNGRADE-first) |
BPM_DISABLE |
master switch: disables all gating and recording |
The
verifier_selfentry inSOURCE_WEIGHTSis reserved for the optional self-verification ablation arm and is disabled in the reported configuration.
| Result | Command |
|---|---|
| Five-signal selectivity dissection | python3 graders/grade_m1v7_selectivity.py --json results/m1v7_full_ON_selectivity.json |
| Path-lift 95% confidence interval | python3 graders/compute_v7_lift_ci.py --json results/m1v7_full_ON_selectivity.json |
| 167K verifier-fed channel cross-check | python3 graders/crosscheck_F1_167k_blocklist.py |
| Full-ON vs full-OFF ablation | bash run_ablation.sh (pipeline placeholders; toggles dbpm.py) |
The aggregate gating-outcome counts behind the lift, confidence interval, and
per-category breakdown are in results/m1v7_full_ON_selectivity.json (counts and
rates only; no clinical text). The cohort is indexed by the UID lists in cohorts/,
which point into the public PMC-Patients corpus.
run_ablation.sh reproduces the full-ON vs full-OFF paired ablation: it starts the
two vLLM servers and runs the pipeline twice on the same cohort, toggling the DBPM
mechanisms via the BPM_* environment flags. The pipeline entry point and model
paths are placeholders (<...>) because the pipeline itself is not included; the
DBPM gating module it toggles is dbpm.py. Grade the two runs with the scripts in
graders/.
This module (dbpm.py) and the graders: none special. Python 3.8+, no GPU.
The extraction pipeline that produced the analysed data (not included here) ran
on 4× NVIDIA H200 GPUs (141 GB HBM3e each): a Llama-3.3-70B generator and an
MMed-Llama-3.1-70B verifier, each tensor-parallel across two GPUs, with ~64 CPU cores
and ~900 GB RAM. The full run processed 167,034 patients over approximately twelve
days of elapsed wall-clock time. See run_ablation.sh for the serving configuration.
@article{lazem2026dbpm,
title = {Dynamic Bidirectional Pattern Memory: A Production-Scale
Empirical Characterisation of Inference-Time Gating in Clinical NLP},
author = {Lazem, Ali H. and Teahan, William J.},
journal = {arXiv preprint arXiv:2607.00870},
year = {2026},
eprint = {2607.00870},
archivePrefix = {arXiv},
primaryClass = {cs.CL}
}See CITATION.cff for machine-readable metadata.
Code is licensed under MIT. The accompanying paper is licensed under CC BY 4.0.
Computation performed on Supercomputing Wales (Falcon, project SCWF00175), with support from the Bangor eResearch Team, including Dr Ade Fewings.