OpenMed 临床 NER 实体级基准评测指南:用 seqeval 风格 scorecard、严格/宽松 span 匹配与逐标签误差分析为模型打分 📅 发布时间:2026/9/18 16:10:55 👁 浏览次数: OpenMed 临床 NER 实体级基准评测指南用 seqeval 风格 scorecard、严格/宽松 span 匹配与逐标签误差分析为模型打分【免费下载链接】openmedLocal-first healthcare AI: clinical NER HIPAA PII de-identification that runs 100% on-device. 2,200 medical models, 21 languages, Apple MLX Python, no cloud, no patient data leaving your network. Apache-2.0项目地址: https://gitcode.com/GitHub_Trending/ope/openmed本指南讲解如何在 OpenMed 中为临床/生物医学 NER 模型生成一份诚实的实体级 scorecard精确率precision/召回率recall/F1 之外还输出逐标签的误差分解混淆矩阵、漏报/误报样例。文章以官方技能文档 skills/benchmarking-clinical-ner/SKILL.md 为骨架结合 openmed/eval/metrics.py、openmed/eval/harness.py、openmed/eval/error_analysis.py 的源码实现展开读完你就能用用户自备的 gold 语料跑通对齐语料 → 跑评测 → 读双 F1 → 误差分析 → 逐标签排障的完整闭环。为什么评测对象必须是 span 而不是 token临床实体几乎都是多 token 的例如 type 2 diabetes mellitus2 型糖尿病由四个 token 组成。如果按 token 粒度打分token 级准确率会被大量非实体 token 稀释一篇病历里 the、patient 这类 token 占绝大多数模型把实体边界预测错半个词漏掉 mellitustoken 级指标几乎看不出差别但实体级指标直接记一次边界错误。因此 OpenMed 的评测遵循 seqeval 传统CoNLL-2000 / SemEval-2013 一脉相承对 span 打分而不是对 token 打分报告中出现的所有数字都是**实体级entity-level**指标。这是整个评测体系的第一个设计前提源码中也能看到对应的强制约束run_benchmark对每个 fixture 的预测结果都会调用validate_entity_spans校验 span 合法性再用统一的normalize_eval_spans归一化后参与计数见 openmed/eval/harness.py。何时使用本评测流程你有一份带 gold 标注的临床语料和一个待评分的 OpenMed NER 模型你需要同时拿到严格精确边界与宽松重叠即算两种 span F1你需要逐标签的数字而不是一个笼统的聚合值——DRUG 的召回率 ≠ DISEASE 的召回率你需要能解释错误哪些实体漏了false negative、哪些是多余的false positive、哪些是标错了标签label confusion。需要特别说明边界如果目标是 PHI 脱敏F1 是必要条件但不是充分条件必须或额外改用 evaluating-with-leakage-gates 里的泄漏门控leakage gates来把关而不是只看 F1。两种匹配模式strict 与 relaxed模式命中条件适用场景Strict / exact严格预测 span 的边界和标签都与 gold 完全一致发布打分、边界敏感任务Partial / relaxed宽松预测 span 与 gold有字符重叠且标签正确面向召回的三方筛选、容忍 tokenizer 边界差异OpenMed 把两种模式都暴露成了独立 API并提供了打包二者的完整指标包compute_exact_span_f1(gold_spans, predicted_spans)—— 严格模式compute_relaxed_span_f1(gold_spans, predicted_spans)—— 宽松模式compute_metrics_bundle(gold_spans, predicted_spans, ...)—— 一次算全的标准 OM-018 基准指标包。源码级解读两种匹配器的真实行为在 openmed/eval/metrics.py 中严格模式的核心循环是matched_predictions: set[int] set() true_positives 0 for gold_span in gold: for index, pred_span in enumerate(predicted): if index in matched_predictions: continue if (gold_span.label pred_span.label and gold_span.start pred_span.start and gold_span.end pred_span.end): matched_predictions.add(index) true_positives 1 break return _f1_from_counts(true_positives, len(predicted), len(gold))关键点有三标签 起始偏移 结束偏移三者完全相等才算 TP差一个字符都是失败一对一贪婪匹配每个 gold span 只匹配第一个未使用的预测 spanmatched_predictions集合保证同一预测不会重复计分最终用_f1_from_counts(true_positives, len(predicted), len(gold))统一换算 precision / recall / F1结果封装为F1Metricsprecision/recall/F1 与计数数据结构见 openmed/eval/metrics.py。宽松模式openmed/eval/metrics.py则不同candidates [ (index, pred_span) for index, pred_span in enumerate(predicted) if index not in matched_predictions and _label_aware_overlap(gold_span, pred_span) ] if not candidates: continue best_index, _ max(candidates, keylambda item: _overlap_len(gold_span, item[1]))它先筛出标签一致且字符有重叠_label_aware_overlap的候选再挑选重叠长度最大_overlap_len的那一个作为该 gold span 的匹配。这就是文档中所说的每个 gold span 匹配单个最优重叠预测——重叠/嵌套标注方案下的确定性规则。快速上手一条命令拿到完整 scorecard假设你有一份用户自备的 gold fixtures 文件OpenMed 仓库本身不捆绑任何 i2b2/n2c2/MIMIC 语料格式为 JSON 列表每个元素形如{id: note-001, text: ..., gold_spans: [{start: 12, end: 34, label: DISEASE}, ...]}跑一次完整评测并打印 scorecardfrom openmed.eval import run_suite, error_report # Fixtures: JSON list of {id, text, gold_spans: [{start, end, label}, ...]} report run_suite( eval/gold/clinical_ner.json, # YOUR gold corpus, not bundled suitegolden, model_nameOpenMed/Disease-Detection, devicecpu, ) m report.metrics print(exact F1 :, m[exact_span_f1][f1]) # strict print(relaxed F1:, m[relaxed_span_f1][f1]) # partial print(recall by label:, m[recall_slices][by_label]) # Per-label confusion matrix capped, no-PHI error examples. errors error_report( OpenMed/Disease-Detection, eval/gold/clinical_ner.json, suite_nameclinical_ner, example_cap5, ) print(errors.to_markdown()) # confusion matrix FN/FP tables errors.write_json(eval/out/error_analysis.json)run_suite 背后的执行链run_suiteopenmed/eval/harness.py的流程是load_fixtures(fixture_path)加载语料 → 交给run_benchmark逐 fixture 推理与计分 → 可选写出 JSON/Markdown 报告。run_benchmarkopenmed/eval/harness.py支持的进阶参数包括参数作用devicecpu推理设备默认 CPUrunner自定义 ModelRunner 可调用对象便于离线/本地评测confidence_intervalsTrueci_resamplesci_seed对文档做非参数 bootstrap为指标附加置信区间默认关闭以保持快速运行固定ci_seed保证结果可复现calibrationTruecalibration_bins附加校准统计abstention_thresholds/abstention_thresholds_path弃权abstention阈值策略cache_dir本地文件缓存键由 model、suite、device、fixture 集合哈希与评测代码哈希共同决定重复运行直接命中缓存BenchmarkFixtureopenmed/eval/harness.py的from_mapping说明 fixtures 的字段兼容写法id或fixture_id、text、gold_spans或entities、language或lang。load_fixtures同时接受 JSON 或 JSONL 两种顶层形态列表或映射。只要指标直接调用度量函数如果 span 集合你已经有了例如来自自己的推理管线无需跑完整评测from openmed.eval import compute_exact_span_f1, compute_relaxed_span_f1 strict compute_exact_span_f1(gold_spans, predicted_spans) partial compute_relaxed_span_f1(gold_spans, predicted_spans)两个函数都接受default_language、default_device、source_text参数内部先用normalize_eval_spans统一 span 表示再计分保证与 harness 中的行为完全一致。BenchmarkReport 里还有什么OM-018 指标包除了两个 F1compute_metrics_bundleopenmed/eval/metrics.py还会一次性产出leakage泄漏率、character_recall字符级召回、recall_slices含by_label的召回切片、critical_finding_recall关键发现召回、over_redaction_loss过度脱敏损失、latency含cold_start_ms冷启动时延等指标。对脱敏任务而言这意味着你在一份报告里同时拿到召回够不够F1和会不会漏 PHI / 误伤非 PHIleakage / over-redaction两个维度的证据。六步评测工作流把语料对齐成 OpenMed fixtures将 CoNLL/BIO 或 BRAT 标注转换为textgold_spans每个 span 含{start, end, label}字符偏移的形态。CoNLL 需要换算成偏移量BRAT 的.ann标注本身就是字符偏移转换成本最低。把标签归一化到 OpenMed 的规范标签集让 DRUG/MEDICATION 这类变体不会互相计成标签混淆。归一化后标签错了但位置重叠的实体会在混淆矩阵的对角线之外显现出来而不是被当作漏报。运行run_suite/run_benchmark得到BenchmarkReport。同时读两个 F1如果 strict 明显偏低而 relaxed 明显偏高说明主要错误是边界错误而非检测失败——通常源于 tokenizer 或空白处理差异。运行error_report得到逐标签混淆矩阵与封顶数量的样例MISSED漏报 召回率问题SPURIOUS误报 精确率问题混淆矩阵非对角项 标签混淆。逐标签排障先修召回率最差的标签——在临床 NER 中通常少数几个标签就占据了大部分误差预算。误差分析逐标签混淆矩阵与无 PHI 样例error_reportopenmed/eval/error_analysis.py签名与默认值error_report( model, suite, *, suite_nameNone, devicecpu, runnerNone, example_capDEFAULT_EXAMPLE_CAP, # 默认 5 context_windowDEFAULT_CONTEXT_WINDOW, # 默认 24 generated_atNone, metadataNone, )返回的ErrorAnalysisReport包含confusion_matrix、false_negatives、false_positives三个核心字段并支持to_markdown()与write_json()输出。其中MISSED/SPURIOUS两个桶常量定义在 openmed/eval/error_analysis.py混淆矩阵的行列由规范标签集加上这两个误差桶构成MATRIX_LABELS LABELS ERROR_BUCKETS逐 fixture 累加时gold span 找不到匹配就写matrix[gold_span.label][MISSED] 1并追加一条漏报样例。ErrorSpanExample设计上就不存明文ErrorSpanExampleopenmed/eval/error_analysis.py保存的是kindmissed/spurious、fixture_id、label、start/end偏移context_start/context_end上下文窗口默认 24 字符text_hash通过openmed.core.audit.stable_hash生成的文本哈希——绝不保存明文匹配到错误标签时还会记录matched_label、matched_start/matched_end与matched_text_hash。这是刻意设计误差分析报告可以在不泄漏 PHI 的前提下被写入日志、模型卡或评审记录。保持这一设计不要在输出里回填明文文本。与其他技能的衔接hand-off上游来源extracting-clinical-entitiesopenmed.analyze_text被评分的模型与预测来自 NER 抽取管线。下游出口 1evaluating-with-leakage-gates对脱敏模型把同一份 fixtures 通过发布门控F1 是必要非充分条件。下游出口 2authoring-model-cards把error_report的混淆矩阵与逐标签 F1 直接放进模型卡的 quantitative-analysis 小节。配套技能building-gold-corpus负责生产 fixtures与 auditing-subgroup-fairness按人口学分组切片同一份运行结果做公平性审计。边界情况与常见陷阱Token F1 会撒谎永远报告 span F1。统一使用compute_exact_span_f1/compute_relaxed_span_f1不要用 token 级准确率替代。重叠/嵌套 gold span 需要文档化的匹配规则。OpenMed 的匹配器为每个 gold span 挑选单个最优重叠预测嵌套方案例如 ANATOMY 内部的 DISEASE应当摊平或按层分别打分。类别不平衡会掩盖失败。宏平均视角能暴露 micro-F1 埋没的稀有但关键的实体如 ALLERGY。错误样例默认无 PHI。ErrorSpanExample只存偏移、上下文窗口与sha256:/stable_hash文本哈希不要引入明文。gold 质量决定你的上限。如果标注者间一致性IAA很低一个低 F1的模型可能是对的、gold 才是错的。先抽查分歧点再责怪模型。仓库不捆绑受限语料。i2b2/n2c2/MIMIC 受 DUA数据使用协议约束只能从用户持有许可的副本在评测时加载绝不能提交进仓库。这同时体现在评测链路上run_multilingual_ner_scorecard支持传入训练清单training_manifest_path做训练/评测重叠检查阻止评测 fixtures 混入训练输入见 openmed/eval/harness.py。指标约定与参考标准seqeval实体级序列标注指标的事实标准本评测的统计口径源于此SemEval-2013 Task 9.1strict/partial/exact/type 四档评估方案的出处CoNLL-2003 NER 共享任务实体级 F1 约定BRAT standoff字符偏移标注格式fixtures 转换的直接参考。OpenMed 评测的权威实现与源码入口openmed/eval/metrics.py度量计算、openmed/eval/harness.pyfixtures 加载与评测运行、openmed/eval/error_analysis.py误差分析。需要快速验证时仓库内 eval/suites 下的评测套件脚本与 tests/unit 中的相关用例都是可对照的本地参考实现。【免费下载链接】openmedLocal-first healthcare AI: clinical NER HIPAA PII de-identification that runs 100% on-device. 2,200 medical models, 21 languages, Apple MLX Python, no cloud, no patient data leaving your network. Apache-2.0项目地址: https://gitcode.com/GitHub_Trending/ope/openmed创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考