第四届“中国法研杯”司法人工智能挑战赛-刑期预测赛道三等奖方案

news2024/11/24 7:58:20

一、前言

本文将回顾第四届“中国法研杯”司法人工智能挑战赛-刑期预测算法赛道比赛。使用多任务预训练、然后进行微调的形式最终在比赛中取得了三等奖的成绩。

二、任务介绍

主办方在第一届“中国法研杯”比赛上提出了刑期预测任务,本届将针对往届刑期预测准确率不高的罪名进行专项研究,并提供更多维度信息(如省份、年份)进行帮助提升。

三、数据集与分析

3.1、数据集介绍

本任务技术评测使用的训练集、验证集、测试集由中国司法大数据院提供,包含大约40余万篇裁判文书的犯罪事实、本院认为、刑期、年份、省份信息。

3.2、数据分析

  • 长文本:从图中可见,数据文本序列较长,需考虑长文本输入问题。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sqiICQN0-1684392501970)(F:\weixin\imgs\image-20230518121449610.png)]

  • 刑期分布:在给出的数据集中,刑期分布在1~234个月区间内,且不是连续的,因此在建模时本文没有使用回归预测的方法,而是使用文本分类的方法。

  • 案由分布:从下图可见,案由分布极不均衡。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DDrh08vh-1684392501971)(F:\weixin\imgs\image-20230518122030651.png)]

  • 数据样例

    在比赛过程中,本文收集了往年的法研杯比赛数据集,通过正则等手段清洗获得了与本次比赛案由相同的数据,进行多任务预训练。

    往年数据清洗过滤后的数据样例,该数据用于多任务预训练:

{
    "caseCause": "故意伤害罪", 
    "justice": "贵州省平坝县人民检察院指控:2014年4月9日下午,被告人王某丁与其堂哥王4某(另案处理)假释驾驶大货车(贵×××××)准备到乐某镇大屯村拉砂,行至大屯村时与被害人王某乙相遇,王4某与王某乙因琐事发生矛盾,准备打架时被路人劝开,双方离开现场。之后,王4某打电话邀约王某乙打架,接着又打电话召集郑3某、艾1某雷、邱某(均另案处理)、。王3某王6某、王某丁与艾1某雷、邱某、郑3某等人聚集后,行至乐某商务宾馆门前大街上时,与被害人高某乙、王某乙、王某甲、李某等人相遇,王4某、王某丁等人就从郑3某驾驶的面包车上拿出杀高某乙系创伤性、失血性休克死亡;王某甲所受之伤为轻伤一级;王某乙所受之伤为轻伤二级;李某所受之伤为轻微伤。公诉机关认为,被告人王某丁伙同王4某等人××他人身体,致一人死亡,二人受轻伤,一人受轻微伤,其行为触犯了《中华人民共和国刑法》××××,犯罪事实清楚,证据确实、充分,应当以××罪追究其刑事责任。王某丁在共同犯罪中其次起次要作用,是从犯,依法应当从轻、减轻或者免除处罚;其到案后如实公式供述自己的罪行,是坦白,依法可从轻处罚。根据《中华人民共和国刑事诉讼法》××的规定,特对被告人王某丁提起公诉。请依法判处。", 
    "opinion": "", 
    "judge": 42
}

​ 本次比赛的数据样例,该数据用于微调阶段:

{
    "caseCause": "走私普通货物、物品罪", 
    "justice": "经审理查明,2015年4月8日15时许,被告人刘某经拱北口岸旅检现场无申报通道进境,无书面向海关申报,被海关关员截查。关员从其携带的手提袋内查获“ ”牌酵素液2瓶、“”牌面霜1瓶、“”牌沐浴乳1瓶、“”牌洗碗精1瓶、“”牌果味软糖3瓶、“”牌花洒1个。被告人刘某自述其为赚取带工费人携带上列货物过关。经闸口海关核定,上述货物偷逃应缴税额共计人民币。 另查明,被告人刘某因走私分别于2014年8月17日、10月7日被闸口海关给予行政处罚。", 
    "opinion": "本院认为,被告人刘某一年内曾因走私被给予二次行政处罚后,又逃避海关监管,走私普通货物入境,其行为已构成走私普通货物罪。公诉机关指控的事实、罪名成立,应予支持。被告人刘某归案后如实供述自己的罪行,可从轻处罚。根据被告人刘某的犯罪情节和悔罪表现,适用缓刑确实不致再危害社会,可以宣告缓刑。依照《中华人民共和国刑法》第一百五十三条第一款第(一)项、第六十七条第三款、第七十二条第一款、第三款、第七十三条第一款、第三款、第五十二条、第六十四条的规定,", 
    "province": "广东省", 
    "judge": 1
}

四、评价指标

给定样本的预测刑期 y i ′ y_i^{\prime} yi和真实刑期 y i y_i yi,当前样本的分数为:
score ⁡ i = { 1 , ∣ y i − y i ′ ∣ ⩽ 0.25 y i 0 , ∣ y i − y i ′ ∣ > 0.25 y i \operatorname{score}_i=\left\{\begin{array}{l} 1,\left|y_i-y_i^{\prime}\right| \leqslant 0.25 y_i \\ 0,\left|y_i-y_i^{\prime}\right|>0.25 y_i \end{array}\right. scorei={1,yiyi0.25yi0,yiyi>0.25yi
即预测刑期和真实刑期的偏离程度≤25%视为正确,否则视为错误。测试集最终准确率为所有样本分数的均值。

五、解决方案

5.1、多任务预训练

所谓多任务预训练指的是在预训练阶段不仅仅是做了MLM任务,还利用往年数据做了一个有监督的分类任务,这种做法的动机是让预训练任务尽可能的贴近下游的微调任务,具体多任务损失函数设计如下:
L o s s 总 = l o s s m l m + l o s s c l s Loss_总=loss_{mlm}+loss_{cls} Loss=lossmlm+losscls

5.2、多任务预训练代码实现:

考虑到文本序列较长,本文在预训练基模型选型上选用了Nezha模型。

代码:

class NezhaPreTraining(NeZhaPreTrainedModel):
    _keys_to_ignore_on_load_unexpected = [r"seq_relationship"]

    def __init__(self, config):
        super().__init__(config)

        self.bert = NeZhaModel(config)
        self.cls = BertOnlyMLMHead(config)

        # 增加分类模块
        self.legal_cls = nn.Linear(config.hidden_size, config.num_labels)

        self.init_weights()

    def get_output_embeddings(self):
        return self.cls.predictions.decoder

    def set_output_embeddings(self, new_embeddings):
        self.cls.predictions.decoder = new_embeddings

    def forward(
            self,
            input_ids=None,
            attention_mask=None,
            token_type_ids=None,
            head_mask=None,
            position_ids=None,
            inputs_embeds=None,
            labels=None,
            next_sentence_label=None,
    ):
        outputs = self.bert(
            input_ids,
            attention_mask=attention_mask,
            token_type_ids=token_type_ids,
            head_mask=head_mask,
            inputs_embeds=inputs_embeds,
        )

        sequence_output, pooled_output = outputs[:2]
        prediction_scores = self.cls(sequence_output)
        seq_relationship_score = self.legal_cls(pooled_output)

        outputs = (prediction_scores, seq_relationship_score,) + outputs[2:]

        total_loss = None
        if labels is not None and next_sentence_label is not None:
            loss_fct = nn.CrossEntropyLoss()
            # MLM损失
            masked_lm_loss = loss_fct(prediction_scores.view(-1, self.config.vocab_size), labels.view(-1))
            # 分类损失
            next_sentence_loss = loss_fct(seq_relationship_score.view(-1, self.config.num_labels),
                                          next_sentence_label.view(-1))
            # 总损失
            total_loss = masked_lm_loss + next_sentence_loss
            outputs = (total_loss,) + outputs

        return outputs

5.3、微调

在比赛过程中,主要采用了两种模型结构实现微调,分别为Nezha+CNN、Nezha+LSTM和Nezha+Linear,下面直接上模型代码。

  • Nezha+CNN

    class NeZhaCNN(NeZhaPreTrainedModel):
        def __init__(self, config):
            super().__init__(config)
            self.num_labels = config.num_labels
            self.bert = NeZhaModel(config)
            self.dropout = nn.Dropout(config.hidden_dropout_prob)
            self.filter_num = 256
            self.filter_sizes = [3, 4, 5]
            self.convs = nn.ModuleList([nn.Conv2d(1, self.filter_num, (k, config.hidden_size)) for k in self.filter_sizes])
            self.fc_cnn = nn.Linear(self.filter_num * len(self.filter_sizes), self.config.num_labels)
            self.classifier = nn.Linear(config.hidden_size, self.config.num_labels)
            self.init_weights()
    
        @add_start_docstrings_to_model_forward(BERT_INPUTS_DOCSTRING.format("batch_size, sequence_length"))
        def forward(
                self,
                input_ids=None,
                attention_mask=None,
                token_type_ids=None,
                position_ids=None,
                head_mask=None,
                inputs_embeds=None,
                labels=None,
        ):
    
            outputs = self.bert(
                input_ids,
                attention_mask=attention_mask,
                token_type_ids=token_type_ids,
                head_mask=head_mask,
                inputs_embeds=inputs_embeds,
            )
    
            last_hidden_state = outputs[0]
            x = last_hidden_state.unsqueeze(1)
            x = [F.relu(conv(x)).squeeze(3) for conv in self.convs]
            x = [F.max_pool1d(item, item.size(2)).squeeze(2) for item in x]
            x = torch.cat(x, 1)
            x = self.dropout(x)
            logits = self.fc_cnn(x)
            outputs = (logits,) + outputs[2:]
    
            if labels is not None:
                if self.num_labels == 1:
                    loss_fct = MSELoss()
                    loss = loss_fct(logits.view(-1), labels.view(-1))
                else:
                    loss_fct = CrossEntropyLoss()
                    loss = loss_fct(logits.view(-1, self.num_labels), labels.view(-1))
                outputs = (loss,) + outputs
    
            return outputs  # (loss), logits, (hidden_states), (attentions)
    
  • Nezha+LSTM

    class NeZhaLSTM(NeZhaPreTrainedModel):
        def __init__(self, config):
            super(NeZhaLSTM, self).__init__(config)
            self.num_labels = config.num_labels
            self.bert = NeZhaModel(config)
            self.dropout = nn.Dropout(config.hidden_dropout_prob)
            self.lstm = []
            self.lstm_hidden_size = 512
            self.lstm_layers = 1
            self.lstm_dropout = 0.1
            for i in range(self.lstm_layers):
                self.lstm.append(nn.LSTM(config.hidden_size if i == 0 else self.lstm_hidden_size * 4, self.lstm_hidden_size,
                                         num_layers=1, bidirectional=True, batch_first=True).cuda())
            self.lstm = nn.ModuleList(self.lstm)
    
            self.classifier = nn.Linear(self.lstm_hidden_size * 2, self.config.num_labels)
    
            self.init_weights()
    
        @add_start_docstrings_to_model_forward(BERT_INPUTS_DOCSTRING.format("batch_size, sequence_length"))
        def forward(
                self,
                input_ids=None,
                attention_mask=None,
                token_type_ids=None,
                position_ids=None,
                head_mask=None,
                inputs_embeds=None,
                labels=None,
        ):
    
            outputs = self.bert(
                input_ids,
                attention_mask=attention_mask,
                token_type_ids=token_type_ids,
                head_mask=head_mask,
                inputs_embeds=inputs_embeds,
            )
    
            last_hidden_state = outputs[0]
            for lstm in self.lstm:
                try:
                    lstm.flatten_parameters()
                except:
                    pass
                output, (h_n, c_n) = lstm(last_hidden_state)
            x = h_n.permute(1, 0, 2).reshape(input_ids.size(0), -1).contiguous()
            x = self.dropout(x)
            logits = self.classifier(x)
            outputs = (logits,) + outputs[2:]  # add hidden states and attention if they are here
            if labels is not None:
                if self.num_labels == 1:
                    #  We are doing regression
                    loss_fct = MSELoss()
                    loss = loss_fct(logits.view(-1), labels.view(-1))
                else:
                    loss_fct = CrossEntropyLoss()
                    loss = loss_fct(logits.view(-1, self.num_labels), labels.view(-1))
                outputs = (loss,) + outputs
    
            return outputs  # (loss), logits, (hidden_states), (attentions)
    
  • Nezha+Linear

    class NeZhaForSequenceClassification(NeZhaPreTrainedModel):
        def __init__(self, config):
            super().__init__(config)
            self.num_labels = config.num_labels
            self.bert = NeZhaModel(config)
            self.dropout = nn.Dropout(config.hidden_dropout_prob)
            self.classifier = nn.Linear(config.hidden_size, config.num_labels)
            self.init_weights()
    
        @add_start_docstrings_to_model_forward(BERT_INPUTS_DOCSTRING.format("batch_size, sequence_length"))
        def forward(
                self,
                input_ids=None,
                attention_mask=None,
                token_type_ids=None,
                position_ids=None,
                head_mask=None,
                inputs_embeds=None,
                labels=None,
        ):
    
            outputs = self.bert(
                input_ids,
                attention_mask=attention_mask,
                token_type_ids=token_type_ids,
                head_mask=head_mask,
                inputs_embeds=inputs_embeds,
            )
    
            pooled_output = outputs[1]
    
            pooled_output = self.dropout(pooled_output)
            logits = self.classifier(pooled_output)
    
            outputs = (logits,) + outputs[2:]  # add hidden states and attention if they are here
    
            if labels is not None:
                if self.num_labels == 1:
                    #  We are doing regression
                    loss_fct = MSELoss()
                    loss = loss_fct(logits.view(-1), labels.view(-1))
                else:
                    loss_fct = CrossEntropyLoss()
                    loss = loss_fct(logits.view(-1, self.num_labels), labels.view(-1))
                outputs = (loss,) + outputs
    
            return outputs  # (loss), logits, (hidden_states), (attentions)
    
    

5.4、Trick

  • FGM对抗训练

  • 模型融合

  • Focal Loss

六、评测性能

阶段性能
复赛阶段69.59
评审阶段74.22

六、总结

本文回顾了第四届“中国法研杯”司法人工智能挑战赛-刑期预测算法赛道比赛中的三等奖方案,使用多任务预训练和微调范式,并结合相关文本分类的上分trick优化nezha+CNN、nezha+LSTM和nezha+Linear三种结构模型,最终获得了不错的性能。

参考文献

比赛链接:http://data.court.gov.cn/pages/laic2021.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/540397.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

《终身成长》笔记六——称赞努力的过程,也将其与结果关联

目录 经典摘录 成为好父母好老师 成长型思维模式的真伪 第一种错误理解:很多人将他们身上某些他们喜欢的优点称作“成长型思维模式” 第二种错误理解:很多人认为成长型思维模式只关乎努力,特别是去夸奖别人的努力 第三种错误理解&#xff…

基于树莓派4B的智能家居

基于树莓派4B的智能家居 前言C语言的简单工厂模式工厂模式介绍类和对象工厂模式的优缺点优点缺点 智能家居框架产品工厂卫生间灯设备二楼灯设备餐厅灯设备客厅灯设备泳池灯设备风扇设备锁设备警报器设备地震监测设备火灾监测设备温湿度检测设备 指令工厂语音控制设备server控制…

如何创建样本手册?

第一步:提前研究和规划 首先明确目标客户群体在其中扮演的角色。 谁会穿你的衣服?您品牌的潜在客户是谁?他们的愿望是什么?他们会被什么打动?设置客户角色至关重要,因为它将决定样本手册的基调&#xff0…

Simulink 自动代码生成电机控制:模型仿真速度的优化

目录 方法一 Simulationmode 方法二 多核并行 方法三 Performance Advisor 总结 方法一 Simulationmode 执行下面的指令获取Simulink仿真实时,这里以霍尔FOC的模型为例,在切换模式为Accelerator时不能使用调用子模型的形式,需要把子模型复制…

map的forEach区别

map的forEach区别 先总结下: map和forEach区别是: 1.map有返回值而且必须return返回一个数组才行 ; 而forEach没有返回值可直接打印结果; 即:forEach()方法不会返回执行结果,而是undefined。也就是说,forEa…

vue 在线聊天实战范例(含选择发送表情、图片、视频、音频,自定义右键快捷菜单,一键复制,左右聊天气泡)

最终效果 完整代码 index.vue <template><div class"page"><div class"leftBox"><h1>访客</h1><div class"chatBox"><div class"chatRecordBox"><div v-for"(item, index) in cha…

DBCO-COOH分子量:305.3,CAS:1353016-70-2,二苯基环辛炔-羧基;类似有DBCO-NH2、SH、MAL、NHS等等

中文名称&#xff1a;二苯基环辛炔-羧基 英文名称&#xff1a;DBCO-acid 英文别称&#xff1a;DBCO-COOH cas: 1353016-70-2 分子式&#xff1a;C19H15NO3 分子量&#xff1a;305.3 DBCO-COOH是DBCO 衍生化的常用构件&#xff0c;在EDC、DCC和HATU等活化剂存在下&#xf…

linux kernel menuconfig kconfig makefile

概述 menuconfig是Linux平台用于管理代码工程、模块及功能的实用工具。 menuconfig的使用方式通常是在编译系统之前在系统源代码根目录下执行make menuconfig命令从而打开一个图形化配置界面&#xff0c;再通过对各项的值按需配置从而达到影响系统编译结果的目的。 Nuttx的me…

Spring Boot 数据库操作Druid和HikariDataSource

目录 Spring Boot 数据库操作 应用实例-需求 创建测试数据库和表 进行数据库开发&#xff0c; 在pom.xml 引入data-jdbc starter 参考官方文档 需要在pom.xml 指定导入数据库驱动 在application.yml 配置操作数据源的信息 创建bean\Furn.java 测试结果 整合Druid 到…

六、easyUI中的window(窗口)组件

1.window&#xff08;窗口&#xff09;组件的概述 窗口控件是一个浮动和可拖拽的面板&#xff0c;它可以用作应用程序窗口。默认情况下&#xff0c;窗口可以移动&#xff0c;调整大小和关闭。它的内容也可以被定义为静态HTML或要么通过Ajax动态加载 2.window&#xff08;窗口&…

MySQL-备份+日志:介质故障与数据库恢复

MySQL-备份日志&#xff1a;介质故障与数据库恢复 第1关&#xff1a;备份与恢复任务描述相关知识MySQL的恢复机制MySQL的备份与恢复工具编程要求代码参考 第2关 备份日志&#xff1a;介质故障的发生与数据库的恢复任务描述相关知识编程要求测试说明代码参考 第1关&#xff1a;备…

《分布式微服务电商源码》-项目简介

1.常见的电商模式 市面上有 5 种常见的电商模式 B2B、B2C、C2B、C2C、O2O 1.1.B2B 模式 B2B(Business to Business)&#xff0c;是指商家和商家建立的商业关系&#xff0c;如阿里巴巴. 1.2.B2C 模式 B2C(Business to Consumer) 就是我们经常看到的供应商直接把商品买个用户&a…

057:cesium设置纯颜色材质

第057个 点击查看专栏目录 本示例的目的是介绍如何在vue+cesium中设置纯颜色的材质,颜色的表达方式可以参考这篇文章 Cesium七种方法设置颜色 直接复制下面的 vue+cesium源代码,操作2分钟即可运行实现效果. 文章目录 示例效果配置方式示例源代码(共87行)相关API参考:专…

用友BIP新零售产品发布,与零售企业共创新未来

随着数智化时代的到来&#xff0c;零售企业不断面临着更多的挑战和机遇。为了满足消费者多元化的需求&#xff0c;零售企业需要采用多种方式来提高竞争力&#xff0c;如多渠道销售、线上线下融合、数智化运营、个性化营销和无缝化体验等。用友BIP新零售为零售企业提供了数智化转…

Jenkins的持续集成与持续部署

系统总体架构 Gitlab Gitlab是一款主要用于代码管理的工具&#xff0c;相较于GitHub&#xff0c;可以自己搭建服务器&#xff0c;这可以避免因为网络速度慢导致部署效率低下&#xff0c;同时&#xff0c;自己搭建服务器&#xff0c;安全性更高。Jenkins Jenkins主要用于管理版本…

改图片分辨率:提升图像质量的关键步骤

无论您是一名摄影师、设计师&#xff0c;还是一个爱好者&#xff0c;改变图片分辨率都是必不可少的工作。在本文中&#xff0c;我们将介绍改图片分辨率的作用以及它在哪些场景下使用。 改图片分辨率介绍 图片分辨率是指图像中所包含的像素数量&#xff0c;通常以“每英寸像素…

threejs 相机OrbitControls常用方法及属性

相机控件OrbitControls 通过OrbitControls可以对三维场景进行缩放、平移、旋转&#xff0c;本质上改变的不是场景&#xff0c;而是相机的参数&#xff0c;相机的位置角度不同&#xff0c;同一个场景的渲染效果是不一样&#xff0c;比如相机围绕着一个场景旋转&#xff0c;就像…

有哪些工具软件一旦用了就离不开?

&#x1f496;前言 目前&#xff0c;随着科技的快速发展&#xff0c;电脑已经进入了许许多多人的生活 &#xff0c;在平日的学习、工作和生活里&#xff0c;我们会用的各种各样的强大软件。市面上除了某些大公司开发在强大软件&#xff0c;还有各路大神开发具有某些功能的强大…

nodejs+vue网上课程在线教学网站平台a53y0

(1) vue引入elementui 1.使用npm安装element-ui npm i element-ui -S 2.在main.js中导入使用vue import element-ui/lib/theme-chalk/index.css //别忘了导入样式 import ElementUI from element-ui Vue.use(ElementUI) 后端&#xff1a;java(springbootssm)/python/php/node…

MySQL入门到精通——运维篇(基础篇——进阶篇——运维篇)本文以MySQL8.0版本以上为例

文章目录 前言MySQL——运维篇一、日志1.日志-错误日志2.日志-二进制日志3.日志-查询日志4.日志-慢查询日志 二、主从复制1.主从复制-概述2.主从复制-原理3.主从复制-搭建3.1.主从复制-搭建-主库配置3.2.主从复制-搭建-从库配置3.2.主从复制-搭建-测试 三、分库分表1.分库分表-…