CCT5: A Code-Change-Oriented Pre-Trained Model
动机
软件是不断变化的,需要开发人员及时地执行一些派生的任务,例如为代码更改的意图编写描述,或者识别容易出现缺陷的代码更改。考虑到处理这些任务的成本可能占总开发支出的很大比例(通常约为70%),自动化这些过程将显著减轻开发人员的负担。
当前研究
- training deep learning models: 使用相对小规模的标记数据进行训练,难以学习和挖掘隐藏在大量未标记代码中的编程语言领域知识
- fine-tuning existing pretrained models: 很难充分利用预训练模型的所学知识,因为现有的预训练模型被设计为编码单个代码片段而不是代码更改(即两个代码片段之间的差异)。
本文方法
本文提出了一个专门为代码更改设计的预训练模型,以便更好地支持开发人员进行软件维护。为此,我们首先收集了一个包含150万+代码更改和提交消息的成对数据的大规模数据集。基于这些数据,我们进行策划五个不同的预训练任务,使模型具备关于代码更改的不同领域知识。我们在三个被广泛研究的任务上对预训练模型CCT5进行微调代码变更和两个特定于代码审查过程的任务。结果表明,CCT5在这些任务上优于传统的深度学习方法和现有的预训练模型。
背景
- 第一段:软件领域发展带来的问题(code change related tasks)
- 第二段:介绍研究现状(DL techniques)
- non pre-training
- achieve progress
- lack of trainging data, a large room of improvement
- a simple heurisitc 启发式方法 能够超过一个sophisticaed DL model 而且节省计算资源
- pre-training model
- large-scale unlabelled datasets with domain knowledge of PL and NL and fine-tune on tasks
- 然后点出文本的motivation;目前的预训练模型都是针对code-related tasks 比如 code search code summarization 和 defect detection 而不是针对code change related tasks;前者学习到的领域知识更多是代码片段的语义和语法信息,而后者code change学习的侧重于两个代码片段之间区别的语义和语法信息,并且两者输入输出也不匹配;
- 基于上述问题提出CCT5,旨在解决code change related tasks预训练模型的空缺;
- 做法:
- 1 构建数据集CodeChangeNet;
- 2 设计5个预训练任务训练模型;
- 最后一段写一个总结性的贡献:数据集、CCT5、性能评估;
- non pre-training
相关工作
数据集处理
CCT5
模型结构
- 基于T5模型,encoder-decoder各有12层Transformer层,每层有12个注意力头;
- 用CodeT5初始化CCT5,目的是赋予其程序语言的领域知识;
- 在5个不同任务上预训练并在很多下游任务上微调;
输入-输出表示
- 如何表示code change
- 如果将旧代码和新代码的序列直接输入到模型中,则输入将非常长,因为代码更改可能发生在不同的文件中,这可能使模型难以收敛;
- 本文中使用diff文件(通过对比新旧代码得到)来表示code change,因此文件中有三种类型的信息(1. “-”表示删减掉的代码,“+”表示增加的代码,已经用来提供上下文信息的未更改的代码);diff文件的好处是大幅度减少了输入的长度(未更改代码只出现了一次);
- 在下游任务中,follow CodeT5将code diff tokenizer成toekn sequence,例如在一个任务里写成
{ [ C L S ] , c 1 , … , c n , [ M S G ] , m 1 , … , m l } \{[CLS],c_1,\dots,c_n,[MSG],m_1,\dots,m_l\} {[CLS],c1,…,cn,[MSG],m1,…,ml},每行还会用 [ D E L ] , [ A D D ] , [ K E E P ] [DEL],[ADD],[KEEP] [DEL],[ADD],[KEEP]表示每行代码的特点;
预训练任务
CCT5的一个重要目标是准确捕获给定代码更改的语义信息。为此,我们需要在预训练阶段构建code change和commit message之间的语义连接。
- MLM(Masked Language Modeling)
-
MLM4CC (Masked Language Modeling for Code Change)
输入: code change and commit message
mask: code lines (不是token是为了维持code diff的完整性)per: 15%
commit message: 帮助code change进行填空任务,提高了NL-PL之间的联系
模型根据commit message中"Enable subqueries in gsheetsdb"这句话理解了code功能是赋予gsheetsdb能力,因此<MASK0>是allows_subqueries=False,而<MASK1>中将False改成了True。 -
MLM4CM (Masked Language Modeling for Commit Message)
输入: code change and commit message
mask: commit message tokens per: 15%(80%[MASK] 10%[Random] 10%[Unchanged])
code diff: 帮助commit message进行填空任务,提高了NL-PL之间的联系
- Code Change-Commit Message Dual Generation
follow CodeT5 设计了Code Change-Commit Message双向生成任务以提高模型连贯输出的能力;
- NL → PL Generation (NL2PL)
输入: old code ,commit message,其中old code用code diff中把[ADD]删除用[DEL]和[KEEP]来表示
输出: new code ([ADD]+[MASK]) - PL → NL Generation (NL2PL)
输入: code diff
输出: entire commit message
- CDG (Code Diff Generation)
follow GraphCodeBERT, a structure-aware pre-training task
(novelty: to our best knowledge, we are the first to involve program structure information when pre-training code-change-oriented models.)
Data flow
- it provides a way to understand the semantics of a variable by concentrating on where its value comes from, rather than focusing on the variable’s name, which is sometimes in poor quality
- it enables the model to consider the long-range dependency for variables with the same names but occur in distant locations.
nodes: variables
edges: two connected variables have dependencies
输入:old data flow、new data flow、old code
输出:code diff
格式: { [ C L S ] , o c 1 , … , o c n , [ S E P ] , V a r i a b l e A , V a r i a b l e B , [ E D G E ] , … , V a r i a b l e X , V a r i a b l e Y , [ S E P ] , V a r i a b l e A ′ , V a r i a b l e B ′ , [ E D G E ] , … , V a r i a b l e X ′ , V a r i a b l e Y ′ , } \{[CLS], oc_1,\dots,oc_n,[SEP],Variable_A,Variable_B,[EDGE],\dots,Variable_X,Variable_Y,[SEP],Variable_{A^{\prime}},Variable_{B^{\prime}},[EDGE],\dots,Variable_{X^{\prime}},Variable_{Y^{\prime}},\} {[CLS],oc1,…,ocn,[SEP],VariableA,VariableB,[EDGE],…,VariableX,VariableY,[SEP],VariableA′,VariableB′,[EDGE],…,VariableX′,VariableY′,}
- Final Loss: 5种loss的总和
实验
Task1: Commit Message Generation
开发人员通常没有足够的时间编写高质量的提交消息说明文档。然而,提交消息在软件维护中非常重要,因为它们描述了代码的更改意图,从而促进程序理解。因此,开发人员可以从自动生成提交消息中受益匪浅,因此这项任务成为软件工程界的热门话题。在此任务中给定了代码更改,自动生成一个简短的提交消息去总结其内容。
-
Baselines: NNGen、FIRA、CodeReviewer、CodeT5
-
Dataset: MCMD (Multi-programming-language Commit Message Dataset)
(如果有baseline在dataset上不能复现,那就要说清楚原因.例如文本中就说明了为什么FIRA不能在MCMD上测试,因为MCMD是多编程语言的,而FIRA只能在Java上测试以及文件不匹配等)。所以为了对比CCT5和FIRA,就在FIRA测试的数据集上测试CCT5的表现。 -
Metrics: B-Norm (BLEU的变体).
-
Results:
- 超过了预训练的方法CodeT5和CodeReviewer,也超过了非预训练的方法NNGen;
- 执行了Wilcoxon signed-rank test, 置信度超过95%;
- 点出缺点(CCT5在C++表现不好),但还是超过其他baslines,并分析原因(预训练时没有学到足够的C++领域知识);
- 与FIRA相比也更高,同时执行了Wilcoxon signed-rank test, 置信度超过95%;
-
Human Evaluation:
- 先解释为什么做人类评估(BLEU更多反映的是lexical gap,而不是semantic gap)
- 接着说明开展的细节(找学生、评估数量、评估指标的设定、分数的设定、匿名评估等)
- 最后展示结果并分析:从模型方面看:CCT5超过其他baslines,并解释原因(CCt5获得更多了语义信息因为它能提供丰富的code change信息同时生成更少的不相关信息);从指标方面看:expressiveness指标大家都很高,说明基本上生成的commit message都可读。
-
Case Stuty:
- 首先说明CCT5生成的commit message与ground truth语义很接近(都表达清楚了添加的绿色部分代码的含义);
- 接着对比其他basline,点出它们的不足(没有一个与ground truth语义接近),然后举了NNGen的例子说明它只点出了fix的意思,又举了CodeT5和CodeReviewer的例子说明它们想解释“merge pull request"或者”cleanup"而不是代码本身想打开LAMBDA_REMOTE_DOCKER的意图;
- 然后用人类评估的结果说明评阅者也是认为CCT5更好,将人类评估结果与case study的分析结合共同论证了CCT5更好这个观点,更加robust
- 具体地用结果数字论证了CCT5效果好(细节性的说明)
- 最后总结性地说明目前的预训练方法(CodeT5)或者特定数据训练的方法(CodeReviewer)在code-change-oriented人物上表现平平,而CCT5正好弥补了这些工作的空白;
Task2: Just-in-Time Comment Update
即时(JIT)注释更新任务旨在基于code changes自动更新代码注释,以便在程序的维护和发展过程中注释可以与代码保持一致,将帮助开发人员的理解程序。在这个任务中,输入是原始的代码注释和代码更改,而输出是新的代码注释。
- Baselines: Toper、CoditT5、CodeReviewer、CodeT5
- Dataset: follow Liu et.al
- Metrics: GLEU (BLEU的变体), Accuracy
- Results:
- 首先说CCT5在GLEU超过其他baseline而且生成的也更准确(Accuracy高),然后用数字具体说超过了多少;
- 执行了Wilcoxon signed-rank test, 置信度超过95%;
- 再说Accuracy超过了1/3,比其他baseline都高;
Task23: Just-in-Time Defect Prediction
即时(JIT)缺陷预测的任务旨在在提交更改时识别有缺陷的代码更改,以便开发人员可以得到通知,这些更改需要进一步检查。如今,它已成为大型软件公司软件进化的杀手。这个与代码更改相关的理解任务是一个二元分类:预测给定的代码更改是否有缺陷。
- Baselines: JITLine、JITFine、CodeReviewer、CodeT5
- Dataset: JIT-Defects4J
- Metrics: F1、AUC
- Results:
- 首先说CCT5在F1-score上比其他baseline高,分别用数字和预训练方法和非预训练方法比较;
- 接着说也超过了SOTA的hybrid方法JITFine;
- 然后说加上EF(expert features)之后,CCT5效果增加了,而且仍然是最高;
- 最后说上述现象说明CCT5是具有拓展性的,通过有用的特征可以提高性能表现;
讨论
CCT5能够做Code Review任务吗?
- code change quality estimation
- binary classification
- code review generation
- case study
- 首先用例子说明CCT5和ground truth都认为只需要执行函数而不需要有返回值;而CodeReviewer认为需要彻底删除这个函数,而这是不对的;
- 通过研究预训练数据集,发现了一些类似的code change;CCT5通过学习data flow的关系获取了相关的领域知识,这也是为什么它能生成语义正确的评论的原因;
- 最后总结说明CCT5比CodeReviewer效果好是因为它能学习到data flow中的知识;
每个独立预训练任务的贡献
- 消融实验
- 每个任务都对性能有贡献;
- PL2NL对性能影响最大,因为下游任务需要模型具有生成通顺的自然语言的能力;
- 缺失CDG任务时GLEU下降明显,说明结构化信息对模型效果也很重要;
有效性方面的威胁
- 外部威胁
- 其他下游任务:automated patch correctness assessment, bug-fixing patch identification, untangling commits etc.
- 内部威胁
- baseline的code和参数都是用的作者开源的;
- 防止数据泄露把项目信息都删去;
总结
一共四句话:
- Motivation
- method
- 一句话说方法
- 一句话说具体实现
- 实验结果