发明内容
鉴于以上所述现有技术的缺点,本发明提供一种基于GVG的代码注释生成方法。能够识别代码类别,对多种编程语言进行注释。
为实现上述效果,本发明的技术方案如下:
第一方面,本发明提供一种基于GVG的代码注释生成方法,包括以下步骤:
步骤1:构建函数/注释对数据集,数据集由代码及其注释构成;
步骤2:将代码函数-注释对数据集划分为训练集、验证集和测试集;
步骤3:将训练集作为训练代码函数数据,通过代码类别分类神经网络对训练代码函数数据进行分类,得到代码类别;
步骤4:对所述训练代码函数数据进行函数预处理,生成代码函数序列数据;
所述代码函数序列数据包括原始单词序列、原始代码标识符序列、标点符号序列,原始代码标识符包括驼峰标识符和蛇形标识符;
步骤5:使用训练集中的代码构建特征向量词库;具体包括:
步骤5.1:通过按行读取的方式获取第一文件中的代码数据,对每一行代码使用空格进行切割,得到代码单词组列表;
步骤5.2:为代码构建代码索引词典,将代码单词组列表中的单词按顺序以“单词-位置”的形式保存到代码索引词典中;
步骤5.3:构建特征向量词库,使用词嵌入的方式将代码索引词典中的单词进行从单词到特征向量的映射;
步骤6:基于特征向量词库,采用多个预设目标编码器、预设目标解码器与判别器构建函数注释生成网络模型;
步骤7:接收并分类目标代码函数数据,采用训练代码函数数据和验证集对预设的函数注释生成网络模型进行训练,生成训练好的函数注释生成网络模型,使用测试集检验模型训练效果;
步骤8:通过目标解码器对目标代码函数数据中的预设特征向量进行解码,生成对应的目标代码函数注释。
进一步的,步骤4对所述训练代码函数数据进行函数预处理,包括:
步骤4.1:将构建数据集时的代码和注释分别作为原始代码和原始注释,对原始代码进行分割以及清洗,生成原始单词序列;
步骤4.2:通过预设语法树解析器将所述训练代码函数数据转换为AST语法树,对AST语法树进行位置编码;
将位置编码融入到对应的AST语法树中作为AST语法树中节点的数据之一;使用正弦函数和余弦函数对AST语法进行位置编码,具体如下:
其中,PE表示位置编码特征向量,pos表示代码元素在输入序列中位置;表示嵌入特征向量的维度;
步骤4.3: 根据AST语法树提取代码的变量关系,将代码的变量关系构建为数据流图DFG。
进一步的,步骤4.1对原始代码进行分割以及清洗包括:
步骤4.1.1:将驼峰标识符按驼峰命名规则进行切割,得到一组分割单词,记为驼峰单词;
步骤4.1.2:将蛇形标识符按蛇形命名规则进行切割,得到一组分割单词,记为蛇形单词;
步骤4.1.3:将单词与单词、单词与标点符号、标点符号与标点符号之间用空格进行分割,使单词与标点符号成为独立的个体;
步骤4.1.4:删除代码中的转义字符;
步骤4.1.5:将删除转义字符后的代码按行的方式保存到预设的第一文件中;
步骤4.1.6:记录单词的处理痕迹,若单词由驼峰标识符或由蛇形标识符切割所得,则记为1,否则记为0;
步骤4.1.7:将代码单词的痕迹记录按行的方式保存到预设的第二文件中。
进一步的,步骤4.4结合AST语法树与数据流图DFG构建数据流语法图DFSG;具体为:
根据数据流图DFG中节点之间数据流的信息,向数据流添加对应的边,构建数据流语法图DFSG;即:
设定AST语法树存在节点a和节点b,若在数据流图DFG中存在节点a到节点b或者节点b到节点a的数据流,则为数据流添加目标连接边,目标连接边的指向取决于数据流图DFG中节点的指向。
进一步的,所述代码类别分类神经网络采用循环递归网络RNN,循环递归网络RNN的训练过程为:
为原始代码标记对应的编程语言种类标签;
将原始代码进行代码分单词与清洗后转化为单词序列,代码分单词与清洗包括分单词操作、去除标点符号;
训练循环递归网络RNN:
使用词嵌入的方法将代码分单词与清洗后的代码转换为特征向量;
使用循环递归网络RNN作为训练模型,利用特征向量及其对应的标签对循环递归网络RNN进行训练,其中,将交叉熵函数作为循环递归网络RNN的损失函数,交叉熵函数如下:
其中,M表示编程语言的类别个数;表示符号函数,取0或1,符号函数中,若数据集中样本i的真实类别等于c,取值1,否则取值0;表示样本i属于类别c的预测概率。
进一步的,步骤6包括:
步骤6.1:
使用节点嵌入技术将数据流语法图DFSG中的节点转换为节点嵌入特征向量;
步骤6.2:使用边嵌入技术将数据流语法图DFSG中的边转换为边嵌入特征向量;
步骤6.3:构建图结构数据,将点嵌入特征向量和边嵌入特征向量通过维度拼接进行结合,得到图结构数据特征向量;
步骤6.4:使用图结构数据特征向量训练第一编码器,输出特征向量。
进一步的,步骤7包括:
步骤7.1:从特征向量提取均值特征向量和标准差特征向量;具体包括:
构建第一全连接层、第二全连接层作为隐层Φ和隐层ψ,通过隐层Φ和隐层ψ提取特征向量的特征信息;将第一全连接层的权重矩阵表示为Φw={Φ1, Φ2, … Φn},将第二全连接层的权重矩阵表示为ψw={ψ1, ψ2, … ψn};每个隐层的输出通过预设的激活函数Relu进行特征向量的非线性变换;
将特征向量输入到隐层Φ输出后再通过激活函数Relu进行激活获得特征向量vΦ,将特征向量vΦ输入到隐层ψ输出后再通过激活函数Relu进行激活后获得特征向量vψ;
构建第三全连接层,权重矩阵表示为muw={ mu1, mu2, …,mun},用于从特征向量提取均值特征向量;
构建第四全连接层,权重矩阵表示为lvw= { lv1, lv2, …, lvn},用于提取标准差特征向量;将特征向量vψ分别输入到第三全连接层和第四全连接层,分别得到均值特征向量和标准差特征向量;
步骤7.2:使用均值特征向量和标准差特征向量进行重参化,得到特征向量;即,
计算标准差特征向量的标准差std,标准差std表示为:
从高斯分布上随机采样噪声特征向量,基于均值特征向量、噪声特征向量,构建特征向量:
。
进一步的,所述采用训练代码函数数据和验证集对预设的函数注释生成网络模型进行训练,生成训练好的函数注释生成网络模型,包括:
将训练代码函数数据和验证集输入所述函数注释生成网络模型,生成对应的训练代码函数注释;
基于预设的损失函数,计算所述训练代码函数注释与关联的标准代码函数注释之间的多个轮次的平均损失值;
计算每一轮次的所述平均损失值与前一轮次的所述平均损失值之差,生成多个目标损失值;
若所有所述目标损失值的绝对值均小于预设的标准阈值时,停止训练,生成训练好的函数注释生成网络模型。
进一步的,步骤8所述通过目标解码器对目标代码函数数据中的预设特征向量进行解码,包括:
使用解码器对特征向量的编码特征进行解码,输出概率分布,将最高概率对应的单词作为输出;若概率最高的单词不是未知单词,则输出最高概率对应的单词;否则,执行以下步骤:
步骤9.1:将特征向量对应的原始代码进行分割以及清洗,得到目标代码函数序列数据;使用空格对目标代码函数序列数据进行切割,得到目标代码单词组列表;将目标代码词组列表中的单词按顺序以“单词-位置”的形式保存到目标代码索引词典中;使用词嵌入的方式将目标代码索引词典的单词进行从单词到特征向量的映射,得到目标特征向量词库;
步骤9.2:在目标特征向量词库中寻找目标替代词来代替未知单词,如果目标特征向量词库中的所有的向量与向量的编码特征的相似度小于设定阈值,则转而在特征向量词库中寻找目标替代词来代替未知单词。
步骤9.3:目标代码解码出注释后,清空目标特征向量词库。
进一步的,述判别器用于对特征向量打分,具体如下:
将原始注释通过词嵌入的方式编码成特征向量;
将特征向量与特征向量输入判别器中进行训练并打分,对特征向量打出高分,对特征向量打出低分;
对判别器使用BCE损失函数进行训练,BCE损失函数表示为:
其中,是第i个样本的二元标签值;p()是第i个样本的打分结果,表示判别器对第i个样本的特征向量打出的评分。
与现有技术相比,本发明技术方案的有益效果是:
通过代码类别分类神经网络对训练代码函数数据进行分类能够识别代码类别,对多种编程语言进行注释。
在本发明中通过使用多个预设目标编码器使目标代码的注释生成更丰富;对不同的编程语言的代码生成相应注释;
通过构建特征向量词库,供解码器在解码输出时使用,更好地处理OOV问题。
具体实施方式
以下将参照附图和优选实施例来说明本发明的实施方式,本领域技术人员可由本说明书中所揭露的内容轻易地了解本发明的其他优点与功效。本发明还可以通过另外不同的具体实施方式加以实施或应用,本说明书中的各项细节也可以基于不同观点与应用,在没有背离本发明的精神下进行各种修饰或改变。应当理解,优选实施例仅为了说明本发明,而不是为了限制本发明的保护范围。
说明的是,以下实施例中所提供的图示仅以示意方式说明本发明的基本构想,遂图式中仅显示与本发明中有关的组件而非按照实际实施时的组件数目、形状及尺寸绘制,其实际实施时各组件的型态、数量及比例可为一种随意的改变,且其组件布局型态也可能更为复杂。
在介绍本发明实施例之前对本发明实施例中涉及到的相关名单词作如下释义:
GVG指的是本发明中用到的三种技术即:GAT(Graph Attention Network), VAE(Variable AutoEncoder), GAN(Generative Adversarial Network)。
“词汇外问题”(Out-Of-Vocabulary,OOV)。
现有技术的缺点:
基于模板的代码注释自动生成技术通过预设模板来达到生成效果,但是其由于其通常依赖预定义的模板或规则,灵活性就有所欠缺;同时,这种方法是通过填充的方式,不仅文本创新受限,即文本生成效果单一,而且通用性差,使用此类方法设定一系列不同的模板来达到对不同编程语言的注释生成效果,限制了自然语言的表达;最终,这种方法在面对多样性和变化时显得力不从心,当遇到无法被模板覆盖的情况时,生成的文本可能变得混乱不堪,增加了模板维护的复杂度。
基于信息检索的代码注释自动生成技术通过预先已有的信息文本,将目标代码文本输入后根据特征信息检索到匹配的代码注释,但是这种方法依赖大量已有的数据,在数据量小的时候会导致生成数据单一的问题,并且其生成的文本风格和内容相对固定,这也限制了内容的多样性;同时,这种方法不能处理复杂的推理和证明,它无法通过代码潜在的意图去生成正确的文本,当面对未知领域或新问题时,这种方法就容易导致崩溃。
基于深度学习的代码注释自动生成技术中,第一,采用自编码器的模型往往会因为接受了训练数据而产生过拟合问题,导致系统泛化性能不佳,并且,自编码器在输入数据中学习特征往往无法提取到最重要的明确信息,同时,解码器的性能很大程度上限制了其性能,更重要的一点是,自编码器模型对噪声过于敏感,这会导致产生的数据不稳定;第二,采用仅时序模型的方法中,如LSTM、GRU和Transformer,训练时往往存在序列顺序的问题,因此其无法并行处理,造成了无法很好地处理长序列问题,并且,长距离依赖问题往往会使得时序模型在某些任务中引起性能问题,最重要的一点,时序模型缺乏对全局信息的掌控,而代码注释生成从全局出发找到最优解的过程;第三,DeepCom方法以及Hybrid-DeepCom方法,虽然将抽象语法树转换为序列,以及通过束搜索来缓解OOV问题,但由于转换过程中没有考虑原始AST语法树的结构对解释的重要作用,会导致结构信息的丢失降低生成注释的质量;第四, ATOM方法借助指针生成网络来缓解OOV问题,但由于指针生成网络生成的文本可能会包含指针,因此会造成生成的注释不够流畅,这种模型对噪声以及不规范输入的处理也同样存在缺陷,生成的文本可能出现严重错误;第五,虽然通过多次生成注释并比较它们的相似度来选择最合适的代码注释表面上看起来能够提高稳定性,但这种方法未考虑到若模型本身的性能较差,生成多次也只是在坏结果中挑选相对较好的结果而已;第六,基于预训练的模型需要大量的计算资源,包括高性能GPU或CPU,以便进行训练和推理,其参数也可能达到惊人的数十亿或数百亿,在一些环境中难以部署,尤其在资源受限的情况下,其在训练时数据,否则训练效果会不佳。
实施例
本实施例提出了一种基于GVG的代码注释生成方法。请参阅图1,包括以下步骤:
步骤1:构建函数/注释对数据集,数据集由代码及其注释构成;
步骤2:将代码函数-注释对数据集划分为训练集、验证集和测试集;
在本发明实施例中,训练集、测试集和测试集互不包含,训练集多于验证集和测试集,验证集和测试集比例相同。训练集占数据集总数的90%,验证集占数据集总数的5%,测试集占数据集总数的5%;将代码函数-注释对数据集划分时,对代码函数-注释对数据集打乱,打乱是指对数据集中的样本进行随机排列的操作,防止模型在训练过程中学习数据样本的顺序而引入的误差。
步骤3:将训练集作为训练代码函数数据,通过代码类别分类神经网络对训练代码函数数据进行分类,得到代码类别;
在本发明实施例中,使用训练完成的循环递归网络RNN对原始代码函数数据进行分类。输入的原始代码为java, python, javaScript三种类别的编程语言的其中一种类别,分类器将代码分类为java, python以及javaScript中的一种。但原始代码不仅局限于java、python和javaScript这三种语言。若要使用其他编程语言,由于本发明涉及到代码所对应的AST语法树,因此使用者对指定的输入语言设置AST语法树转换工具。这种转换工具可以是使用者根据AST语法树原理自己制定的代码策略,采用AST语法树生成工具。例如,若添加的编程语言为C++,使用Clang作为AST语法树转换工具。Clang可以将C++代码转换为AST语法树,以便将其输入到本发明的模型中。
步骤4:对所述训练代码函数数据进行函数预处理,生成代码函数序列数据;预处理可以减少噪声数据,提高数据的质量。
所述代码函数序列数据包括原始单词序列、原始代码标识符序列、标点符号序列,原始代码标识符包括驼峰标识符和蛇形标识符;
步骤5:使用训练集中的代码构建特征向量词库;具体包括:
步骤5.1:通过按行读取的方式获取第一文件中的代码数据,对每一行代码使用空格进行切割,得到代码单词组列表;
在python中使用codeData.split()的方式获取到代码单词组列表;
步骤5.2:为代码构建代码索引词典,将代码单词组列表中的单词按顺序以“单词-位置”的形式保存到代码索引词典中;
步骤5.3:构建特征向量词库,使用词嵌入的方式将代码索引词典中的单词进行从单词到特征向量的映射,将映射的关系按行存储的形式保存到code_word.voc文件中。
词嵌入的方式采用Word2Vec或BERT。Word2Vec是一种用于将单词表示为特征向量的技术,其作用在于将语言中的单词汇嵌入到高维特征向量空间中,使得具有相似语境的单词在特征向量空间中更接近。通过学习大规模语料库,Word2Vec能够捕捉到单词之间的语义关系,为自然语言处理任务提供更丰富的语义信息。这些特征向量可以用于计算单词语的相似性、聚类、命名实体识别等任务,也可以作为预训练模型的输入,提高文本处理任务的性能。因此,在本发明中word2Vec的作用是更好地将代码映射为特征向量表示。
例如,目标代码片段为:
public int my Funtion Name ( int my variable name ) { int a = 1 ; intb = 2 ; int c = 3 ; return a * ( b + c ) – my variable name ; }
经过步骤5.1后,得到:
['public', 'int', 'my', 'Funtion', 'Name', '(', 'int', 'my', 'variable', 'name', ')', '{', 'int', 'a', '=', '1', ';', 'int', 'b', '=', '2',';', 'int', 'c', '=', '3', ';', 'return', 'a', '*', '(', 'b', '+', 'c', ')','–', 'my', 'variable', 'name', ';', '}']
经过步骤5.2后,得到:
{ 'public': 0,'int': 1,'my': 2, 'Function': 3,'Name': 4,'(': 5,… }
经过步骤5.3后,得到:
{'public': {'index': 0, 'vector': array([0.1, 0.2, 0.3])},
'int': {'index': 1, 'vector': array([0.4, 0.5, 0.6])},
'my': {'index': 2, 'vector': array([0.7, 0.8, 0.9])},
'Function': {'index': 3, 'vector': array([0.2, 0.3, 0.4])},
'Name': {'index': 4, 'vector': array([0.5, 0.6, 0.7])},
'(': {'index': 5, 'vector': array([0.8, 0.9, 0.1])}, …}
步骤6:基于特征向量词库,采用多个预设目标编码器、预设目标解码器与判别器构建函数注释生成网络模型;
预设目标编码器包括第一编码器和第二编码器;所述第一编码器基于图神经网络;第二编码器基于VAE编码器(Variational Auto-Encoder,变分自动编码器),用于提取特征向量中的潜在信息;预设目标解码器采用基于Transformer的解码器;
步骤7:接收并分类目标代码函数数据,采用训练代码函数数据和验证集对预设的函数注释生成网络模型进行训练,生成训练好的函数注释生成网络模型,使用测试集检验模型训练效果;
步骤8:通过目标解码器对目标代码函数数据中的预设特征向量进行解码,生成对应的目标代码函数注释。
引入判别器的目的是提高VAE编码器的生成能力,使VAE编码器生成更逼真的数据,通过引入对抗性损失即生成器与判别器之间的竞争,来迫使模型学习数据分布的更多细节,提高生成特征向量的质量。这里是一种对抗训练的思想,若判别器分辨不出来特征向量由编码器所生成的还由原始注释所生成的,则说明编码器生成的特征向量能够接近于由原始注释所生成的特征向量,判别器最终目的是使编码器所生成的特征向量最大可能地接近原始注释生成的特征向量,即通过此方法得到的注释质量将会最大可能地接近原始注释。本发明中判别器的工作流程如图10所示。
作为优选的技术方案,本实施例中,步骤4对所述训练代码函数数据进行函数预处理,包括:
步骤4.1:将构建数据集时的代码和注释分别作为原始代码和原始注释,对原始代码进行分割以及清洗,生成原始单词序列;
步骤4.2:通过预设语法树解析器将所述训练代码函数数据转换为AST语法树,对AST语法树进行位置编码;
关于预设语法树解析器将代码转换成AST语法树的方法,本发明中java代码使用ANTLR进行处理,python代码使用python库AST语法树进行处理,JavaScript代码使用Esprima进行处理。
对AST语法树进行位置编码,之后还包括:
使用位置编码能使模型更好地理解节点之间的位置关系;位置编码是额外的特征向量,将位置编码融入到对应的AST语法树中作为AST语法树中节点的数据之一;使用正弦函数和余弦函数对AST语法进行位置编码,具体如下:
其中,PE表示位置编码特征向量,pos表示代码元素在输入序列中位置;表示嵌入特征向量的维度;本发明设定为512,在本发明中位置编码特征向量的维度与嵌入特征向量的维度相同;n是用户定义的标量,本发明n=10000;i是位置编码特征向量的维度索引,,在本发明中i设定为的一半减1即255。
代码元素有五类,即常量、标识符、运算符、分隔符和保留字;嵌入特征向量的维度是指位置编码特征向量的维度;引入i 的目的是为了引入不同维度上的周期性信息,确保位置编码特征向量在不同维度上有所不同。这种设计有助于模型学习捕捉输入序列中不同位置的关系。本发明中,n,和i可以根据具体情况进行设定。
嵌入空间的维度:指数据中嵌入的表示对象特征的特征向量的维度,在机器学习中,通常使用嵌入维度来表示对数据进行学习和分类的特征。
例如,输入代码为:
def min(a, b):x = 0,if a<b:x = a,else:x = breturn x
此Python代码在通过工具处理后得到AST语法树(如图4)。
对AST语法树中每个节点进行位置编码后,位置编码将作为节点中数据的一部分,记录到AST语法树节点中,比如:AST语法树中节点“函数模块”的数据结构为:
{“name”:”函数模块”,“child”:[“函数定义:min”],“positionEncoding”:(sin(0),cos(0))}。
步骤4.3: 根据AST语法树提取代码的变量关系,将代码的变量关系构建为数据流图DFG;
根据AST语法树提取代码的变量关系,将代码的变量关系构建为数据流图DFG;数据流是表示变量之间依赖关系的图,其中,节点表示变量,边表示每个变量值的来源,对于不同编程语言但功能相同的原始代码,数据流在不同的抽象语法下是相同的。
将AST语法树转为数据流图DFG使用Graph Code BERT开原始代码中的数据流图DFG转化方法,其中的数据流图DFG.py就有从AST语法树到数据流图DFG的转换代码。
如图5是示例代码函数min对应的数据流图DFG。变量上标代表的是代码元素在输入序列中的位置,实线代表确定的数据流,虚线代表可能的数据流。
作为优选的技术方案,本实施例中,步骤4.4结合AST语法树与数据流图DFG构建数据流语法图DFSG;具体为:
根据数据流图DFG中节点之间数据流的信息,向数据流添加对应的边,构建数据流语法图DFSG;即:
设定AST语法树存在节点a和节点b,若在数据流图DFG中存在节点a到节点b或者节点b到节点a的数据流,则为数据流添加目标连接边,目标连接边的指向取决于数据流图DFG中节点的指向,若数据流图DFG中节点a是指向节点b的,则在AST语法树中添加的边从节点a指向节点b。续上述代码例子,结合了AST语法树和数据流图DFG后生成的数据流语法图DFSG如图6所示。
本发明使用图注意神经网络实现对代码的语法、语义以及时序完整性的提取;使用VAE编码器从训练集中学习到数据潜在的特征,生成多样化的注释内容,提高生成注释文本的多样性;
通过使用图注意神经网络、多个预设目标编码器以及Transformer模型,能够实现对代码长序列的优化处理。
本发明能完整地提取AST语法树中结构信息,将数据流图DFG与AST语法树结合提供数据流信息,并引入图注意神经网络,使函数注释生成网络模型同时提取到代码的语法、语义和时序等方面的信息,使生成的注释能更好地描述代码的功能;
通过代码分类,实现对不同编程语言的注释生成,VAE编码器通过引入噪声后能够将离散的空间转化为连续的空间,使得本发明能够更好地处理OOV问题。
作为优选的技术方案,本实施例中,所述代码类别分类神经网络采用循环递归网络RNN,循环递归网络RNN的训练过程为:
为原始代码标记对应的编程语言种类标签;
比如java代码的标签为”java”,python代码的标签为”python”等,本发明推荐使用已公开的数据集进行训练和测试,其中数据集都是对某一语言的集合,比如Cleaned_CodeSearchNet数据集中已经将代码分为java文件夹,python文件夹,javaScript文件夹等,举例来说,提取的代码为java文件夹下的代码,则贴上的标签应为”java”;
将原始代码进行代码分单词与清洗后转化为单词序列,代码分单词与清洗包括分单词操作、去除标点符号,例如输入代码为:
public static void main(String[] args) {System.out.println("Hello,World!");}
经过处理后的结果为:
public static void main String args System out println Hello World。
训练循环递归网络RNN:
使用词嵌入的方法将代码分单词与清洗后的代码转换为特征向量;
在数据集中取80%作为训练集、10%作为验证集以及取10%作为测试集;
使用循环递归网络RNN作为训练模型,利用特征向量及其对应的标签对循环递归网络RNN进行训练,其中,将交叉熵函数作为循环递归网络RNN的损失函数,交叉熵函数如下:
其中,M表示编程语言的类别个数;表示符号函数,取0或1,符号函数中,若数据集中样本i的真实类别等于c,取值1,否则取值0;表示样本i属于类别c的预测概率。
具体的,若所述交叉熵函数大于第一预设阈值,则根据所述交叉熵函数调整所述循环递归网络RNN参数,并继续执行对所述数据集的训练,直至损失函数满足预设阈值条件后,输出训练结果,得到训练好的循环递归网络RNN;
若所述交叉熵函数小于或等于所述第一预设阈值,则输出训练结果,得到训练好的循环递归网络RNN。
公式中M理解为,比如输入的编程语言类别有:java, python和javaScript,M则等于3;符号函数中,举例来说,若样本代码是java编程语言的代码,恰好此时c的类别是java,则就等于1。
作为优选的技术方案,本实施例中,步骤6包括:
构建基于图注意神经网络(Graph Attention Network, GAT)的第一编码器,用于从数据流语法图DFSG中提取与代码函数相关的信息,与代码函数相关的信息包含在数据流语法图DFSG的节点与边中,节点代表了代码中的某个符号,包括变量、常量以及函数;边表示代码中符号之间的关系,包括数据依赖关系、数据传递关系等。
在本发明中,使用数据流语法图DFSG训练第一编码器,其中G=(V,E)由其顶点V和边E定义的图,V是指数据流语法图DFSG中的节点,E是指数据流语法图DFSG中边。
步骤6.1: 使用节点嵌入技术将数据流语法图DFSG中的节点转换为节点嵌入特征向量;
步骤6.2:使用边嵌入技术将数据流语法图DFSG中的边转换为边嵌入特征向量;
步骤6.3:构建图结构数据,将点嵌入特征向量和边嵌入特征向量通过维度拼接进行结合,得到图结构数据特征向量;
步骤6.4:使用图结构数据特征向量训练第一编码器,输出特征向量。
在本发明中,节点嵌入技术包括DeepWalk, Node2vec, SDNE等,用于节点特征向量化。边嵌入的技术有TransE, DistMult等,用于将边表示为特征向量。
维度拼接是指将两个特征向量在某个维度上连接在一起,以实现特征组合,拼接的维度取维度,这取决于实际情况。在pytorch中,使用torch.cat()函数进行维度拼接。pytorch是基于Torch的python开源机器学习库,用于自然语言处理等应用程序,不仅能够实现强大的GPU加速,同时还支持动态神经网络。
作为优选的技术方案,本实施例中,步骤7包括:
步骤7.1:从特征向量提取均值特征向量和标准差特征向量;具体包括:
构建第一全连接层、第二全连接层作为隐层Φ和隐层ψ,通过隐层Φ和隐层ψ提取特征向量的特征信息;将第一全连接层的权重矩阵表示为Φw={Φ1, Φ2, … Φn},将第二全连接层的权重矩阵表示为ψw={ψ1, ψ2, … ψn};每个隐层的输出通过预设的激活函数Relu进行特征向量的非线性变换,使图注意神经网络能够学习和捕捉到更复杂的模式和特征,激活函数Relu的公式如下:
全连接层的个数可以根据实际需求进行调整。
术语解释:
非线性变换:指对输入的变量进行的变换,其变换关系不是线性关系,这样能够使模型更加复杂,能更好地拟合和解释数据。
将特征向量输入到隐层Φ输出后再通过激活函数Relu进行激活获得特征向量vΦ,将特征向量vΦ输入到隐层ψ输出后再通过激活函数Relu进行激活后获得特征向量vψ;
构建第三全连接层(即全连接层mu),权重矩阵表示为muw={ mu1, mu2, …,mun},用于从特征向量提取均值特征向量;
构建第四全连接层(即全连接层lv),权重矩阵表示为lvw= { lv1, lv2, …,lvn},用于提取标准差特征向量;将特征向量vψ分别输入到第三全连接层和第四全连接层,分别得到均值特征向量和标准差特征向量;
在VAE编码器中,均值特征向量和标准差特征向量都是通过神经网络自主学习后得到的结果。
术语解释:
(1)均值特征向量:均值特征向量是指潜在变量在潜在空间的平均位置,在本发明中可以理解为表示了一种代码的平均语义;
(2) 标准差特征向量:标准差特征向量表示了变量在潜在空间中的分散程度,它控制着模型在潜在空间中进行采样时的随机性,在本发明中可以理解为代码在语义空间中的不确定性或变化程度。
(3) 平均语义:指的是一组文本、句子或单词的平均含义或语义表达,比如:“猫是宠物”以及“狗是宠物”,这两个句子都涉及“宠物”的概念,通过单词特征向量嵌入以及VAE编码器网络学习,这个平均语义特征向量就可能捕捉到关于“宠物”这一概念的性信息。
步骤7.2:从转换为均值特征向量和标准差特征向量的全过程如图7所示。使用均值特征向量和标准差特征向量进行重参化,得到特征向量;即,重参化是因为基于VAE和基于GAN的模型都需要使用反向传播算法来对网络进行训练更新各网络层的参数,而反向传播算法保证网络中的每个操作都是可微分的,因此使用两个特征向量进行重参化;具体为:
反向传播算法是一种训练时优化神经网络的方法,通过前向传播计算网络输出和损失函数,然后反向传播梯度,逐层计算参数的梯度,这些梯度用于更新网络参数,通过梯度下降等优化算法最小化损失,能够使网络学习到输入数据的特征表示。
术语解释:
重参化:重新参数化的意思,参数化是指将某个过程、函数、模型等表示成一组参数的形式,重参化是一种特殊的参数化方法,用于处理对随机变量的采样操作。
计算标准差特征向量的标准差std,标准差std表示为:
在pytorch中,使用torch.exp(0.5*)的方法来获取std。
从高斯分布上随机采样噪声特征向量,噪声特征向量用于增加模型的鲁棒性,提高生成多样性;
术语解释:
(1) 噪声:在本发明中,噪声指的从高斯分布(也称正态分布)中抽取的随机性元素。在VAE编码器中,设定潜在空间中的每个点都可以生成观察到的数据,但为了引入一定程度的随机性,通常使用标准正态分布(均值为0,方差为1)的采样结果。这个随机性使得相似的输入在潜在空间中可能被映射到不同的点,增加了模型的表达能力和生成多样性。通过在潜在空间引入噪声,VAE编码器能够更好地捕捉代码中的不确定性和多样性,生成更富有创意和合理的注释;
(2)采样:采样指的从概率分布中选择元素或数值的过程,在本发明中指的是按照高斯分布的概率密度函数,在分布中随机选择点,这个点的坐标就构建为了噪声特征向量,引入随机性能够使每次采样后都可能得到不同的噪声特征向量,增强模型的鲁棒性和生成多样性。
基于均值特征向量、噪声特征向量,构建特征向量:
在本发明中,整个基于VAE编码器的网络模型的工作流程如图9所示。
作为优选的技术方案,本实施例中,所述采用训练代码函数数据和验证集对预设的函数注释生成网络模型进行训练,生成训练好的函数注释生成网络模型,包括:
将训练代码函数数据和验证集输入所述函数注释生成网络模型,生成对应的训练代码函数注释;
基于预设的损失函数,计算所述训练代码函数注释与关联的标准代码函数注释之间的多个轮次的平均损失值;
计算每一轮次的所述平均损失值与前一轮次的所述平均损失值之差,生成多个目标损失值;
若所有所述目标损失值的绝对值均小于预设的标准阈值时,停止训练,生成训练好的函数注释生成网络模型。
本实施例中,预设的损失函数由两部分组成,分别是:
(1) 重构误差,使用均方误差MSE表示,用于衡量特征向量与特征向量之间的差异,重构误差目标为最小化均方误差MSE,均方误差MSE表示为:
其中,n是样本数量,是第i个样本所对应的,是第i个样本对应的特征向量;
KL散度(Kullback-Leibler Divergence),目标损失值为最小化KL散度;表示为:
其中,μ表示潜在均值,σ表示潜在标准差,表示均值特征向量中的第i个元素,表示标准差特征向量中的第i个元素。
(2) BCE损失BCELoss,由判别器引入,目标损失值为最小化判别器的损失。
在训练过程中,损失函数通过MSE损失、KL散度以及BCE损失加权求和所得,在本发明中,总损失函数表示为:
total_loss = λ * MSELoss + μBCELoss+ ( 1-λ-μ ) * KLDivergence
其中,λ,μ表示权重,值由具体情况所决定,取值范围均为[0,1]。
为训练损失值设定阈值,包括:设定轮次数m以及标准阈值threshold,m与threshold的值由网络模型训练者根据实际情况决定。连续计算m个轮次的平均损失值,由此计算当前轮次的平均损失值与前一轮次的损失值之差,若所有损失值之差的绝对值都小于threshold,则停止训练,获得函数注释生成网络模型;反之,则按照预设梯度分别自动调整编码器、判别器以及解码器的参数。
作为优选的技术方案,本实施例中,步骤8所述通过目标解码器对目标代码函数数据中的预设特征向量进行解码,包括:
使用解码器对特征向量的编码特征进行解码,解码器根据特征向量以及上一阶段的输出预测当前阶段输出位置的内容,解码器输出概率分布,将最高概率对应的单词作为输出;若概率最高的单词不是未知单词,则输出最高概率对应的单词;否则,在目标代码所构成的目标向量词库以及代码向量词库中寻找目标替代词来代替未知单词。
概率分布表示在给定上下文情境下,输出下单词或字单词的可能性;
作为本发明一个实施例,
(1) 从第一文件、第二文件以及code_word.voc文件中获取所有数据,按行的方式遍历文件中的数据并存储为列表,分别记为code_process_list, code_record_list以及code_voc_list。
(2) 根据特征向量在目标向量词库中”vector”字段进行最相似匹配,本发明所采用的最相似匹配方法为余弦相似度,如果最相似的特征向量的余弦相似度小于设定阈值,则返回余弦相似度最大的特征向量所对应的键值对,比如特征向量与vector为[0.1,0.2,0.3]的值的余弦相似度最大,则返回'public': {'index': 0, 'vector': array([0.1, 0.2, 0.3])};否则,遍历code_voc_list列表,将code_voc_list中的每个元素记为code_voc,根据特征向量对code_voc中的值字段中的”vector”字段进行最相似匹配。code_voc的形式为key-value,即键-值。余弦相似度又记为余弦相似性,是通过计算两个特征向量的夹角余弦值来评估他们的相似度。
(3) 遍历code_record_list列表,将code_record_list列表中的每个元素记为code_record,将当前遍历的code_record_list元素的索引记为current_num,将code_record使用空格分隔后得到列表record_list;从record_list中取出索引为index的数据record;若record为0,表示对应位置的代码非分单词所得,则仅输出步骤(2)返回的数据所对应的key即示例中的“public”;若record为1,表示对应位置的代码由原始代码通过驼峰命名规则或者蛇形命名规则分单词所得,则在record_list中检索位置索引为index前后连续为1的所有索引,组成索引列表indexes,在code_process_list列表中查找索引为current_num的元素,记为code_process,将code_process使用空格分隔后得到列表process_list,再根据indexes从process_list中取出相应索引的单词。例如,解码器预测到的结果为:Function,则根据Function所在位置的前后连续为1的结果有:my FunctionName,因此解码器输出my Function Name。
作为优选的技术方案,本实施例中,所述判别器用于对特征向量打分,用于增强特征向量的质量;具体如下:
将原始注释通过词嵌入的方式编码成特征向量;
将特征向量与特征向量输入判别器中进行训练并打分,对特征向量打出高分,对特征向量打出低分;
在本发明中,判别器对特征向量打出的评分范围在[0,1]之间,对判别器进行训练所使用到的损失函数有:二元交叉熵损失函数BCELoss(Binary Cross Entropy Loss),即计算对抗损失,即判别器的判别误差;在计算之前分别为特征向量与特征向量贴上二元标签值1和0;
对判别器使用BCE损失函数进行训练,BCE损失函数表示为:
其中,是第i个样本的二元标签值;p()是第i个样本的打分结果,表示判别器对第i个样本的特征向量打出的评分。
需要说明的是,本发明在具体测试中使用的数据集是Cleaned_CodeSearchNet,Cleaned_CodeSearchNet数据集由Microsoft团队在原CodeSearchNet数据集上进行筛选所得到,由其数据集训练的CodeBERT和GraphCodeBERT已证明了其数据集的可行性。
实施本发明实施例,具有如下有益效果:
本发明旨在提高代码语法和语义的提取效果,并减少最终注释生成中会导致OOV问题的概率。通过将代码分单词以及清洗,同时记录分单词信息,通过将处理好的代码转换为抽象语法树AST语法树,并对AST语法树进行位置编码,随后从AST语法树中提取数据流图DFG,将数据流图DFG融入到AST语法树中形成数据流语法图DFSG,将数据流语法图DFSG送往网络模型中进行训练;
本发明旨在更精准地捕捉代码的结构、时序和潜在信息。具体而言,将数据流语法图DFSG输入到基于图注意神经网络GAT的编码器后得到饱含代码结构与时序信息的特征向量,然后将输入到基于VAE的编码器以得到其对应的标准差特征向量和均值特征向量,通过引入噪声以及特征向量运算后得到饱含代码潜在信息的最终特征向量;通过这个方法能够使模型更好地提取到代码的结构、时序和潜在信息,使生成的注释能更好地描述代码的功能;
本发明采用基于Transformer的编码器,引入单词库检索机制,用于处理解码器输出未知字段的情况,可以转而在代码单词库中进行单词组选择并输出,降低OOV问题的概率。
显然,本发明的上述实施例仅仅是为清楚地说明本发明所作的举例,而并非是对本发明的实施方式的限定。对于所属领域的普通技术人员来说,在上述说明的基础上还可以做出其它不同形式的变化或变动。这里无需也无法对所有的实施方式予以穷举。凡在本发明的精神和原则之内所作的任何修改、等同替换和改进等,均应包含在本发明权利要求的保护范围之内。