随着BERT等预训练模型在自然语言表示学习中大放异彩,在代码智能领域,许多基于源代码的预训练语言模型被提出用来对代码的上下文进行表示学习,并支撑了各种代码智能下游任务,例如代码补全、代码搜索和代码摘要等。尽管当前基于Transformer的预训练代码表示模型在不同任务上取得了不错的性能,其可解释性方面仍然缺乏研究,导致目前尚不清楚它们为何能够工作以及它们到底可以捕获哪些特征相关性。为此,我们进行了结构化分析,旨在从不同的视角探究源代码预训练模型的可解释性,并得到了一些有趣的发现。
该成果 “ What Do They Capture? - A Structural Analysis of Pre-Trained Language Models for Source Code ” 已被国际顶级会议ICSE 2022录用。ICSE是软件工程领域的旗舰会议。
论文链接:
https://dl.acm.org/doi/abs/10.1145/3510003.3510050
摘要
近些年来,已经提出了许多用于源代码的预训练语言模型来对代码的上下文进行建模,并作为下游代码智能任务的基础。然而,目前在现有预训练代码模型的可解释性方面进展甚微,尚不清楚这些模型为何起作用以及它们可以捕获哪些相关特征。基于此,我们进行了详细的结构分析,旨在从三个不同的角度为源代码预训练语言模型(例如CodeBERT和GraphCodeBERT)提供可解释性。具体包括:(1)注意力机制分析,(2)代码预训练模型词嵌入探究,以及 (3) 语法树归纳。通过综合分析,我们得到一些有意思的发现,可能会启发未来的研究。具体发现包括:(1)注意力分布与代码的语法结构高度一致,(2)代码预训练语言模型可以在每个Transformer层的中间表示中嵌入代码的语法结构, (3) 代码预训练模型具有归约代码语法树的能力。这些发现表明,将源代码的语法结构合并到预训练过程中以获得更好的代码表示可能会有所帮助。
背景与动机
代码表示学习(也称为代码嵌入)的目标是将代码语义编码为分布式矢量表示,并在基于深度学习的代码智能模型中扮演重要角色。代码嵌入可用于支持各种下游任务,例如代码补全代码搜索和代码摘要等。受到通过Mask语言建模预训练的自监督模型在自然语言处理(NLP)取得惊人效果的启发,在开发针对软件工程任务的大规模代码预料库预训练模型方面做出了一些成就,例如关于源代码和自然语言描述的双模态预训练模型CodeBERT。随着各种代码预训练模型逐渐成为主流,理解这些模型为什么能工作,以及它们到底捕捉到了代码的什么信息,变得尤为迫切。
在自然语言处理社区中,从注意力分析和任务探测的角度来解释预培训的语言模型,例如BERT。这种研究已成为“BERTology” 的子方向,它重点研究BERT模型的内部机制。但是,在软件工程中,这种理解尚未实现。通常,我们会看到预训练语言模型在各种软件工程任务中都能达到卓越的性能,但不明白它们为什么效果好。虽然到目前为止已经进行了几项实证研究,旨在研究代码嵌入的有效性。但是,这些研究只显示了代码嵌入技术在哪些情况下效果更好,而没有解释为什么代码嵌入能获得良好效果的内部机制。即,在软件工程任务的背景下,仍然不清楚预训练语言模型能得到这么好结果的内在原因以及它们在预训练过程中捕获哪些信息。为此,我们探讨了代码预训练模型的可解释性。更具体地,我们尝试回答以下问题:现有的预训练语言模型可以了解编程语言编写的源代码的语法结构吗?解决这个问题在理解深度神经网络的学习结构方面发挥着重要作用。我们提出了三种不同的分析方法进行了详细的结构分析,旨在为代码预训练模型(例如,CodeBERT,GraphCodeBERT)提供可解释性。
初步探索
从自然语言处理领域的可解释性研究中可以探得,Transformer中的自注意力机制(Self-Attention Mechanism)具有捕获自然语言语法和语义等信息的能力。基于此灵感,我们可视化并调查了单个代码片段的预训练模型的注意力分布情况,如图1所示。其中 (a) 显示了带有抽象语法树(AST)的Python代码片段,我们将代码的AST语法结构定义为由其非叶子节点和其子女组成为其一个基元(motif)结构,并认为代码的语法信息可以由一系列基元结构表示。
图1 CodeBERT中单个代码片段中self-attention的可视化分布
图1 (b) 和 (c) 所示中,我们发现其在一定程度表现出了类似于抽象语法树的语法结构。具体来说,我们观察到(b)中的一些模式经常在自注意热图中表现为明确的水平线或不同大小的矩阵块,或两两单词之间的热力值比周围高亮。由于输入的序列中,一个单词的注意力分布对应一个热图中的一行,这些模式的表现说明存在一组单词,且同一组的单词在语法树中的表现为处于同一个父节点下,也就是符合基元结构。这些现象都表明模型中确实存在一些与语法树结构相匹配的模式,因此我们从三个不同的视角对以CodeBERT和GraphCodeBERT为代表的源代码预训练模型进行了详细的结构化分析。
自注意力机制分析
直观地,注意力权重的不同可以表示代码词素(Token)关注的信息不同,权重越大表明越关注此词素。在这里,我们认为在抽象语法树结构中处于同一个父亲节点下的词,在注意力机制分布中应该有被注意到。具体地,我们计算了在AST中属于处于同一个父亲节点下的关系的注意力分布占总注意力分布的比例。该分数分析了注意力分布如何与树结构关系相一致,如下公式所示:
其目标是探究语法树中对齐的节点对占所有节点对的比例,即针对一对词素,如果其在抽象语法树中拥有同一个父节点,且它们在模型中通过注意力机制相连,则表明注意力机制捕获到了它们之间的语法信息。图2展示了三种常见编程语言(Python、Java和PHP)计算的结果。在该图中,我们给出了每一层每一个注意力头(head)的分布情况,其展示的是注意力分布和AST之间的一致性,其中高分数表示注意力在当前层当前注意力头上与AST中的语法结构明显一致。
图2 CodeBERT和GraphCodeBERT在不同编程语言(Python、Java和PHP)上的注意力和AST之间的一致性
词向量探测分析(Word Embedding Probing)
如图3左图所示,在抽象语法树中,我们假定两个节点之间的距离为边的数量且边的长度为1的话,则可认为抽象语法树结构中节点与节点之间满足L2距离的平方。
图3 词向量探测分析
因此,可以通过一种结构探针“structural probe“,计算词向量在高维语义空间(比如1024维)中的距离,并将其映射到语法树中词与词之间的距离,借此观察词向量是否嵌入了语法树信息。如图4,显示了给定输入Python代码片段的标准词与词之间的的距离以及给定代码预训练模型词向量计算的词与词的距离,结果表明模型的词向量确实在训练的过程中捕捉到了代码语法信息。
图4 基于Python中的预训练的CodeBERT和GraphCodeBERT模型,金标准距离和预测距离的热图
语法树规约(Syntax Tree Induction)
根据距离公式可以计算出词与词之间的距离,与前一个方法有所不同的是,这里只计算了相邻之间的距离。我们认为处于同一个父节点下的词,其注意力分布是相似的,即它们之间的注意力分布和输出向量的距离之差很小。通过两两之间距离的差值,我们通过简单递归算法生成二叉树结构。通过观察它与抽象语法树之间的关系,我们能够探究预训练模型是否归纳出代码的语法信息。
图5列出了在Python测试数据集上的各种语法树规约模型的结果。结果表明从预训练模型中可以归纳出一定程度的代码语法树结构。
图5 基于Python语言的语法树规约结果
总结
通过以上三种不同的视角进行探测分析,揭示了几个可能启发未来研究的发现:
(1)代码表示预训练模型的中间表示向量中蕴含了代码的语法结构;
(2)预训练模型能够通过注意力机制捕捉到代码的语法信息。
总的研究结果表明,在代码表示学习的过程中考虑代码语法结构有利于模型性能的提升。
详细内容请参见:
Yao Wan, Wei Zhao, Hongyu Zhang, Yulei Sui, Guandong Xu, and Hai Jin. 2022. What Do They Capture? - A Structural Analysis of Pre-Trained Lan- guage Models for Source Code. In 44th International Conference on Software Engineering (ICSE ’22), May 21–29, 2022, Pittsburgh, PA, USA. ACM, New York, NY, USA, 12 pages.
https://doi.org/10.1145/3510003.3510050
网友评论已有0条评论, 我也要评论