赞
踩
本文提出了一种新颖的方法:AST-based Neural Network
下图是一段来自开源软件项目的源代码
方法分为三步:
astnn 的目标是学习更多关于源代码的语法和语义信息,而不是最先进的基于ast的神经模型。它具有通用性,可用于许多与程序理解相关的任务,如源代码分类和代码克隆检测。
基于树的神经网络
基于树的神经网络(TNNs)——接受ast作为输入。给定一棵树,TNNs 通过自底向上递归计算节点嵌入来学习它的向量表示。最具代表性的基于树的ast模型有递归神经网络(RvNN)、基于树的CNN (TBCNN)和基于树的长短期记忆(Tree-LSTM)。
现有工作的限制
这三种基于树的方法有两个主要的局限性。
首先,在基于梯度的树拓扑训练中,通过反向传播结构来计算梯度。由于程序的复杂性,ast的结构通常又大又深,尤其是嵌套结构。因此,从叶节点到根节点的自下而上的计算可能会遇到梯度消失的问题,并且很难捕获长期依赖关系,这将错过一些由距离根节点很远的节点携带的语义,例如叶节点中的标识符。
其次,现有的基于树的方法将ast视为二叉树,将父节点的三个或更多子节点移动到新的子树中进行简化,这改变了源代码的原始语义,使长期依赖问题更加严重。
本节将介绍基于AST的神经网络(ASTNN)。ASTNN的整体架构如图2所示。
首先,将源代码片段解析为AST,并设计一个先序遍历算法,将每个AST分割为语句树序列(st-树,它是由作为根的语句节点和相应的语句AST节点组成的树),如图1所示。
所有st-树都由语句编码器编码为向量,表示为e1,····等。然后我们使用双向门控循环单元(Bi-GRU)来建模语句的自然性。Bi-GRU的隐藏状态通过池化采样到单个向量,这是代码片段的表示。
AST 的拆分和 st树序列的构造是通过一个遍历器和一个构造器直接实现的。
这样的做法保证了一个新的 st树是按照源代码中的顺序追加的。这样,就得到 st树的序列作为ASTNN的原始输入。选择 st树,因为语句是携带源代码语义的基本单元。我们的实验结果表明,所提出的语句级粒度更好,因为它在st树的大小和句法信息的丰富度之间有很好的权衡
① 语句向量:
设计了一个基于RvNN的语句编码器,用于学习语句的向量表示。
本文采用恒等函数。类似地,我们可以递归地计算和优化 st-树 t 中所有节点的向量。
另外,为了确定节点向量的最重要特征,所有节点都被推入堆栈,然后通过最大池化(max-pooling) 进行采样。
我们通过下面这个公式得到 st-树 的最终表示形式和相应的表述,其中N为 st-树 的节点数。
e
t
=
[
max
(
h
i
1
)
,
⋯
,
max
(
h
i
k
)
]
,
i
=
1
,
⋯
,
N
(
3
)
e_t=\left[\max \left(h_{i 1}\right), \cdots, \max \left(h_{i k}\right)\right], i=1, \cdots, N (3)
et=[max(hi1),⋯,max(hik)],i=1,⋯,N(3)
这些语句向量可以捕获语句的词汇级和语句级语法信息。
② 批处理
直观地看,虽然父节点的子节点数量不同,但该算法可以动态地检测出所有可能的位置相同的子节点,并将其放入组中,然后利用矩阵运算批量地加快每组方程2的计算速度。
基于 ST-tree 向量序列,本文将利用 GRU(门控循环单元) 来跟踪语句的自然度(naturalness)
给定一个代码片段,假设我们从AST中提取出了ST树 T,令
Q
∈
R
T
×
k
=
Q \in \mathbb{R}^{T \times k}=
Q∈RT×k=
[
e
1
,
⋯
,
e
t
,
⋯
,
e
T
]
,
t
∈
[
1
,
T
]
\left[e_1, \cdots, e_t, \cdots, e_T\right], t \in[1, T]
[e1,⋯,et,⋯,eT],t∈[1,T]
表示 ST-树 序列中已编码的 ST-树 向量,在时间 t 内,转换方程为:
r
t
=
σ
(
W
r
e
t
+
U
r
h
t
−
1
+
b
r
)
z
t
=
σ
(
W
z
e
t
+
U
z
h
t
−
1
+
b
z
)
h
t
~
=
tanh
(
W
h
e
t
+
r
t
⊙
(
U
h
h
t
−
1
)
+
b
h
)
h
t
=
(
1
−
z
t
)
⊙
h
t
−
1
+
z
t
⊙
h
~
t
(
4
)
其中:r是重置门,用于控制前一状态的影响
zt 是更新门,用于组合旧信息和新信息
ht是候选状态,用于与上一状态ht-1一起完成线性插值,以确定当前状态
ht,W,,Wz,Wh,Ur,Uz,Uh∈Rk×m是权重矩阵,而br,bz,bh 是偏差项。
通过迭代计算所有时间步骤的隐藏状态后,可以得到这些语句的自然顺序。
为了进一步增强递归层获取依赖信息的能力,本文采用双向GRU,将两个方向的隐藏状态连接起来,形成新的状态,如公式5所示:
h
t
→
=
G
R
U
→
(
e
t
)
,
t
∈
[
1
,
T
]
h
t
←
=
G
R
U
←
(
e
t
)
,
t
∈
[
T
,
1
]
h
t
=
[
h
t
→
,
h
t
←
]
,
t
∈
[
1
,
T
]
(
5
)
与语句编码器类似,这些状态的最重要特征将通过最大池化或平均池化进行采样。考虑到直观上,不同语句的重要性是不相等的。例如,MethodInvocation 语句中的API调用可能包含更多的函数信息,因此本文默认使用最大池化来捕获最重要的语义。模型最终生成一个向量:
r
∈
R
2
m
r \in \mathbb{R}^{2 m}
r∈R2m即目标代码片段的向量表示。
ASTNN是通用的,它可以被训练作为源代码片段的特定任务向量表示,为许多程序理解任务描述不同的源代码语义。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。