谷歌提出最新的基于规则和机器学习混合的代码补全方法
日益复杂的代码对软件工程的生产率提出了关键挑战。代码补全是一种重要工具,有助于缓解集成开发环境(IDE)中的这种复杂性。通常,代码完成建议使用基于规则的语义引擎(semantic engines,SE)实现,这些引擎通常可以访问完整的存储库并理解其语义结构。最近的研究表明,大型语言模型(例如Codex和PaLM)可以实现更长更复杂的代码建议,因此,出现了有用的产品(例如Copilot)。然而,由机器学习(ML)支持的代码补全如何影响开发人员的生产力,而不仅仅是感知的生产力和可接受的建议,这个问题仍然悬而未决。
今天,我们将介绍如何将ML和SE结合起来,开发一种新的基于Transformer的混合语义ML代码补全,现在可供内部谷歌开发人员使用。我们讨论了如何通过(1)使用ML对SE单标记建议重新排序,(2)使用ML应用单行和多行补全并使用SE检查正确性,或(3)使用单标记语义建议的ML的单行和多行延拓来组合ML和SE。我们将10k以上的Googler的混合语义ML代码完成情况(跨越八种编程语言超过三个月)与对照组进行比较,发现当暴露于单行ML完成时,编码迭代时间(构建和测试之间的时间)减少了6%,上下文切换(即离开IDE)减少了7%。这些结果表明,ML和SE的结合可以提高开发效率。目前,3%的新代码(以字符为单位)是通过接受ML完成建议生成的。
补全transformers
代码补全的一种常见方法是训练transformer模型,该模型使用自注意力机制进行语言理解,以实现代码理解和完成预测。我们处理类似于语言的代码,用子词标记和句子段词汇表表示,并使用TPU上运行的编码器-解码器-转换器模型进行完成预测。输入是围绕光标的代码(约1000-2000个令牌),输出是一组完成当前或多行的建议。序列是通过解码器上的波束搜索(或树探索)生成的。
在谷歌monorepo的训练期间,我们屏蔽了一行的其余部分和一些后续行,以模拟正在积极开发的代码。我们在八种语言(C++、Java、Python、Go、Typescript、Proto、Kotlin和Dart)上训练单个模型,并观察到所有语言的性能都得到了改善或相同,从而消除了对专用模型的需要。此外,我们发现,约0.5B参数的模型大小可以在低延迟和资源成本的情况下很好地权衡高预测精度。该模型极大地受益于单一回购协议的质量,这是由指导方针和审查强制执行的。对于多行建议,我们迭代应用具有学习阈值的单行模型来决定是否开始预测下一行的完成情况。

使用ML对单个令牌建议重新排序
当用户在IDE中键入代码时,会在后端同时从ML模型和SE交互请求代码完成。SE通常仅预测单个令牌。我们使用的ML模型预测多个令牌,直到行尾,但我们只考虑第一个令牌来匹配SE的预测。我们确定了前三个ML建议,它们也包含在SE建议中,并将其排名提升到首位。然后,重新排序的结果在IDE中显示为对用户的建议。
实际上,我们的SE在云中运行,提供开发人员熟悉的语言服务(例如语义完成、诊断等),因此我们将SE配置为在与执行ML推理的TPU相同的位置上运行。SEs基于一个内部库,该库提供了低延迟的类似编译器的功能。由于设计设置,请求是并行完成的,ML通常更快地提供服务(中位数约40毫秒),我们不会给完成增加任何延迟。我们观察到,在实际使用中,质量有了显著提高。对于28%的已接受完井,由于提升,完井排名更高,在0.4%的情况下更差。此外,我们发现用户在接受完成建议之前键入的字符减少了10%。



