1. 项目概述:当在线评测系统遇上可解释的机器学习
在线评测系统(Online Judge, OJ)对于计算机相关专业的学生和编程爱好者来说,是再熟悉不过的“练兵场”了。从经典的LeetCode、Codeforces,到各大高校自建的OJ平台,它们通过自动化的代码编译、运行和测试,为学习者提供了即时、客观的反馈。然而,传统的OJ系统更像是一个“结果裁判”——它告诉你“对”或“错”,有时附带一个运行时间或内存消耗的数据,但对于“为什么错”、“学生卡在了哪个思维环节”、“他距离掌握这个知识点还有多远”这些问题,往往无能为力。教育者面对后台海量的提交记录,也很难精准定位到每一位陷入困境的学习者。
这正是我们这项研究的出发点。我们尝试构建一个系统,它不仅能预测学生在OJ上的未来表现(比如,下次提交能否通过?解决下一道类似题目的概率有多大?),更能提前识别出有学习风险的学生(例如,可能无法通过课程考核、学习动力持续下降)。更重要的是,我们不想让这个预测系统成为一个“黑箱”。教育场景下的决策关乎学生的成长,我们必须能够解释:“系统是基于哪些证据,判断这位学生可能存在风险?” 这就是我们将多示例学习与可解释人工智能结合起来的核心原因。
简单来说,MIL帮助我们处理OJ中天然存在的“包-示例”结构——一次编程作业(一个“包”)由多次代码提交(多个“示例”)组成,我们最终需要给这个作业打分或评估;而XAI则负责打开模型的黑箱,告诉我们模型做出某个判断时,具体关注了学生提交记录中的哪些行为模式。这不仅仅是技术上的结合,更是对“以学生为中心”的教育理念的技术回应。
2. 核心思路与技术选型:为什么是MIL+XAI?
2.1 问题本质与MIL的天然契合
在线评测场景下的学生行为数据,具有鲜明的层次化结构,这与多示例学习的经典假设完美匹配。
一个学生在一门课程中,会完成多个编程作业。每个作业(比如“实现快速排序”)就是一个“包”。学生对于这个作业的多次代码提交(包括编译错误、答案错误、时间超限、最终通过等),构成了这个包内的多个“示例”。最终,这个作业会有一个总体评价(如得分A,或通过/未通过),这就是“包标签”。而包内的单次提交,其本身(如一次编译错误)很难直接定义为一个明确的正面或负面示例,它的意义需要在包的上下文中解读。
传统机器学习方法处理这种数据时,通常需要进行特征聚合,比如将一个作业的所有提交,统计其“提交总次数”、“最终通过次数”、“平均耗时”等,将这些统计值作为特征输入模型。这种方法丢失了大量时序信息和行为模式细节。例如,学生A和学生B的“提交总次数”都是5次,但A的提交轨迹是“编译错误 -> 编译错误 -> 答案错误 -> 答案错误 -> 通过”,而B是“通过 -> 通过 -> 通过 -> 通过 -> 通过”。两者的学习状态和稳定性天差地别,但统计特征可能完全相同。
MIL允许我们保留每次提交的原始或细粒度特征序列,直接对整个“提交序列包”进行建模。模型会学习去关注那些对最终作业结果有指示性的关键提交模式(例如,反复出现同一类逻辑错误后的突然通过,可能意味着顿悟;而多次通过后突然出现编译错误,可能意味着粗心或状态下滑)。我们选择了基于注意力机制的MIL模型,因为它不仅能做出预测,其内部的注意力权重天然可以作为解释性的初步来源——模型对哪些提交示例赋予了更高的注意力权重?
2.2 XAI的必要性与方法选择
在教育领域应用预测模型,可解释性不是“加分项”,而是“必选项”。想象一下,你向老师报告“系统预测张三同学本课程挂科风险高达85%”,老师必然会问:“依据是什么?” 如果系统只能回答“这是模型算出来的”,那么这个系统的可信度和可用性将大打折扣。
因此,我们在基于注意力的MIL模型基础上,集成了事后可解释性方法。我们主要采用SHAP和LIME。
- SHAP:基于博弈论,为每个输入特征(可以是单次提交的特征,也可以是聚合特征)计算一个SHAP值,量化该特征对模型最终预测结果的贡献度。例如,它可以告诉我们,“在预测张三风险高时,‘最近三次提交间隔时间急剧缩短’这一特征的贡献最大”。
- LIME:通过局部拟合一个简单的、可解释的模型(如线性模型)来近似复杂模型在某个特定预测点附近的行为。它可以生成类似“如果该生将调试时使用的
print语句减少50%,其预测通过率将提升20%”这样的解释。
我们的策略是混合使用:利用MIL注意力权重识别出关键的“提交示例”,然后针对这些关键示例,使用SHAP或LIME对其特征进行深入解释,从而形成“从作业到关键提交,再到具体行为特征”的多层次解释链条。
注意:在特征工程阶段,我们刻意设计了一些教育学上有意义的特征,而不仅仅是技术特征。例如,“从首次提交到最终通过的时长”反映坚持度,“相邻提交间代码相似度的变化”可能反映调试策略,“借鉴参考代码后首次提交的通过率”反映理解能力等。这些特征更容易被教育者理解和接受。
2.3 整体技术架构
我们的系统架构分为四个核心层:
- 数据层:从OJ数据库原始日志中提取数据。核心表包括用户表、题目表、提交记录表。一次提取围绕一个
(学生, 作业)对进行,形成一个提交序列包。 - 特征工程层:
- 示例级特征:针对每次提交,提取代码特征(如长度、复杂度、特定API使用)、执行特征(运行时间、内存、结果状态)、时序特征(相对于作业开始的时间、与前次提交的间隔)。
- 包级聚合特征:在MIL模型之外,我们也计算一些传统的统计特征作为补充,或供对比实验使用。
- 模型层:
- MIL模型:采用基于注意力机制的MIL网络。输入是一个变长的示例特征序列,通过一个示例编码器(如LSTM或Transformer)得到每个示例的嵌入表示,再通过注意力层聚合为包表示,最后通过全连接层输出预测(如风险概率)。
- 可解释模块:在模型推断时,记录注意力权重。对特定预测,调用SHAP/LIME解释器,计算特征重要性。
- 应用与可视化层:将预测结果(风险等级、预测分数)和解释(关键提交序列、重要特征及其贡献)通过教师仪表盘进行可视化展示。例如,用时间线展示学生的提交历程,高亮注意力权重高的提交;用柱状图展示TOP特征的SHAP值。
3. 特征工程:从原始日志到模型可理解的信号
特征工程是整个项目的基石,决定了模型能“看到”什么。我们从海量、杂乱的OJ日志中,提炼出以下几类特征,力求全面刻画学生的编程行为与认知状态。
3.1 代码静态特征
这些特征从提交的源代码本身提取,不涉及运行。
- 基础指标:代码行数、字符数、注释比例。突然的代码量锐减可能意味着抄袭或放弃;缺乏注释可能反映习惯不佳。
- 复杂度指标:采用圈复杂度、Halstead复杂度度量。复杂度的异常波动可能意味着学生在尝试不同的、可能更混乱的解决方案。
- 语法元素分析:特定语言结构的使用频率,如循环嵌套深度、递归调用、特定数据结构(如
HashMap、PriorityQueue)的使用。这能间接反映学生对题目涉及知识点的掌握情况。 - 代码相似度:计算相邻提交间代码的相似度(如基于AST树或token序列)。相似度持续很高可能意味着在微小调试;相似度骤降则可能意味着推倒重来或更换了解题思路。
3.2 运行时动态特征
这些特征来自OJ评测机的反馈。
- 判决结果:编译错误、答案错误、时间超限、内存超限、运行时错误、通过。这是最直接的特征。我们不仅记录类型,还对其进行编码和序列化。
- 资源消耗:通过测试用例的平均/最大运行时间和内存占用。接近限制阈值的提交,即使通过,也暗示代码效率存在隐患。
- 错误信息挖掘(针对编译错误):对编译错误信息进行粗略分类,如“语法错误”、“类型不匹配”、“未定义符号”。同一类错误的重复出现,是重要的风险信号。
3.3 时序与行为特征
这类特征捕捉学生的学习习惯和毅力。
- 时间分布:首次提交时间点(反映主动性)、从首次提交到最终通过的耗时(反映持久性)、提交间隔的规律性(如集中在截止时间前是常见模式,但过于集中可能意味着拖延)。
- 尝试模式:通过前失败的次数、连续失败的次数。我们定义“挣扎区间”为连续失败次数超过阈值的一段序列,其长度和强度是风险识别的强指标。
- 求助行为:是否在提交失败后查看了题目讨论区或提示(如果平台有相关日志)。合理的求助是学习策略,过度依赖则可能存在问题。
3.4 特征处理与标准化
- 序列化与填充:一个作业的提交次数可变。我们设定一个最大长度,短序列进行填充,长序列进行截断或采样。这里我们采用了保留最早和最新若干次提交的策略,因为“开始”和“结束”阶段的行为通常信息量最大。
- 归一化:对数值特征进行标准化。对于类别特征,如判决结果,我们采用嵌入层进行学习。
- 缺失值处理:对于极少数的缺失运行时特征,我们采用同一学生同一题目类型的平均值进行填充。
实操心得:特征工程中最耗时的部分是对编译错误信息的分类。我们最初尝试了精细的NLP分类,效果提升有限却引入了巨大复杂性。后来退而求其次,采用基于关键词的规则匹配(如“syntax”、“undefined”、“type mismatch”),实现了快速、鲁棒的粗分类,在实际预测中已被证明足够有效。在工程中,要警惕“完美主义”,平衡效果与实现成本。
4. 模型构建与训练:让MIL模型学会关注关键提交
4.1 基于注意力的MIL网络结构
我们设计了一个相对简洁但有效的神经网络结构:
- 示例编码器:每个提交示例的特征向量(包含静态、动态、时序特征)首先通过一个全连接层进行初步融合和降维。然后,将所有提交示例按时间顺序排列,输入一个双向LSTM层。LSTM擅长处理序列数据,能捕捉提交间的依赖关系(如前一次的错误如何影响后一次的修改)。LSTM最后一个时间步的隐藏状态作为该示例的最终编码。
- 注意力聚合层:这是MIL的核心。我们将所有示例的编码输入一个注意力网络,该网络计算每个示例的注意力权重。权重的计算基于示例编码本身和一个可学习的上下文向量。最终,包的表示是所有示例编码的加权和,权重即注意力权重。公式可简化为:
包表示 = sum(注意力权重_i * 示例编码_i)其中,注意力权重_i = softmax(示例编码_i * 上下文向量)。 - 输出层:将包表示输入另一个全连接层,输出最终的预测结果。对于风险识别,我们将其构建为二分类任务(高风险/低风险),使用Sigmoid激活函数输出概率。对于表现预测(如下次提交通过率),我们将其构建为回归任务。
4.2 模型训练细节
- 损失函数:对于二分类任务,使用二元交叉熵损失。我们采用了焦点损失的变体,因为高风险学生样本通常远少于低风险样本,焦点损失可以自动降低易分类样本(大量低风险样本)的权重,使模型更关注难分类的高风险样本。
- 优化器:使用Adam优化器,初始学习率设为1e-4,并配合学习率衰减。
- 正则化:在编码器和全连接层广泛应用Dropout(比率0.3-0.5)以防止过拟合,特别是考虑到我们的数据量可能有限。
- 训练技巧:我们采用了课程学习的思路。先让模型学习预测“作业是否通过”这个相对简单的任务,再利用该任务预训练的模型权重,微调去完成更复杂的“课程最终风险预测”任务。这种方法在实践中显著提升了模型的收敛速度和最终性能。
4.3 可解释性模块的集成
模型训练完成后,解释模块相对独立地工作:
- 注意力权重可视化:对于任何一个学生作业包的预测,我们可以直接提取注意力层输出的权重,将其与原始提交序列对应。权重高的提交,就是模型认为对本次预测最重要的“关键提交”。
- SHAP值计算:我们使用Kernel SHAP或Deep SHAP(针对神经网络)。由于我们的特征包括序列化的示例级特征,计算开销较大。我们采用了对背景样本进行采样的策略,并主要针对被识别出的“关键提交”的示例级特征进行SHAP分析,以获取更精细的解释。
- 解释合成:最终呈现给教师的,是一个综合报告。例如:“系统预测王同学在本课程有高风险(概率72%)。主要依据是:在‘图遍历’作业中,模型高度关注其最后三次提交(注意力权重合计65%),这三次提交均因‘递归深度超限’错误而失败。SHAP分析表明,‘连续相同错误类型次数’这一特征对高风险预测贡献最大。建议教师关注该生对递归边界条件的理解。”
踩坑记录:最初我们试图直接用整个包的所有特征(成百上千维)计算SHAP值,不仅计算缓慢,而且解释结果过于分散,难以理解。后来我们调整为“两步走”策略:先用注意力机制定位到关键示例(时间点),再对这些关键示例的特征进行解释。这样得到的解释既高效又聚焦,更符合人类的认知习惯。
5. 系统评估与结果分析:不仅仅是准确率
评估这样一个系统,不能只看预测的准确率,还必须评估其解释的合理性和实用性。
5.1 预测性能评估
我们在一个包含约5000名学生、两年编程课程OJ记录的数据集上进行了实验。按时间划分训练集和测试集。
| 预测任务 | 模型 | 准确率 (Accuracy) | 精确率 (Precision) | 召回率 (Recall) | F1分数 | AUC |
|---|---|---|---|---|---|---|
| 作业通过预测 | 传统聚合特征+LR | 0.841 | 0.832 | 0.865 | 0.848 | 0.901 |
| MIL-Attention模型 | 0.892 | 0.883 | 0.904 | 0.893 | 0.945 | |
| 课程风险识别 | 传统聚合特征+XGBoost | 0.768 | 0.712 | 0.654 | 0.682 | 0.823 |
| MIL-Attention模型 | 0.815 | 0.789 | 0.731 | 0.759 | 0.882 |
结果显示,我们的MIL-Attention模型在两个任务上都显著优于使用传统聚合特征的基线模型。特别是在风险识别任务上,AUC达到0.882,表明模型具有良好的排序能力,能将高风险学生排在前面。
5.2 可解释性评估
这是本项目的重点。我们采用了两种评估方式:
- 人工评估:邀请3位有经验的编程课程教师,对系统为50个高风险预测案例生成的解释报告进行评分(1-5分,5分为最佳)。评分标准包括:解释是否易于理解、是否与教师经验相符、是否指出了具体可干预的学习问题。平均得分为4.2分,表明解释具有较高的实用性和可信度。
- 忠诚度评估:通过计算解释方法(如SHAP)的特征重要性排名,与通过“特征消融”实验(即遮住某个特征看模型预测变化)得到的真实重要性排名之间的相关性(如Spearman相关系数)。我们的方法相关系数在0.75以上,表明生成的解释是相对忠实于模型内部决策逻辑的。
5.3 案例分析
案例一:成功预警与精准解释学生李四在“动态规划”单元的前两次作业中表现尚可,但系统在第三次作业后即发出中等风险预警。教师查看解释报告:模型关注到其在最近两次作业中,“从错误到通过的提交间隔时间”显著增长,且“通过前答案错误次数”增多。SHAP指出“调试效率下降”特征贡献突出。教师及时约谈,发现该生对“状态转移方程”的理解存在模糊,通过针对性辅导避免了后续的彻底掉队。
案例二:解释揭示异常行为系统预测一位平时表现中等的学生王五某次作业风险极低,但解释报告却显示模型高度依赖其“首次提交即通过”且“代码与公共参考资源相似度极高”的特征。这引发了教师的警觉,经核查,该生存在抄袭行为。这说明解释系统不仅能服务于风险学生预警,有时也能反衬出异常的成功模式。
6. 部署考量与未来展望
6.1 实际部署中的挑战与应对
将研究原型转化为教师日常使用的工具,我们面临并解决了以下问题:
- 数据实时性:模型需要定期(如每天)增量更新。我们设计了轻量化的特征实时计算流水线,并将模型推断服务化,提供API供OJ系统调用。
- 解释的呈现:复杂的SHAP图对教师不友好。我们开发了交互式仪表盘,用时间轴、热力图、自然语言摘要(如“该生在过去一周调试效率下降30%”)来呈现解释。
- 误报处理:任何预测模型都有误报。我们设定了风险阈值,并允许教师对预警进行反馈(如“确认有风险”、“误报”),这些反馈会作为新的标签数据,用于模型的持续在线学习,形成闭环。
- 隐私与伦理:所有数据和分析结果严格限定于授课教师和教学管理人员可见,并告知学生相关数据的使用目的,遵循教育数据隐私规范。
6.2 未来可扩展的方向
- 细粒度知识追踪:将预测对象从“作业/课程”层面,下沉到具体的编程知识点(如“指针操作”、“递归思想”)。通过分析代码与知识点的关联,绘制学生的个性化知识掌握图谱。
- 多模态数据融合:结合OJ数据与其他学习管理系统数据,如视频观看时长、论坛发帖内容、同伴互评反馈等,构建更立体的学习者画像。
- 干预建议生成:当前系统止步于“风险识别”和“原因解释”。下一步可以结合教育心理学和教学法知识,尝试自动生成个性化的学习建议或资源推荐(如“针对递归边界问题,推荐完成练习A和观看视频B”)。
- 模型轻量化:探索更轻量的MIL模型(如基于Transformer的简化版)和更高效的解释算法,以支持在资源有限的学校服务器上部署。
这项研究最深的体会是,技术之于教育,其价值不在于替代教师的判断,而在于增强教师的感知能力。MIL模型像是一个不知疲倦的助教,从海量数据中筛查出异常模式;XAI则像是一份详尽的诊断报告,把助教的“直觉”翻译成教师能理解、能行动的“证据”。当教师看到系统高亮出学生那一段反复挣扎于同一语义错误的提交序列时,他获得的不仅仅是一个预警,更是一个切入对话、提供帮助的精准起点。这才是教育智能化最有温度的打开方式。