分享嘉宾 | 卢帅

整理 | 王子彧

出品 | CSDN(ID:CSDNnews)

2023 年 3 月 25 日下午,在 CSDN 与《新程序员》联合主办的“新程序员(NPCon)——AIGC 与大模型技术应用峰会”上,微软亚洲研究院高级研究工程师卢帅受邀出席,并发表了题为《基于预训练的代码理解与生成》主题演讲,与现场开发者围绕智能代码生成展开激烈的观点碰撞。

微软亚洲研究院高级研究工程师 卢帅

以下为卢帅的现场演讲实录。

大家好,我今天分享的主题是《基于预训练的代码理解与生成》。本次分享的内容主要包括微软亚洲研究院团队在过去几年中在预训练模型方面的实践经验,以及如何将预训练模型应用于具体的代码智能任务和场景中。

什么是代码智能?

近年来,代码智能逐渐成为关注焦点,它巧妙地融合了人工智能与软件工程领域。其主要目标在于使模型掌握自动化代码理解与生成的技能,而其核心挑战则是如何让模型理解并推断代码背后的意图。如今,最好的 AI 解决方案便是采用预训练模型。

如何进行代码预训练?

代码预训练的灵感来源于自然语言预训练。将代码语言视为自然语言,其预训练范式非常简单。

首先,我们可以从软件工程领域的开源社区中获取高质量的代码库,例如 GitHub 开源社区。接着,我们可以将这些代码库构建成一个预训练的语料库或数据集。最后,我们将所得到的代码视为一串文本,直接输入到模型中进行预训练,就可以得到一个完整的预训练框架。

之前的 GPT 系列训练、GitHub Copilot 和 OpenAI 提出的 Codex 等常用的代码补全工具都使用了预训练框架,但是这些模型并没有经过较多的优化。

源代码和自然语言有何不同?

如果站在一个软件工程的角度来看,源代码和自然语言有一些区别,通过这套框架所进行预训练,可能只探索到了源代码的冰山一角。

源代码和自然语言的不同之处在于它有非常明确的结构性,源代码可以解析成一个非常明确的抽象语法树,其中包含控制流信息和数据流信息。这些信息可以在预训练技术中让模型学习,从而促进模型对源代码的理解。

源代码还有不同的展现形式。比如带 bug 代码是否会影响预训练模型的输出内容?但是,如果合理运用,预训练模型可能会帮助人们判断代码是否有错误,甚至修复错误。另外,Code Diff 是代码审查场景中广泛使用的形式。如果让预训练模型学习 Code Diff,它也可以帮助一些特定场景,比如代码审查。此外,底层代码如汇编代码可能会让预训练模型学习到代码的最底层逻辑等等。

团队尝试

微软亚洲研究院团队在代码与训练模型上起步较早。

2020 年初,提出了首个将文本和代码结合作为训练的模型——CodeBERT。随后,我们对其进行了不断的优化,例如加入一些代码特有的信息。这些尝试都是基于 foundation models 的探索之一。其次,对一些特定的具体的代码应用场景做了较深入尝试,比如 Code Generation 和 Code Review。最后,为学术界提供了一个 Code benchmark 数据集,方便大家评估和测试自己的模型。

首个代码+文本预训练模型 CodeBERT

代码智能的核心挑战在于如何让模型理解和推断代码背后的意图。注释是我们人类通常使用的自然语言,因此在阅读代码时,如果代码前面有注释,理解它就会更容易。在预训练模型发展到编程语言之前,预训练模型已经在自然语言上获得了很多知识,如 BERT。因此,让模型快速扩展到编程语言上的关键是将编程语言和自然语言连接起来。

在处理源代码时,我们可以提取与之相关的注释,将它们作为一对输入直接输入到模型中。这种做法可以帮助 CodeBERT 模型更好地理解和推断代码背后的意图。这是团队最初的尝试,未涉及代码的特殊性信息分析。在之后的工作中,我们需要将代码的特有结构信息融入预训练模型中,以进一步提高模型的表现能力。

GraphCodeBERT:建模代码变量关系

我们考虑到代码的结构性以及可能蕴含数据流的信息,因为数据流包含了代码当中丰富的语义信息。为了将代码的结构信息融入预训练模型中,我们采用以下具体做法:

首先,将一段源代码解析成其抽象语法树。其次,从抽象语法树中提取出变量序列,并分析变量在语法树上的路径关系,以抽取出变量之间的关系。如上图最右侧图表示在代码执行时,数据流会从哪个变量流向其他变量,这就包含了代码执行的一些语义信息。如果将其融入预训练模型中,可以增强模型对代码的理解能力。

将这些代码结构信息融入预训练模型的具体方法是,在 CodeBERT 的基础上,将变量序列拼接到文本和代码中,并将原来的注意力机制改为只能看到与自己相关的变量或有数据流向的变量的注意力。从而使模型获得数据流信息。由于我们成功地建模了语义信息,GraphCodeBERT 在代码理解任务上的表现要比 CodeBERT 更好。

UniXCoder:统一代码预训练

2022 年,我们提出了统一代码预训练模型框架 UniXCoder。在此之前,自然语言和代码的生成和理解往往需要采用两种不同的范式。对于理解性模型,通常采用纯编码器结构,例如 CodeBERT 和 GraphCodeBERT。如果需要进行生成任务,则需要采用解码器结构。基于这一背景,我们在 UniXCoder 中将这两种范式进行了结合。

具体而言,我们使用不同的预训练任务和注意力机制,使模型能够同时进行代码理解和生成任务。同时,我们也将包含结构性信息的抽象语法树融入到 UniXCoder 的预训练中,以进一步提高模型的表现能力。

在 GraphCodeBERT 时,团队就设想将抽象语法树融入预训练模型中。但当时我们受到了两个问题的限制,其中一个问题至今仍未完全解决。第一个问题是模型所能接受的输入长度是有限的。对于理解性模型来说,输入长度可能为 512 个词,现在可能已经提高到了 1024 个词。因此,我们当时将输入长度提高到了 1024,才能够将语法树结构的信息融入到模型中。因为语法树结构比正常的代码要长 1-2 倍,如果将其全部输入模型,则输入长度就会爆炸。

第二个问题是,transformer 结构的预训练模型无法直接处理树形结构的输入。因此,如果要将树形结构输入模型,就需要将其拍扁。一般来说,拍扁的过程有两种方法:深度优先和广度优先。但无论采用哪种遍历方法,都会丢失一定的信息。为了解决这个问题,我们在遍历时采用了深度优先遍历,并添加了左边界和右边界的特殊标记,使得它在回溯时可以一一对应。这样,可以将抽象语法树与相应的序列一一对应。

在训练过程中,我们将代码和抽象语法树的信息随机输入到模型中,使得模型在训练时既可以学习序列化的代码信息,又可以学习结构化的代码信息。经过多轮训练后,模型就可以同时具备这两种能力。

UniXCoder 在当时的 10 项常见代码智能任务中,包括代码克隆、代码补全、代码生成、代码摘要生成等等任务上,取得了非常不错的结果。

在代码克隆检测任务中,UniXCoder 展现了出色的成果。该任务的定义是从候选代码库中搜索与当前代码具有相同功能的代码。因此,对于代码预训练模型的理解能力要求很高。

UniXCoder 的方法是将每个代码片段通过预训练模型输出为一个向量,并比较向量之间的距离,选择与当前搜索向量最相似的代码片段。

如图所示,与 OpenAI-embedding 相比,UniXCoder 的效果更好,因为 AST 提供了更丰富的代码信息,从而能更好地表示代码。

如何将预训练的模型应用于具体的代码智能任务和场景?

首先,是代码生成场景,我们主要关注的就是代码补全。

GPT-C:多语言代码补全模型

它提供了代码补全的插件,可以在 VS Code 上下载使用。无论是哪种模型,甚至是 ChatGPT,基础的训练框架都是给定上文预测下一个 token 的训练范式。同时,GPT-C 在 10 种编程语言上都可以做代码补全。

微软研究更注重在预训练模型的基础上加入一些优化。这些优化既适用于规模稍小的模型,也适用于规模更大的模型。我们的优化从以下几个方面入手。

优化一:扩展上下文模型技术

首先,一个问题是模型输入长度的限制。GPT-C 当时限制输入长度为 1024,而 GPT-3 和 GPT-3.5 最大支持的输入长度可能是 4096 个 token。需要注意的是,token 并不是词,因为在训练模型时,每个词都需要经过一层词表编码到模型中。词表并不是按每个词来计算的,而是按某种特殊的子词计算的。

GPT-4 发布了两个版本,一个版本支持 8192 个 token。另一个版本暂未发布,它可以支持 32000 个 token,大大提高了输入长度,缓解了这个问题。但是,如果使用相同的训练框架来训练一个完全相同的模型,时间和内存开销将非常大。

因此,我们提出了扩展上下文模型技术。通过限制模型的输入长度,并根据一些手动规则定义优先级,可以将更重要的信息放入有限的输入长度中。这种方法可以在不增加模型复杂度的情况下,提高模型的性能和效率。

首先,需要获取代码的具体语法树。其次,根据一些定义规则,对各语法单元进行优先级的定义。比如,当前待补全函数的签名和注释、所在类的签名、文件 import 和所定义的全局变量等,都可能对当前所写函数有重要的作用。接下来,我们认为当前函数所在类的成员函数或全局属性的优先级可能排第三。

最后,根据优先级获取上下文,将其填满模型输入窗口。这种方法比将上文直接输入更有效,因为它可以确保更重要的信息被纳入考虑范围。

 优化二:Grammformer 生成代码骨架

另一个优化方法是 Grammformer,它用于生成代码骨架。这种方法抛弃了从左到右生成的方式,让代码具有非常强的结构性。每一步都从其生成式入手,从而能够保证其语法正确性。这种方法可以解决从左到右生成代码的缺陷,从而保证代码的语法正确性。

具体的结构如上图所示。最下面的两个 expression 最初为空,我们需要选择接下来应该扩展哪个 expression。通过从语法生成式入手,让模型去生成正确的代码结构。不断地循环迭代,直到完成。由于语法树的叶子节点通常是数字、自定义标识符或变量名等,因此让模型进行推荐或留空有很多好处。

留空的好处在于,人在编写代码时很难预测需要定义的变量名是什么。如果模型提供了一个不太好的建议,反而会影响用户的体验。而留空则能够增强用户的体验。因此,在选择扩展哪个 expression 时,我们需要权衡推荐和留空的优劣,并根据具体情况进行选择。

优化三:ReACC 基于检索相似代码的补全模型

“在编写代码时,并不是所有的代码都是程序员自己原创的。”

ReACC 是一种基于检索相似代码的补全模型。它的基本思想是将未完成的代码作为输入,从一个大的代码库中检索出与当前代码在语义上相似的代码,并将其作为生成模型的输入。ReACC 的好处在于,它可以提供更准确的代码补全建议,因为它是基于实际的代码库进行搜索和推荐的。同时,它还可以帮助程序员学习如何编写更好的代码,因为程序员可以看到他人是如何处理类似问题。

在 Python 中使用补全模型可以显著提高编程效率,特别是在处理大量重复代码时。在 Python 上效果最强的 Codex 模型可以从我们的框架中受益,进一步提高其准确性和效率。

CodeReviewer:预训练模型带来代码审查自动化

CodeReviewer 是一个针对代码审查场景的自动化工具,它利用人工智能和预训练模型来优化和提高开发效率。在代码审查场景下,可以通过以下三种任务来使用人工智能或预训练模型来优化和提高开发效率:

1. 评估代码更改的质量:在代码审查过程中,我们需要评估代码更改的质量,以确保代码的正确性、可读性和性能。

2. 辅助生成代码审查意见:在代码审查过程中,审查人员需要提供有关代码更改的意见和建议。

3. 代码优化:在代码审查过程中,审查人员需要对代码进行优化,以提高代码的性能和可读性。

综上所述,代码审查的三个重要的步骤,都可以用 AI 来去提升效率。

如图所示,开发者添加了一个新的函数,需要进行代码审查。如果审查人员反馈的信息量很少,那么开发人员可能无法理解审查人员的意见,也无法及时修复问题。但是,如果使用 CodeReviewer,它可以基于预训练模型和机器学习算法来分析代码更改,并自动生成相关性强、有信息量的审查意见。

大模型时代仍需优化模型结构,覆盖更广泛智能代码场景

GPT 系列的前两代在代码场景中的表现非常有限,只能够完成一些简单的代码补全工作。但是,GPT-3 的推出及其表现引起了广泛关注,GPT-4 更是在参数量上取得了大幅提升,能够覆盖绝大部分的代码场景。

但是,目前 GPT-4 仍然存在一些问题,例如缺少代码语法树等信息、无法对项目级代码进行分析等。此外,个性化模型问题也是未来需要思考的方向之一。

在大型模型时代,GPT-4 的优化方向已经从增加参数量转变为从数据优化和训练方式的角度。但是,当前的研究方向仍然需要继续探索如何让神经网络模型更好地理解程序,以覆盖更广泛的智能代码场景。

卢帅及其团队的下一步研究方向是如何让神经网络模型更好地理解程序,而不是简单地增加模型的参数量。他们认为,未来的发展趋势应该是在探讨如何利用大模型来完成任务的同时,进一步优化模型的结构,以覆盖更广泛的智能代码场景。

点击阅读原文或在CSDN视频号观看『新程序员大会(NPCon):AIGC 与大模型技术应用峰会』直播回放视频。

☞GPT-4 遭投诉要求禁用,OpenAI 为何成为众矢之的?
☞现在就是成为“新程序员”的黄金时刻!
☞挑战微软 + GitHub!谷歌联手 Replit,升级 AI 编程“神器”:曾拒绝微软 10 亿美元的收购

让模型理解和推断代码背后的意图是预训练模型的核心挑战 | NPCon演讲实录相关推荐

  1. 如何获取高精度CV模型?快来试试百度EasyDL超大规模视觉预训练模型

    在深度学习领域,有一个名词正在被越来越频繁地得到关注:迁移学习.它相比效果表现好的监督学习来说,可以减去大量的枯燥标注过程,简单来说就是在大数据集训练的预训练模型上进行小数据集的迁移,以获得对新数据较 ...

  2. 【AI开源大模型】GLM-130B:开放的中英双语预训练模型

    文章目录 GLM-130B:开放的中英双语预训练模型 摘要:何为 GLM-130B? 快速上手 环境配置 自回归文本生成 / 中间文本填空 Example 1 Example 2 (Chinese) ...

  3. 关于NLP相关技术全部在这里:预训练模型、图神经网络、模型压缩、知识图谱、信息抽取、序列模型、语法分析、文本处理...

    在过去几年时间里,NLP领域取得了飞速的发展,这也推动了NLP在产业中的持续落地,以及行业对相关人才的需求. 但这里我们要面对的现实是,行业上90%以上的NLP工程师是"不合格的" ...

  4. word2vec模型评估_干货 | NLP中的十个预训练模型

    Word2vec, Fasttext, Glove, Elmo, Bert, Flair pre-train Word Embedding源码+数据Github网址:https://github.co ...

  5. 腾讯基于预训练模型的文本内容理解实践

    分享嘉宾:赵哲博士 腾讯 高级研究员 编辑整理:张书源 爱丁堡大学 出品平台:DataFunTalk 导读:预训练已经成为自然语言处理任务的重要组成部分,为大量自然语言处理任务带来了显著提升.本文将围 ...

  6. MedicalGPT:基于LLaMA-13B的中英医疗问答模型(LoRA)、实现包括二次预训练、有监督微调、奖励建模、强化学习训练[LLM:含Ziya-LLaMA]。

    项目设计集合(人工智能方向):助力新人快速实战掌握技能.自主完成项目设计升级,提升自身的硬实力(不仅限NLP.知识图谱.计算机视觉等领域):汇总有意义的项目设计集合,助力新人快速实战掌握技能,助力用户 ...

  7. 腾讯开源大规模X光预训练模型及代码 |MICCAI 2020

    论文导读 " 预训练模型能够加速任务模型收敛速度和提升模型性能.自然场景图像有ImageNet预训练模型,但此类数据和医学图像差异较大.因此腾讯提出了一个基于70万X光数据进行训练的模型,以 ...

  8. 深入理解深度学习——预训练模型

    分类目录:<深入理解深度学习>总目录 近些年基于深度学习的NLP技术的重大进展主要包括NNLM(2003).Word Embedding(2013).Seq2Seq(2014).Atten ...

  9. Paddle加载NLP的各类预训练模型方法总结(以文本分类任务为例,包含完整代码)

    一.Introduction 最近宅在家,有空只能搞搞NLP的比赛.由于缺乏GPU的加持,只好白嫖百度的AI Studio(毕竟人家提供免费的Tesla V100).在此不得不赞扬一下优秀的国产深度学 ...

最新文章

  1. 为什么要打jar_生活在西北的兰州人过春节为什么要打太平鼓?
  2. 加速 cinder 删除volume速度
  3. PCB 零件尺寸图:Arduino Mega 2560 尺寸
  4. [Vue 牛刀小试]:第八章 - 组件的基础知识
  5. DROP TABLE、TRUNCATE TABLE和DELETE的区别
  6. python笔记之while循环
  7. h5关于选择器以及class的小加强
  8. java 根据时间范围自动算间隔_Java根据开始时间结束时间计算时间间隔 x年x月x日...
  9. mysql定制化_【MySQL技巧】定制你的MySQL命令行
  10. ubuntu 的问题,我一个人使用,却显示两人登录?
  11. R_ggplot2基础(三)
  12. 深度强化学习之近端策略优化(Proximal Policy Optimization)
  13. linux调sqlloader命令,Linux环境SQLLDR导入出现SQLLOADER-553、509错误
  14. 【光学】基于matlab介电常数计算【含Matlab源码 1926期】
  15. java多线程并发测试工具_【漫画】JAVA并发编程之并发模拟工具
  16. C++黑客项目:U盘病毒免疫器
  17. You are creating too many HashedWheelTimer instances.
  18. Delphi程序破解技术概要
  19. 从虚拟主机迁移数据至VPS/云主机/独立服务器的方法
  20. 2021衡阳田家炳高考成绩查询,衡阳2021高考最高分多少分,衡阳历年高考状元资料...

热门文章

  1. 【计算机网络】Transmission-Control-Protocol拥塞控制
  2. DD-WRT端口绑定两个端口合并带宽
  3. html5图层重叠,如何在html5中的canvas下实现ps中的叠加效果?
  4. 阿瑞斯病毒手游怎么在电脑上玩?阿瑞斯病毒安卓模拟器使用教程
  5. 外汇天眼:即使与世界第一的差价合约提供商交易也会被骗!
  6. SDU 和 PDU区分
  7. 记一次从kindle云端阅读器爬取书籍
  8. 文献管理软件CNKI E-study学习心得
  9. E-study使用记录
  10. Java 字节数组流之图片转成字节数组