如何用 Transformers-Tutorials 里的 LayoutLMv3 自动抽取病历关键字段:手把手完整指南
2026/9/14 7:04:10 网站建设 项目流程

如何用 Transformers-Tutorials 里的 LayoutLMv3 自动抽取病历关键字段:手把手完整指南

【免费下载链接】Transformers-TutorialsThis repository contains demos I made with the Transformers library by HuggingFace.项目地址: https://gitcode.com/GitHub_Trending/tr/Transformers-Tutorials

医院信息科要把出院小结、处方单、检验报告录入系统时,人工逐页抄写一天能处理两三百页已是极限,而且剂量、药名一旦抄错一个字符就可能引发用药安全问题。Transformers-Tutorials 项目里的 LayoutLMv3 教程正是为这类文档设计的:模型能同时"读"文档图像里的文字和它所在的位置,再配合一份现成的微调 Notebook,三步就能搭起一条病历信息抽取流水线。

为什么这类任务难做

先说三个绕不开的低效点,你大概率都遇到过:

  • OCR 只认字,不懂字段。同一页上出现两个2023-05-01,一个是出生日期、一个是入院日期,只靠文字内容根本分不出谁是谁,必须结合坐标位置才能判断。
  • 版面不规整,规则写不牢。病历扫描件有倾斜、有印章压字、字体大小不一,用"固定坐标框切区域"的方式一碰到字段错位就全盘失效。
  • 纯文本模型看不见位置。同一个词在"诊断"栏和"用药"栏里含义完全不同,只看 token 序列会猜错,模型需要知道每个词"在哪"。

LayoutLMv3 的思路就是把图像、文本、边界框三种信号一起喂进 Transformer,让位置信息直接参与理解。

在项目的哪里做

打开仓库根目录下的 LayoutLMv3/,里面就两个文件:

  • 主教程 Fine_tune_LayoutLMv3_on_FUNSD_(HuggingFace_Trainer).ipynb.ipynb):完整的"数据准备 → 微调 → 推理"流程,基于 HuggingFace Trainer 实现;
  • README.md:讲了一个很关键的性能细节(segment 位置编码,后面调优部分会用到)。

这个示例做的是 FUNSD 数据集(一批带标注的表单文档)上的命名实体识别——把每个词标成"字段头""地址""其他"之类的类别。这跟病历场景几乎同构:病历本质上也是"带固定字段的表单",所以这套流程不用改架构,只需把 FUNSD 换成你的病历数据、把标签集换成"患者姓名/诊断/用药"即可。

🛠️ 三步跑起来

第一步:把原始数据喂给模型

先明确数据格式要求。每条样本需要四样东西:image(PIL 图像)、tokens(OCR 切出的词列表)、bboxes(每个词的坐标[x1, y1, x2, y2],归一化到 0–1000)、ner_tags(每个词的标签编号)。OCR 这一步可以交给 Tesseract 这类引擎,它能给出带坐标的词级结果。

拿到这四样后,加载处理器(注意apply_ocr=False表示 OCR 结果由你外部提供,模型内部不再跑 OCR):

from transformers import AutoProcessor processor = AutoProcessor.from_pretrained("microsoft/layoutlmv3-base", apply_ocr=False)

然后写一个批量处理函数,把原始样本变成张量。这一步 processor 会自动完成两件事:把图像缩放归一化成 RGB 通道的pixel_values(224×224),把词和坐标转成 token 级的input_idsbboxlabels

def prepare_examples(examples): encoding = processor(examples["image"], examples["tokens"], boxes=examples["bboxes"], word_labels=examples["ner_tags"], truncation=True, padding="max_length") return encoding

注意一个容易踩的坑:LayoutLMv3 的图像通道要求 RGB 格式,而上一代 LayoutLMv2 用的是 BGR,直接从旧代码迁移时颜色通道不对会白白损失精度。

第二步:微调,参数怎么设

在预训练底座上挂一个随机初始化的 token 分类头,加载方式如下:

from transformers import LayoutLMv3ForTokenClassification model = LayoutLMv3ForTokenClassification.from_pretrained( "microsoft/layoutlmv3-base", id2label=id2label, label2id=label2id)

核心超参照抄教程即可,每个参数的取值理由整理在这里:

参数取值为什么这么设
learning_rate1e-5底座是预训练权重,小学习率微调不易破坏已有知识
max_steps1000FUNSD 样本少,按步数控制比按 epoch 好掌握
per_device_train_batch_size2base 模型 + 224×224 图像较吃显存,显存富裕可上调
evaluation_strategy / eval_steps"steps" / 100每 100 步看一次 F1,及时发现问题
load_best_model_at_end / metric_for_best_modelTrue / f1训练结束自动回退到验证 F1 最高的 checkpoint

组装 Trainer 并启动训练(指标函数用seqeval算实体级 F1):

from transformers import TrainingArguments, Trainer training_args = TrainingArguments(output_dir="test", max_steps=1000, per_device_train_batch_size=2, learning_rate=1e-5, evaluation_strategy="steps", eval_steps=100, load_best_model_at_end=True, metric_for_best_model="f1") trainer = Trainer(model=model, args=training_args, train_dataset=train_dataset, eval_dataset=eval_dataset, tokenizer=processor, compute_metrics=compute_metrics) trainer.train()

按教程跑完,验证集 F1 可以稳定到 90% 上下,对表单类 NER 是个相当可用的水平。

第三步:推理,拿到结构化结果

训练完的 checkpoint 加载方式跟加载底座完全一样,推理时把新病历的图像、词和坐标交给 processor,再取 logits 的 argmax 就是每个词的预测类别:

inputs = processor(image, words, boxes=boxes, return_tensors="pt") predictions = model(**inputs).logits.argmax(-1).squeeze().tolist() # 把 token 编号映射回实体名,非 O 的位置就是抽出的字段 for tid, pred in zip(inputs.input_ids[0].tolist(), predictions): if model.config.id2label[pred] != "O": print(processor.tokenizer.decode([tid]), "->", model.config.id2label[pred])

一句话解释:模型输出形状为(batch, seq_len, num_labels)的 logits,逐 token 取最大值编号,再用id2label反查成"患者姓名""诊断"这类名称,配合该词自带的 bbox 就能把结构化字段连同位置一起拿到。注意真实推理时你手上没有标签,教程末尾演示了如何用 tokenizer 返回的offset_mapping把 token 对齐回原始词,需要时翻到那一段。

📈 效果调优与常见坑

  • 改用 segment 级位置编码。让同一个字段里的词(比如一整个地址、一整个日期)共享同一个 bbox,从而获得相同的 2D 位置嵌入。README 明确指出这是 FUNSD 上 F1 突破 90% 的关键,Tesseract 这类 OCR 引擎本身就能识别出 segment。
  • 图像增强扩样本。对病历图做旋转、缩放、对比度抖动,直接扩大有效训练量,降低扫描件质量差异带来的掉点。
  • 后处理加规则校验。对日期、ICD 编码、剂量单位做正则校验,明显不合法的结果直接丢弃或标记人工复核,端到端精度会有一截提升。
  • 多任务辅助。并行加一个"病历类型分类"头,与实体抽取共享底座,能给小样本场景提供额外监督信号。
  • 小数据压住学习率。病历标注数据通常有限,保持 1e-5 到 5e-5 量级并配合早停,比激进的大学习率更不容易把验证集 F1 冲垮。

一句话收尾

把 FUNSD 换成你的病历数据、把标签集改成临床字段,这条从数据到推理的链路就通了——剩下的工作量主要在标注。接下来可以顺着这几个方向走:

  • 手写病历场景:上游接一个手写识别(OCR)流水线,把识别出的词和坐标按本教程格式灌入;
  • 结果可信度:把抽出的诊断、用药字段接入 ICD 编码库做交叉校验,明显矛盾的输出转人工;
  • 落地部署:对微调后的 checkpoint 做量化或蒸馏,让单页推理成本降到可以支撑批量扫描件的量级。

【免费下载链接】Transformers-TutorialsThis repository contains demos I made with the Transformers library by HuggingFace.项目地址: https://gitcode.com/GitHub_Trending/tr/Transformers-Tutorials

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询