本文整理自北京航空航天大学软件开发环境国家重点实验室副教授罗杰的主题分享——基于大模型的代码生成及其发展趋势。
模型驱动的
代码生成
代码生成问题是软件工程和人工智能领域的一个经典难题,其核心在于针对给定的程序需求说明,生成符合需求的程序代码。
经典研究主要采用模型驱动的代码生成方法,通过采用形式化建模语言建立严格的需求和设计模型,再通过基于编译规则的代码生成方法,从形式语言模型等语义等价转换到程序代码,以保证程序代码和需求的一致。
这种方法从理论上说是完美的,甚至可以通过对编译规则的证明来确保形式语言模型和程序代码之间保持完全一致,但是它的问题也很突出:模型驱动代码生成方法成立的前提是需要建立一个形式语言模型。
通常来说,需求都是通过自然语言进行描述,因此需要有理解需求并熟悉形式语言建模的人才,在理解自然语言需求的基础上,将其建模为形式语言的模型。但是这一步相对比较困难,且消耗代价很高。因此,这种方法目前只在一些小领域,如机载软件的开发中得到应用。这一应用场景可以接受比较高的开发代价,但不能在软件开发场景中进行大规模推广。
基于大模型的
代码生成
近年来,随着人工智能的发展,研究人员开始尝试一条不同的路径,即基于预训练大规模语言模型进行代码生成。该方法的基本思想是基于自然程序代码的预训练,获得一个能够理解这个代码的大语言模型。基于这样的语言模型,可以采用自然语言的需求描述或其他提示,通过预训练代码大模型直接生成满足需求的程序代码。
如上图所示,这种方法首先会通过自然语言文本、一种或多种程序语言代码进行模型预训练,生成预训练语言模型,将模型在面向具体任务的数据上进行一些微调,就可以得到面向具体代码生成任务的生成模型。通过该模型大量生成的代码样本,可以通过某种后处理程序,从大量的样本中筛选出正确的代码,并作为最终的生成结果。
从以上结构中可以看到,基于大模型的代码生成,核心就是“代码大模型”,目前其主要类别可以分成三类:
- 左到右语言模型,比如GPT系列模型,典型代表比如CodeParrot、Codex、PolyCoder模型,均采用了此种语言模型架构。
- 编解码的语言模型,比如最近DeepMind推出的AlphaCode,就是基于编解码模型架构来进行实现。
- 掩码语言模型,这类方法主要是基于BERT架构来进行实现。
目前的代码大模型,从整体上出现了一定的特点,从代码参数规模上整体呈现增长趋势。研究人员尝试着训练这种更大规模的预训练代码大模型,观察它在不同领域里可能的应用。
代码大模型的
发展现状
接下来对目前最新的一些代码大模型进行简单介绍。
第一个模型是MIT提出的PolyCoder模型,它采用了GPT-2架构,使用程序设计语言的代码进行预训练,使用了12种程序设计语言的代码,却并没有使用任何自然语言的文本进行预训练。可以看出,这样的代码大模型,用它生成程序测试时,能够直接通过测试的概率非常低,虽然生成更多的样本,测试通过概率会更高,但本质上看,它的正确率整体来说还是非常低。所以,预训练代码大模型直接生成的程序代码质量相对较低。
第二个模型是DeepMind提出的AlphaCode,它的框架基于编解码器架构,与PolyCoder相同,也是基于多种程序设计语言进行模型的预训练,使用了12种不同的程序设计语言。在AlphaCode编解码器设计架构时,采用了异构与非对称结构,在编码器部分,虽然使用的层数较少,但维度较大,这部分主要用于处理输入的自然语言描述的需求和提示。在解码器部分,采用了比较多的层数,但比较小的维度,专门用来生成代码。通过这种架构,就能够在同样的参数规模下更好地提高代码生成质量。
DeepMind的研究人员同样发现了从预训练语言模型里生成的代码质量相对较低。所以,他们采用了后处理的策略进行筛选和过滤,以得到正确的代码。他们试图通过生成海量样本的形式,从中找到正确的生成代码。
从实验结果中得出,生成的样本数量越大,获得正确代码的概率越高,甚至已经可以从百万级代码中筛选正确代码。同时我们发现,通过需求中给出的测试样例可以过滤掉99%的生成样本,在所有问题里,有10%的问题找不到一个能够通过需求给出测试样例的生成样本,更找不到正确的代码生成结果。因此,预训练语言模型直接输出代码的质量还是不太理想。
微软研究人员提出了代码生成方法“Jigsaw”,它采用了和DeepMind同样的策略,通过对代码的后处理方式提高生成代码的质量。与DeepMind不同的是,他们采用了程序代码的修复方法进行代码质量的提升。
实验结果中可以看到,从预训练代码大模型直接生成代码正确的概率较低。代码大模型倾向于使用出现频率高的变量名,而不是用户给定的变量名,可能会导致静态语义错误。代码大模型还倾向于重复犯同样的语法和语义错误,如左右括号不匹配的语法错误),逻辑运算的语义错误。
此外,Salesforce提出了CodeGen模型(A Conversational Paradigm for Program Synthesis),通过大型语言模型进行对话式程序生成的方法,将编写规范和程序的过程转换为用户和系统之间的多回合对话。它把程序生成看作一个序列预测问题,用自然语言表达规范,并对程序进行抽样生成。同时,CodeGen(16B)在HumanEval benchmark上已经超过OpenAI's Codex。
目前,PaddleNLP已经内置代码生成CodeGen模块,可以通过Taskflow一键调用。代码生成模型的好坏,一般可以通过求解一些算法题来评估。这里以 LeetCode第一题[1]为例,尝试让PaddleNLP模型自动补全代码。题目如下所示:
给定一个整数数组nums和一个整数目标值target,请你在该数组中找出和为目标值target的那两个整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。你可以按任意顺序返回答案。
1.Taskflow一键调用
代码语言:javascript复制from paddlenlp import Taskflow#Taskflow调用codegen = Taskflow("code_generation", "Salesforce/codegen-2B-mono")prompt = "def twoSum(nums, target):n hashmap={}n for ind,num in enumerate(nums):n hashmap[num] = indn for i,num in enumerate(nums):"code = codegen(prompt)print(prompt)print(code[0])
2.输出结果
代码语言:javascript复制def twoSum(nums, target): hashmap={} for ind,num in enumerate(nums): hashmap[num] = ind for i,num in enumerate(nums): if target - num in hashmap and hashmap[target - num]!= i: return [i,hashmap[target - num]]
3.提交到LeetCode验证,执行结果显示通过
使用同样的调用方法,针对LeetCode第三题[2],PaddleNLP也通过了测试。这次我们的Prompt仅为函数名:
代码语言:javascript复制def lengthOfLongestSubstring(self, s: str) -> int:
题目如下图所示:
给定一个字符串s,请你找出其中不含有重复字符的最长子串的长度。
示例 1:
输入: s = "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
除此之外,Prompt也可以为自然语言,例如注释、功能表述等,同样可以生成与之对应的代码。
代码语言:javascript复制Prompt = "# this function prints hello world"Model Output = def hello_world(): print("Hello World")hello_world()
当前代码大模型
存在的问题
北京航空航天大学软件开发环境国家重点实验室与百度合作,在飞桨平台上进行的大模型代码生成实验,也发现上述类似问题,比如会生成一些无意义的代码或者重复的代码。这些都会导致代码大模型的方法在进行应用时会出现问题。
当前代码大模型采用了“淘金”模式,从大量的泥沙里挑选金子。从软件工程角度,它的编码模式可以称为比较粗糙的Code&Fix模型,通过计算机的算力进行整体输入,通过不断试错或海量试错找到符合需求的正确代码,但这样的做法风险高、缺少质量控制、效率低。
综上所述,我们可以思考,是否可以提出一些新的代码生成方法,以提高代码生成的效率,这是未来一个可能的研究方向。
代码大模型
未来发展趋势展望
我们发现,目前的代码大模型是使用与自然语言大模型相同的架构来实现的。但实际上,自然语言和程序设计语言之间的差别较大,自然语言语法复杂不严格,层次结构不清晰,语义不严谨,表达存在多义性。而程序设计语法简单严格、层次结构清晰、语义严格确定、表达不具有二义性,总体上看,是一种递归结构。
我们或许可以构造一个新型代码大模型架构,使其生成的程序更加符合程序语法和静态语义——这也是未来代码大模型发展的方向之一。
在实验过程中,大模型在代码生成时,会复制训练数据中的代码片段,导致生成代码出现版权问题。之所以会出现这种现象,是因为与目前大模型架构的学习理解的能力较弱,以记忆为主的特点相关。
未来的大模型可能会从记忆代码片段到学习人类编程的模式,而不是记忆代码片段。
总体来说,我们希望代码大模型未来能够得到更长远的发展,更好地学习代码中的编程模式,提高软件开发效率。
以上就是我的分享,谢谢大家。
本文转载自:AI大模型