
一种基于图引导的transformer模型代码注释自动生成方法
技术领域
1.本发明属于软件工程技术领域,具体涉及一种基于图引导的transformer模型代码注释自动生成方法。
背景技术:2.代码注释自动生成也称源代码摘要,旨在为代码自动生成简明扼要的自然语言描述。好的代码注释能够使程序员快速的了解一段程序代码的功能,并将精力更多地专注于代码逻辑的编写,从而大大提高代码的重用性以及编程的效率。人工编写代码注释不仅费时费力且效率低。除此以外,代码注释需要随着代码的改动而更新,很多现有的代码注释往往会出现不匹配、过时等问题。因此代码注释自动生成这项研究十分必要并且已引起了广泛的关注。
3.代码注释自动生成问题是一个多领域交叉的研究问题,涉及到软件工程、自然语言处理等多个不同领域。随着深度学习在自然语言处理(nlp)领域的发展,深度神经网络逐渐被引入到代码注释自动生成任务中。基于深度学习对代码注释任务进行建模的方法主要是将其视作神经机器翻译(nmt,neural machine translation)问题。经典的有编码器-解码器结构,也称序列到序列(seq2seq)模型。这类方法利用编码器先将源代码编码为一定长度的向量表示,然后利用解码器将其解码生成由自然语言描述的注释序列。
4.然而传统的seq2seq模型存在两个方面的问题,(1)基于rnn或cnn的序列模型无法捕获代码token的长距离依赖关系;(2)代码的结构信息在特征表示上没有得到充分利用,或是使用抽象语法树来提取代码中的结构化特征带来了一些不必要的深层次结构,从而导致模型过于复杂。
技术实现要素:5.针对目前存在的问题,本发明提出了一种基于图引导的transformer模型代码注释自动生成方法,既可以很好地提取源代码的结构化特征,还大大缓解了代码的长距离依赖问题,提高了生成注释的准确性。
6.与现有的其他方法不同,本发明的改进主要体现在以下两个方面:(1)使用代码中的语义级图结构——数据流来代替语法级图结构——抽象语法树,提取代码结构化特征,并利用这一结构化特征改进transformer,从而使模型更好地学习到代码语义表示;(2)利用改进后的集束搜索算法对解码器输出的概率分布进行采样以生成最可能的注释序列。为了提高句子生成的准确性,对所采样的句子长度进行归一化,并在评分函数中加入了覆盖惩罚机制。
7.本发明提出的一种基于图引导的transformer模型代码注释自动生成方法,主要包括以下步骤:
8.s1、从github上下载开源的java代码数据集deepcom;
9.s2、对数据集中的源代码进行预处理,解析为抽象语法树,提取变量依赖关系,构
造数据流图,再将其转换为数据流引导的mask矩阵;
10.s3、用构造好的mask矩阵改进自注意力机制从而构建新的transformer编码器;
11.s4、解码时,将句子的长度进行归一化,并在score函数中加入覆盖惩罚机制,以此来改进原始的启发式算法——集束搜索算法;
12.s5、在java数据集deepcom上对已构建好的模型dfg-trans进行训练,学习代码结构和语义信息;
13.s6、输入测试集中的代码序列,使用已训练好的模型进行测试,生成java代码对应的注释。
14.所述步骤s2中,具体地:
15.给定源代码c={c1,c2,...,cn},将源代码解析为抽象语法树后,提取源代码中所有的变量节点并构造数据流图,将得到的数据流图用g=(v,e)表示,其中v表示顶点的集合,e表示边的集合,将数据流图中的顶点记作v
ipos(i)
,pos(i)表示第i个顶点在源代码序列中的位置信息,矩阵m记录源代码中的变量数据依赖关系。
16.所述步骤s3中,具体地:
17.编码器和解码器模块均基于transformer,其中编码器由数据流引导的编码器层与基础编码器层堆叠而成,带有数据流引导的编码器层采用改进后的自注意力机制。
18.所述步骤s4中,具体地:
19.在解码时,transformer解码器会在输出词的词汇表中生成概率分布,利用改进后的束搜索算法对概率分布进行采样以生成最可能的注释序列,为了提高句子生成的准确性,对所采样的句子长度进行归一化,并在评分函数中加入了覆盖惩罚。
附图说明
20.图1为本发明中的模型整体架构。
21.图2为本发明中构造数据流引导的mask矩阵的方法。
具体实施方式
22.下面结合附图,对本发明提出的方法作进一步详细说明。
23.参见附图1,本发明提出的一种基于图引导的transformer模型代码注释自动生成方法,包括以下内容:
24.s1、从github上下载开源的java代码数据集deepcom。
25.s2、对数据集中的源代码进行预处理,解析为抽象语法树,提取变量依赖关系,构造数据流图,再将其转换为数据流引导的mask矩阵。
26.s201、数据流的结构化表示:
27.数据流是表示变量之间依赖关系的图,其中节点表示变量,边表示变量之间数据的流动关系。与抽象语法树不同,即便是在不同的抽象语法下,代码的数据流图也是不变的。这种特有的代码结构能够为机器翻译模型提供更好的代码语义信息,很多程序员在编写代码时并没有严格按照命名规范,因此仅仅将代码注释生成任务视作机器翻译问题去建模,对于模型而言很难理解代码真正的语义。因此,为了更好地提取代码结构中的语义信息,参照附图2,将给定源代码解析为抽象语法树后,提取源代码中所有的变量节点并构造
数据流图,将得到的数据流图用g=(v,e)表示,其中v表示顶点的集合,e表示边的集合,将数据流图中的顶点记作v
ipos(i)
,pos(i)表示第i个顶点在源代码序列中的位置信息,矩阵m记录源代码中的变量数据依赖关系,src_len表示源代码序列长度,
[0028][0029]
其中《vi,vj》∈e表示vi与vj存在数据依赖关系,当vi与vj之间存在边或i等于j时,将m
pos(i)pos(j)
置为1,否则为负无穷。将m矩阵引入自注意力机制,当m等于1时,注意力得分不变,当m等于负无穷时,注意力得分将会被计算为0。这样就可以将序列中没有数据依赖关系的两个token的注意力得分覆盖掉,从而使后续构建的transformer模型更能关注到代码中的数据流动关系,学习到变量的语义,帮助模型生成代码注释。
[0030]
s3、用构造好的mask矩阵改进自注意力机制从而构建新的transformer编码器。如附图1所示,模型的整体架构主要由编码器和解码器两个部分组成,编码器由n个编码器层堆叠而成,每一个编码器层主要由多头自注意力层和前馈神经网络层组成,将这些编码器层划分为两类,分别是带有数据流引导和无数据流引导的,因此在计算注意力得分时有所不同。
[0031]
s301、嵌入编码:
[0032]
给定源代码片段,经过嵌入层(embedder)编码后得到代码序列的向量表示,transformer与循环神经网络不同,循环神经网络是一种顺序结构,可以很自然地捕获词序信息,为了捕获每个token在序列中的位置信息,每一个token的位置编码方式可以定义为:
[0033][0034][0035]
其中i∈[0,d/2],pos表示词的位置,通过这样的编码方式用词的位置信息对序列中的每个词进行二次表示,将位置编码与词向量相加得到最终的词向量表示,记作x=[x1,x2,...,x
src_len
],其中x∈r
src_len
×
d_model
,d_model指的是模型嵌入维度。
[0036]
s302、自注意力机制:
[0037]
transformer中的自注意力机制通过查询,键,值三个矩阵的计算实现,将代码序列的向量表示x=[x1,x2...x
src_len
]通过三个线性层映射为q,k,v三个矩阵,
[0038]
q=qw
iq
,k=kw
ik
,v=vw
iv
[0039]
wq,wk,wv是可训练的权重矩阵,其中wq,wk∈r
d_model
×
d_k
,wv∈r
d_model
×
d_v
,q,k,v矩阵的初始值为x,无数据流引导的编码器层采用的自注意力机制为缩放点积注意(scaled dot-product attention),将映射后得到的q,k,v矩阵传入多头自注意力层,注意力输出计算为:
[0040][0041]
s303、数据流引导的自注意力机制:
[0042]
为了引导模型关注代码中的数据依赖关系从而学习代码语义,定义了数据流邻接
矩阵m作为mask矩阵(见步骤s201),在数据流引导的编码器层采用了改进后的自注意力机制,自注意力输出计算c’为:
[0043][0044]
矩阵m记录了代码中的数据流信息,当第i个token与第j个token存在数据依赖关系时m
ij
等于1,否则m
ij
为负无穷,经过softmax的计算后,没有数据依赖关系的两个token之间的注意力得分会被覆盖掉,计算出一头的注意力值后,多头自注意力矩阵的计算定义如下:
[0045]
multiattn(q,k,v)=concat(head1,...,headh)wo[0046]
模型将各头自注意力输出通过concat函数拼接起来得到最终的多头注意力矩阵,其中headi表示第i头的自注意力输出,h为head的数量,wo是模型的可训练参数。
[0047]
s304、前馈神经网络:
[0048]
多头自注意力层的输出经过残差连接和归一化后作为全连接前馈神经网络层的输入h,该层中包括两个线性变换,
[0049]
ffn(h)=relu(hw1+b1)w2+b2[0050]
其中w1,w2∈r
d_ff
×
d_model
,b1∈r
d_ff
,b2∈r
d_model
均为模型可学习参数,relu函数用于激活输出。
[0051]
s4、解码时,将句子的长度进行归一化,并在score函数中加入覆盖惩罚机制,以此来改进原始的启发式算法——集束搜索算法。
[0052]
s401、改进的集束搜索算法:
[0053]
解码器会根据编码器的输出在自然语言构成的词汇表中生成词的概率分布,然后利用解码算法对概率分布进行采样以生成最可能的注释序列。本发明在模型的解码阶段采用集束搜索,将编码器的输出与前t-1步解码得到的当前预测序列s
t-1
作为下一步的输入,计算第t步预测词的概率分布,并从中选择前k个概率最大的候选词构造新的预测序列s
t
,k为集束宽度。当句子长度达到设定的最大长度,或当前句子中已包含《/s》,则将该句子剪切出来作为候选预测序列之一并退出循环,最后在所有的候选句子中计算出得分最高的序列作为输出。
[0054]
常规的集束搜索算法以对数似然作为得分函数,然而因为对数似然产生的概率为负数,负的对数概率随着句子长度的增加而累积,导致长句更容易产生更低(更负)的分数。因此通过对句子的长度进行归一化以改进原始启发式算法。除此以外,为了使输入序列中的每一个token被解码器均匀地注意到,即覆盖整个输入序列,在得分函数中添加了覆盖惩罚机制。改进后的得分函数score(x,y)定义为:
[0055][0056]
将原始算法使用的对数似然除以l
α
来进行长度的归一化,其中l是生成的候选注释的长度,α是模型的超参数,它的值在0到1之间。cp(x;y)为覆盖率惩罚函数,具体定义为:
[0057][0058]
p
ij
表示第j个目标候选词与第i个输入词之间的注意力得分,l
x
指输入序列的长
度,β是模型的超参数,它的值在0到1之间。
[0059]
s5、在java数据集deepcom上对已构建好的模型dfg-trans进行训练,学习代码结构和语义信息。
[0060]
s6、输入测试集中的代码序列,使用已训练好的模型进行测试,生成java代码对应的注释。表1给出了测试集中的一个java代码示例,并分别展示了在不引入数据流和不拆分编码器以及完整的dfg-trans模型下生成的注释结果。根据结果可以看出dfg-trans生成的注释相比之下更接近于真实的注释。
[0061]
表1
[0062][0063]
以上所述仅为本发明的实施例,并非因此限制本发明的专利范围,凡是利用本发明说明书及附图内容所做的等效结构或等流程变换,或直接或间接运用在相关技术领域,均同理包括在本发明的专利保护范围。