443. Coleridge Initiative - Show US the Data | coleridgeinitiative-show-us-the-data
比赛终于结束了,从最开始处于奖牌圈外围时的斗志昂扬,到代码调试后占据前排时的自满,再到后半段像坐过山车一样起伏不定的心情,直到比赛结束后的些许波澜。这段心路历程远比比赛本身带来的感受要丰富得多。最终结果虽然不尽如人意,但至少获得了一枚银牌🥈。有些结果本被视为有金牌实力,但因各种原因(稍后我会讨论)我无法提交最好的结果。当然,比赛最重要的不是结果,现在来谈谈这2个多月比赛后的感受和收获。
起初面对这场比赛时,我以为只是常见的NER(命名实体识别)或QA(问答)类比赛,而且我之前有过相关比赛的经验。在学校时时间最充裕,现在每天下班后基本上只有几个小时,所以开始阶段的很多周末时间都用来做比赛,因为比赛的乐趣真的很吸引人。这些问题在前几周的挣扎中逐渐显现,只能通过超过2个月的较长跨度来缓解。
但随着模型增加和特征修改,调试次数也增多,最初主要用于打通整个预处理流程,训练过程也越来越耗时,这个问题在“白嫖”Kaggle官方机器时尤为突出!CPU的问题导致官方训练时间(不包括调试)翻了几倍,每次达到30分钟(你知道我每天下班后只有这几个小时的有效时间😞),而官方GPU资源的时间限制以及每次训练9小时的限制让我体验到了GPU焦虑。经过几天的摸索和实践,使用离线多线程处理可以显著减少预处理时间。另外,对于训练,适当租用GPU云服务器是一个选择,但费用依然不便宜,一次训练需要几十块钱。
更糟糕的是,我遇到了很少有人遇到的“内存爆炸”问题,即在私有测试集上进行预测时内存不足。当然,这是个人训练模型时数据预处理和训练流程构建粗糙造成的。之前我主要参加国内比赛,使用实验室充足的资源,自然没注意内存不足的问题,但Kaggle比赛有13G的内存限制,这让我花了1-2周时间处理这个问题。最后,我通过将预训练输入(如input id, type id)迁移到数据集类中进行批量生成解决了这个问题。
总结一下,时间少的问题可以通过参与跨度长的比赛并利用周末来缓解;使用多线程可以有效减少预处理时间;通过流程优化可以减少内存占用;适当租用GPU云服务器可以解决燃眉之急(当然我也在考虑购买自己的服务器主机,尽管目前显卡溢价太高)。
无论是比赛还是研究实验室,模型对数据的理解决定了你的模型是过拟合还是具有良好的泛化性能。因此,高质量数据集的数量极大地影响模型的最终结果,这也是许多比赛禁止手动标注额外数据的原因。
在本次比赛中,首先进行的是数据分析,这决定了我们任务的目标、所需模型的类型以及预处理和后处理的方式。我个人使用的是阅读理解模型,当然也可以看作是NER任务。数据分析后能对数据有一个整体概览,比如文本数量、文本长度分布、标签数量和长度分布、不同标签的占比、数量不平衡的严重程度等,这是特别重要的一步。
在这次比赛中,我也进行了上述操作,结果确实令人惊讶。
官方给出了超过1万个样本,样本长度远超512,因此需要使用阅读理解中常见的预处理方法——滑动窗口。样本标签少于200个,这意味着平均每个标签可能包含在50个样本中。事实证明,由于长尾现象,标签“adni”出现在超过60%的样本中,这会阻碍模型学习其他类型的标签,也会因为泄漏的存在使我们的验证变得毫无意义,严重影响训练。
此外,标签中同时存在包含关系的标记文本被标记为TP(真正例),这使得在生成预测结果时无法进行有效的后处理来过滤掉不合适的FP(假正例)(当然最终对此问题也没有好的解决方案)。
最后还有一个影响巨大的问题,即训练集标注不完全。也就是说,训练集中存在一些有效标签未被标注。因此,我们无法通过验证集的效果来判断模型的性能,只能通过公共测试集上的分数来体现。
由于问题一是常见问题且不是本次比赛的痛点,未进行优化。针对问题二和三,我尝试了一系列方法,确定了一些可以缓解问题的策略。
由于之前的问题,为了尽可能有效地进行验证,应该使验证集中不包含训练时见过的标签,因此我使用了并查集划分集合的方式,使训练集和验证集没有相同的标签,这样验证最接近私有数据集的分数。但由于在公共测试集上结果不佳,我没有在此基础上优化策略,而是专注于与文本匹配方法的融合,这也是我最终模型效果不佳的原因。另外,如果在span上执行类似操作可能会更好,因为这样可以允许包含足够数量标签的验证集来验证效果,尽管分数较低。
由于训练集中存在一些未标注的标签,在训练时有必要限制输入QA模型的文本长度,且不使用负样本,以尽量减少隐藏样本的负面影响。我还添加了一些可能的有效标签(这些标签来自bigger-govt-d