背景
简历解析是把简历文件的各个字段抽取出来,生成标准简历/结构化简历,它是招聘场景的一项很重要的基础AI能力。
目前字节招聘的简历解析已通过飞书人力套件赋能数百家企业。
简历解析 VS 网页解析
网页解析是传统搜索引擎的一个基础子系统,它需要从大量简历文件中提取很多结构化文本信息。相比网页解析,简历解析会容易很多,具体:
- 输入无结构化信息 - 简历解析的输入文件无结构化,需要重新排版,恢复文字阅读顺序,简历无固定模版,每份简历排版各异,因此需要排版兼容各种版面类型,网页解析本质上有html语言作为基础,有结构化,无需再排版
- 输入无标签 - 简历解析的输入文件无标签,需要简历解析识别板块内容,还需通过ner模型识别实体
- 文件类型复杂多样 - 简历解析需要支持pdf/word/图片/excel/html等等很多格式,而每种格式转文字存在一定信息丢失,而网页解析基本只有html,不存在重要信息丢失word文档 - 转出的文字无坐标/颜色/大小等文本信息,还存在隐藏文字,偶尔还有顺序错乱图片 - OCR存在文字识别错误/水印、页眉页头PDF - 水印、文字字典映射问题、页眉页头
- 快速修复能力 - 简历解析的输出需要直接面向客户,一线反馈case需要尽快优化好,才能达到客户预期,因此需要快速优化,如果各处都模型化了,很难做到这一点,网页解析不存在这个问题
相关概念
TCS
字节内部面向全员提供的数据标注平台。
LEECH
字节AI团队内部开发的工具平台,主要用在简历解析,为简历解析提供查询简历、调试简历、标注数据、查阅敏感日志等等功能。
全篇准确率
- 核心字段:姓名、电话、邮箱、工作经历(公司、职位、起始时间、结束时间、工作描述、工作类型)、教育经历(学校、学历、专业、起始时间、结束时间),总共14个字段(每个人平均两段教育经历+两段工作经历,总字段会有25个)
- 全篇准确率:评估简历解析效果的最重要指标,等于 核心字段全正确的简历数 / 总的简历数
富文本信息
pdf和图片转换生成的文字带有额外可利用信息——文字xy 坐标位置、字体大小、字体颜色、字体类型、字体高度、字体粗细等等。
排版恢复
由于简历模版多种多样,而文本抽取服务只能保证将每行文本提取出来,而每行文本的阅读顺序是不被保证的,因此需要有一套排版算法来恢复正常的阅读顺序。
板块识别
简历中一般都可划分出边界清晰的各大板块,比如基础信息、教育经历、工作经历、项目经历、技能、证书、兴趣爱好、个人荣誉、自我评价、社会实践等等。
Tika
Tika是一种开源的内容检测和分析工具包,可以从各种文件(pdf/doc/excel/xml/html/txt等等)中提取出文字内容。
Rich Tika
Tika的增强版,在tika的基础上增强实现了富文本信息提取能力,能从PDF中提取到富文本信息。
OCR
OCR是从图片中提取文本的AI基础能力。
概要介绍
核心处理流程
简历解析的总体技术路径是以一种pipeline的工作方式来实现,具体可分为文本抽取、排版恢复、文件纠错、实体抽取、版面分析、以及分模块解析6个步骤。
服务调用链路
优化成果
中文解析指标——大幅提升(67%-86%)
经历了一年时间的集中优化
指标中存在变低的情况是因为新增标注数据
英文解析指标——大幅提升(11%-65%)
虽然英文解析优化相对时间短,但见效快,一个主要原因就是借鉴了中文解析优化的经验以及平台
指标中存在变低的情况是因为新增标注数据
同类产品对比——行业领先
下面是2021年做的同类产品对比结果
|
| 飞书招聘 | 产品A | 产品B | 产品C |
个人信息 | 对 | 197 | 192 | 189 | 187 |
| 错 | 3 | 8 | 11 | 13 |
| 平均字段准确率 | 98.50% | 96.00% | 94.50% | 93.50% |
工作经历 | 对 | 165 | 133 | 127 | 138 |
| 错 | 35 | 67 | 73 | 62 |
| 平均字段准确率 | 82.50% | 66.50% | 63.50% | 69.00% |
教育经历 | 对 | 188 | 142 | 129 | 154 |
| 错 | 12 | 58 | 71 | 46 |
| 平均字段准确率 | 94.00% | 71.00% | 64.50% | 77.00% |
全篇准确率 | 对 | 159 | 108 | 94 | 105 |
| 错 | 41 | 92 | 106 | 95 |
| 正确率 | 79.50% | 54.00% | 47.00% | 52.50% |
性能优化——解析速度大幅提升(2秒-1秒)
在测试集上平均耗时从 2 s 下降到 1 s,平均耗时减少了50%,对于长文本简历,提升十分明显。
主要优化措施
优化体系闭环
优化过程:效果优化提升->给到标注平台的预标注数据质量提升->标注质量提升->更加优质的测试集->更好体现优化结果->接着下轮优化
每一批数据只标注500份简历,开发集和测试集轮流切换,循环迭代10次+
- 为什么不是一次性将数据标完?数据质量不是很快就能提升到很高的水平的,特别是标注的任务比较复杂时,规范也需要花大量时间去完善,我们这里规范确实经过很多次调整。
- 为什么这样循环迭代会更好?数据驱动的优化需要大量高质量的数据来验证优化思路,更高质量的预标有利于标注质量提升,更高质量地标注数据,也有利于数据驱动的优化,因此是一个相互支撑的过程
一、数据标注
曾有人提出AI的成绩,7成在数据,3成在模型,意在说明数据的重要性。
优化前只有几百份测试集,数量少且质量一般,我们需要大规模高质量的开发集+测试集才好支撑我们不断的优化,因此在标注效率和质量上做了不少努力,最终得到了万级高质量中文+英文数据集
数据标注对效果指标的提升无法直观体现,但它是基石,标注质量不行,其他都是浮云,因此将其排在各项优化措施首位。
- 提升标注效率
- 标注平台:在tcs标注平台的基础上设计实现一套适合简历标注的交互模式,降低了标注难度(tcs平台提供了框架,可在此基础上设计实现适合自身特点的交互页面)
- 预标注:标注前提前灌入预标数据(通过简历解析预测生成预标数据),标注人员只需检查标注结果,只有存在标注错误才修改,大大提升了标注效率,也会提升标注质量
- 提升标注质量
- 标注模式:为提升标注质量,采用 双标+质检 模式,虽然更耗人力,但是在简历标注这种需要提取信息较多且规则复杂的场景,该模式很重要
- 标注类型轮换:采用测试集 和 开发集 按批次轮换标注模式,这能不断提升预标注的质量,也就能不断提升整体标注质量,特别是在初期预标质量比较低的情况下效果尤为显著(初期预标质量低,如果一批次标太多,质量都不太好,如果标一段时间停下来,等质量提升了再标,标注人力资源可能面临无人/换人/需重新培训等问题,且让整个标注周期长了很多)
- 标注结果diff分析:标注完后,会第一时间将标注结果与预测结果打出diff数据分析标注问题,会发现不少是标注错了,需要纠正过来。即使有了这步操作,还是无法解决大部分问题,在随后的优化过程中,还需每隔一段时间,回归diff数据再改标准答案,不断提升数据质量。
- 标注规范:建立比较详尽的标注规范对质量很重要,最初只有一个很基础的规范,但在标注过程中,会有不断的规范性问题提出来,总结归纳形成文档很重要
- 其他需要注意的点:标注初始阶段明确定义准确率目标,把压力给到标注人员,让其对质量更加重视标注初期给标注人员做培训,明确需要注意的事项标注初期需要关注每个标注人员质量指标(平台会基于质检数据自动生成准确率指标),对质量差的标注人员给出警告(比如让其降低速度、更加关注标注问题、多抛问题)标注初期需及时质检验收,可在群里抛出标注错误,并提醒错误原因,以暴露更多标注问题,及时纠正,并需总结归纳问题记入规范让标注人员定期总结标错的case,存疑的case集中收集后让质检人员答疑
二、自动化评测
优化前效果评估方式比较粗暴,采用 人工标注 的方式评估,效率极低,这么做的原因主要是:
- 很多字段并没有无可争议的标准答案,存在不少模棱两可的地方(比如在学校里兼职图书管理员算不算工作经历)
- 没有很具体的标注规范,当时的规范等于字段解释,没有更具体的规则和案例说明
- 部分字段多一些文字或少一些文字,有的可以,有的不行(比如公司加不加后面括号中的地名是无碍的,而职位“算法工程师-P7”中存不存在“算法工程师”是关键,没它不行)
针对上述问题,做了如下操作实现自动化评测:
- 完善规范,既要有抽象的规则,又要有案例说明
- 字段评测方式部分字段采用完全匹配(姓名、邮箱、手机、教育经历中时间/学历,工作经历中时间/工作类型)部分字段采用部分匹配——预测结果包含标准答案或标准答案包含预测结果(教育经历中学校/专业,工作经历中公司/职位)部分字段采用子串占比——工作描述采用公共子串占比是否超过60%判断
- 实验采用部分匹配/子串占比 后,误判的概率,实验结果表明新的字段评测方式是完全可行的,误判概率极低
在后续的优化过程中,我们做了上千次开发集/测试集自动化评测(case优化需要经常评测优化思路是否正确),大幅提升评测效率。
三、数据驱动优化
经过数据分析,我们发现大部分问题不是出在模型预测的实体词不对(而且大部分模型预测问题能通过规则优化解决),而是我们代码逻辑各种问题,因此需要大量的badcase来驱动调优逻辑,这也是上面提到准备大规模开发集+测试集的重要原因。
代码逻辑调优是效果提升最重要的措施,大概占了八成。
通过优化leech工具平台,建立了一套基于Case by Case的分析优化机制
- 开发集调优工具将开发集上预测结果与标注结果做diff处理,结果当日志存入数据库,再通过leech查询出diff数据,再调试分析问题原因
- 代码逻辑优化
- 语义深度学习识别实体——采用深度模型+规则+字典提取实体
- 深度模型预测实体作为基础
- 通过规则和黑名单过滤掉不合理的实体
- 接着提取符合规则的字典词为实体
- 另外提取符合规则的字符串为实体
- 增强自学泛化能力——自动挖掘数据潜在规律,让算法拥有举一反三的泛化能力
- 通过已经提取的工作经历/教育经历泛化生成模版提取新的经历,并依据富文本信息和大量规则判断是否正确;
- 针对各大猎头来源简历做了针对性的模版提取
- 依据已经提取的工作/教育经历的字段统计信息,判断新增的经历各个字段的提取是否合理
- 多通路解析,交叉验证
- 将简历走文本和图片并行解析,将结果进行交叉验证,通过置信度计算等方式,给出综合结果
- 重构排版恢复:通过板块的识别以及文本空间位置关系来实现文本阅读顺序的恢复
- 增强时间提取能力:依据case增加时间提取的泛化正则表达式
- 增强板块识别能力:主要是增加各大板块关键词,并增强提取规则
- 水印破解:通过对简历中各段文字的富文本信息统计特征对水印文本进行去除
四、实体词挖掘
通过实体词挖掘,总共积累100万+的实体词,是效果提升中仅次于case优化的措施。
- 中文实体词挖掘将人才库中的标准简历中的实体与标注的实体、来自知识图谱的学校、公司、专业、职位等实体进行组合,清洗bad case,得到最终的实体词库。
- 英文实体词挖掘针对英文简历,从人才库中获取学校、公司、专业、职位等词语,这些词语属于英文以及其他拉丁化的语言,这部分词语用于补充在英文简历中,模型对实体预测的遗漏。构建高质量的实体词典能够提高实体预测的准确率,而来自人才库的实体词质量不高,因此使用如下步骤对实体进行进一步清洗:从人才库获取学校、公司、专业、职位等实体词,根据实体词的特点,首先使用规则对置信度不高的实体进行清洗;为了直接将在conll-2003、ontonotes5以及公开英文简历数据集上的预训练模型的知识融入到词典中,通过将实体词填入模板中,如针对公司类型实体词,构造:“He works in {company}”,如针对Microsoft公司,构造“He works in Microsoft”, 针对专业类型实体词,构造:“Bachelor in {major}”,如针对gestion cultura专业,构造“Bachelor in gestion cultural”;将构造好的句子使用多个预训练模型进行预测,将多个模型的输出以投票的方式进行结合 ,若结果与待确认实体类型相同,则保留该实体,加入词库,否则清洗改实体;将清洗后的四类实体词库,构建AC自动机,并用于线上的NER工作。
整个流程的示意图如下:
五、模型训练
简历解析用到了ner模型(lstm+crf 和 bert)提取实体词(姓名/公司/学校/专业/职位)。
主要优化方式:
- 数据增强学习:替换简历中实体词数据清洗/调优设计专门针对简历实体的标注模式,增强标注质量
- 模型迁移学习参数调优模型更换(lstm+crf -> bert)
技术难点突破
长时间遗留的疑难杂症,经过集中力量技术攻关得到突破性进展
一、参数自动化调优
问题:简历解析中存在很多参数,如相对位置关系、相对高度关系等。这些参数是通过个人经验进行赋值,没有经过大数据进行验证。
解决方案:设计实现了一套参数自动化调优的机制,通过在一定的空间内对多个参数的值进行搜索,找到最适用于简历的参数,从而提升算法的效果。
效果:在英文解析中已有一定效果,取得1个百分点的提升。
二、复杂结构排版
问题:在某些上下结构的设计简历或者普通简历中,穿插着左右分栏的多段工作经历或教育经历。在使用文本提取工具,从上至下逐行提取文本时,会将多段经历杂糅在一起,最终导致提取错误。
分析:此类左右分栏的案例中,多段经历的前几行均有一个或者两个时间实体,通过这一特征,可以将不同经历的文本通过富文本信息进行分组,从而得到正确顺序的工作经历。
解决方案:通过在segments中搜寻多个以时间实体为主体、并排出现的segments,并将这些segments作为名为"split_time"的section的起始,通过原有的分组(group)逻辑之上,为split_name这个sections配置相应的规则,从而能够将多段经历分到不同的group,将杂糅的文本分开,以获取正常阅读顺序的文本,从而提取到正确的工作或教育经历。
三、性能优化
问题:在大量规则代码下,每一次解析时间较长,甚至有的简历需要几十秒时间。
分析:简历解析中存在大量的正则表达式,而python的正则表达式缓存机制只缓存最近编译的正则表达式,因此,在简历解析中,正则表达式的反复实时编译需要消耗大量时间。
解决方案:设计了一个正则表达式的缓存类,在每一个正则表达式被编译后便缓存下来,下一次调用时,不需要再次编译。在设计此缓存类时,复用了python的接口的形式,采用了LRU的缓存机制,可以在对代码在最小改造的情况下,提升运行速度。
除此之外,将一些功能函数进行解耦、降低常用函数的时间复杂度、限制使用深拷贝等操作,同样提升了代码的运行速度。
效果:在测试集上平均耗时从 2 s 下降到 1 s,平均耗时减少了50%,对于长文本简历,提升十分明显。在上线后,端到端时延变化情况如下图所示,可以看到不仅平均时延降低,尖刺现象也得到缓解。
总结
- 依据能力短板制定优化策略在算法优化时,不能先入为主,而应先通过数据分析目前的问题集中在哪,再制定优化策略。
- 优质数据在效果提升中极其重要优质的数据在很多场景都显得尤为重要,因此如何能得到尽量优质的数据是大家都比较关心的话题。上面的优化措施里多数都跟数据关系密切