Page 26 - 《软件学报》2024年第4期
P. 26
1604 软件学报 2024 年第 35 卷第 4 期
SBT [13] , 此算法消除了结点冗余和括号重复的现象, 极大程度地缩短了 AST 特征序列, 更简短且精
准地表示 AST;
(2) 设计了两种特别的数据增强方法: PL 型和 NL 型, 集成编程语言 4 个不同层级的特征. PL 型旨在学
习符合编程语言特点的特征的语义等价性, NL 型可以弥合自然语言与编程语言的语义鸿沟;
(3) 提出了多模态对比学习预训练目标, 用于增强模型的代码表征能力, 从而提升模型的下游任务
表现.
本文第 1 节介绍 REcomp 所涉及的相关工作, 包括预训练编程语言模型、多模态学习和对比学习. 第 2
节详细地阐述 REcomp 的模型架构. 第 3 节描述 REcomp 的有关实验. 在第 4 节总结全文工作.
1 相关工作
本文方法和预训练编程语言模型、多模态学习和对比学习的现有研究之间存在相关性, 下面对这些相关
内容进行介绍.
1.1 预训练编程语言模型
预训练模型首先通过一个或者多个任务来预先学习相对泛化的知识, 然后在微调阶段, 利用学到的具体
[3]
知识进行下游任务 . 本节将简要地介绍 CodeBERT [29] , GraphCodeBERT [30] , UniXcoder [32] . 这 3 个将分别作为
REcomp 预训练的初始化模型, 它们都是在开源基准数据集 CodeSearchNet [33] 上进行预训练的.
CodeBERT 模型架构与 RoBERTa [25] 相同, 利用多层双向 Transformer [23] 进行自监督学习. CodeBERT 由 12
个相同的层组成, 每层的维度大小为 768. 模型参数总数达到 125M. CodeBERT 的掩码语言建模目标用的是带
有函数注释的双峰数据, 然后替换令牌检测目标进一步训练在双峰和单峰样本上, 旨在学习一个代码字符是
否是原始的. 在微调阶段, CodeBERT 在语义代码检索和源代码文档生成上的实验表明, 它优于监督学习的
方法.
GraphCodeBERT 在 CodeBERT 基础上结合了代码的数据流, 在预训练阶段对变量之间“值从哪里来”的数
值传递关系进行编码. 除了掩码语言建模, 它还引入了两个新的数据流结构感知的预训练任务:数据流图边预
测和变量间结点对齐. GraphCodeBERT 利用 CodeSearchNet 的双峰数据进行预训练, 针对代码检索、克隆检
测、代码翻译和代码细化等任务微调. 实验表明, 其微调结果超过了 CodeBERT.
UniXcoder 在 GraphCodeBERT 基础上将 AST 作为结构级特征, 是一种跨模态的编程语言预训练模型.它
设计了一个前缀适配器, 这个适配器通过掩码注意力矩阵来控制模型的行为, 这统一了理解任务、生成任务
和自回归任务. 它设计了一个 AST 和代码字符一对一的映射方法, 旨在将结构信息和语义信息融合. 此外,
它通过跨模态生成任务在不同编程语言之间的对齐表示来学习代码的通用表征.它在 9 个公开数据集上的 5 个
代码相关的任务上进行评估, 结果表明, UniXcoder 在大多数任务上都达到了显著的效果.
CodeSearchNet 是含有 6 种编程语言的数据集, 分别包含双峰数据(注释-代码)约 213 万条和单峰数据(没
有注释的代码)约 645 万条. CodeSearchNet 数据集在 6 种语言上的数据详情见表 1.
表 1 关于 CodeSearchNet 的数据统计
编程语言 Ruby Java JavaScript PHP Python Go All
单峰数据 164 048 1 569 889 1 857 835 977 821 1 156 085 726 768 6 452 446
双峰数据 52 905 500 754 143 252 662 907 458 219 319 256 2 137 293
1.2 多模态学习
多模态学习可以通过利用多模态数据之间的信息互补性, 从多源数据中学到更好的特征表示, 有利于下
游任务的学习 [36] . 因为编程语言含有多个抽象层次的特征, 所以用单个特征来表示编程语言是远远不够的,
很难覆盖所有视角. 并且不同的模态都是代码表示的平行语料, 具有语义等价性. DeepCS [37] 是第一个用 RNN
融合功能级的 API 序列、函数名和语义级的代码字符等特征的代码表征模型. 然后, Comformer [38] 开始关注结