AI编程辅助 | 基于代码生成模型的实践 精华
一、编程辅助例子
GitHub Copilot[1]基于OpenAI的Codex[2]模型(GPT-3[3]的后代)实现,可以在代码编写的时候实时地提供代码补全建议和注释,并且在多个编辑器的插件市场都可以下载使用。
不管是从Copilot官网上的例子,还是在互联网上搜索关于Copilot的使用案例,你都可以发现它比一般的代码补全工具更为先进和灵活,它不仅能补全代码,更能创造代码,通过理解使用者简单的自然语言指令,它能够按照这些指令直接构建代码片段,并且正确率超过4成。
图1 Copilot示例-注释生成代码
另外在代码补全功能上Copilot每次可以提供多个建议,你可以从多个候选项中选择合适的代码片段进行补全。
图2 Copilot示例-代码补全
抛开上面这些较为“先进”的功能,Copilot是否能在日常工作中真正地帮助程序员提升工作效率呢?从笔者使用的经验上来说,Copilot最大的作用在于可以帮我们解决掉大量重复的、枯燥乏味的代码编写工作,而且越是这样重复的代码Copilot补全预测的越精确,这样一来你大部分的精力和时间只需要花在最核心最富有创造力的部分上,而那些脏活累活就由“AI”帮你完成,程序员的工作效率和身心健康都能得到极大地提升。下面是一些Copilot在实际业务场景中使用时较为出彩的例子:
- 程序日志记录:比如在Java或者Golang中使用日志组件打印一些调试信息或者记录一些变量信息,每次使用时都需要写一长串代码,而使用了Copilot后你刚打出logging,后面的代码就自动补全了,你需要的变量信息、日志的级别、格式化字符串都已经生成完毕。
- 条件判断&循环体:判断某个数值变量是否在一个范围中或者各种条件判断,比如Python中写了个for循环前面又有个数组没用过,就立马帮你补全上for item in items。
- 模板代码:例如 React 中,每次用 useState 都要写一行模板性的初始化代码。如果第一个变量名是 someVariable,第二个一定是 setSomeVariable。这种根本不需要过脑子的东西,最适合 Copilot 补全了。
二、背后的技术
1.Codex模型
Copilot工具背后真正的基石是Codex,是一个基于 GPT 的语言模型,在阅读了Codex原始论文后,笔者发现它是GPT-3使用代码文本数据进行了Fine-Tuning之后的产物,在模型的结构上Codex没有做任何创新的地方。
这里是比较有意思的地方,因为GPT系列模型的卖点就是从来不做微调,而且GPT3跟 GPT本质上差别也不大,所以Codex创新不在于模型的本身,而是在于实际的应用上面,这时候去使用微调这样的方法无疑性价比更高,也是合理的。
另外的创新点在于他提出了一个HumanEval的数据集来衡量模型的好坏,在这个数据集上Codex能够解决28.8%的问题,相比之下如果直接使用GPT-3则解决不了任何问题。另外如果允许sampling的话(模型跑100遍,得到100个不一样的结果,只要其中一个正确就算解决问题)能提升到70.2%的成功率。总而言之Codex没有做特别大的改动,它提出了一个问题,然后把GPT-3在大量代码组成的数据集上微调了一下并尝试解决这个问题,最后使用了一个全新的评测数据集来评判代码生成质量的好坏。
论文中的重点主要聚焦于他整体的评估框架,因为通过语言模型来生成复杂代码这个问题相对来说还比较新颖,在GPT-3刚问世的的时候OpenAI也给大家做过展示,GPT-3可以生成一些简单的代码片段,但是如果用来生成较为复杂的代码时效果很差,毕竟 GPT-3的训练数据中没有包含特别多的代码,因此一个Code Fine-Tuning数据集就呼之欲出了,根据论文介绍,Codex在2020年5月从Github 的 54,000,000 个公开代码仓上收集了数据,在经过过滤后,最终的数据集大小为159GB。
那么在评测数据集上采用哪种指标来判断模型的好坏呢?我们知道文本生成任务的输出为一个文本序列,比如说机器翻译经常用的一个评估方法叫做 BLEU score,BLUE这个分数计算的是生成的序列和正确答案序列在一些子序列上的相似度,是一个模糊的匹配过程,因此在代码生成上面BLUE分数会存在一个大问题——就算你在子片段上跟真实的代码非常相近,但是很有可能你生成的代码甚至连编译都无法通过。最终Codex使用的是一个pass@k 的分数,其含义表示生成 k 个不同的结果,其中只要有一个结果能够通过所有测试用例的话那么就认为正确。
最后是HumanEval这个评测数据集,数据集中包含164个编程的问题,主要涉及到语言的理解、算法能力、简单的数学推理以及一些简单的编程面试问题,数据量不是那么大,其中每个编程问题包括函数头、docstrings、函数体和几个单元测试用例,目前该数据集已经开源→https://github.com/openai/human-eval。
2.模型推理优化
基于预训练模型实现的工具应用在实际业务场景中有一个不容忽视的问题,那就是模型的推理性能是否能够满足需求,而Codex实际上就是GPT模型,在推理过程中需要逐字生成代码,因此如果需要实时地提供补全建议则对模型的推理性能有很高的要求。
图3 模型加速手段
上图中包含了一些常用的模型加速手段,在论文中OpenAI并没有披露针对模型部署方面的优化,但是在后面我们实际尝试去私有化部署代码生成模型时还是应用了多种模型加速方式,期望让使用感受能够接近Github Copilot。
3.组装你自己的AI编程助手
在实际私有化部署我们的“AI辅助”前先看看我们手上有哪些资源:
开源模型:虽然我们无法直接基于Codex部署私有化模型服务,但是在Hugging Face的Model Hub社区上与代码生成相关的开源模型仍然有许多可供我们选择,更让我们意外的是其中的开源模型CodeGen[4]甚至在HumanEval评测集上击败了Codex。
计算资源:只要不使用参数量最大的CodeGen-16B,服务器上的T4显卡就有足够的显存来进行推理,另外我们会测试INT-8量化下使用CPU部署服务的表现如何。
部署方式:在模型的推理服务器上我们使用了Triton Inference Server[5],因为可以很好的适配 FasterTransformer[6],另外也能搭配各种加速手段。
插件化方式:好消息是Github Copilot插件中的高级配置有调试选项,可以直接配置模型服务的地址,因此当启用该选项时可以将其设置为我们自己的模型服务地址,另外在插件市场同样有一些类似于Copilot的插件,并且可以配置本地的代码生成服务地址。
接下来就是部署我们自己的代码生成服务了,在使用GPU服务器进行部署时我们选择了CodeGen-2B模型支持多语言模式的版本:
图4 CodeGen系列模型
然后使用Triton Inference Server以及 FasterTransformer backend来启动我们的模型服务:
图5 模型服务
修改Copilot的插件的配置选项:
图6 配置选项参考
最终让我们看一下代码生成的效果,就让AI解一下斐波那契数列吧:
图7 代码生成效果
在使用GPU部署代码生成模型服务的情况下,从代码生成的速度上来说并已经完全不亚于于Github Copilot的速度了,通常来说服务器上的GPU计算资源较为宝贵,但是却有许多空闲的CPU资源,因此我们需要测试CPU部署时代码的生成速度是否能够满足日常需求,首先是我们期望模型生成的代码片段,这是Bert[7]模型定义中Embedding的一部分,实际测试时我们只键入Class名称,蓝色的注释,然后让模型来生成接下来的代码片段:
图8 Bert代码片段
我们试用了CodeGen的多个模型,并且记录在不同情况下他们返回结果的延时:
模型 | 生成用时(ONNX+FP16) | 生成用时(TRT+INT8) |
codegen-6B-multi | 846s | 293s |
codegen-2B-multi | 79s | 18s |
codegen-350M-multi | 9s | 4s |
服务器CPU:Intel(R) Xeon(R) Gold 6240 CPU @ 2.60GHz |
从结果来看,使用CPU部署后在经过INT8量化技术的加持下,当我们使用参数量最小的代码生成模型,至少在速度上可以获得还不错的体验。
四、总结与思考
从本次探究Github Copilot背后的技术以及进行简单的代码生成实践来看,基于GPT系列模型在文本生成这个领域上的确有着许多应用落地的可能,然而代码生成这一技术并不是“无害”的,首先是在模型训练过程中使用的“开源代码数据集”中包含许多个人数据,在笔者使用过程中发现,如果涉及到文件路径的键入,经常会出现一些带用户名的路径补全建议,其直接使用他人的开源代码来作为训练数据也在社区上引起了广泛的争议,甚至有许多开源社区的作者期望制定一个新的开源协议,限制他们的开源库不被用来作为深度学习的数据。另外经过Copilot生成的代码质量难以把控,还是会存在“埋坑”的可能性,很有可能在某天当你debug一个问题时却完全想不起来自己为什么会写下这一段代码,直到最后才意识到这是AI帮你生成的。
当然我们并不会直接放弃这样一个可以帮你干“脏活累活”的工具,毕竟如果只是作为一个“副驾驶”,时不时对你进行提醒,而不是代替你开车,它还是可以做的非常好的。另外就像开头所说的,其实是随着Github Copilot的收费才促成了笔者的这一次实践,许多社交媒体上的程序员都声称他们已经离不开Copilot了。而目前来看我们已经有了较为完善的私有化部署方式,还有开源模型CodeGen可供使用,作为一个在日常开发工作中的私有化工具已经足够好了。不过这还不够,如果可以使用完全开源并且脱敏的代码数据,并按照合适的模型参数量来定制化的训练我们的模型🤔......总之,敬请期待吧😜。
参考文献
[1] 代码生成工具GitHub Copilot:https://copilot.github.com/
[2] 代码生成模型OpenAI-codex:https://openai.com/blog/openai-codex/
[3] https://gpt3demo.com
[4] 代码生成模型CodeGen:https://github.com/salesforce/CodeGen.com/
[5] NVIDIA's Triton Inference Server:https://developer.nvidia.com/nvidia-triton-inference-server
[6] NVIDIA's Triton FasterTransformer:https://github.com/NVIDIA/FasterTransformer
[7] Devlin J, Chang M W, Lee K, et al. Bert: Pre-training of deep bidirectional transformers for language understanding[J]. arXiv preprint arXiv:1810.04805, 2018.
[8] FauxPilot - an open-source GitHub Copilot server:https://github.com/moyix/fauxpilot
[9] 盘点开源“Copilot”,do it yourself:https://lowin.li/2022/06/27/pan-dian-kai-yuan-copilot/
本文转载自 AI遇见云,作者: 张宇博