好大夫在线每天的线上问诊中,包含了大量的各种医院报告单、化验单等图片,如何识别并格式化这些报告单数据,成了我们面临的一大难题。如果这些报告单仅以图片形式存储在服务器中,就难以发挥其在问诊过程中的重要价值,无法为问诊医生提供更准确的参考信息。本文将从实际业务需求、技术挑战、各种算法的尝试等方面,逐一探讨我们是如何解决这类问题的。
一、项目背景及挑战
1.1项目需求背景
好大夫网站上,用户平均每天上传数万张图片,这些图片中大部分都是医学检查报告单(如血常规、肝功能等)。其中蕴含着大量的有价值的信息,但由于这些照片不是结构化的数据,导致无法进行索引和检索等一系列复杂功能。
一方面,医生有将报告单中的关键信息誊写到病历上的需求,这可以使医生能更加清楚明白地跟踪患者病情发展,但是这个过程太过于繁琐。
另一方面,无法提取报告单中的具体信息导致这部分医疗数据无法被利用起来。
“医学报告单结构化”项目便是在这个需求背景下成立了。该项目要求算法能读取出患者上传报告单中的文本信息,并将其组合成表格的形式,以便存储和利用(如图1.1所示)。
1.2所用技术概述
本项目所用的技术都属于人工智能的范畴。图1.2展示了“人工智能”技术领域的三大分支,以及各分支的主要细分支。
该项目同时涉及图像处理和自然语言处理两大人工智能技术分支。
首先,我们需要用到OCR(OpticalCharacterRecognition,光学字符识别)技术将图像转化为文字。OCR技术是图像处理技术的一个分支,其通常包含“文本区域检测”和“文字识别”。
其次,需要用“文本分类”技术项将报告单分类为血常规、肝功能等一系列的类别,该技术是NLP(NaturalLanguageProcessing,自然语言处理)的一个重要分支。
最后,需要用到NER(NamedEntityRecognition,命名实体识别)技术从识别出的文本中准确地提取“检查项名”、“项数值”、“项范围”等字段,该技术同样是NLP的一个重要分支。
1.3项目面临的挑战
准确率方面。由图1.3可以看出,用户上传的报告单照片的干扰是非常大的,不仅有噪声的问题,还有文本倾斜,甚至文本弯曲。这些干扰会严重影响文字识别的准确率。为了评估报告单图像识别难度,我们整理了“好大夫在线医学报告单文本行数据集v1.0”(如图1.4所示),是从报告单图像中切割出近2000个文本行切片,然后进行人工标记。将该数据集输入到百度通用OCR接口和腾讯OCR接口中进行识别,结果“字符串”准确率都没超过85%(实验详细结果详见本文2.2),远不能满足我们最终的要求。同时也可以看出该项目的难度之大。
数据数量方面。虽然服务器中储存了上亿张医学报告单照片,但都是没有被标记的数据。人工智能算法的完善是需要大量被标记的数据,数据质量越高,算法表现越好。但标记的过程需要大量人工成本。
硬件配置方面。考虑到项目投入的性价比问题,我们舍弃了一些运行负载非常高的算法。
共分为:1)文字区域检测2)文字识别3)报告单分类4)命名实体识别5)结构化内容提取,这五个部分。
2.1文字区域检测模块
“文字区域检测”,是将图像中的每一行文本切割出来形成一条一条的文字切片,其具体过程如图2.2所示。目前流行的“文字区域检测”算法主要分为基于回归的方法和基于分割的方法:
第一版是基于一个开源项目修改而来,其采用的主体结构是Yolo[1]文字区域检测+CRNN[2]文字识别。Yolo文字区域检测算法属于基于回归的方法。第一版的Yolo文字区域检测算法在一般的医学报告单上面的效果是比较令人满意的,其文字检测效果不亚于市面上的一些付费OCR公共接口。
对于一般的文字区域检测算法,单独出现的’+’、’-’等符号通常是被视作噪声的。我们的Yolo文字区域检测算法也倾向于将这些符号视作噪声。这个先验知识在大部分医学报告单上是可行的。但仍然有占总数比例很小的一些类别的报告单(如尿常规、便常规等)上面会出现这些字符,而这些字符在这些类报告单上代表的却是非常关键的意义:如‘+’通常代表阳性,‘-’通常代表阴性(如图2.3所示)。为更好地处理这些类别的报告单,我们仍然需要一种效果更好、可以检测出这些不起眼的小字符的文字区域检测算法。
CVPR2019的一篇论文所提出的Craft算法[3]进入了我们的视野。Craft算法是一种基于分割的文字区域检测算法。在这里,我们先重点介绍Craft算法与Yolo算法在文字区域检测任务上的不同。
Yolo文字区域检测使用固定宽度的小包围盒来覆盖检测到的文字区域以达到文字区域检测的目的。该算法先使用卷积神经网络提取图像高维特征,然后用回归的方法获取文字区域的候选小包围盒,最后使用非极大值抑制和循环神经网络来过滤这些小包围盒结果。由于使用了循环神经网络,因此该算法是将文字区域检测看作“序列处理”任务。这种方式对中长序列的文本区域检测非常有效。但报告单里单独出现的’+’、’-’等符号没有前后文字符,因此“序列处理”反而会降低算法对这些字符的检测。
Craft算法则不将文字区域检测看作“序列处理”任务,而是将它看作图像分割任务。因此该算法对所有的文字序列的图像(无论长短)都一视同仁。Craft算法会对图像中的所有像素进行二分类——文字区域像素和非文字区域像素。因此Craft算法更容易检测到单独出现的’+’、’-’等符号。
综上,我们选择了Craft算法替代原有的yolo算法。
然而算法被选定后,一个更大的问题出现了:没有标记好的数据。Craft算法的训练数据需要人工框定每一个字符的包围盒。根据预测,标记一张报告单图像大概需要25分钟。标记出一个满意的数据集需要1000人/天以上的工作量,代价实在太大。
最终训练出的Craft算法在其他字符检测效果没有退步的前提下,大大提升了该模块算法检测单独出现的’+’/’-’等小字符的能力。新旧两种算法的对比结果如图2.5所示:
2.2文字识别模块
“文字识别”的任务是将切下来的文本行切片转换为文字。本项目一直使用的是CRNN算法[2]进行文字识别处理。训练数据集为人为收集的报告单字段随机自动生成的图片。我们尝试过使用注意力机制的DAN算法[7],但公司机器扛不住它的负载。
在“好大夫在线医学报告单文本行数据集v1.0”上,我们分别试验了我们的算法、百度OCR和腾讯OCR三种算法(如表2.1表2.2所示)。为公平起见,当百度云OCR接口和腾讯云OCR接口没有从图像中检测出正确的文字区域时,我们则跳过这些图片,不统计这些图片的错误。表2.3展示了百度云OCR接口和腾讯云OCR接口每一类的文字区域检测错误图片的占比:
2.3报告单分类模块
“报告单分类”本质上是文本分类任务。
该模块最初的版本为我们和产品经理一起设计的关键字分类方法,其思想是提取文本检测结果中的关键字,根据关键字加权结果进行分类,我们将其称为“加权关键字分类算法”。“加权关键字分类算法”在一般情况下还是比较准确的。在项目初期,它为我们提供了较高质量的报告单分类图像数据。但这个版本的算法由于参数是人为设定的,因此噪声对算法的影响非常大。如“血常规”报告单在表头出现“肝功能”等分类权值非常大的字样就极易让算法误以为它是“生化、肝肾功”类报告单。因此我们仍然需要用一种效果更好,速度更快的算法去替代我们的“加权关键字分类算法”。
报告单分类模块我们调研了很多算法。舍弃了效果最好的Bert算法[8],主要是因为其运行速度较慢,占用内存资源太多。最终我们选择的算法是FastText算法[9]。
FastText算法有几个优点:
1.运行速度快,i7十代的CPU下该算法处理一张图片的文本平均15毫秒;
2.由于其只有2层全连接层,所以内存资源占用非常低;
得益于之前设计“加权关键字分类算法”,我们可以获取较为可信的报告单图像分类数据集。人工过滤该数据集,并标记出5000多张图像后即可训练FastText算法。
在实际的实验中,我们将训练得到的FastText算法在随机选取的近500张报告单图像的文本检测结果上进行分类测试,准确率为92.2%,而“加权关键字分类算法”的准确率为75.2%。
2.4命名实体识别模块
命名实体识别(NER)的任务是抽取句子中的某类特殊名词。我们项目的“命名实体识别”模块任务如图2.9所示,需要从报告单文本中提取诸如“检查项名”、“项数值”、“项范围”等字段。
近些年,学术界开始研究用深度学习的办法去解决“命名实体识别”任务。长短记忆单元(LSTM)[14]开始被人用作处理“命名实体识别”任务。长短记忆单元(LSTM)理论上可以将字与字之间的联系扩展到无限远的地方,这进一步提高了其处理NER任务的效果。然而百度研究院的黄志恒博士发现长短记忆单元(LSTM)虽然加强了算法对中长距离字间联系的感知,但是却在超短距离的字间感知上不如线性链条件随机场。于是黄博士将线性链条件随机场架设在双向长短记忆单元(BiLSTM)后面,创造了效果更好的BiLSTM-CRF算法[15]。
2018年,一个里程碑式的算法——Bert[8]算法诞生了,它在11项自然语言处理任务上都取得了令人瞩目的成果。无论在前面提到的“文本分类”任务上还是当前小节的“命名实体识别”任务上,Bert算法都是毫无疑问的王者。
公司有一个医患交流的命名实体识别数据集,该数据库有近100万被标记的字符。在该数据库上,我们进行过三种算法的测试:1)Bilstm-crf;2)Bert-crf;2)Bert-Bilstm-crf。
根据以往学者的建议,我们选择的算法都含有条件随机场(CRF)进行超短距离标签修正。最终三种算法效果最好的是Bert-crf算法,于是该模块所用的算法最初为Bert-crf算法。
提取OCR识别的文字结果后,我标记了200多万的字符数据,涉及24种标签,如表2.4所示:
表中(B)代表首部标签,(I)代表非首部标签。其他标记没有首部与非首部之分。患者性别由于通常为一个字,故只有首部标签,没有非首部标签。
Bert也是一种基于注意力机制的算法。基于注意力机制的算法有一个明显的缺陷,即有最大处理长度,Bert算法的最大处理长度为512字。然而有很多报告单如血常规、超声检查等,字数均在千字以上。血常规等表格式报告单行间联系不大,尚可用行分割处理。超声检查等两段式报告单前后联系极大,不能简单的以行为标准进行分割处理。
将Bert-crf算法替代为Bert-rb-crf算法后,这个模块即拥有了理论上一次性处理无限长报告单文本的能力。
在实验中,Bert-rb-crf算法处理超长两段式报告单的效果基本与不分割处理的Bert-crf算法的效果一致,而不分割处理的Bert-crf算法却只能处理最多512字符长度的文本。这表明了Bert-rb-crf算法的先进性和有效性。
解决了算法问题,算法也就能在已经标记的200多万的字符数据上进行训练了,表2.5是Bert-rb-crf算法在标记的数据集的测试集上的表现。
2.5结构化内容提取
获取报告单图像文本数据中的命名实体信息后,需要将这些信息组合成表格的形式。其思想非常简单,首先找“检查项名”,然后在“检查项名”的当前行和下一行寻找尚未被匹配到的“项数值”、“项范围”即可。
三、存在的问题
虽然该项目各个模块取得了喜人的成果。但不可否认该项目依旧存在一些问题。
比如文字区域检测模块的Craft算法缺乏“印章检测”功能,所以当报告单中文字上出现印章时会对“文字区域检测”的结果产生干扰。Craft算法也喜欢将折线图误认为文字,令人欣慰的是,折线图上通常没有重要信息,错误识别对最终结果没有多大影响,还有就是某些纹理(如蓝色条纹毛衣等)依旧会对Craft算法造成干扰,幸运的是这些纹理上一般没有文字。文字识别模块的CRNN算法在报告单图像上的效果虽然超过市面上的某些云OCR接口,但是其依旧有不小的提升空间,这要求我们进一步利用现有的前沿技术,实现产品上的突破。
报告单分类的分类准确率仅有92.2%,我们对这个结果不太满意,感觉应该能进一步提升至95%以上,但这需要更多高质量数据集。