Page 25 - 《软件学报》2024年第4期
P. 25
杨宏宇 等: 基于多模态对比学习的代码表征增强预训练方法 1603
近年来, 大规模语言模型已成为自然语言处理及其相关领域的强大工具, 展现出惊艳的性能和多样的应
用潜力. 这些模型的成功, 促使研究者开始思考: 是否能将其强大的表示学习能力应用于代码智能领域? 同
时, 编程语言(programming language, PL)和自然语言(natural language, NL)有诸多相似之处: 都具有可重复并
带有可预测的统计学规律, 所以自然语言处理领域中很多的方法在代码智能领域同样适用. 于是, 研究者尝
试将自然语言处理中能够自监督学习的预训练模型, 如 Transformer [23] , BERT [24] , RoBERTa [25] , GPT [26] ,
BART [27] 等应用到代码表征中. 为此, 编程语言预训练模型 [28−32] 被提出, 并逐渐统一了生成类、理解类和自回
归任务,得到的代码的通用表示能在下游任务上复用. PLBART [28] 是 BART [27] 在编程语言方面的变体, 将文本
级的注释或者语义级的代码字符单独作为代码的特征进行预训练. CodeBERT [29] 是 BERT 在编程语言上的双模
态扩展,将注释和代码字符融合在同一个序列中以表征代码. GraphCodeBERT [30] 在 CodeBERT 基础上进一步添
加了数据流图的变量序列作为代码结构级特征的补充表示, 并设计了数据流边预测和变量结点对齐等预训练
任务.然而, 在从 AST 中提取数据流时, 只考虑了存在数值流动关系的代码字符, 这导致部分 AST 结构信息的
遗漏.针对数据遗漏的现象, SynCoBERT [31] 直接使用完整的 AST 作为结构信息的代表, 并将文本级、语义级和
结构级特征融合在一个输入序列进行预训练, 同时设计了多模态对比学习、AST 边预测和标识符预测等 3 个
预训练任务. 随后, UniXcoder [32] 提出了新的融合 AST 和代码字符的一对一映射算法, 以引入结构级特征并缩
短特征序列. 虽然这些编程语言预训练模型在代码智能领域取得了一定的效果, 但它们尚未完全利用代码的
各个层次特征(文本级、语义级、功能级和结构级). 目前, 集成所有特征面临以下挑战: 如何减少不必要的结
点引入以及如何有效缩短特征序列长度, 同时节省存储、传输和计算资源. 目前尚未有一个预训练模型能够
集成所有特征, 现有模型各自涵盖的特征层次各不相同. 因此, 对于综合多个层次特征的编程语言预训练模
型, 仍然需要进一步的研究和探索.
图 1 REcomp 优化的 AST 序列化算法的示例
为了充分挖掘代码各个层次的特征并更加准确地表征代码的语义信息, 本文提出了一个新的编程语言预
训练模型, 称作 REcomp. 它旨在融合代码的文本级的注释、语义级的代码字符、功能级的函数名和结构级的
AST, 并通过设计多模态对比学习的预训练方法来学习这 4 个特征之间的语义等价性. 与其他领域有所不同,
在代码智能研究中, 将代码不同视角或层次的特征称为代码不同的模态, 因此, 多个特征的融合称为多模态
表征. 之所以选择多模态对比学习的方法对代码进行建模, 是因为它可以通过共享学习的方式将代码的不同
模态特征进行交叉融合, 从而进一步提高模型表征代码语义的能力. 这种共享学习的方式不仅减少了多个单
一模态模型的训练和推理过程, 也减少了计算资源的开销. 此外, 本文还设计了两种新的数据增强方法, 即编
程语言型(PL 型)和自然语言型(NL 型), 以此构建正负样本进行对比学习.
[2]
最后, 本文在公开基准 CodeXGLUE 数据集上进行了实验, 验证了所提模型的有效性. REcomp 很大程
度地减少了资源的的消耗, 仅使用了极少的计算资源就达到了极快的训练速度, 并且在极短的时间内收敛.
以初始化模型 UniXcoder 为例, REcomp 仅使用了约 UniXcoder 算力资源的 1/20, 就将训练至收敛的时间约缩
短为 UniXcoder 的 1/32. 在语义代码检索任务上, REcomp 在 CodeSeachNet [33] 数据集上提升了约 1.9%的准确
率; 在代码克隆检测任务上, REcomp 在 BigCloneBench [34] 数据集和 POJ-104 [35] 数据集分别取得了 4%和 0.9%
准确率的提升. 本文的主要贡献如下:
(1) 设计了一种优化的 AST 序列化方法, 它在保留 AST 中控制结点信息并且不破坏树结构的前提下,
按序地将非叶结点的结构信息和叶结点的语义信息融合, 得到语义级-结构级的复合特征. 相比