ChatGPT生成的代码真的正确吗?代码生成的大型语言模型的严格评估

互联不一般哥 2024-06-28 18:56:39

Is Your Code Generated by ChatGPT Really Correct? Rigorous Evaluation of Large Language Models for Code Generation

Jiawei Liu, Chunqiu Steven Xia, Yuyao Wang, Lingming Zhang

University of Illinois Urbana-Champaign, Nanjing University

引用

Liu J, Xia C S, Wang Y, et al. Is your code generated by chatgpt really correct? rigorous evaluation of large language models for code generation[J]. Advances in Neural Information Processing Systems, 2024, 36.

论文:https://arxiv.org/pdf/2305.01210

摘要

编程基准,连同精心策划的合成问题和测试用例,被用来衡量各种LLM在代码合成上的性能。然而,为了充分评估生成的代码的功能正确性,这些测试用例在数量和质量上都是有限的。现有基准测试的这种限制引出了以下问题:在LLM时代,生成的代码真的正确吗?为了回答这个问题,我们提出了EvalPlus——一个代码综合评估框架,以严格基准测试LLM合成代码的功能正确性。EvalPlus通过自动测试输入生成器(由基于LLM和基于突变的策略提供支持)新生成的大量测试用例来增强给定的评估数据集。我们对26种流行的LLM(例如GPT-4和ChatGPT)进行了广泛的评估,结果表明HUMANEVAL+能够捕获大量以前未检测到的LLM合成的错误代码,将pass@k降低了19.3-28.9%。我们的工作不仅表明了之前流行的代码综合评估结果并不能准确地反映LLM在代码综合方面的真实性能,而且为通过自动化测试来提高此类编程基准开辟了新的方向。

1 引言

自动生成准确符合用户意图的程序是计算机科学中一个长期存在的挑战,被称为程序合成。在过去的几十年里,经典的程序合成技术得到了发展,包括演绎合成、归纳合成和神经引导合成。最近,随着大型语言模型(LLM)的出现和开放代码库的丰富,研究人员一直专注于将LLM应用于直接代码生成。然后将生成的代码片段与上下文结合起来,形成与用户意图一致的完整函数。利用自然语言理解和生成能力,LLM在代码合成方面表现出令人印象深刻的性能。

图1:ChatGPT为HUMANEVAL #58合成的典型错误代码。

足够的测试。当前的编程基准通常对每个编码问题平均只包含不到10个测试。此外,这些测试相对来说过于简单,无法完全探索代码的功能或角落用例。图1显示了一个由ChatGPT合成的错误代码示例,它从两个列表中返回经过排序的唯一公共元素。乍一看,该函数看起来是正确的,并且在使用来自HUMANEVAL的基本测试输入时计算所需的输出。然而,在return语句中,它错误地将中间列表转换为不再保留已排序列表顺序的集合。这个例子表明,逻辑上有缺陷的解决方案仍然可以通过所有简单的测试,并且由于测试不足而被误认为是正确的。

不精确的问题描述。代码生成的输入除了函数签名之外还包括自然语言描述。现有基准中的这些任务描述常常过于模糊,无法完全阐明预期的程序行为。例如,输入的docstring可能没有指定期望的输入域或函数应该如何处理异常。因此,这些编程问题可能会被LLM根据实际测试以不同的方式解释,从而导致有能力的LLM被错误地判断为无能。

我们的建议。在这项工作中,我们着手回答这个重要问题并评估评估数据集。因此,我们构建了EvalPlus——一个评估框架来改进现有的代码基准,以便精确地评估LLM生成的代码的功能正确性。EvalPlus的核心是一个自动测试输入生成引擎,它通过生成有趣的测试输入来增强现有的代码基准,以充分执行代码解决方案,并通过交叉检查基本事实实现来检查其功能正确性。具体来说,EvalPlus采用了基于LLM和基于突变的方法来自动生成和多样化额外的测试输入。EvalPlus首先使用ChatGPT生成一组高质量的种子输入,目的是在有效的输入结构内测试困难的角落用例和程序的功能。使用这些高质量的种子输入,EvalPlus然后执行类型感知突变,以有效地生成大量额外的测试输入。然后使用这些新生成的测试输入,通过对真实实现的差异测试来评估LLM生成的代码。

图2:EvalPlus的概述

本文贡献如下:

研究:我们是第一个研究当前编程基准测试中的测试不足问题的人,这可能导致很大程度上过度近似的功能正确性。本研究也为精确、严谨地评价LLM合成代码开辟了新的研究方向。方法:我们提出EvalPlus——一个评估框架来揭示LLM合成代码的真正正确性。EvalPlus的测试用例生成方法结合了新兴的基于LLM和传统的基于突变的测试输入生成。它首先使用基于LLM的策略来引导具有高质量种子输入的测试生成器,然后通过类型感知突变进一步扩展大量输入。然后,我们有选择地通过贪婪集覆盖将生成的测试“提炼”成一个更小但几乎同样有效的测试套件。我们还建议使用程序契约对每个编程任务进行注释,以过滤掉无效的输入。结果:EvalPlus将流行的HUMANEVAL基准扩展为HUMANEVAL+,将测试用例规模提高了80倍。通过减少测试套件,我们还生产了HUMANEVAL+ -MINI,它将HUMANEVAL+测试提炼了47倍,同时仍然达到了类似的测试效率水平。我们对26个流行的LLM进行了广泛的评估,令人惊讶地发现,新数据集上的pass@k比基本的HUMANEVAL低19.3-28.9%(对于不同的ks),这表明测试不足可以在很大程度上影响几乎所有基于LLM的代码生成的最新工作的结果分析。同时,在原始HUMANEVAL上,34B的wizardcode - codellama和Phind-CodeLlama模型都被认为并不比ChatGPT好,而HUMANEVAL+修正了排名,表明这两个开源模型实际上更好。此外,我们甚至发现HUMANEVAL的基本解决方案可能是错误的,这进一步引发了对代码合成基准质量的质疑。

2 技术示例

图2显示了EvalPlus的概述。我们首先将原始数据集作为输入,其中包含ground-truth实现和基本测试输入。EvalPlus首先使用原始的基本事实、示例性测试输入作为演示,以及查询ChatGPT和生成一组高质量种子输入的专门指令构建提示。ChatGPT通过遵循基本输入格式和检查基本真实解决方案,可以作为生成有效但严格的测试输入的工具。从这些种子输入开始,我们执行类型感知突变,快速生成大量新输入和种子输入,以广泛评估LLM生成的代码的功能正确性。我们使用差分测试作为oracle来交叉检查ground-truth和LLM生成的解的输出。作为最终输出,EvalPlus使用生成的高质量测试输入获得增强基准,以充分评估LLM合成代码的功能正确性。

表1:输入x上的基本类型感知突变列表。

2.1 自动化测试输入生成

通过ChatGPT初始化种子。EvalPlus首先使用ChatGPT生成一组高质量的种子输入,用于以后的突变。在图2中,我们使用(i)问题的真值解构造一个提示,供ChatGPT检查;(ii)一组测试输入作为示范;以及(iii)鼓励ChatGPT提出有趣输入的指令。具体来说,每个提示都从基本事实实现开始,然后从现有数据集中随机抽样测试输入。然后,我们使用图2中选定的指令完成提示,并查询ChatGPT以生成新的输入。EvalPlus旨在利用ChatGPT强大的理解能力来学习有效的输入格式(例如,变量类型)以及基于真实解决方案的所需功能,以便生成有意义的测试输入,以揭示错误合成代码中的错误。程序可以有自己的预期输入格式,其中不应该将无效输入传递到函数中,因为它们可能导致未定义的行为,从而在差分测试中产生误报。因此,我们过滤掉任何违反真值实现所需的输入前提条件的无效输入。

类型感知输入突变。我们遵循典型的基于突变的模糊工作流程来连续创建输入:(i)使用ChatGPT的种子输入语料库来初始化种子池并引导生成管道;(ii)每次从种子池中随机选择一个输入(即种子),将其突变为新的输入(即突变体);(iii)符合程序合同的新输入被添加到种子池中,我们从(ii)开始继续生成过程。

2.2 减少测试套件

代码覆盖率:代码覆盖率度量每个测试执行的代码元素(例如,语句或分支)的数量,并且在实践中被广泛用于度量测试的有效性。在这个策略中,遵循传统的测试套件缩减,我们利用广泛使用的分支覆盖作为测试需求。换句话说,使用这个指标的目标是只保留最小的测试子集,它可以覆盖与完整测试相同的分支集。

变异杀死:覆盖率衡量代码被执行的程度;然而,高覆盖率的测试用例在发现其覆盖代码中的关键缺陷方面并不一定是有效的。因此,研究人员提出了突变检测 (也称为突变分析)来更精确地评估检测的有效性。简而言之,突变测试将一组预定义的突变规则(例如,更改“<”和“≤”)应用于被测试程序(即本例的基本真值解),以创建大量人工错误程序,每个程序称为突变程序,并且只包含一个细微的错误种子。这样,测试检测到的突变虫的比率(也称为被杀死的)可以用来评估测试的有效性。事实上,研究表明,在测试有效性评估中,突变测试可以在很大程度上优于代码覆盖。根据先前的工作,我们还利用每个测试杀死的突变体集作为我们的测试需求。因此,目标是尽量减少测试的数量,同时仍然能够检测到相同的一组突变错误。

LLM样本丢失:不同的LLM在某些测试用例中通常会失败。因此,除了这些理论度量之外,我们还通过经验地观察样本杀戮来作为测试需求,例如,测试用例可以检测和伪造的错误LLM样本集。当然,对于一个正在评估中的新LLM,我们没有它的代码样本的任何测试执行结果。因此,我们只使用其他LLM生成的样本的执行结果来评估测试的有效性,以减少(即留一交叉验证)。因此,我们最小化了测试的数量,同时确保所有由其他模型合成的错误样本都可以被减少的测试套件检测到。

2.3 程序输入约定

评估代码合成的目标是检查合成的代码是否准确地反映了期望的用户意图。这是通过使用几个测试输入并将生成的代码的输出与真值解决方案的输出进行比较来完成的。前面的部分演示了如何改进用于更严格地评估合成代码的测试输入。然而,这些用户意图(表示为自然语言文档字符串)可能过于模糊,LLM无法理解。因此,LLM可能允许对所需功能、输入格式以及如何处理极端情况的不同解释。

为此,我们采用契约式编程的理念,系统地以代码断言的形式注释函数的先决条件(例如,断言n > 0),以确保函数的测试输入格式良好。合约的好处是双重的:(i)它们可以补充自动输入生成步骤,以过滤掉任何生成的违反合约的无效输入。这种形式不良的输入可能会导致未定义的行为,这对于评估LLM合成代码是不合理的;(ii)它们可以与提示符中的自然语言描述一起作为正交描述符,以便进一步澄清。

表2:evalplus改进基准的概述。

3 实验评估

实验设置。我们的评估侧重于使用pass@k的无偏版本来准确评估LLM合成代码的功能正确性。为了提高通用性,我们对26种流行的、最先进的LLM和各种温度设置进行了全面评估。

表3:对LLM在HUMANEVAL和HUMANEVAL+上的评价。

LLM评估。表3显示了同时使用基本的HUMANEVAL和HUMANEVAL+评估LLM时的pass@k。我们首先观察到,在所有LLM、模型大小和k值中,使用HUMANEVAL+,与使用基本HUMANEVAL相比,几乎所有pass@k结果都持续下降。值得注意的是,性能下降非常显著,与评估模型相比,下降幅度高达23.1% (pass@1*)/ 19.3% (pass@1) / 24.9% (pass@10) / 28.9% (pass@100)。这种性能下降不仅出现在流行的开源LLM中,例如广泛使用的CodeGen-16B[46](降低18.5%)以及新兴的codellam - 34b (降低17.6%)和StarCoder (降低14.1%),而且还出现在最先进的商业ChatGPT(降低12.6%)和GPT-4(降低13.1%)模型中。总的来说,我们的结果总体上证实了我们的假设,即先前对HUMANEVAL的评估不够鲁棒,无法检测出LLM合成的错误代码。这些LLM不仅广泛用于日常编程,而且还作为评估新代码合成技术的共同参考点。因此,强烈建议使用更加健壮的基准(如HUMANEVAL+)进行评估,以便得出精确的结论。

表4:HUMANEVAL+的简化测试套件。

减少测试套件的有效性。基于HUMANEVAL+平均为每个编程任务获得764.1个测试(表2),我们的测试套件将其最小化为HUMANEVAL+ MINI,每个任务只有16.1个测试(小了47倍)。表4执行留一交叉验证,以显示表3中研究的代表性模型子集(由于时间/空间限制)上的pass@1*。也就是说,对于每个评估的LLM,我们构建简化的测试套件,而不考虑它自己的样本kill。Full列显示,缩减后的测试套件可以实现与HUMANEVAL+几乎相同的pass@1*,只需使用少47x的测试用例。仔细看一下,在每个指标上单独执行集合覆盖可以在一定程度上利用基本HUMANEVAL的pass@1 *。具体而言,使用经验LLM样本杀戮是最有效的,导致与完整方法相同的有效性,但也比其他理论指标消耗更多的测试。虽然除了使用样本剔除之外,使用覆盖度和突变分析似乎是不必要的,但它们仍然是理论测试充分性的基本保证。

通过率分布。图3显示了每个编程任务的HUMANEVAL和HUMANEVAL+测试的总体通过率。HUMANEVAL和HUMANEVAL+的通过率差距表明,总的来说,HUMANEVAL+可以检测出所有难度级别的问题中被HUMANEVAL错误识别的解决方案。我们还观察到,HUMANEVAL中的问题是不平等的。

图3:通过率分布。

HUMANEVAL中不正确的“真值”。除了使用EvalPlus检测LLM的错误代码外,我们还发现了18个缺陷(11%的问题),甚至在HUMANEVAL的原始基本事实中,包括(1)未处理的边缘情况:五个先前的基本事实无法处理角落情况输入(例如,空列表或字符串);(2)逻辑错误:10个先验事实错误地实现了期望的功能;(3)性能问题:三种低效的实现导致在合理大小的输入上性能缓慢。其中,不良逻辑最为严重,因为原始的“groundtruth”不能准确反映用户意图。这样的缺陷也可以通过差异测试来检测,但要在我们自己重新实现的真值和HUMANEVAL中的原始真值之间进行测试。

图4:HUMANEVAL中错误逻辑真值解决方案的示例(#124)

图4显示了一个来自HUMANEVAL的不正确的真值实现(validate_date),它被归类为具有错误的逻辑。所需的任务是检查输入日期格式是否正确。我们看到,在核心逻辑中,条件首先尝试检查月份条件,然后处理相应的日期条件。然而,这是不正确的实现,因为在Python5中" and "的优先级高于" or ",导致基真函数检查两个条件是否满足,而不是两个条件都必须满足。这是通过我们自动生成的12-31-1999的测试输入暴露出来的,其中ground-truth实现错误地将其标记为无效日期。令人惊讶的是,HUMANEVAL中的任何基本测试输入都没有暴露出这个严重的错误,这进一步表明了原始测试输入的弱点和有限的评估能力。

我们提出EvalPlus——一个严格的程序综合评估框架,由自动化测试生成驱动。EvalPlus结合了基于LLM和基于突变的输入生成,以获得多样化的测试输入集,以准确评估LLM生成代码的正确性。EvalPlus创建了HUMANEVAL+,建立在流行的HUMANEVAL之上,具有额外的高质量和自动生成的测试输入。随着测试套件的减少,EvalPlus还产生了HUMANEVAL+ -MINI,它比HUMANEVAL+小47倍,同时保持了类似的测试效率。我们广泛地评估了一组不同的LLM,并表明HUMANEVAL+可以识别大量以前未检测到的LLM生成的错误代码,证明了它在增加编程基准以进行更准确评估方面的有效性。

转述:王凌杰

0 阅读:0

互联不一般哥

简介:感谢大家的关注