|
|
51CTO旗下网站
|
|
移步端
创造专栏

让代码自动补全的全方位流程

AI 如果真的可以写代码了,程序员将何去何从?近几年,NLP 天地的变通式任务有显著的升级,那通过 AI 咱们可以让代码自动完成后续补全吗?本文主要介绍了如何使用 GPT2 框架实现代码自动补全的效应。

笔者: 腾讯技术工程| 2020-07-31 07:44

笔者:熊唯,黄飞 ,腾讯 PCG/QQ研发中心/CV使用研究组

AI 如果真的可以写代码了,程序员将何去何从?近几年,NLP 天地的变通式任务有显著的升级,那通过 AI 咱们可以让代码自动完成后续补全吗?本文主要介绍了如何使用 GPT2 框架实现代码自动补全的效应。

如果 AI 真的可以团结写代码了,程序员将何去何从?

我去年做过一个代码补全的小功能,打包为 androidStudio 硬件,采用效益如下:

代码补全模型预测出的结果有时的确会惊吓到我,这也能学到~? 那如果给他见识了海内外的可以代码,再送足够量级参数和拔尖的模子框架,真的可以实现需求作为输入,直接出口代码吗?

"我之急需讲完了,你的编码呢?" 瞩望可以看出这一角。

代码补齐功能有其它优秀插件也已落实,比如 tabnine,Kite 和国产的 aixcoder。本文主要介绍下代码补全功能需要实现的整个流程。重点包括数据,书法和工程。

数量

强烈,书法工程师大部分时间都在拍卖数据。

深度学习是采取大数量训练模型的一个过程,数量是很重大的一个模块。人口是会累的,休息不好还导致记忆不好。AI 是你送多少多少它就能存储接收多少多少,学不到信息那是人之错,送的多寡不好或者算法设计不好。故此我们先尽可能多之准备好训练数据。

1、数据采集

本文的目的是代码补全,训练数据就是代码段。考虑到每种语言风格和语法都不一致,故此单个模型只针对一种代码语言。

我利用的教练数据主要来源于 GitHub,编纂了一番简单的爬虫代码,指定语言后根据 stars 的排序下载工程。

Github 的 search API 法定地址:

https://developer.github.com/v3/search/

2、数量清理

直接下载的多寡肯定是不能直接用之,咱们还要求对数据进行清理。

第一,咱们的教练数据只要求工程中的代码文件,以 java 水利为例,咱们只保留.java 最后的公文,其它文件可剔除。

从,我之编码补全目标是代码段,不针对注释功能。而且对于代码补全训练时,咱们是会给定一定规模之上文,如果存在注释段会占用有效代码信息。此外注释除英文外其他字符不在我之教练 vocab 范围内,故此需要对代码中注释和日志进行清理。

1.剔除代码行中生存除符号和英文外的字符

2.剔除日志行

3.剔除注释行,重点针对以下格式

      
  1. /* 诠释文本*/ 
  2.  
  3. /** 
  4. 诠释段落 
  5. */ 
  6.  
  7. // 诠释文本 
  8.  
  9.  code //诠释 

历经以上数据清理后,得到纯代码数据。

3、数量编码

得到了训练数据后还要求把代码文本进行编码。本文使用的是 bpe(byte pair encoder)字节对编码,重点为了多少压缩。bpe 大概理解为将一个单词再拆分为多个字母组合,比如 tencent 拆分为 ten-cent,该署组合方式则是根据大量数目,统计频率得到。出于我们希望的编码补全功能是在行首跃入几个字母,根据上文预期出同行业内容。

假设 tensorflow 其一 token 把编码对应到一个 id,那我期望输入 ten 就输出 tensorflow 是心有余而力不足实现的。故此在训练过程中,我会随机把 token 打断,比如将 tensorflow 打断为 t-en-sor-flow 拓展编码,打断原则是把切分的一部分一定要在词汇表中。数量编码后,代码的每股 token 把编码为 1~N 个 id。模型预测到的 id 反编码为 token 即可。回车符认为是展望的终止符。历经以上处理,咱们就准备好了训练数据,下就足以拓展书法部分了。

模型算法

强烈,书法工程师大部分时间都在研讨算法。

在腾讯文档的错别字纠错需求中,咱们采取了基于 LSTM 的 seq2seq 以及 facebook 谈起的基于 CNN 的 seq2seq,可以得到正确的纠错效果。直到 NLP 出现了一番"网红"--BERT,利用后精度直接提升 8 个点控制,不亏是 google。下先简单介绍下 bert 和 gpt2。

BERT 和 GPT2

2017 年中 google 谈起了 Transformer 布局。无需 rnn,无需 cnn,谈起 attention is all you need。2018 年 openAI 利用了 transformers 布局在 18 年发布了 GPT。同年 google AI Language 通告了 bert 舆论,谈起的 BERT 模型在 11 个 NLP 任务上刷新了记录。2019 年 openAI 又推出了 GPT-2 模型。。

BERT(Bidirectional Encoder Representation from Transformers)是基于 transformers 框架的 encoder 局部,自编码语言模型,相当 N-1(比如句子分类),N-N(比如词性标注)的天职,但是它并不适宜做生成任务。

GPT(Generative Pre-Training)基于 transformers 的 decoder 局部,自回归语言模型,相当生成式任务。

Transformer框架图

GPT2和BTER框架示意图

代码补全功能就是基于 GPT2 框架,OPenAI 法定提供了多套 GPT2 预训练模型:

法定提供GPT2数

表现一个经常要把模型部署到移动端的 CVer,观看这个参数级别,我选择最小的模子进行 finetune。

对于 GPT 书法,下这篇文章讲的很好,感兴趣同学可以看看:

https://zhuanlan.zhihu.com/p/137350403

GPT2的预测过程

本文在训练中采用 512 个上文,展望到回车符为停止。模型网络使用超参:12 个层,768 个隐藏节点,12 个 heads,利用了 uber 的 Horovod 分布式框架进行训练。

infer 阶段采取 beam-search 会导致整个预测过程特别耗时,故此参考了https://arxiv.org/abs/1904.09751舆论,利用 top-k sampling,每次预测 top3 的结果再通过概率阈值过滤后作为最终候选输出。

末了 infer 功能:

步入一段代码,展望出继续代码,以回车符截止。

水利

强烈,书法工程师大部分时间都在做工程。

训练出模型后,还要把模型应用起来,故此还要求一些工程工作要求实现。代码补全功能,最适合的使用场景就是上 IDE。nlp 模型不太方便在本机部署,末了摘取了在 GPU 机械上布置模型,下一场终端通过 http 呼吁获取预测文本显示的提案。

看台部署

Flask 是一番 Web 使用程序框架,灵活,方便,轻而易举上手。本文简单介绍如何利用 flask 起先一个 web 劳务,以及如何访问和滥用我们的效应接口。第一我们创建一个 conda 空气:

      
  1. conda create -n flask python=3.6 
  2. source activate flask 
  3. pip install flask 

代码中增加一个接口函数:

      
  1. from flask import Flask 
  2. from flask import request 
  3. app = Flask() 
  4.  
  5.  
  6. # route把一个函数绑定到对应的 url 上 
  7. @app.route("/plugin",methods=['GET',]) 
  8. def send(): 
  9.     data = request.args.get('data'
  10.    # 模型预测逻辑 
  11.     out =  model_infer(data) 
  12.     return out 
  13.  
  14. if __name__ == '__main__'
  15.     app.run(host='0.0.0.0',port=8080, debug=False

推行 run.py 代码,看台服务开启运行:

客户端请求:

      
  1. url = http://ip:8080/plugin?data="步入" 

其中 model_infer 函数需要实现模型的 infer 明天向计算逻辑,副请求中获取 data 字段作为输入,infer 展望的结果列表作为输出返回给调用方。

历经上面的上班,咱们已经提供了一番劳动接口,回到我们代码补全的预测结果。

硬件编写

说到底一地就是如何在 IDE 上采取效益了。咱们要付出 AS 的软件,要求采取 IntelliJ,第一需要在本机安装配置 IntelliJ IDEA

载入地址:

https://www.jetbrains.com/idea/download/

镇区版源码:

https://github.com/JetBrains/intellij-community

好用之软件可以节约程序员很多时间,在软件实现时,我还添加了一番小的 git-blame 效益,实时查看指定行的 git 付出人,对于手 Q 这种多人口合作之上班,比起实用。大家也得以通过 IntelliJ 和谐开发一些常用功能。

gitBlame 的首要代码:

      
  1. public class GitBlame extends AnAction { 
  2.  
  3.     private void showPopupBalloon(final Editor editor, final String result) { 
  4.         ApplicationManager.getApplication().invokeLater(new Runnable() { 
  5.             public void run() { 
  6.                 JBPopupFactory factory = JBPopupFactory.getInstance(); 
  7.                 factory.createHtmlTextBalloonBuilder(result, null, new JBColor(new Color(186, 238, 186), new Color(73, 117, 73)), null
  8.                         .setFadeoutTime(5000) 
  9.                         .createBalloon() 
  10.                         .show(factory.guessBestPopupLocation(editor), Balloon.Position.below); 
  11.             } 
  12.         }); 
  13.     } 
  14.  
  15.     @Override 
  16.     public void actionPerformed(AnActionEvent e) { 
  17.         // TODO: insert action logic here 
  18.         //拥有当前当地代码根目录 
  19.         String base_path = e.getProject().getBasePath(); 
  20.         String file_path = e.getProject().getProjectFilePath(); 
  21.         //获取编辑mEditor 
  22.         final Editor mEditor = e.getData(PlatformDataKeys.EDITOR); 
  23.         if (null == mEditor) { 
  24.             return
  25.         } 
  26.         SelectionModel model = mEditor.getSelectionModel(); 
  27.         final String selectedText = model.getSelectedText(); 
  28.         if (TextUtils.isEmpty(selectedText)) { 
  29.             return
  30.         } 
  31.  
  32.         //获取当前编辑文档的目录 
  33.         PsiFile mPsifile = e.getData(PlatformDataKeys.PSI_FILE); 
  34.         VirtualFile file = mPsifile.getContainingFile().getOriginalFile().getVirtualFile(); 
  35.         if (file != null && file.isInLocalFileSystem()) { 
  36.             file_path = file.getCanonicalPath(); 
  37.         } 
  38.         //gitkit工具 
  39.         JGitUtil gitKit = new JGitUtil(); 
  40.         String filename = file_path.replace(base_path+"/",""); 
  41.         //得到blame消息 
  42.         int line_index = mEditor.getSelectionModel().getSelectionStartPosition().getLine(); 
  43.         String blame_log = gitKit.git_blame(base_path,filename,line_index); 
  44.  
  45.         //展示 
  46.         if (!blame_log.isEmpty()){ 
  47.             showPopupBalloon(mEditor, blame_log); 
  48.         } 
  49.     } 

本文的编码补全插件主要代码逻辑为调用上一地后台部署之呼吁。

      
  1. // 呼吁url分立式(和flask接口一致) 
  2. String baseUrl = "http://ip:8080/plugin?data="
  3. // 获取当前编辑位置文本 
  4. PsiFile str = position.getContainingFile(); 
  5. // 根据模型上文限制获取代码端 
  6. String data = getContentCode(); 
  7. String url = baseUrl+data; 
  8. // 发送请求 
  9. String result = HttpUtils.doGet(url); 
  10. // 后处理逻辑,在指导框显示预测结果 
  11. show() 

末了呈现形式:

可以看到,模型的预测结果还是天经地义的~

上述为代码补全功能的贯彻和运用,算是 AI 机动写代码的一小步。

AI 是否自己写代码,到达疑犯追踪里 TM 某种水平,我不敢说一定不可能,但以我目前的体会是促成不了,毕竟写代码的是程序员,送算法喂数据的是程序员,书法设计还是程序员,AI 连帮人类解 bug 的效应都还不出现!\

参考资料:

[1] https://arxiv.org/abs/1706.03762

[2] https://arxiv.org/abs/1810.04805

[3] https://github.com/openai/gpt-2

[4] https://arxiv.org/abs/1904.09751

【编纂推荐】

  1. 在 Android 付出中采用协程 | 代码实战
  2. 写代码之前应该做的几件事
  3. 如何写出健壮的编码?
  4. 程序员们,请你们不要看低零代码
  5. Go+ 可有效补全 Python 的欠缺
【义务编辑: 武晓燕 TEL:(010)68476606】

点赞 0
  • 代码  机动  补充全
  • 分享:
    大家都在看
    猜你喜欢
    1. <label id="ac2566e1"></label>
      1.     

          
             
          <dd id="c025e4ad"></dd>