论文精讲 | 当深度学习遇见软件工程,源代码预训练模型调查分类汇总

预训练模型(Pre-trained Models, PTMs)是一种机器学习模型,它们是使用大规模数据集进行预训练的模型。在预训练过程中,模型学习了丰富的特征表示,这些特征可以被用于各种不同的任务,如图像分类、自然语言处理等。总的来看,预训练模型PTMs的优势包括:

1、在庞大的无标注数据上进行预训练可以获取更通用的语言表示,并有利于下游任务;

2、为模型提供了一个更好的初始化参数,在目标任务上具备更好的泛化性能、防止在小数据集合上过拟合,并加速收敛。

最近阅读了《Deep Learning Meets Software Engineering A Survey on Pre-Trained Models of Source Code》,本篇文章将分享深度学习在软件工程领域的应用,关于源代码预训练模型的调查。

01 概述

曾几何时,软件工程(SE)领域中的软件智能水平非常低,许多决策或是基于直觉,或是通过与资深开发人员咨询进行决策。随着软件开发和演进生命周期中大量数据的产生,软件开发和演进范式也从基于人类经验的决策转向了基于数据驱动的决策。虽然AI研究人员已经意识到深度学习对计算机视觉和自然语言处理(NLP)等AI应用领域的影响,但很多人并未意识到近年来深度学习技术已经在软件工程任务中广泛应用并取得了成功。

虽然深度学习在很多领域的应用取得了成功,但深度学习的应用还是面临着挑战。其中一个挑战是需要大量的、带注释的训练集(通常难以获得)来训练深度神经网络中的数百万甚至数十亿个参数。为了解决数据注释瓶颈,NLP研究人员提出了预训练的概念。即与其从头开始训练模型(即使用随机初始化的网络权重),通常需要大量特定于任务的注释数据,不如先在一个或多个所谓的自监督任务(即可以自动生成注释数据的任务,因此大量训练数据容易获得)上对其进行预训练,然后可以以通常的监督方式使用(潜在少量的)任务特定的注释训练数据来精细调整所得到的预训练模型以学习目标任务。当前已有大量的预训练语言模型在NLP中广泛应用,如BERT、XLNet、RoBERTa、BART等。

上述预训练模型能应用于软件工程(SE)任务吗?由于源代码可以被视为一系列的代码标记序列,因此原则上可以在源代码上重新训练这些模型,并将它们应用于SE任务。然而,在实践中,这并不理想,因为代码特定的特征可能无法被这些模型正确处理。例如,源代码不像NL那样同质化,它包括用编程语言(PL)编写和用NL编写的可选注释。将代码和注释以统一的方式(即作为标记序列)处理可能利用这两种信息来源的的最佳方式。此外,代码具有语法结构和语义结构。虽然近年来NLP社区中已经开发了一些语法感知的预训练模型,但大多数现有的预训练模型无法利用结构化信息。因此,SE研究人员开发了许多针对源码的预训练模型(CodePTMs)。

本文对近几年来软件工程任务(SE)上基于代码的预训练模型(CodePTMs)的工作进行了一个汇总。

02 任务、数据集和评估指标

SE研究涉及到软件系统的设计、开发、维护、测试和演进问题。表1列举了预训练模型已应用的关键SE任务。如前两列所示,作者将每个任务按照两个维度进行分类:

1、任务是否涉及理解型(Und.)或生成型(Gen.);

2、任务假设的输入类型和输出类型(I-O),其中C、NL和V分别表示代码、自然语言和预测目标值。

表1:CodePTMs应用的18个SE任务分类

此外,表1还显示了每个任务的基准数据集和相应的评估指标。对于检索和分类任务,通常使用的指标包括Acc(准确率)、Acc@k(计算前k个预测答案的准确率)、P/R/F1(P精确度,R召回率)、MRR(平均倒数秩)、MAP@R(平均精度)和NDCG(归一化折损累计增益)。

03 CodePTMs

在本节中,作者概述了SE社区最近开发的20个CodePTMs。为了让读者更好地理解它们的相似性和差异,以及它们的优劣势,作者从架构、模态、预训练任务、编程语言等4个维度进行了分类。

架构

首先,现有的CodePTMs在底层网络架构上有所不同。要了解网络架构,需要先简要介绍编码和解码的概念。编码器将输入序列转换为固定长度的向量表示形式,而解码器则根据输入的表示形式生成输出序列。SE研究人员在设计CodePTMs时,不是设计新的网络架构,而是基于现有的架构进行设计。大体上,这些架构分为如下四类:

1、LSTM:一种经典的循环神经网络架构;

2、Transformer:一种相对较新的编码器-解码器架构,相对于LSTM来说,其训练速度更快,能够更好地捕捉长距离依赖关系;

3、Transformer-Encoder(TE):与Transformer编码器部分相对应,适合理解型下游任务;

4、Transformer-Decoder(TD):与Transformer解码器部分相对应,适合生成性下游任务。虽然可以仅使用编码器模型(如TE)和解码器模型(如TD)进行序列到序列(seq2seq)任务,但是在生成/解码任务和分类任务中,仅使用编码器模型或者解码器模型会处于劣势。

模态

在使用神经模型处理源代码时,能够将嵌入在代码中的自然语言(如注释、变量名)和代码结构(如ASTs)进行整合,可以提高模型理解代码的能力。因此,将NL和代码结构作为输入,再加上代码本身,已经成为CodePTMs中常见的做法。由于Code、NL和Structure在表示和处理上有所不同,它们可以被视为不同的输入模态。因此,在第二维度上,作者将CodePTMs分为三类——单模态(Uni)、双模态(Bi)和多模态(Multi),依据它们使用的输入模态数量。

当模型采用多个输入模态时,可以将从不同模态提取的特征拼接成单个训练实例,或者使用从不同模态提取的特征创建不同的训练实例。作者分别将上述两种策略称为Together和Standalone。可以想象,Together相对于Standalone的优势在于前者允许模型通过多模态表示学习。

预训练任务

在第三个维度上,作者根据用于预训练的任务进行区分。在高层次上,可以将这些任务分为两类,具体取决于任务是源自NLP或者专门设计用于源代码(SE),如表2所示。

表2:目前现有CodePTMs预训练任务分类及描述

从表2中可以看出,NLP预训练任务可以分为四类:

1、语言建模(Language Modeling,LM),即指给定周围上下文的情况下,预测给定单词的任务集合;

2、掩蔽语言建模( Masked Language Modeling,MLM ),将掩蔽标记的单词作为输入,旨在预测掩蔽标记的任务集合;

3、去噪自编码(DAE),旨在从损坏的文本中恢复原始文本;

4、对比学习(Contrastive Learning,CTL),使模型学习哪些数据点是相似或不同的。

另一方面,SE预训练任务可以根据输入模态分为三类:

1、代码感知(Code-Aware,CA)任务,旨在从代码文本中挖掘潜在信息;

2、结构感知(Structure-Aware ,SA)任务,旨在学习代码结构的表示;

3、跨模态感知(Cross-Modal-Aware,CMA)任务,旨在从多个输入模态获取知识。根据输入模态的不同,CMA任务可以进一步分为三类,即Code-NL(CN)、Code-Structure(CS)和Code-NL-Structure(CNS)。

当使用多个任务进行CodePTM的预训练时,任务之间可以同时学习(即每个数据实例支持所有任务,并且任务损失可以联合最小化),顺序学习(即首先在指定的步骤上对第一个任务进行训练,然后逐一训练剩余的任务),或随机学习(即任务按照一定的数据实例组成批次,在训练过程中随机选择一个任务进行优化)。因此,同时预训练对数据和任务有最严格的要求,因为它要求对于每个数据实例,所有的预训练任务都可以在一次前向传播中完成,以便它们的损失可以相加形成最终的优化目标,并在后向传播过程中联合最小化。换句话说,如果能够同时进行预训练,那么也可以进行顺序/随机预训练,但反之则不行。然而,在现有的CodePTMs中,当有多种选择时,预训练策略的选择似乎是随机的。

表3:现有CodePTMs按四个维度分类及其对下游SE任务的表现

编程语言

最后一个维度中,作者根据CodePTMs是在一个PL(单语言)或多个PL(多语言)上预训练对其进行分类。

04 讨论

在本章,作者探讨了CodePTMs和SE任务之间的关系(如表3的右半部分所示)。表3的右半部分按照CodePTM是否已应用于特定的SE任务进行了分类,如果是,则列出了CodePTM在哪些基准数据集上进行了评估,并且是否已达到最先进(state-ofthe-art,SOTA)。下面陈述下基于表3和文献所得出的主要观察结果。

架构:如表3所示,基于TE的预训练主要应用于理解型任务(对于理解型下游任务,选用TE网络结构效果比较好),而基于TD和TF的预训练主要应用于生成型任务(对于生成型任务,选用TF和TD结构效果好)。如第前面架构章节所述,仅使用编码器模型在应用于生成型任务时是处于劣势的。原因在于编码器模型只能将输入序列映射到已知长度的输出序列,而对于生成型任务,输出长度通常是未知的。相比之下,基于TD和TF的预训练中有解码器,自然使它们更适合生成型任务。

模态:在输入中加入代码结构信息可以提升模型的效果,从输入中删除此类信息总是会降低它们在下游SE任务中的性能。

其次,当下游任务的I-O涉及到NL时,将NL作为预训练输入模态会对模型的性能产生积极影响。

预训练任务:相对于没有进行预训练,对数据进行预训练在SE下游任务上会产生更好的结果。

其次,在保持前期预训练任务类型与下游任务类型尽可能相似的情况下,会获得最佳结果。理论上,前期训练任务的知识能够在模型学习下游任务时得到成功利用,这种知识转移在模型学习下游任务时更有效,如对于理解任务,最好使用前期训练任务也是理解任务的类型。

编程语言:如果预训练与下游任务使用的PL在语法上相似,则会提升训练效果。相反,预训练与下游任务使用的PL在语法上不同,则可能导致训练效果下降。例如,PLBART在Java和Python上进行了预训练,在C#代码表现更好,但在PHP代码表现不好,因为C#与Java语法相似,而PHP与Java语法的差异较大。

其次,多语言模型通常比单语言的效果更好,尤其是在预训练时的PL和下游任务时的PL,两者语法相近时。例如,CodeT5,在6个PL上进行了前期训练,相比T5-learning和DeepDebug只在Java上进行了前期训练,CodeT5在代码转换上表现更好。

05 CodePTMs的有效性如何?

CodePTMs已成功应用于各种SE任务,但它们的有效性如何?在表格4中列举了在每个SE任务的数据集进行了预训练时所取得的最佳结果(见“Best CodePTM”列)。为了帮助读者评估CodePTMs的有效性,作者在“Best non-CodePTM”列中显示了每个数据集上不涉及预训练时所取得的最佳结果。表格的最后一列显示了每个数据集的相对误差减少率,计算方法是预训练相对于在数据集上未预训练时所产生的误差减少量。正值表示使用预训练实现了SOTA结果。可以看出,所有数据集的SOTA结果都是使用预训练实现的,以百分比表示的相对误差减少率在0.9 ~ 78.7之间。这些结果证明预训练对于解决各种SE任务,是一种有前景的方法。

表4:CodePTMs在SE任务/数据集上实现的相对误差减少率

备注:

1、“DS”列显示每个SE任务的常用评估数据集(有关这些数据集的详细信息,请参见表1)。

2、“Best CodePTM”列显示到目前为止预训练在相应数据集上取得的最佳结果和预训练的名称。

3、“Best non-CodePTM”列显示到目前为止不涉及在相应数据集上进行预训练的方法所取得的最佳结果和方法的名称(请注意,“-”表示non-CodePTM方法尚未应用于相应数据集)。

4、“ER”列显示每个数据集的相对误差减少率。有关每个数据集使用的评估指标的信息可以在表1中找到。

06 结论

虽然预训练已经在SE中取得成功,但并未释放其全部潜力。在本节中,将会概述了一些未来的发展方向。

超越NLP的思维方式

Tokenization and embedding:目前,CodePTMs使用和自然语言使用的是同样的Tokenization和embedding方法。但是,代码并不完全等同于NL:代码包含不同类型的词法分析(lexical tokens),例如变量、运算符和关键字。将NL中的Tokenization和embedding方法可能无法为CodePTMs提供最佳效果,因此需要设计新的(针对代码的)。

预训练方法:为了训练更强大的CodePTM,可能需要能够更好地利用代码所具有的特点(例如,代码结构、分支的存在等)来进行预训练任务。代码的预训练方法的设计目前部分受限于目前正在使用的NLP的Tokenization和embedding方法,并且可能需要重新设计涉及代码中Tokenization和embedding方法。

学习代码形式和功能

Code具有形式和功能,形式由具体的编程代码标识符组成,而功能是独立于任何特定的编程代码标识符的。表5中列出的所有CodePTMs都是从“形式”而不是“功能”的角度学习源代码。然而,学习代码功能无疑将有助于CodePTMs更好地理解代码,并在SE任务上取得更高的性能。因此,作者认为设计可以学习代码形式和代码功能的CodePTMs将是一个有价值的研究方向。

表5:CodePTM预训练的详细信息

适应下游任务

目前,微调(fine-tuning)是将预训练模型转移到下游任务的主要方法。然而由于需要更新所有模型参数,微调可能会效率低下。为了缓解这个问题,NLP社区提出了几种解决方案,例如模型重训,使用prompt tuning 微调范式,使用模型压缩。对于CodePTMs的微调,如何适应或扩展这些方法,将是一个有前景的研究方向。

面向特定应用的CodePTMs

作者不建议设计一个对所有SE任务都有效的CodePTMs,而是应该为不同类别的SE任务设计专门的CodePTMs(例如,理解型与生成型)。例如,从理论上讲,TE-based模型在理解型任务上往往比TD-和TF-based模型表现更好,而在生成型任务上则通常相反。专门的CodePTMs有额外的优势:它们往往更小,因此可能更高效,从而可以解决模型架构和微调所带来的效率问题。

统一评估和分析

目前对现有CodePTMs的优势和不足的认识受限于所评估的任务类型。为了更好地了解CodePTMs,需要对讨论的18个SE任务所涉及的所有基准数据集上的CodePTMs进行系统评估。除了全面的定量评估外,对每个模型常见错误的进行定性分析也很重要。

参考资料

[1]Changan Niu, Chuanyi Li, Bin Luo, and Vincent Ng. 2022. Deep Learning Meets Software Engineering: A Survey on Pre-Trained Models of Source Code. arXiv preprint arXiv:2205.11739 (2022).

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值