CodeGen4Libs: A Two-Stage Approach for Library-Oriented Code Generation论文阅读笔记

在这里插入图片描述

摘要——自动代码生成在最近的文献中得到了广泛的研究。在这项工作中,我们首先对66名参与者进行调查,以激发更实用的代码生成场景,即面向库的代码生成,其中生成的代码应实现自然语言查询的功能。

作者重新审视现有的基于学习的代码生成技术,并发现它们在这种面向库的代码生成场景中的效果有限。为了解决这个问题,我们提出了一种新的面向库的代码生成技术CodeGen4Libs,它包括两个阶段:导入生成和代码生成。导入生成阶段为给定的第三方库的自然语言查询生成导入语句,而代码生成阶段则基于生成的导入和查询生成具体代码。为了评估我们的方法的有效性,我们在一个包含403,780个数据项的数据集上进行了广泛的实验。我们的结果表明,CodeGen4Libs在导入生成和代码生成阶段都优于基线模型,在EM(精确匹配)上提高了97.4%,在BLEU上提高了54.5%,在Hit@All上提高了53.5%。总的来说,我们提出的CodeGen4Libs方法在使用特定的第三方库生成高质量代码方面表现出了很好的前景,这可以提高软件开发的效率和效果。

1. Introduction

近年来,随着深度学习(DL)和大型语言模型(LLM)的先进发展,代码生成技术越来越受欢迎 ¹²。代码生成技术通过自动生成代码片段(例如方法)来实现给定自然语言需求中所描述的所需功能,从而大大减少了软件开发中涉及的手动编码工作量。主流的代码生成技术首先使用自然语言查询作为输入,使用代码作为输出在训练数据集上训练DL模型,然后利用训练好的模型为未见过的自然语言查询生成代码。最近出现的技术利用LLMs(例如CodeT5 [3]、CodeGPT [4]和PLBART [5])进行代码生成,由于模型规模大且在大型代码语料库上进行了预训练,因此已经证明具有更好的效果。

根据最新的关于使用代码生成工具的开发人员观点的调查,开发人员通常希望这些工具能够使用特定的框架/库在生成的代码中了解更多上下文/知识,特别是能够使用特定的第三方库(例如,调用库中的API)生成代码。然而,大多数现有的代码生成技术仅设计用于为独立的自然语言描述生成代码片段(例如方法)。换句话说,这些技术仅将独立的功能要求作为输入,而不考虑代码生成期间的其他上下文。因此,现有技术在这种更实用的代码生成场景(即面向库的代码生成)中的表现仍不清楚,其中生成的代码不仅应实现所需的功能,还应使用开发人员提供的库。这一点在像Stack Overflow这样的平台上经常遇到与库相关的how-to问题所强调。例如,一个典型的查询可能是“如何在Java中使用Gson读取JSON?”。

为了填补这样的知识空白,我们进行了一项实证研究,以(i)通过66名参与者的调查首先激发面向库的代码生成问题,以及(ii)然后重新审视现有代码生成技术在这样的面向库的代码生成任务中的有效性。特别是,我们的调查结果确认了开发人员对面向库的代码生成的普遍需求,即大多数开发人员确实对其代码中使用的第三方库有个人偏好。此外,我们的调查结果进一步证明了自动化面向库的代码生成技术的必要性,因为开发人员经常发现自己难以使用其首选库中的类和方法,并经常花费适度的时间寻找答案。总之,调查结果表明了面向库的代码生成问题的必要性和动机。基于此,我们重新审视现有的代码生成模型(例如CodeT5 [3]、CodeGPT [4]和PLBART [5])在这样的面向库的代码生成场景中,并发现现有模型表现不佳。

作者受到开发人员的普遍做法的启发,即首先通过专业知识或搜索引擎确定他们想要使用的API,然后根据此编写代码,进一步提出了一种新的面向库的代码生成技术CodeGen4Libs,它包括两个阶段(即导入生成和代码生成),以促进更强大的面向库的代码生成。

1)导入生成阶段首先为给定库的自然语言查询生成导入语句
2)代码生成阶段基于生成的导入和自然语言查询生成具体代码

作者的主要直觉是中间导入不仅可以弥合指定库和代码之间的差距,还可以在代码生成期间提供有关给定库的更多上下文。

总之,本文的贡献如下:

  • 一项涉及66名参与者的调查,以激发面向库的代码生成问题,这表明开发人员在其代码中使用特定库的需求普遍存在,并且自动化面向库的代码生成技术的必要性。
  • 一项研究,证明现有代码生成技术在这种面向库的代码生成场景中的有效性是有限的。
  • 一种新的方法CodeGen4Libs,它包括两个阶段(即导入生成和代码生成),以实现更准确的面向库的代码生成。
  • 一项广泛的评估,证明了所提出的方法CodeGen4Libs在面向库的代码生成场景中的有效性。
  • 一个专门为面向库的代码生成任务构建的新数据集。数据可以在[13]处找到。
实证研究(发现motivation)=》审视现有模型的不足 =》 提出新的方法 =》评估提出的方法的有效性

II. MOTIVATIONAL STUDY

在本节中,作者旨在增强对第三方库的代码生成的理解。为了实现这一目标,他们进行了一项调查,以调查开发人员对第三方库的熟悉程度和偏好(第II-A节)。此外,作者还评估了当前代码生成模型在小规模数据集上的性能,特别是它们在没有针对库相关数据进行特定微调的情况下生成特定第三方库的代码的能力(第II-B节)。作者的研究旨在回答以下研究问题:

  1. RQ1:开发人员在编码时有多喜欢特定的第三方库?
  2. RQ2:开发人员在编码时对第三方库的上下文细节有多熟悉?
  3. RQ3:当前的代码生成模型在没有针对库相关数据进行特定微调的情况下生成特定第三方库的代码的效果如何?

A. Survey

为了回答RQ1和RQ2,我们针对具有工业经验的计算机科学学生和开发人员进行了一项电子调查,要求他们填写问卷。调查收集了66个来自不同参与者的回复,包括本科到博士级别的学生,以及在该领域具有不同经验水平的开发人员,经验范围从1到5年不等。

  1. 问卷设计:问卷包括三个问题(Q1、Q2和Q3),如表I所示。Q1是一个多项选择问题,要求参与者选择一个或多个相关选项作为答案。另一方面,Q2和Q3是排名问题,要求受访者根据发生频率对选项进行排名。此外,问卷还包括有关受访者背景(例如,他们是本科生还是研究生)和他们在开发领域的经验(例如,他们的经验持续时间)的问题。
  2. 结果:根据Q1的调查结果,可以推断出只有6名参与者(9.1%)没有偏好,而大多数参与者喜欢使用熟悉的第三方库。在66名受访者中,49名参与者(74.2%)表示喜欢使用熟悉的第三方库。在这些参与者中,39人(59.1%)喜欢知名的第三方库,38人(57.6%)喜欢已在项目中使用的库。14名参与者(21.2%)表示希望使用符合其他非功能性项目约束条件的库。值得注意的是,所有未表达偏好的参与者都是本科生或研究生,而所有博士生和职业人士都表达了偏好。这一观察结果突显了开发人员,特别是那些具有专业经验的开发人员,在编码时对特定第三方库有特定需求。
  3. Q2的调查结果表明,开发人员面临的最常见问题是不确定要使用哪些类和方法来实现所需的功能,平均排名为1.4。这表明开发人员可能缺乏必要的知识或经验,无法有效地利用第三方库进行编码。此外,第二个最常见的问题是明确要使用哪些类,但不确定要使用哪些方法,平均排名为1.6。这一发现表明,即使开发人员熟悉第三方库,他们仍可能在确定最有效的方法方面遇到困难。最后,开发人员报告了相对较少的清楚要使用哪些库和方法的情况,其平均排名为1.8,这表明开发人员通常需要更多时间来找到他们需要的信息。
  4. Q3的调查结果显示,寻找答案所花费的时间最多的是5-10分钟,平均排名为1.3。这一发现表明,开发人员可能对他们正在使用的库有一定的了解,但仍需要一些额外的时间来找到他们需要的信息。第二个最常报告的时间是超过10分钟,平均排名为1.6,这表明一些开发人员可能需要更多时间来充分理解和利用第三方库。此外,最少报告的响应是找不到答案,排名为2.5。这表明开发人员通常能够找到他们需要的信息,即使可能需要一些时间。

总之,调查结果表明,开发人员喜欢使用熟悉的第三方库,但由于不确定要使用哪些类和方法,他们在有效使用这些库时遇到困难。此外,调查结果表明,开发人员花费了适度的时间寻找答案。

B. Code Generation Model Analysis

为了调查现有模型在生成特定第三方库的代码方面的性能,我们在小型数据集上进行了实验。

1)数据集

作者从GitHub上的开源项目中提取与第三方库相关的方法级代码片段作为代码语料库,用于实证研究和我们的方法的模型训练和评估。

为了获取必要的数据,作者使用了CodeParrot组织提供的GitHub Code数据集[14],其中包含了32种不同编程语言编写的1.15亿个代码文件的大量收藏。在本研究中,由于Java语言的普及,作者专注于Java语言。从GitHub Code数据集中过滤掉500万个Java代码文件后,他们从代码文件中提取了由代码片段元组组成的初步代码语料库。

代码片段元组的形式为<NL,Libs,Imports,Code>,具体如下:

  • NL字段提供与Code对应的编程任务的自然语言描述
  • Libs字段包含Code中使用的一个或多个第三方库
  • Imports字段指示代码中使用的来自第三方库的类级导入。
  • Code字段表示包括方法声明和实现代码的完整方法级代码片段

具体操作流程如下:

  1. 对于Java代码文件,使用javalang [15]代码分析工具提取了方法级代码片段(Code)
  2. 对于每个代码片段,进一步分析了代码文件并提取了其相应的方法注释作为任务的自然语言描述(NL)。
  3. 过滤掉没有注释的代码片段,再从代码文件中提取了类级导入语句。
  4. 对于每个代码片段,作者将其与文件的导入语句进行匹配,以获取相关的导入语句(Imports)。如果代码片段中包含导入的类名,则认为代码片段与导入语句相关。
  5. 最后,根据导入语句和库之间的映射获得了代码片段中使用的第三方库(Libs)

值得注意的是,为了方便起见,我们将**JDK [16]和Android SDK [17]**视为第三方库。为了确保代码语料库的质量,作者对NL和代码片段进行了一系列数据清理步骤。

具体而言,

  1. 通过删除注释中的“@param”和“@return”等注释及其内容,消除非英文内容并删除超链接(例如“http://”和“https://”)来清理从NL中提取的注释
  2. 通过删除单行注释,将方法名称统一为“function”,删除连续的空格,并使用占位符标记“STR”替换长字符串常量

最终,作者获得了一个包含2,916,582个代码片段元组的代码语料库。

为了减小语料库的大小,我们基于第三方库过滤了代码片段元组。

  1. 最初,作者计算了代码片段中使用的第三方库的频率,并提取了排名前500的最常用库,不包括JDK和Android SDK。
  2. 随后,我们仅保留了使用这些前500个第三方库的代码片段元组,从而得到了一个包含1,215,900个代码片段元组的语料库。这种过滤方法使我们能够专注于最常用的第三方库,并排除不常用的库,从而减小了语料库的大小,同时仍然确保它代表了实际使用情况。
  3. 我们从排名前500的最受欢迎的100个库中随机选择了5个相应的代码元组,并从代码语料库中选择了每个库的5个相应的代码元组。

最终,我们得到了一个由500个代码片段元组组成的小规模测试数据集。

2)模型:作者主要比较了几种现有的代码生成模型,这些模型是基于预训练语言模型进行微调的,他们使用的预训练模型包括:

  • **PLBART。**PLBART基于BART [19]架构,使用去噪目标在自然语言和编程语言的语料库上进行预训练。
  • **CodeGPT。**CodeGPT是一个GPT-2 [20]风格的模型,它在CodeSearchNet数据集[4]上进行了预训练。为了进行比较,我们使用了Java领域自适应模型[21],该模型从GPT-2模型开始,并在CodeSearchNet数据集中不断训练Java代码。
  • CodeT5。CodeT5改编自T5 [22]模型,并考虑来自标识符的关键令牌类型信息。它还允许在下游任务上进行多任务学习。

Zeng等人[23]评估了上述三个模型在代码生成任务中的有效性,但他们只提供了预训练的代码生成模型。为了获得相应的代码生成模型,作者应用了他们的相关模型微调代码和所有超参数设置,这些设置来自他们的工作的复制包[24],并使用了CONCODE数据集[25],该数据集包含来自GitHub存储库的Java类文件的100,000多个示例用于训练。

最终,作者获得了三个可以将NL作为输入并生成相应代码片段的代码生成模型。

3)指标:对于测试数据集中的每个代码片段元组<NL,Libs,Imports,Code>,我们使用将NL和Libs连接起来作为代码生成模型的输入,例如, “read a Json array” “using the following libraries: com.google.gson”,最终为“read a Json array using the following libraries: com.google.gson”。然后,作者将模型生成的预测代码片段与ground truth Code进行比较,并计算以下指标以评估三个模型的性能:

  • 精确匹配(EM):此指标衡量完全匹配地预测的百分比。
  • 双语评估协作(BLEU):测量预测序列和ground truth序列之间的n-gram重叠,通常用于机器翻译。
  • CodeBLEU:BLEU度量标准的修改版本,专为代码设计,是词汇、抽象语法树和数据流匹配的加权平均值。
  • Hit@All:此指标衡量生成的代码中是否包含属于指定第三方库的所有正确类。如果类也出现在ground truth代码中,则认为该类是正确的。
  • Hit@1:此指标衡量生成的代码中是否包含属于指定第三方库的至少一个正确类。
  • Precision:此指标衡量包含在生成的代码中的属于指定第三方库的正确类的比例。
  • Recall:此指标衡量与ground truth中所有正确类相比,包含在生成的代码中的属于指定第三方库的正确类的比例。
  • F1:精确度和召回率的调和平均值,用于衡量模型在预测给定库的正确类方面的整体效果。

EM、BLEU和CodeBLEU是用于评估代码生成任务的常用指标[26],[27],[3]。HIT@All、HIT@1、精确度、召回率和F1专门用于生成特定第三方库的代码,用于衡量生成的代码在正确使用指定的第三方库API类方面的有效性。

4)结果:如表II所示,可以看到,三个代码生成模型在生成特定第三方库的代码方面表现不佳。例如,CodeGPT生成的代码仅包含指定库中7.7%的API类。在三个模型中,基于CodeT5的模型表现相对较好(9.9%),但仍然不理想。

这种差的表现可能有两个可能的原因。

  1. 首先,这些模型的训练数据并没有特别考虑库的输入,而且模型可能没有在包含库的数据上进行微调。即使Libs作为模型输入的一部分,模型也可能不会很好地理解它们。
  2. 其次,输入中包含的库与代码中实际使用的API类之间的差距可能很大。在输入中包含一些与给定NL相关的给定第三方库的导入语句可能有助于模型(因为导入语句与Libs和代码中使用的类都有关系)。
    在这里插入图片描述
    总之,实验表明,现有的代码生成模型在生成特定第三方库的代码方面表现不佳,这表明需要专门的微调和设计工作。

III. APPROACH

作者将面向库的代码生成问题定义为从自然语言描述(NL)和一个或多个指定的第三方库(Libs)生成方法级代码片段(Code),即NL+Libs->Code。然而,由于受限制的生成场景,生成特定库的代码比普通代码生成更具挑战性。

为了解决这个任务,作者提出了一个两阶段的方法:CodeGen4Libs,将其分为导入生成和代码生成子任务。第一个任务从NL和Libs(即NL+Libs->Imports)生成API类级别的导入语句(Imports),而第二个任务从NL、Libs和Imports(即NL+Libs+Imports->Code)生成Code。

图1提供了CodeGen4Libs的概述
在这里插入图片描述将任务分为两个子任务的做法是受到开发人员的启发,他们在面对任务和第三方库时,通常首先通过专业知识或搜索引擎确定他们想要使用的API,然后根据此编写代码。

将任务分为两个步骤允许不同的模型进行训练以处理导入生成和代码生成。与训练单个端到端模型以生成特定库的代码相比,将任务分为两个子任务在代码生成期间提供了更多关于给定库的上下文(由第一个子任务生成的API类导入提供)。这很重要,因为它有助于弥合指定库和生成的代码之间的差距,从而产生更加限制于给定库的代码。

总的来说,这种两阶段方法使他们能够更有效地和更高效地为特定的第三方库生成代码。

在导入生成和代码生成中,作者采用检索增强技术[28]来提高模型的性能,分别在第III-A节和第III-B节中详细阐述了我们的方法。

A. Import Generation

作者将导入生成任务形式化为类似于代码生成任务的序列到序列生成任务。为了实现这一目标,作者微调了CodeT5,这是一种最先进的模型,因为它在与代码相关的任务上表现出色[3]。为了进一步增强导入生成,作者采用检索增强技术来检索与给定NL和Libs相关的导入语句Imports(Ret),这些导入语句作为导入生成模型的输入。

检索增强技术已被证明可以提高序列到序列生成任务的性能[28],并广泛应用于软件工程相关任务,如代码生成[29]和提交消息生成[30]。如图1所示,整个导入生成过程包括三个主要模块: the import retriever 导入检索器、导入生成器The import generator和导入清理器 the imports cleaner。

  • 导入检索器 the import retriever 负责从基于给定NL和Libs的大规模语料库中检索相关的导入Imports(Ret)
  • 导入生成器The import generator将NL、Libs和Imports(Ret)的连接输入作为输入,并使用预训练的导入生成模型生成原始导入语句
  • 导入清理器 the imports cleaner负责清理生成的导入,以获得更高质量的导入语句Imports(Gen),以作为后续代码生成模型的输入。

在这里插入图片描述
接下来将具体对各个模块的功能进行一个详细介绍:

1) 导入检索器 the import retriever

为了检索给定NL和Libs的相关导入,作者采用BM25算法,该算法广泛应用于文本相似性任务[31]。BM25是一种流行的词袋检索函数,用于估计两个句子之间的词汇级别相似性。BM25分数越高,句子越相似。

为了检索相关的导入,作者按如下步骤进行操作处理:

  1. 将BM25应用于预先收集的代码语料库,该语料库包含一系列代码片段组,其形式为<NL,Libs,Imports,Code>
    具体操作=> 检索与给定NL最相似的前k(例如,1000)个代码片段祖
  2. 按降序相似性的顺序过滤它们,直到找到使用所有给定Libs的代码片段组
  3. 然后从当前代码片段组的Imports一栏中删除未指定Libs的import语句
  4. 按字母顺序排序剩余的import,以获得最终的相关导入Imports(Ret)

3,4 可以看Import Cleaner中的部分
在这里插入图片描述
例如,考虑到实际使用中会出现的情况

  • NL 为 “Gets the detailed information for a given agent pool”的情况
  • Libs 中有两个libary: com.azure.core 和 com.azure.resourcemanager

基于BM25的检索器可能会检索到一个代码片段元组,其最相似的NL为“Gets the detailed information for a given run”.

这个元祖中共包含了四个import语句

  • import com.azure.core.annotation.ReturnType;
  • import com.azure.core.annotation.ServiceMethod;
  • import com.azure.core.http.rest.Response;
  • import com.azure.resourcemanager.containerregistry.fluent.models.RunInner;

这已经包含了当前要实际使用中的两个Libs。

作者还进行了后面两步的处理:

  1. 应用了过滤步骤,以避免引入未指定的第三方库的导入,这可能会误导代码生成模型
  2. 应用了排序步骤,以规范来自不同来源的导入

经过排序和过滤步骤之后,获得了最终的相关导入Imports(Ret)

Import Generator

为了实现的导入生成器import generator,作者采用了基于CodeT5的encoder-decoder神经网络,该网络在代码相关任务上表现出色[3] [32]。

如图2所示,模型架构由双向encoder 和 自回归 decoder组成。
具体的,作者对CodeT5进行了微调,用于导入生成,将其建模为sequence to sequence的生成任务

在这里插入图片描述

  1. 将输入NL、Libs和Imports(Ret)与特殊分隔符标记[SEP]一起连接,形成单个输入序列
  2. 对输入序列进行分词处理,并使用双向变压器编码器将处理后的输入序列编码为向量表示,该编码器用于捕获输入序列的上下文信息
  3. 使用基于变压器的自回归decoder生成import的目标序列。decoder是自回归的,这意味着它基于先前生成的标记逐个生成标记。
    =》 具体的,它以输入序列的向量表示作为其初始输入。在每个解码步骤中,解码器在先前生成的标记的条件下生成可能的下一个标记的概率分布。然后从该分布中抽样下一个标记,并将其用作下一个解码步骤的输入。重复此过程,直到生成序列结束标记(例如,)为止。

在训练期间,作者使用交叉熵损失来优化模型的参数,以最小化生成的导入和地面真实导入之间的差异,并使用第IV-A1节中描述的训练数据微调预训练的CodeT5模型,用于的import generation任务。我们的实现细节在第IV-A2节中描述。”

3) Import Cleaner

模型生成的导入可能会受到噪声的影响,例如重复和不完整的语句,这可能会对代码生成过程的有效性产生负面影响。例如,模型可能会输出包含重复或不完整的导入语句,如“import com”或“import com.google.gson.Gson; import com.google.gson.Gson;”

这个问题源于import generator中基于encoder-decoder的架构,某些内容可能具有更高的解码概率,导致重复生成。此外,生成的内容可能超过长度限制,导致不完整或截断的语句。为了缓解这些问题,作者应用了几个标准来清理生成的导入语句。

  • 删除任何重复的import语句,以消除最终import列表中的冗余。
  • 过滤掉任何不完整的导入语句,即没有以分号结尾或没有以关键字“import”开头的语句。
  • 将导入语句中的完全限定类名拆分为表示包和类名的字符串列表,然后删除包含重复包或类名的import语句。
  • 将生成的导入与给定的Libs进行比较,并过滤掉不属于给定Libs的任何导入。

“fully qualified class names” 的中文翻译是 “完全限定的类名” ⁵。在Java编程中,完全限定的类名是指类名前缀加上包名,例如,如果类Address在包com.mycompany.myproject中,则Address类的完全限定名为com.mycompany.myproject.Address 。

在这里插入图片描述
从这个例子可以看出,得类名和包名都相同才会被过滤,包相同不会被过滤

最后,作者按字母顺序排序剩余的导入语句,并将它们组合成一个名为Imports(Gen)的最终cleaned 的导入语句集

B. Code Generation

作者将代码生成任务形式化为序列到序列生成任务。与导入生成类似,作者将CodeT5微调为代码生成模型,并采用检索增强技术来检索与给定NL和Libs相关的代码片段Code(Ret)作为代码生成模型的输入。整个过程如图1所示,由两个主要模块组成:代码检索器Code Retriever和代码生成器Code Generator。

1) Code Retriever

为了检索给定NL和Libs的相关代码片段,作者使用BM25算法,该算法类似于第III-A1节中讨论的导入检索过程,具体步骤如下:

  1. 将BM25应用于预先收集的代码语料库,例如在第II-B1节中收集的Java代码语料库,该语料库包含一系列代码片段元组,其形式为<NL,Libs,Imports,Code>
  2. 检索与给定NL最相似的前k(例如,1000)个代码片段元祖,并按降序相似性的顺序过滤它们,直到找到使用所有给定Libs的代码片段。

如图1所示,检索到的代码片段Code(Ret)使用了给定的两个Libs,并且与给定的NL“Gets the detailed information for a given agent pool.”具有最高的相似度得分。
在这里插入图片描述

2) Code Generator

Code Generator模块采用与导入生成器相同的模型架构,使用CodeT5作为核心模型。生成代码的任务被建模为序列到序列生成任务,其中输入序列包括自然语言描述NL、所需库Libs、生成的导入Import(Gen)和使用BM25算法检索到的相关代码片段Code(Ret)(如第III-B1节所述)。目标序列是生成的代码Code(Gen)。

为了为模型准备输入序列,作者使用了如下的操作

  1. 使用特殊分隔符标记[SEP]将输入字段连接起来,创建单个输入序列
  2. 对输入序列进行标记化,并使用双向encoder将tokenize后的输入序列编码为向量表示
  3. decoder生成Code(Gen)的目标序列,该序列是基于输入序列的编码向量表示进行生成的

更重要的是,Imports(Gen)和Code(Ret)的组合对代码生成任务提供了如下的好处:

  1. “Imports(Gen)”为模型提供了可能需要生成代码的关键第三方库API,从而减少了对库的广泛搜索的需求
  2. 同时,“Code(Ret)”提供了模板,例如循环控制结构和特定第三方库API的使用模式,可用作代码生成期间的参考。

虽然“Imports(Gen)”和“Code(Ret)”都不能确保正确性,但它们的组合使模型能够集中于在“Imports(Gen)”和“Code(Ret)”中经常出现且对任务至关重要的关键API。这两个输入一起有助于减少最终代码生成中的噪音和干扰。

作者使用了第IV-A1节中描述的训练数据微调预训练的CodeT5模型,用于代码生成任务。

  • 在训练期间,作者对于每个代码元组使用模型生成的Imports(Gen),而不是依赖于地面真实的Imports。这种方法能够最小化训练时输入和推理期间输入之间的差距,因为两个输入都使用相同的导入生成器生成Imports(Gen)。通过减少这种差距,可以更好地模拟实际情况,并提高模型在实际任务中的性能。更多实现细节在第IV-A2节中描述。

IV. EVALUATION

在本节中,作者通过回答以下研究问题来评估CodeGen4Libs的有效性:

RQ1(面向库的导入生成的有效性):CodeGen4Libs在生成高质量的面向库的导入方面的效果如何?
RQ2(面向库的代码生成的有效性):CodeGen4Libs在生成高质量的面向库的代码方面的效果如何?
RQ3(导入生成质量的影响):导入生成质量对代码生成结果的质量产生了多大的影响?

A. Experimentation Setup

1) Benchmark 基准测试

作者使用第II-B1节中描述的代码语料库创建了一个用于训练和评估的基准测试

  1. 最初,作者从语料库中随机抽取了600,000个代码片段元组<NL,Libs,Imports,Code>
  2. 过滤掉了标记化代码长度超过512个标记的元组样本和输入(NL+Libs+Imports)超过512个标记的样本,因为我们的模型具有最大输入长度限制。
  3. 此外,还删除了具有相同NL和Libs但不同Code的样本,因为它们可能会干扰模型的学习
  4. 为了标准化基准测试,作者按字母顺序排序库和导入语句。
  5. 为了确保数据集的平衡,作者为每个库提供了最多5,000个相应的代码片段元组
  6. 生成的基准测试包括500个库的403,780个代码片段元组。
  7. 随机将基准测试分成训练、验证和测试数据集,并对元组进行分区,以确保平衡并在训练和验证数据集中包含每个libary至少1.5%的相关代码片段,表III显示了数据集的统计信息。
    在这里插入图片描述
    这个图的表述不是很明白,待会下去之后再看看

2) Implementation 实现

为了构建导入检索器和代码检索器,作者利用了开源搜索引擎Elasticsearch [33],并在代码语料库的NL上建立了索引,该语料库包含1,215,900个代码片段元组(请参见第II-B1节)。这能够使作者有效地检索给定自然语言查询的相关代码片段和导入。

使用训练集对基准数据集进行了导入生成模型和代码生成模型的训练,并使用验证集验证了它们的性能。

作者的模型使用Python库transformers [34]实现,使用CodeT5-base [35]模型进行初始化。对于模型优化,作者使用交叉熵损失和Adam优化器,学习率为4e-5,批量大小为8。在30个epoches期间使用基于验证损失的早期停止,这些训练时期在单个Nvidia 3090 GPU上进行,并遵循了先前工作[23]中的相同超参数和训练过程。

B. RQ1: Effectiveness of Library-oriented Imports Generation

为了评估 CodeGen4Libs 在导入生成中的有效性,作者在基准数据集上将他们的方法(这里的用词是approach)与多个baseline进行了比较。

1)Baseline 基线

作者将导入生成的方法称为 Import(Gen),它代表了通过我们的import Generator和Import cleaner获得的导入语句。作者将其与以下基线方法进行了比较:

  • Imports(Ret)。 NL+Libs-Imports 任务的最简单方法是基于检索的。在第 III-A1 节中,作者使用 BM25 算法检索给定 NL 和 Libs 的最相关导入。作者将这个基于 BM25 的导入语句检索器作为基线,并将其与他们的基于生成的方法进行了比较。
  • Import(Gen)-NL+Libs。为了调查检索增强技术是否有助于导入生成任务,作者使用相同的数据集和超参数训练了一个新的导入生成模型,但只使用 NL 和 Libs 作为输入,标记为 Import(Gen)-NL+Libs。这种比较可以评估检索相关导入作为导入生成模型输入是否真正提高了导入生成的有效性。
    在这里插入图片描述
  • Import(Gen)∩Imports(Ret). 一个可能的猜测是,将基于生成的方法和基于检索的方法生成的导入组合起来可以进一步提高效果。Import(Gen)∩Imports(Ret) 表示将两种方法生成的导入语句取交集作为最终的导入生成结果,这可以减少导入生成结果中的噪声。
  • Import(Gen)∪Imports(Ret). Import(Gen)∪Imports(Ret) 是另一种结合两种方法的方式,表示取得两种方法生成的导入语句的并集,这可能会提高生成导入的覆盖率。

2)Metrics 指标

作者在导入生成的测试数据集上评估了我们的方法和基线,使用的评估指标包括 EM、BLEU、HIT@All、HIT@1、Precision、Recall 和 F1。这些指标已在第 II-B3 节中介绍。作者不使用 CodeBLEU 来评估生成的导入质量,因为导入不包含像数据流这样的附加信息。为了计算 HIT@All、HIT@1、Precision、Recall 和 F1 指标,作者将生成的导入和基准导入按分号拆分为单独的导入语句,并在语句级别进行比较。

3) Results

表 IV 提供了导入语句生成的各种方法的全面比较,结果清楚地表明,基于生成的两种方法 Imports(Gen) 和 Imports(Gen)-NL+Libs 在所有七个指标上均优于基于检索的方法 Imports(Ret)。这表明,直接从自然语言描述和相关库中生成导入语句比仅基于给定描述和库进行检索更为有效。此外,Imports(Gen) 的性能显著优于 Imports(Gen)-NL+Libs,证明了在生成过程中加入相关库的好处。
在这里插入图片描述
通过取得两种方法生成的导入语句的并集,Import(Gen)∪Imports(Ret) 方法在 EM 和 BLEU 得分方面低于 Import(Gen),但在 Hit@All、Hit@1 和 recall 得分方面更高,表明导入语句的覆盖范围更广。通过取得两种方法生成的导入语句的交集,Import(Gen)∩Imports(Ret) 方法在除精确度之外的所有指标上性能较差,但精确度高于其他方法。这表明,通过取两种方法的导入语句的交集来结合两种方法可能会减少噪声,但覆盖范围较小。

总体而言,结果表明:提出的基于生成的方法对于导入生成是有效的,并且结合检索方法可能会带来潜在的好处。然而,作者最终选择 Imports(Gen) 作为我们的代码生成方法,因为它在覆盖率和精度之间取得了良好的平衡(最高的 F1 分数),并且在 EM 和 BLEU 得分方面明显优于结合基于生成和基于检索的方法的方法。”

在这里插入图片描述

图 3 展示了两个导入语句生成的测试用例,其中所有方法的结果都用不同的颜色标记。Imports(GT) 一词是指基准导入语句(就是指实际上正确的imports)。在第 1 种情况下,作者观察到只有 Imports(Gen) 能够正确预测导入语句,而 Imports(Ret) 中甚至包含一个错误的导入语句(“import org.eclipse.jdt.core.dom.DoStatement”)并漏掉了一个正确的导入语句(“import org.eclipse.jdt.core.dom.IfStatement”)。然而,导入生成器不受此影响,仍然能够预测出正确的导入语句。此外,将 Imports(Gen) 与 Imports(Gen)-NL+Libs 进行比较,我们可以看到,在生成过程中加入相关库有助于模型生成更多正确的导入语句并提高模型的有效性。在第 2 种情况下,我们观察到 Imports(Gen)-NL+Libs 生成了一个额外的导入语句,但在检索增强技术的帮助下,这个错误消失了。总的来说,检索增强技术通过提高精度和召回率大大提高了导入生成的效果。

4) Summary 总结

总的来说,与基线相比,作者的方法在导入生成方面表现出了卓越的有效性。

C. RQ2: Effectiveness of Library-oriented Code Generation

1) Baselines

作者使用基准数据集对在第 II-B 节中介绍的预训练语言模型进行了微调,即 CodeGPT、PLBART 和 CodeT5。与作者的方法相比,这些模型仅将 NL+Libs 作为输入并生成相应的代码 Code 作为输出,没有任何额外的输入。作者通过向模型提供 NL+Libs 的输入序列并训练它们生成相应的代码 c 来微调这些模型。微调过程按照之前的工作 [23] 进行,与第 II-B2 节相同。

为了展示作者的方法在整合额外输入方面的有效性,他们使用 CodeT5 训练了两个代码生成模型的变体。第一个变体将 NL+Libs+Import(Gen) 作为输入,而第二个变体将 NL+Libs+Code(Ret) 作为输入。作者遵循了第 IV-A2 节中详细介绍的相同超参数和训练过程。这种方法允许他们比较他们的方法在是否整合通过他们的方法生成的导入语句以及使用检索代码作为输入的情况下的性能。

2) Metrics

评估指标包括 EM、BLEU、CodeBLEU、HIT@All、HIT@1、Precision、Recall 和 F1。它们评估了生成代码的质量以及生成代码与基准代码之间的匹配。

3)Results

表 V 展示了不同模型和输入变体的代码生成实验结果。在这些模型中,作者的代码生成模型,即 CodeT5,使用 NL+Libs+Import(Gen)+Code(Ret) 输入,在所有评估指标上都取得了最佳性能。

与基线模型相比,他们的方法在所有评估指标上都取得了显著的改进,EM 改进范围从 10.8% 到 97.4%,BLEU 改进范围从 16.1% 到 54.5%,CodeBLEU 改进范围从 7.9% 到 49.8%,HIT@All 改进范围从 8.0% 到 53.5%,HIT@1 改进范围从 1.0% 到 11.0%,精确度改进范围从 2.8% 到 16.5%,召回率改进范围从 63.0% 到 71.1%,F1 改进范围从 3.7% 到 23.0%。这些结果表明了我们的方法在面向库的代码生成方面的有效性,通过精确使用第三方库的 API,可以生成比其他模型更准确、更一致的代码。
在这里插入图片描述
CodeGen4Libs 的两个变体,即 NL+Libs+Import(Gen) 和 NL+Libs+Code(Ret),也取得了良好的结果,但是被 CodeGen4Libs(NL+Libs+Import(Gen)+Code(Ret))超越了。这表明,将生成的导入语句和检索到的代码片段结合起来可以提高代码生成性能,但将它们结合起来会产生更好的结果。

图 4 展示了三个代码生成的测试用例,其中不同方法的结果用不同的颜色标记。Code(GT) 一词是指输入的基准代码。

  • 在第 1 种情况下,作者观察到 NL+Libs+Imports(Gen) 和 NL+Libs+Imports(Gen)+Code(Ret) 的代码生成模型都生成了正确的结果,而仅使用 NL+Libs 和 NL+Libs+Code(Ret) 的模型生成了错误的代码。尽管检索到的代码 Code(Ret) 与给定任务 NL 和 Libs 无关,但他们的方法仍然可以根据生成的导入 Imports(Gen) 的帮助生成正确的代码,即使存在来自检索到的代码的噪声。
  • 在第 2 种情况下,只有他们的 NL+Libs+Imports(Gen)+Code(Ret) 方法生成了正确的代码。这是因为它将 Imports(Gen) 和 Code(Ret) 提供的信息结合在一起,而 Code(Ret) 中的噪声(使用一些不相关的 API)不会影响生成的效果,因为模型使用 Code(Ret) 提供的代码结构。
  • 类似地,在第 3 种情况下,仅提供 Imports(Gen) 的信息是不够的,结合 Imports(Gen) 和 Code(Ret) 可以得到最佳结果。这些结果表明,Imports(Gen) 和 Code(Ret) 可以在面向库的代码生成任务中相互补充。通过将它们结合起来,我们的方法可以利用它们的优点并生成更准确、更一致的代码。

在这里插入图片描述

在这项研究中,作者微调了 CodeT5,开发了导入生成和代码生成模型,因为与其他现有的预训练语言模型相比,它在与代码相关的任务上表现出了卓越的性能 ³ 。然而,需要注意的是,我们的方法可以作为一个基础框架,未来更先进的模型可以取代 CodeT5,以获得更好的结果。

4) Summary

实验表明,作者的方法将生成的导入语句和检索到的代码片段结合起来,可以有效提高面向库的代码生成的准确性和一致性。”

D. RQ3: Imports Generation Quality Impact

在本节中,作者研究了导入质量对 CodeGen4Libs 中代码生成结果的影响。

1) Design

具体而言,作者在基准测试数据集上比较了使用不同导入作为输入的 CodeGen4Libs 的性能,即表 IV 中显示的不同导入(请参见第 IV-B1 节)。作者还尝试使用基准测试数据集中的基准导入 Imports(GT) 作为输入,并使用了与第 IV-C2 节相同的指标评估性能。

2)Results

Table VI 展示了导入质量对 CodeGen4Libs 中代码生成结果的影响。该研究考察了五种不同的导入策略。结果表明,使用 Imports(GT) 作为输入在所有指标上都取得了最佳性能,其次是 Imports(Gen)。Import(GT) 的 Hit@1 为 0.969,F1 为 0.842,分别比其他策略高出 8.15%-17.03% 和 15.82%-31.56%。该研究表明,作为输入使用的导入质量对 CodeGen4Libs 的性能有重要影响。值得注意的是,使用 Imports(Gen) 也表现良好,表明 CodeT5 模型可以生成高质量的导入。然而,Imports(Gen) 的性能仍然低于 Imports(GT),这表明模型的导入生成能力仍有改进的空间。
在这里插入图片描述

3) Summary

总的来说,实验结果强调了将高质量的导入作为输入用于代码生成模型的重要性,并暗示增强导入生成能力可以进一步提高代码生成模型的性能。

E. Threats to Validity

作者的研究可能面临三个有效性威胁。

  • 第一个与作者的调查主观性和代表性不足有关。为了解决这个问题,作者邀请了来自不同背景的参与者,以确保我们的结论具有普适性。
  • 第二个有效性威胁涉及从头构建数据集,因为没有专门为第三方库的代码生成而设计的现有数据集。为了减轻这种威胁,作者采用了与之前的工作类似的做法,并确保数据集涵盖了各种第三方库。
  • 第三个有效性威胁涉及提出的模型和基线方法的实现。为了解决这个问题,他们采用了相关工作的现有微调脚本和超参数,并公开了我们的源代码和数据集以供验证。此外,作者的数据集包含 6,002 个代码片段对,比广泛使用的 CONCODE 基准测试的 2,000 个测试用例要多得多,以提高模型的鲁棒性。尽管重点是 Java,但他们的方法并不特定于语言,可以应用于任何涉及大量第三方库 API 的面向对象语言。作者计划在未来扩展他们的数据集,以支持多种编程语言。

V. RELATED WORK

代码生成旨在从给定的自然语言描述或要求中生成源代码,长期以来一直是软件工程研究的核心内容[36],[37],[38],[39]。传统的代码生成方法包括基于序列和基于树的方法。基于序列的模型利用神经网络根据输入描述逐个生成源代码标记,而基于树的模型从自然语言描述中构造程序的解析树,然后将其转换为相应的代码[40],[41]。

近年来,预训练语言模型彻底改变了与代码相关的任务的格局,相比传统的基于序列和基于树的方法,它们表现更好。在这个领域中,一些著名的大规模预训练模型包括 CodeBERT、CodeT5、InCoder、CodeGPT 和 PLBART。微调这些模型已经成为代码生成的新范式。在本研究中,作者微调 CodeT5,开发了导入生成和代码生成模型。与一般的代码生成不同,我们的重点是特定情境下的面向库的代码生成。事实上,与库相关的代码生成引起了人们的极大兴趣。虽然现有的面向库的代码生成工作主要支持一些特定的第三方库(例如 Numpy),或者专注于生成涉及单个外部库的代码,但作者的工作提出了一种新颖的两阶段方法,能够为多个任意库生成代码。

检索增强技术在自然语言文本生成任务[28]和软件工程任务(如代码生成、摘要和完成)[29],[47],[48],[49],[50]中受到关注。Parvez等人[29]提出了REDCODER框架,使用密集嵌入检索检索相关的代码/摘要,并将其补充到代码生成/摘要模型中。我们的方法也使用检索来获取与给定描述相似的特定库的导入语句/代码片段。据我们所知,这是将检索增强技术应用于导入生成任务的首次尝试。

研究人员已经为各种软件工程任务创建了基准测试,包括代码生成、代码搜索和缺陷修复,以便在同一基准测试上进行评估。CONCODE是一种广泛使用的自然语言到代码生成基准测试,由Iyer等人创建,包括来自在线代码存储库的Java类的100,000多个示例。然而,它侧重于一般的代码生成,而不是针对面向库的代码生成任务,作者的工作是为面向库的代码生成任务构建大规模数据集的第一步。

核心目的:面向库的代码生成任务

VI. Conclusion

在本研究中,作者提出了 CodeGen4Libs,这是一种新颖的方法,它结合了两个阶段(即导入生成和代码生成),以实现更准确的面向库的代码生成。作者的实验结果表明,与现有方法相比,它具有卓越的性能,而他们的问卷调查则提供了有关面向库的代码生成需求的见解。作者的工作强调了在代码生成任务中考虑导入语句的重要性,有可能显著提高软件开发的效率和效果。未来的工作包括扩展到其他编程语言和库,并提高导入生成性能。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值