一种基于Transformer的代码摘要方法
摘要
生成描述程序功能的可读摘要称为源代码摘要。在这个任务中,通过对代码token之间的成对关系建模来学习代码表示,以捕获它们的长期依赖关系是至关重要的。为了学习用于摘要的代码表示,我们探索了使用自注意机制的Transformer模型,该模型在捕获长依赖关系方面已经证明是有效的。在这项工作中,我们表明,尽管方法很简单,但它比最先进的技术有显著的优势。我们进行了广泛的分析和控制变量研究,揭示了几个重要的发现,例如,源码token的位置障碍的绝对编码,而相对编码显著提高了摘要性能。我们已经公开了我们的代码,以方便未来的研究。
1 介绍
程序理解是软件开发和维护不可缺少的组成部分(Xia et al.,2018)。源代码的自然语言摘要可以大大减少开发人员的工作,从而促进程序的理解(Sridhara等人,2010)。源代码摘要指的是创建可读的摘要来描述程序的功能。
随着深度学习技术和大量开源仓库对大规模数据的可用性的发展,自动源代码摘要已经引起了研究者们的关注。大多数基于神经网络方法都是按序列到序列的方式生成源代码摘要的。最初的工作之一Iyer等人(2016)训练了一个嵌入矩阵来表示单个的代码token,并通过注意机制将它们与循环神经网络(RNN)结合起来,生成自然语言摘要。后续研究(Liang and Zhu,2018;Hu et al.,2018a,b)在不同的代码摘要上采用了传统的基于RNN的序列到序列网络(Sutskever et al.,2014)和注意力机制(Luong et al.,2015)。
基于RNN的序列模型在学习源代码表示方面有两个局限性。首先,当它们按顺序处理代码token时,它们不会对源代码的非顺序结构进行建模。第二,源代码可能非常长,因此基于RNN的模型可能无法捕获代码之间的长依赖关系。与基于RNN的模型相比,利用自我注意机制的Transformer (Vaswani et al.,2017)可以捕获长依赖关系。Transformer在许多自然语言生成任务中表现良好,如机器翻译(Wang et al.,2019)、文本摘要(You et al.,2019)、故事生成(Fan et al.,2018)等。
为了学习序列中token的顺序或为token之间的关系建模,Trans-former需要注入位置编码(Vaswani等人,2017;Shaw等人,2018;Shiv和Quirk,2019)。在这项工作中,我们表明,通过使用相对位置表示对源代码token之间的两两关系建模(Shaw等人,2018),相比于使用绝对位置表示学习代码token的序列信息有显著提升(Vaswani等人,2017)。
我们想要强调的是,我们提出的方法简单但有效,因为它的性能大大超过了花哨和复杂的最先进的源代码摘要技术。我们在两个从GitHub收集的较好的数据集上进行实验,结果证实了我们的方法相比最先进的方法更为有效。此外,我们还提供了详细的控制变量研究,以量化Transformer模型中几种设计选择的影响,为未来的研究提供坚实的基础。
源代码的自然语言摘要。代码和摘要都是由向量序列表示的token序列, $x=(x_1,\ldots,x_n)$,其中$x_i\in R^{d_{model}}$。在本节中,我们将简要描述Transformer的架构,以及如何在Transformer中对源代码标记的顺序或它们的成对关系进行建模。
2 方法
我们提出使用Transformer(Vaswani等人,2017)生成给定一段源代码的自然语言摘要。代码和摘要都是由向量序列表示的token序列,$x=(x_1,\ldots,x_n)$,其中$x_i\in R^{d_{model}}$。在本节中,我们将简要描述Transformer的架构,以及如何在Transformer中对源代码标记的顺序或它们的成对关系进行建模。
2.1 架构
Transformer由用于编码器和解码器的多层注意事项和参数化线性转换层组成。在每一层中,多头注意利用h个注意头,执行自注意力机制。
自注意力机制: 我们在Shaw等人(2018)的基础上描述了自注意力机制。在每个注意头中,输入向量的序列,$x=(x_1,\ldots,x_n)$,其中$x_i\in R^{d_{model}}$,被转换为输出向量序列,$o=(o_1,\ldots,o_n)$,其中,$o_i\in R^{d_k}$,为: $$o_i=\sum_{j=1}^{n}{a_{ij}(x_jW^V)},$$ $$e_{ij}=\frac{x_iW^Q\left(x_jW^K\right)^T}{\sqrt{d_k}},$$ 其中,$a_{ij}=\frac{\exp{e_{ij}}}{\sum_{k=1}^{n}{exp{\ e}_{ik}}}$,且$W^Q,W^K\in R^{d_{model}\times d_k},W^V\in R^{d_{model}\times d_v}$,为每层和注意头唯一的参数。
复制注意力: 我们在Transformer中加入了复制机制(See等人,2017),允许从词汇表生成单词,也可以从输入源代码中复制单词。我们使用一个额外的注意层来学习解码器堆栈上的副本分布(Nishida等人,2019)。复制注意力使Transformer能够从源代码中复制罕见的token(例如,函数名,变量名),从而显著提高摘要性能。
2.2 位置表示
现在,我们将讨论如何了解源代码标记的顺序或对它们的关系进行建模。
编码绝对位置: 为了使Transformer能够利用源代码令牌的顺序信息,我们训练一个嵌入矩阵$W^{P_e}$,该矩阵学习将令牌的绝对位置编码为维数$d_{model}$的向量。然而,我们发现捕获代码标记的顺序对学习源代码表示并没有帮助,并且会导致较差的摘要性能。 值得注意的是,我们训练了另一个学习对摘要标记的绝对位置进行编码的嵌入矩阵$W^{P_e}$。
编码之间的关系: 代码的语义表示并不依赖于符号的绝对位置。相反,它们之间的相互作用会影响源代码的含义。例如,表达式a+b和b+a的语义是相同的。 为了编码输入元素之间的成对关系,Shaw等人(2018)将自我注意机制扩展如下。 $$o_i=\sum_{j=1}^{n}{a_{ij}\left(x_jW^V+a_{ij}^V\right)},$$ $$e_{ij}=\frac{x_iW^Q\left(x_iW^k+a_{ij}^k\right)^T}{\sqrt{d_k}},$$ 其中,$a_{ij}^V$和$a_{ij}^k$是两个位置$i$和$j$的相对位置表示。Shaw等人(2018)建议将最大相对位置剪切为$k$的最大绝对值,因为他们假设,在一定距离之外,精确的相对位置信息是没有用的。 $$a_{ij}^K=w_{clip\left(j-i,k\right)}^K,a_{ij}^V=w_{clip\left(j-i,k\right)}^V,$$ $$clip\left(x,k\right)=\max(-k,\min{\left(k,x\right)}).$$ 因此,我们学习了2k + 1个相对位置表示:$(w_{-k}^K,\ldots,w_k^K)$和$(w_{-k}^V,\ldots,w_k^V)$。 在这项工作中,我们研究了一种忽略方向信息的相对位置表示的替代方法(Ahmad等人,2019)。换句话说,忽略第$j$个token是在第$i$个token的左边还是右边的信息。 $$a_{ij}^K=w_{clip\left(\left|j-i\right|,k\right)}^K\ ,\ a_{ij}^V=w_{clip\left(\left|j-i\right|,k\right)}^V,$$ $$clip\left(x,k\right)=\min(\left|x\right|,k).$$
3 实验
3.1 设置
数据集和预处理。 我们在Java数据集(Hu et al.,2018b)和Python数据集(Wan et al.,2018)上进行了实验。两个数据集的统计数据如表1所示。
除了使用Wei等人(2019)的预处理步骤之外,我们还将驼峰命名法和蛇形命名法的源代码token拆分为各自的子token。我们证明这样的代码token分割可以提高摘要性能。
评估指标。 我们使用三个指标来评估代码摘要性能,BLEU (Papineni等人,2002年)、METEOR(Banerjee和Lavie,2005年)和ROUGE-L(Lin,2004年)。 基线方法。我们将基于Transformer的源代码摘要方法与Wei等人(2019)报告的五种基线方法及他们提出的对偶模型进行了比较。
超参数。 我们遵循Wei等人(2019)在这两个数据集中为代码和摘要设置了最大长度和词汇量。我们使用Adam优化器(Kingma和Ba,2015)对Transformer模型进行训练,初始学习率为 。我们将小批量尺寸和丢弃率分别设置为32和0.2。我们将Transformer模型训练为最多200个epoch,如果验证性能在连续20次迭代中没有改善,我们将提前停止。我们在推理过程中使用波束搜索,并将波束大小设置为4。详细的超参数设置可以在附录A中找到。 我们使用三个指标来评估代码摘要性能,BLEU (Papineni等人,2002年)、METEOR(Banerjee和Lavie,2005年)和ROUGE-L(Lin,2004年)。
基线方法。 我们将基于Transformer的源代码摘要方法与Wei等人(2019)报告的五种基线方法及他们提出的对偶模型进行了比较。
3.2 结果分析
整体结果。 我们提出的模型和基线的总体结果在表2中给出。
结果表明,我们的基础模型优于基线(java中ROUGE-L除外),而全模型进一步提高了性能。我们在原始数据集上运行基础模型(没有切分驼峰命名和蛇形命名的代码token),观察到在Java和python数据集的性能。BLEU指标分别下降了0.60和0.72。ROUGE-L指标分别下降了1.66和2.09 。我们在附录c中提供了几个定性的例子,展示了超越基本模型的完整模型的实用性。 与基线方法不同,我们提出的模型采用了复制注意力机制。如表2所示,对于java和Python数据集,复制注意力机制在BLEU指标上分别提高了0.44和0.88的性能。 位置表示的影响。我们进行了控制变量研究,以调查编码代码token的绝对位置或建模它们的成对关系对源代码摘要任务的影响,结果见表3和表4。
表3表明,学习代码token的绝对位置是无效的,因为我们可以看到,与排除它相比,它会略微降低性能表现。这一实证发现证实了Iyer等人(2016)的设计选择,他们没有使用源代码token的序列信息。 另一方面,我们发现,如表4所示,通过相对位置表示来学习源代码token之间的成对关系有助于提升表现。我们改变剪切距离,k,并考虑忽略方向信息,但是建模成对的关系。实证结果表明,方向信息确实重要,而16、32和$2^i$相对距离导致在两个实验数据集上相似的表现。 改变模型大小和层数。我们通过改变模型的大小和层数的控制变量实验结果如表5所示。
在我们的实验中,我们观察到一个更深的模型(更多的层数)比一个更宽的模型(更大的模型)表现得更好。直观地说,源代码摘要任务依赖于更多的语义信息,而不是语法信息,因此更深层次的模型会有所帮助。
抽象语法树(AST)的使用。 我们在Transformer中使用源代码的抽象语法树(AST)结构进行了额外的实验。我们使用Hu等人(2018a)的方法,使用基于结构的遍历(SBT)技术将AST结构转换为线性序列。除了在复制注意力机制中,我们使用了一个掩码来阻止从输入序列中复制非终结符token之外,我们保持了我们提出的transformer架构的完整。需要注意的是,有AST和没有AST时,输入代码序列的平均长度分别为172和120。由于Transformer 是$O(n^2 \times d)$的复杂性,因此,使用AST会带来额外的成本。我们的实验结果表明,在Transformer中加入AST信息并不能改善源代码摘要。我们假设在摘要中利用代码结构信息的优势是有限的,当Transformer通过相对位置表示隐式地学习它时,这种优势就会减少。
定性分析。 表6中的例子定性地证明了我们建议的方法的有效性(更多的例子在附录中的表9和表10中提供)。
定性分析表明,与Vanilla Transformer模型相比,启用复制注意力模型生成的摘要更短,关键词更准确。此外,我们观察到,在一个支持复制的模型中,当使用相对位置表示时,与绝对位置表示相比,代码片段中频繁的token会获得更高的复制概率。我们怀疑这是由于学习代码token之间关系的灵活性,而不依赖于它们的绝对位置。
4 相关工作
大多数神经网络源代码摘要方法将问题框架为序列生成任务,并使用循环的编码器-解码器网络,将注意力机制作为基本构建模块(Iyer等人,2016;Liang和Zhu,2018;Hu等人,2018a,b)。与这些研究不同的是,Allamanis等人(2016)提出了一个卷积注意模型,将源代码总结成简短的、类似名称的摘要。最近在代码摘要方面的工作利用了抽象语法树(AST)形式的程序的结构信息,可以使用树结构编码器进行编码,如Tree- lstm (Shido et al.,2019)、Tree- transformer (Harer et al.,2019)和图神经网络(LeClair et al.,2020)。相比之下,Hu等人(2018a)提出了一种基于结构的遍历(SBT)方法来将AST扁平化成序列,并显示出了对基于AST方法的改进。后来,LeClair等人(2019)使用了SBT方法并将代码结构从代码token中解耦,以学习更好的结构表示。其他值得注意的工作包括API使用信息(Hu et al.,2018b)、强化学习(Wan et al.,2018)、对偶学习(Wei et al.,2019)、基于检索的技术(Zhang et al.,2020),这些都被用来进一步增强代码摘要模型。我们可以用先前提出的技术增强Transformer。然而,在这项工作中,我们仅研究Transformer的不同设计选择,而没有打破它的核心架构设计理念。
5 结论
本文对使用Transformer模型完成源代码摘要任务的优势进行了实证研究。我们证明,具有相对位置表示和复制注意力的Transformer比最先进的方法表现要好得多。在我们未来的工作中,我们希望学习如何将代码结构有效地整合到Transformer中,并应用到其他软件工程序列生成任务中的技术(例如,提交源代码更改的commit消息生成)。