Competition_CAIL
比赛简介
为了促进法律智能相关技术的发展,在最高人民法院信息中心、共青团中央青年发展部的指导下,中国司法大数据研究院、中国中文信息学会、中电科系统团委联合清华大学、北京大学、中国科学院软件研究所共同举办“2018中国‘法研杯’法律智能挑战赛(CAIL2018)”。
比赛任务:
罪名预测:根据刑事法律文书中的案情描述和事实部分,预测被告人被判的罪名;
法条推荐:根据刑事法律文书中的案情描述和事实部分,预测本案涉及的相关法条;
刑期预测:根据刑事法律文书中的案情描述和事实部分,预测被告人的刑期长短。
2018.07.13说明:
转眼间第一阶段的比赛还有两天就结束了,实现之前的承诺,公开全部代码和分析思路。ps:后来用公司注册的账号,自己的账号提交了三四次就不用了,反正很伤心555~
说实话还是有点小郁闷的。因为没有用服务器参赛的经验,一开始是8G内存1060maxq的游戏本;在6月5日配的一块P4显卡服务器开始做正赛,训练速度只有1060maxq的一半,一层最简单的卷积要训练2.5小时;后来在7月5号新配了一台一块P100的服务器,速度是P4的7倍,但是在数据加强后超过三层的CNN和单层RNN依然需要将近2小时才能完成一轮训练,所剩无几的时间也基本放弃了,提交了一次简单数据加强后的模型第一问成绩提高了0.5%。虽然在一开始三问成绩都还不错,但是后来大牛越来越多、大家使用的模型越来越复杂,硬件不足以再深入研究更多的模型和优化方法。还是要向nevermore、HFL等大神致敬,赛后要多学习他们的处理方法!
后面提供的分析思路、网络代码、效果分析、模型评估,都是在不超过2层卷积和轻度数据增强的基础上实现的,不代表复杂模型的效果,仅供参考!
PS:因为不同时间在不同机器上做的,有几个版本找不到了,代码可能不连贯、存在路径错误或者函数丢失,各位轻喷~
2018.06.20说明:
鉴于主办方禁止共享代码和模型,代码更新将在比赛结束后进行。
此前上传的代码(2018.5.24)仅仅是刚刚参赛时的一个分析思路,但足够超过基准线。但是要获得好名次,需要对预处理和神经网络做不少调整。毕竟,数据决定模型能达到的高度,模型仅能逼近那个高度。
20180525成绩
针对比赛群还有github的小伙伴的一些疑问,统一回复:
问:xx函数有错误哎?
答:一个原因可能是模块的版本不一样导致函数用法有变动,另一个原因是代码我一开始很粗糙写的交交差啦,后面做了不少修改。
问:代码好像没写完哎,能上传全部吗?
答:我的本意是上传全部代码供交流的,后来主办方警告说发现代码雷同者成绩作废,吓得我瑟瑟发抖,毕竟这是一项工作任务,只能比赛结束上传全部代码了。
问:你是怎么对训练模型做评价的,F1得分好像不高,你的成绩如何?
答:我这人比较懒,直接用准确率了(就是结果是否完全一样)。发布的训练数据和官网评测数据绝对不是同分布的,各位用valid和test测一下就会发现差很多。所以啥得分高上传啥模型也会有很多意外的哈哈。
问:大数据集你的代码内存不够
答:大数据集要特别处理的,要一次跑完内存最少80G。我针对大数据集重写了预处理过程,处理后的序列数据都有5G,中间步骤的数据大概在50G左右。老大前几天给我配了96G内存的服务器,可惜我都预处理完了...另外我小数据集成绩不错的模型传到大数据评测惨不忍睹啊,用大数据重新训练的还不错曾经暂居第一(真的很看运气的,拿不到奖的话不知道会不会被老大暴打一顿...希望各路大神让让小弟,奖金请你们吃饭~)
暂时就这些,平时我只上传代码没看过评论,所以不能及时回复各位请海涵~由于老大要每周汇报进展,这是20180531的排名(现在已经不知道掉哪里去了,哈哈),相信各位都能取得好成绩
分析思路:
我理想中的流程是:
第一轮: 分词 》 剔除停用词 》 特征表达 》 单一模型训练 》评估 》优化
第二轮: 数据增强 》 单一模型训练 》评估 》优化
第三轮: 模型融合 》 评估 》优化
基于此,我的做法是:
分词:结巴,可以考虑引入外部词库提高分词精确性
剔除停用词:我直接把长度为1的字符串删了,这个也是偷懒但还挺有效的方法,标点、语气词等一般都是1个长度
特征表达:我是先将词语转成id,一开始保留4万个词语效果不太好,成绩大致是86-83-72;后来保留8万个词语,成绩大概是87.5-84-73.5,然后接入embedding层计算词向量。词语少了特征表达不足,多了很多低频词汇干扰词向量的表达效果。这里可以尝试tf-idf来选择保留哪些词语,不过很多人名地名会有特殊性,有能力的还可以采用实体识别的方式做过滤
单一模型训练:受限于硬件,Embedding(80000词语,400长度,词向量512维),接一层CNN1D(512个卷积核、卷积核大小3),接全局最大池化(GlobalMaxPool1D),再正则化(BN)后接全连接,最后用sigmod做类别得分,第三问用relu。因为没有足够的时间去训练深度网络和模型融合,只能力求增加模型宽度+BN加速收敛
另外第三问有很多人用分类模型,我在训练赛试过成绩不太好。我猜测是分类的话可能稍有不慎就归到了差距很大的类别,如果当成连续变量至多是两类的平均数,所以我更倾向于用连续变量来做。
评估:一开始我是用准确率(accu)来做的,因为一开始探索的时候训练一般都是不充分的,accu可以看出多类别是不是能有效预测出来,训练赛感觉提交分数和accu的结果正相关;后来大数据集的时候多标签的样本显著减少,并且数据大了容易达到数据和模型的瓶颈,就考虑和官网一样用f1来评估,关注样本少的类别效果。
优化:我能做的也只是1层变2层、RNN换CNN、增加词向量维度、增加卷积核数量和改变卷积核尺寸。测试下来1-3层卷积的成绩差不多,2层是最好的,但也只是高了0.1%左右,很可能只是运气问题。词向量512要高于256、卷积核数量512要高于256,rnn效果不如cnn(后面我会谈一下原因,但是多层的话我就不知道了)
数据增强:因为句子长度差距比较大(我记得200长度好像92%,300长度95%,400长度98%),我最终是取了400长度。
尝试过对句子内部词语做混洗打乱顺序,成绩只降低了一点点。结合断案的思路,一般也是看fact的关键词,所以我认为CNN在这里的特征提取表现会好于RNN的上下文理解。
尝试过对类别样本少的做重抽样,试了几次扩大不超过60000、扩大倍数不超过10的效果比较好,扩大不超过100000、扩大倍数不超过100效果很差。可能因为类别样本少的特征不具有代表性,重抽样过拟合的可能性很大。
模型融合:提交过一次RNN、CNN和残差CNN的融合,因为那天比赛服务器断电提交失败就没试过,一般情况下都会有提升。
成果说明:
代码分三大块,分别是:
1.数据预处理(这是练习赛写的)
由于170万数据比较大,我采用分块处理,在文件夹data_preprocessing中。方法模块为data_transform.py(因为更换服务器新写的代码不见了,懒得改了就上传原来的)包含读取数据文件、数据内容提取、分词、转成序号列表、文本长度统一。脚本代码在data_preprocessing文件夹,数据强化在data_augmentation文件夹
受限于数据大小,仅提供验证集预处理后的数据供参考
检查了预测结果,展示部分,仅从文本数据的角度上看可能罪名标签应该需要人为的做进一步加工(不是质疑判决)
例如valid数据中第10条
{
"criminals": ["连某某"],
"term_of_imprisonment": {"death_penalty": false, "imprisonment": 14, "life_imprisonment": false},
"punish_of_money": 10000,
"accusation": ["盗窃"],
"relevant_articles": [264]},
"fact": "经审理查明:一、2016年8月16日早上,被告人连某某在保定市满城区精灵网吧二楼包厢内盗窃被害人李某某OPPOR7S手机一部。所盗手机已销售,赃款已挥霍......五、2015年9月23日下午,被告人连某某从保定市满城区野里村连某家里骗走金娃牌柴油三轮车一辆卖掉,所骗取三轮车已销售,赃款已挥霍。2016年9月份左右一天下午,连某某从保定市满城区野里村连某甲经营的石板厂骗走金娃牌柴油三轮车一辆卖掉,所骗取三轮车已销售,赃款已挥霍。2016年8月份左右一天下午,连某某从保定市满城区白堡村曹某某经营的鸡场骗走爱玛牌电动车一辆卖掉,所骗取电动车已销售,赃款已挥霍。 经保定市满城区涉案物品价格鉴证中心认定,被盗两辆三轮车、一辆电动车价值分别为1700元、1500元、1250元......"
}
该论述出现的粗体属于诈骗,预测结果是 ['诈骗', '盗窃'] ,但是数据集中仅有 ['盗窃']
例如valid数据中第520条
{
"criminals": ["周某"],
"term_of_imprisonment": {"death_penalty": false, "imprisonment": 7, "life_imprisonment": false},
"punish_of_money": 3000,
"accusation": ["盗窃"],
"relevant_articles": [264]},
"fact": "经审理查明,2015年5月27日16时许,被告人周某为筹措毒资,窜到灵山县旧州镇六华村委会那旺村与合石村交叉路口处,使用随身携带的小刀割断电门线,打火起动摩托车的方法,将被害人张某乙停放在该处的一辆价值人民币1680元的红色豪日牌HR125-9型无号牌两轮摩托车盗走...2015年5月28日,被告人周某驾驶盗窃得来的摩托车到灵山县旧州镇六华村委会福龙塘队欲购买毒品时,被灵山县公安局旧州派出所民警抓获,并当场扣押其驾驶的无号牌摩托车。 ..."
}
该论述出现的粗体属于'走私、贩卖、运输、制造毒品',预测结果是(目前贩毒未遂属于争议,国内从重判罚一般认定毒品进入交易环节即为贩毒) ['走私、贩卖、运输、制造毒品', '盗窃'] ,但是数据集中仅有 ['盗窃'] 。
2.训练模型
我是分任务做的,也可以一个网络多个输出,不过我觉得那样可能会互相干扰。我主要用了一层CNN,另外提供TextCNN、attention、resnet简化版供参考。已经尝试过的TextCNN效果不好、CNN+attention效果不好、4层CNN的resnet效果不好,两层CNN构成的resnet效果比较好,可能是因为我一开始的网络太宽了过拟合比较严重。一般我只训练10-20个epoch很可能没有收敛,后来为了提高收敛速度batchsize改成256可能过拟合了。
我自己一层CNN+轻度数据增强,成绩为87.99-85.92-73.68,如果能够精细的做好数据增强、搭建合理的融合网络,加上几块1080ti做好调参工作,训练足够多的次数,应该能获得不错的成绩。这里提供任务一代码,任务二没区别,任务三最后用一个神经元激活用relu,损失函数mae或者mse
练习赛的一层RNN
3.预测模块
按照大赛要求将分词、转成序号列表、文本长度统一和模型预测等步骤封装在predictor文件夹中
from predictor import Predictor
content = ['菏泽市牡丹区人民检察院指控,被告人侯某于2014年10月14日晨2时许,'
'在菏泽市牡丹区万福办事处赵庄社区罗马皇宫KTV,因琐事对点歌员张某实施殴打,'
'致张某双侧鼻骨骨折、上颌骨额突骨折,经法医鉴定,被害人张某的损伤程度为轻伤二级。']
model = Predictor()
p = model.predict(content)
print(p)
最后祝愿各位选手获得好成绩!如果有什么数据量比较小、不拼硬件的文本分类中文比赛也请推荐下,kaggle上好像都是英文的,我想学习一下中文预处理的各种提升方法