CodeT5: Identifier-aware Unified Pre-trained Encoder-Decoder Models for Code Understanding and Generation
摘要
最近,BERT和GPT等自然语言(NL)的预训练模型已被证明可以很好地转移到编程语言(PL),并在很大程度上使一系列与代码相关的任务受益。
尽管取得了成功,但大多数当前的方法要么依赖于仅编码器(或仅解码器)的预训练,这种预训练对于生成(或理解)任务来说不是最优的,或者其(编码器-解码器)以与NL相同的方式处理代码片段,忽略了PL的特殊特征,如token类型。
我们提出了CodeT5,这是一个统一的预训练编码器-解码器Transformer模型,可以更好地利用开发人员分配的标识符所传达的代码语义。
我们的模型采用统一的框架来无缝支持代码理解和生成任务,并允许多任务学习。
此外,我们提出了一种新的标识符感知预训练任务,使模型能够区分哪些代码token是标识符,并在它们被掩码时恢复它们。
此外,我们建议通过双峰双生成任务利用用户编写的代码注释,以实现更好的NL-PL对齐。
综合实验表明,CodeT5在理解任务(如代码缺陷检测和克隆检测)以及跨PL-NL、NL-PL和PL-PL等各个方向的生成任务方面明显优于现有方法。进一步的分析表明,我们的模型可以更好地从代码中捕获语义信息。
编码NL和PL
利用PL或PL-NL作为输入,使用哪个取决于代码片段是否具有注释,对于NL-PL输入,将两种类型信息串联后编码,其中编码向量中利用cls作为开头,sep作为分隔符。
利用标识符(变量、函数)等代码特有的特征来获取丰富的代码语义
将programing language 编译成抽象语法树,提取树中每个节点的类型,并将代码标记序列构造利用二元标签位串编码,其中编码位0表示该token不是一个标识符,编码为1表示他是一个标识符
预训练任务:标识符感知去噪预训练
掩码跨度预测
去噪序列到序列(Seq2Seq)预训练已被证明在广泛的NLP任务中非常有效。这种去噪目标通常首先用一些噪声函数破坏源序列,然后要求解码器恢复原始文本。
在这项工作中,作者利用了类似于T5的跨度掩蔽目标,该目标随机掩蔽任意长度的跨度,然后在解码器处结合一些哨兵标记预测这些掩蔽的跨度
采用15%采样率,跨度期望为3
子词标记化之前通过采样跨度来使用整个词掩码,这旨在避免掩码部分子标记(?)
预训练多语言共享模型,学习更强的跨语言表示。
标识符标签
目的:辨认一个词是否为标识符
手段:将编码器对PL段的输出映射为概率序列,让模型进行分类。
请注意,通过将任务转换为序列标记问题,模型有望捕获代码的代码语法和数据流结构(?)。
交叉熵介绍 : 交叉熵
掩码标识符预测
不同于MSP, MIP将所有的PL中的标识符都进行掩码,并为每一个标识符赋予一个唯一的标记,这不会改变代码语义。
MIP将每个标识符的掩码和标识符本身组织成一个序列,通过自回归预测掩码值。
这要求模型能够深刻理解代码语义,感知到标识符的数据流向。
双模态双向生成
在预训练阶段,由于模型只关注孤立的标识符和掩码段,这可能导致预训练结果不能很好的用于下游任务,因为下游任务往往需要生成流畅的文本或语法正确的代码片段,需要看到联系。
为了减小预训练和微调任务的差距,提出了利用NL-PL双模态数据来训练,通过将每一个NL-PL数据点构造出两个反向的训练实例:一个是从PL生成NL,另一个是从NL生成PL,并为其加上对数据类型的描述信息,生成训练样本。通过同时在模型中优化两个训练目标,取得文本和代码之间的更好对齐。
Fine-tuning
通过迁移学习和多任务学习调优
迁移学习在理解和生成任务上进行
多任务学习同时在一个共享模型上训练多个任务,通过共享参数提升泛化性能。文中对每个任务使用统一的模型,单允许设置不同的最佳检查点。为了区分不同任务,设置了统一格式的任务控制代码并将其加入到输入中。为了解决不同任务数据集的大小不同的问题,采用了平衡采样策略进行采样。
实验设置
预训练数据集
CoodeSearchNet + C/CSharp from BigQuery
利用抽象语法树提取标识符并过滤各编程语言的保留字
结果表明不同编程语言有不同的标识符比例。
Code-specific Tokenizer
BPE分词
添加额外的特殊标记([PAD]、[CLS]、[SEP]、[MASK0]、…、[MASK99])
在整个训练集上训练,包括不可打印字符,但低频词将被过滤
结果:分词长度减小,有利于训练和促进代码生成任务。
下游任务和评价指标
下游任务:
- 交叉生成任务:代码总结和代码生成
-
code-to-code 任务:代码翻译和代码调优
-
基于代码理解的任务:缺陷检测和克隆探测
比较模型:encode-only(graphcodebert), decode-only, encode-decode model
评价指标:BLEU-4 scores and exact match (EM) accuracies 等
模型配置
在微调阶段,、发现CodeXGLUE(Lu等人,2021)中的任务对一些超参数非常敏感,如学习率、训练步骤和批量大小。
解决方案:进行网格搜索,并根据验证集选择最佳参数。
结果分析
通过设置不同大小的模型进行比较能有效排除size的影响
同时在预训练,预训练+双模态训练,预训练+多任务微调得到了多组结果。
Code Summarization
和encode-only 相比:确认仅编码框架对于生成任务来说不是最优的。
和其他decode-encode 相比:标识符感知去噪预训练和更好地利用双峰训练数据
Code Generation
CodeT5可以在标识符感知预训练的帮助下更好地理解代码语法和语义
Code-to-Code Generation Tasks
code translation
显示了编码器-解码器模型在代码到代码生成设置中的优势
它还表明,BLEU分数不是代码生成任务的完美评估指标,有时更高的分数可以反映神经模型的有问题的复制问题。
code refinement
专注于精确匹配(EM)指标来评估此任务
指出更长的代码片段更难修复错误
Understanding Tasks.
使用编码解码器框架,CodeT5仍然可以很好地适应理解任务
Effects of Bimodal Dual Generation and Multi-task Learning
Bimodal Dual Generation
双模态预训练为CodeT5 small和CodeT5基础上的代码摘要和生成任务带来了持续的改进。
然而,这种预训练任务对PL-PL生成和理解任务没有帮助,有时甚至会略微影响其性能。
可能原因: 这是因为双峰双代学习了PL和NL之间更好的对齐,这自然有利于涉及PL和NL的先前任务。作为副作用,这一目标可能会使模型偏向PL-NL任务,并影响其在PL-PL任务上的性能。
multi-task learning
改进除代码翻译和缺陷检测之外的大多数下游任务。
特别是,它大大提高了代码摘要的性能,因为代码摘要占据了子任务的最大部分(十三分之六),从而从多任务学习中获益最多。
改善了代码修复(code refinement):可能受益于中小型数据的联合训练,另一个可能的原因是,具有缺陷检测的多任务训练将使模型能够更好地理解错误检测的代码语义,这也是代码修复的必要中间步骤(缺陷检测性能下降,代码修复性能上升?)
Analyzing Identifier-aware Pre-training
通常,删除其中一个目标会降低所有任务的性能,这表明所有目标都有助于更好地理解我们的CodeT5代码
然而,每个目标的效果因任务而异。
具体而言,删除MSP将大大降低所有生成任务的性能,但会提高缺陷检测性能。这表明,掩码跨度预测对于捕获生成任务的句法信息更为关键。
相反,删除MIP对缺陷检测任务的伤害最大,这表明它可能更侧重于代码语义理解。
通过结合这些目标,我们的CodeT5可以更好地从代码中捕获语法和语义信息。
标识符感知去噪预训练可以更好地区分和利用标识符信息
对于MIP和MSP,只用其中一个任务取预训练会使得其在另一个未被使用的任务中取得极差的结果。
有趣的是,我们发现,在MSP任务中,仅MIP目标有在掩码数量预测的正确性上有较好的性能,反之不然。这意味着从多对一映射到一对一映射更容易适应,反之则很难。
结论是,将它们结合起来可以帮助我们的模型在这两项任务上做出良好的权衡
标签:Pre,Unified,NL,训练,Models,代码,任务,标识符,PL From: https://blog.csdn.net/2301_80351584/article/details/144032744