ErrorCLR

ErrorCLR: Semantic Error Classification, Localization and Repair for Introductory Programming Assignments

基本信息

2023-07发表于会议SIGIR '23

博客贡献人

徐宁

作者

Siqi Han,Yu Wang,Xuesong Lu

摘要

    规模化的编程教育越来越依赖于自动化反馈来帮助学生学习编程。其中一个重要的反馈形式是指出学生程序中的语义错误,并提供程序修复的提示。这种自动化反馈主要依赖于解决语义错误的分类、定位和修复任务。尽管存在用于这些任务的数据集,但我们观察到它们并不具有支持所有三个任务的注释。因此,现有的语义错误反馈方法将错误分类、定位和修复视为独立的任务,导致每个任务的性能都不理想。此外,现有数据集要么包含少量的编程作业,要么每个作业的程序数量很少。因此,现有方法通常利用基于规则的方法,并使用少量的编程作业进行评估。为了解决这些问题,我们首先描述了一个新数据集 COJ2022 的创建过程,该数据集包含了提交给介绍性编程课程中 498 个不同作业的 5,914 个 C 程序,每个程序都带有错误类型和位置的注释,并且与同一学生提交的修复程序相对应。我们展示了 COJ2022 在各个方面的优势。其次,我们将语义错误分类、定位和修复视为相关任务,并提出了一种新颖的两阶段方法 ErrorCLR 来解决它们。具体来说,在第一阶段,我们基于图匹配网络训练模型,共同分类和定位学生程序中潜在的语义错误;在第二阶段,我们使用错误类型和位置的信息掩盖错误程序中的错误范围,并训练一个 CodeT5 模型来预测正确的范围。预测的范围替换错误范围以形成修复程序。实验结果表明,ErrorCLR 在 COJ2022 和其他公共数据集上对所有三个任务的表现都显著优于比较方法。我们还进行了一个案例研究,以可视化和解释 ErrorCLR 中图匹配网络所学到的内容。

目前研究存在问题:

  • 数据集方面

    • 现有数据集仅支持错误分类、定位和修复种的一两个任务,这限制了各种类型反馈方法的开发
    • 现有数据集大部分是针对于大型开源项目的缺陷程序
    • 其余数据集要么包含很少的编程作业,要么每个作业的平均程序数量较少,这限制了语义错误的多样性和相关方法效果的提升。
  • 方法方面

    • 现有的学生程序反馈研究通常集中于一两个任务并独立解决它们,导致每项任务的表现不佳。

本文主要贡献:

  • 创建一个新的学生 C 程序数据集 COJ2022,以支持程序自动反馈方法的开发。COJ2022不仅包含大量的编程作业,而且每个作业提交的程序数量也足够多。
  • 开发了一个两阶段模型 ErrorCLR,用于同时进行语义错误分类、定位和修复,且在三个任务上效果都较好。

COJ2022

  • 该数据集从入门编程课程作业的OJ系统中收集,由2019-2022学年的新生提交,共包含5914个有错误的程序,其中包含8511个错误行。

  • 数据集由所有有语义错误的程序组成,并筛选掉其中需要进行重大修改的程序

    • 筛选方式:通过difflib库筛选出与已修复的对应程序有单行差异的有缺选的程序。
    • 筛选标准:
      • 要修改连续的两行来修复程序认为是重大修改并丢弃
      • 数据集中只存在单行修改的程序,或一个程序存在多个不连续的单行错误
  • 数据集中包含了4种语义错误,涵盖了16个子类型

    • Control:代表与控制语句有关的错误
    • Function:代表与函数调用和声明有关的错误
    • Declaration:代表与变量声明有关的错误
    • Expression:代表正常表达式内的错误
  • 该数据集的标签由语义错误的行号、类型、子类型构成,用于微调模型

  • 该数据集还为每个编程任务维护一组所有不同的正确程序的候选集用于训练ErrorCLR。

表1. COJ2022程序中的语义错误类型和子类型。

在这里插入图片描述

ErrorCLR模型方法:

    ErrorCLR主要分为两个阶段,在第一阶段,我们首先预训练一个图匹配神经网络(GMN)来学习有缺陷的程序和参考程序之间的匹配性。 然后我们使用有错误的程序中的错误位置、类型和子类型的标签来微调 GMN用于分类和定位任务。 在推理时,我们将一个有错误的程序和与其最相似的正确程序输入到 GMN 中来预测标签。 在第 2 阶段,我们使用真实错误信息来屏蔽和注释有错误的程序,并将它们用作输入来训练 CodeT5 模型来预测已修复的程序。 在推理时,我们使用阶段 1 预测的错误信息来屏蔽和注释有错误的程序。
在这里插入图片描述

图1. ErrorCLR概述。
阶段一:使用GMN完成分类和定位任务:

    本文需要将一个有错误的程序 p b u g p^{bug} pbug与提交给同一编程作业的最相似的正确程序 p s i m p^{sim} psim进行匹配,并了解它们的差异以进行错误分类和定位。 相似度是根据使用 ASTNN 获得的程序嵌入之间的距离来测量的。
    从技术上讲,在训练时,我们将一对程序 p b u g p^{bug} pbug p s i m p^{sim} psim转换为两个控制流图(CFG),并将它们输入GMN以获得 p b u g 的 C F G 中的节点表示。节点表示进一步聚合为 p^{bug}的CFG中的节点表示。 节点表示进一步聚合为 pbugCFG中的节点表示。节点表示进一步聚合为p^{bug}$中的线表示,这些表示被转换以预测错误概率和错误类型/子类型。 表示的质量取决于 GMN 将 p b u g p^{bug} pbug p s i m p^{sim} psim 进行匹配并找到不匹配的能力。 为了增强匹配性学习的能力,本文在使用 GMN 进行错误分类和定位之前,对 GMN 进行预训练,以区分匹配和不匹配的程序对。 因此,第一阶段的训练过程分为预训练步骤和微调步骤。

GMN预训练

    对于每一个有缺陷的程序 p b u g p^{bug} pbug,候选集中都有多个与之对应的参考程序 p r e f p^{ref} pref,其中 p r e f p^{ref} pref要么是有缺陷程序的修复版本,要么是由另一名学生完成相同的编程作业。因此每个缺陷程序都会形成多个程序对。
    GMN通过真实匹配对和不匹配对进行预训练来学习程序对之间的匹配性。

  • 目的

    • 能够对匹配和不匹配的程序对进行分类
    • 使模型能够在匹配过程中学习到更通用的特征
  • 训练标签

    • 通过ASTNN获得程序的嵌入并计算嵌入的余弦相似度来作为每对程序之间的相似度。
    • 将其中相似度高于阈值 s h i g h s_{high} shigh的对视为匹配,低于阈值 s l o w s_{low} slow的视为不匹配,其中 s h i g h s_{high} shigh s l o w s_{low} slow根据相似度分布凭经验确定,本文将 s h i g h s_{high} shigh设置为0.98, s l o w s_{low} slow设置为0.88,最终获得65104个匹配对和81216个不匹配对
  • 预训练步骤

    • 预处理
      • 1.对于每对程序对 p b u g p^{bug} pbug p r e f p^{ref} pref使用Joern3生成相应的CFG对作为GMN的输入,如图2(d)(e)所示
      • 2.对于每个CFG通过结合类型嵌入和内容嵌入来获取每个节点嵌入。其中通过torch.nn来嵌入节点类型,使用InferCode来嵌入节点内容,因为InferCode方法嵌入了内容的子AST表示并捕获了更好的语义特征。
        在这里插入图片描述
    • GMN网络结构
      • GMN的每层中,首先使用两个独立的GNN更新两个图的节点的内部表示,再通过交叉图信息来更新交叉图节点表示。本文所使用的GNN为门控图序列神经网络(GGSNN)
      • 每层 G b u g G^{bug} Gbug G r e f G^{ref} Gref的节点表示更新可以表示为:

在这里插入图片描述 在这里插入图片描述

    其中在这里插入图片描述表示第i个节点的内部表示, h i ( t ) h^{(t)}_i hi(t)表示第t层的第i个节点的跨图表示, H i ( t ) H^{(t)}_i Hi(t)表示第t层时与节点i相邻的所有节点的跨图表示, A i A_i Ai表示与节点i相关的邻接矩阵块。Matching函数通过将节点i的跨图表示 h i ( t ) h^{(t)}_i hi(t)与另一个图中所有节点的跨图表示 H c r o s s ( t ) H^{(t)}_{cross} Hcross(t)进行匹配,来更新节点i的跨图表示。这里的Matching可通过多种方法实现,主要目的即为找出另一个图中与节点i匹配的节点,本文中采用基于注意力的方法实现,通过计算节点i对另一个图中每一个节点的注意力得分,再通过加权使用注意力得分的方式来聚合得到另一个图中所有节点的跨图表示。这样对于一对输入图, h i ( t + 1 ) h^{(t+1)}_i hi(t+1)不仅捕获了节点i所属图的特征,还捕获了与另一个图中节点的匹配性

在这里插入图片描述

图2. 程序对示例。(a) 和(b) 分别显示了 COJ2022 中的一对程序对示例,其中 (a) 中的错误行为红色。 (c)显示了(a)程序的两行标签,每行表示行号、类型和子类型以及语义错误的修复行。 请注意,(b) 中的参考程序与修复后的程序具有不同的实现。 (d)和(e)分别显示了(a)和(b)中两个程序的CFG。 节点左侧的数字是节点 ID。 每个节点由三部分组成:类型、内容和行号。 例如,(d)中的节点1具有类型“METHOD”和内容“main”,属于程序中的第1行。 与错误行相关的节点为红色。
GMN微调

    在预训练之后,本文对 GMN 进行微调,用于语义错误的分类和定位。我们将 𝑝𝑏𝑢𝑔 和 𝑝𝑠𝑖𝑚(或 𝑝𝑟𝑒𝑝)输入到 GMN 中,并获得节点表示。只保留 𝑝𝑏𝑢𝑔 的节点表示来预测错误标签,其中这些表示同时捕获了 𝑝𝑏𝑢𝑔 的语义和与 𝑝𝑠𝑖𝑚(或 𝑝𝑟𝑒𝑝)节点的匹配性。我们使用图中的 CFGs 来说明这个想法。在图 2 中,“lessThan”节点 5 应该通过基于 CFG 结构的预训练 GMN 与图 3 中的“lessEqualThan”节点 6 进行匹配。由于它们具有不同的节点类型和内容,模型可能会推断节点 5 含有错误。由于节点 5 位于循环内部,并且具有类型“小于”,模型可能会推断错误类型为控制。最后,由于匹配的节点 6 具有类型“小于等于”和内容“i<=n”,模型可能会推断错误子类型为错误操作符。
    由于错误是在行级别标记的,我们通过对所有属于行 𝑖 的节点的表示进行平均来计算每行 𝑖 的表示。
    对于定位,我们将行的错误概率计算为除了“无错误”类型之外的每种错误类型的预测概率的总和。

阶段二:使用CodeT5进行掩蔽跨度预测的程序修复:
  • 训练:
    • 在训练时我们使用真实的错误信息来掩盖𝑝𝑏𝑢𝑔中的错误跨度,并训练 CodeT5 来恢复𝑝𝑟𝑒𝑝 中的正确跨度。
  • 推理:
    • 在推理时,我们使用在第一阶段预测的错误信息来掩盖错误跨度并预测更正信息。有了错误信息,我们找到了问题程序中的错误行,并根据错误子类型对每个错误跨度进行掩盖。图 4 显示了图 2(a) 中问题程序的掩码程序。根据图 2©,它包含了第 2 行的一个 InitializationMissing 错误和第 4 行的一个 WrongOperator 错误。对于 InitializationMissing 错误,我们在该行的每个变量后添加一个掩码(即,MASK0、MASK1 和 MASK2)。对于 WrongOperator 错误,我们将该行的所有运算符进行掩码(即,MASK3)。其他错误子类型对应的行都会根据相应的策略自动进行掩码。在出现 Undefined 错误时,我们将整行进行掩码。此外,我们会对错误行进行注释,并将其保留在问题程序中作为提示,这有助于模型了解原始错误。

在这里插入图片描述

图3.掩码示例。
实验结果:

对于论文的三个任务(分类、定位、修复)分别采用不同的数据集和baseline进行实验评估

  • 分类任务
    • 使用了COJ2022和CodeFlaws(一个程序只包含一个错误)数据集
    • baseline:SVM、XGBoost、ASTNN、PIPE
    • 评价指标:宏观,微观的精度、召回率、F1分数(COJ2022,程序级别,因为一个程序可能包含多个错误,所以使用多标签分类的指标)、top-k命中率(行级别)
      • 微观:微观指标是在所有类别的预测和真实标签上计算的总体精度、召回率和 F1 分数。它考虑了所有类别的预测情况,但不考虑类别的不平衡性。
      • 宏观:计算每个类别的指标后,然后取其平均值。这个指标将所有类别的精度同等对待,不考虑类别的样本数量大小。

在这里插入图片描述

在这里插入图片描述

  • 定位任务

    • 数据集:COJ2022 和 Prutor

    • Baseline 方法:

      • 软件工程中故障定位方法:Ochiai、Tarantula
      • 针对于学生程序的深度学习方法:NBL、FFL
    • 评价指标:top-k 命中率

    • 实验结果:

      • ErrorCLR在除Prutor上的top-1 HR之外的所有指标上表现都比所有比较方法好得多
      • 在Prutor的top-1 HR上较差的原因是在Prutor的评估集中,作者直接将与有错误程序差异最小的正确程序与错误程序进行配对,而不考虑这两个程序的内容和结构是否最相似。这种配对策略可能会导致与ErrorCLR匹配策略不匹配,从而降低了ErrorCLR在top-1 HR上的效果。

在这里插入图片描述

  • 修复任务

    • 数据集:COJ2022(不使用其他数据集是因为本文方法需要对不同数据类型设置特定的掩码策略,在其他数据集上不便设置)

    • Baseline 方法:

      • Clara:一种代表性的基于规则的修复学生程序的方法
      • DeepFix:一种用于修复学生程序中语法错误的深度学习模型
      • TFix:一种基于 Transformer 的用于修复通用程序错误的模型
      • CodeT5:第二阶段 ErrorCLR 的骨干模型。只需将问题程序和修复程序用于对其进行微调.
    • 评价指标:

      • 编译率:衡量了可修复程序的比例
      • 接受率:衡量了通过相应任务所有测试用例的修复程序的比例
      • 通过的新测试用例数量:计算了每个程序修复后新通过的测试用例数,并对所有程序求和
    • 修复方法:

      • perfect:以真实错误信息作为提示进行修复的程序,体现了该修复方法的性能上限
      • top-k:找出程序中具有最高预测错误概率的k行,并随机组合k行中的l行(l=1,2,3)作为最终错误行交给方法进行修复。
    • 实验结果

      • Clara和DeepFix的接受率和通过的新测试用例数量非常低,DeepFix的编译率相对较高,因为它旨在修复编译错误。
      • TFix和ErrorCLR都需要错误信息进行修复,所以这里涉及到了perfect修复和top-k修复,除了perfect修复使用真实错误信息之外,top-k修复两个方法都使用ErrorCLR第一部分提供的预测信息。
      • 对于TFix和ErrorCLR,较大的𝑘值会产生更好的性能,而ErrorCLR的性能要比TFix好得多。这也说明了ErrorCLR的屏蔽错误跨度预测策略对程序修复的非常有效。
      • 并且perfect的效果也比top-k的方法更差,这是因为具有真实错误信息的模型每个有错误的程序只能输出一个修复后的程序,而具有顶部5或顶部10预测的模型可以为测试排列组合输出多个程序。
      • CodeT5只会简单的接受一个错误程序然后输出一个修复后的程序。从它的接受率和新测试用例通过数量大于ErrorCLR的top-1可以看出其第一部分预测的错误信息的噪声对修复性能是存在负面影响的。

在这里插入图片描述

  • 消融实验
    • w/o matching:没有使用跨图注意力的匹配模块的模型
    • w/o pre-training:没有进行区分匹配和不匹配程序对的预训练的模型
    • w/o classification:没有进行分类任务训练的模型
    • w/o localization:没有定位任务训练的模型。
    • 可以观察到没有匹配机制或预训练,分类性能会大幅下降,表明学习有错误程序和正确解决方案之间的匹配性的重要性。此外,没有进行分类和定位任务的联合学习,性能也会显著下降,表明多任务学习的有效性。
      在这里插入图片描述

相关知识链接

下载

论文下载
论文代码

总结

启发

  • 本文将学生程序反馈研究中主要的三个任务(分类,定位,修复)耦合在同一个框架下,且在三个任务上效果都超过了以往的方法
  • 提出的COJ2022数据集具有借鉴意义,不仅可以对语义错误分类,也可对编译错误分类。
  • 图匹配网络的方法充分利用了参考程序来进行分类,从而避免了对分类类型复杂的特征构造。

BibTex

@inproceedings{han2023errorclr,
  title={Errorclr: Semantic error classification, localization and repair for introductory programming assignments},
  author={Han, Siqi and Wang, Yu and Lu, Xuesong},
  booktitle={Proceedings of the 46th International ACM SIGIR Conference on Research and Development in Information Retrieval},
  pages={1345--1354},
  year={2023}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值