从程序员到数据工程师,时代编写程序代码是码补一项基本功,但是全利器效编写冗长代码的过程也极大地消耗了开发者的耐心。近来,果远有不少关于代码补全工具的超语消息爆出,例如,言模来自美国的时代 Kite,来自加拿大的码补 TabNine 等,一时间获得了不少程序员的全利器效关注。但其实很多人还并不知道,果远在这些国外产品不断被媒体推送的超语背后,有一款能力更为强大、言模更早将深度学习应用于代码补全的时代产品,一款源自中国的码补工具——aiXcoder,它的全利器效研发者们来自于北京大学。 aiXcoder 的云服务器代码补全效果 我们先看看写 TensorFlow 时的代码补全效果: aiXcoder 用起来怎么样 aiXcoder 是如何打造的 如图所示,实现 list_a 的代码可以是多种多样的,但语言模型会将它们学习为完全不同的表征。 3. 程序语言序列模型:当然,程序语言也具有与自然语言相似的一面,因此可以利用程序标识符之间的序列关系建立程序语言模型。aiXcoder 也使用了最新的深度学习语言模型对程序中的序列信息进行建模。如上所示,aiXcoder 在 TensorFlow 的代码环境下能够直接「猜测」到模型建立后的一系列代码流程。例如,在定义了 loss 之后需要定义 optimizer,之后需要 train_op、init 方法,然后最终定义模型的保存方式 saver,以及开始运行计算图。这样一个流程基本上是深度学习开发者所知晓的,但是按照流程写下来非常繁琐。在 aiXcoder 的提示下,开发速度得到了提升。 aiXcoder 支持 Java、C++/C、Python、PHP、JavaScript 等语言,以插件的方式集成到现有的 IDE 中,如 Pycharm、Android Studio、VS Code、Eclipse、Webstorm、高防服务器Sublime 等,插件的背后是一个强大的云端深度学习引擎。 针对开发者,该产品目前分为社区版、专业版和企业版。社区版是完全免费的,专业版也可以通过分享而免费获得。它们间的不同之处在于模型会不会继续学习,社区版主要利用事先训练好的公用模型做预测,而专业版则会根据用户的代码习惯及结构作进一步的调整。 企业版是 aiXcoder 功能最为强大的版本,它能够在企业内部的私有云中进行部署,并能够利用企业自己的代码来进行模型的优化训练,从而具有更高的准确率和运行性能。
对于一些变量,aiXcoder 可根据变量类型提出该变量可能的操作,比如,对于下图的变量「m」,aiXcoder 提出了一个对字符串进行增加的代码:
对比测评aiXcoder 官方也将产品和其他代码补全工具进行了对比,包括 Kite 和 TabNine 等。
在对比过程中,aiXcoder 会使用 Kite 或 TabNine 官方提供的示例代码,并测试完成这段代码到底需要多少次按键。结果表明,aiXcoder 较其他插件在效率上提升 1.5 倍以上。
对于图像识别或图像分类任务而言,机器学习的目标是建立一个连续的数据集(图像数据)到一个近乎连续的、有着接近清晰边界的数据集(标签)之间的映射关系。 这样一来,由于图像数据异常的稠密,而标签集又有足够清晰的边界,那么这就相当于一个标签拥有大量的数据可以学习。这样的映射关系是比较容易建立的,这也是机器学习中和图像相关的任务相对较为容易完成的原因。
对于自然语言处理任务而言,机器学习需要从一个较为连续的(离散度高于图像)、有着较清晰边界的数据集建立与另一个较为连续的、有着较清晰的边界的数据集之间的映射关系。 而由于自然语言处理中的文本数据相比图像数据更为稀疏,因此自然语言处理相关的任务更难取得较好的模型性能。
但是在代码生成方面,从编程者的意图(intent)生成程序代码的问题,可以看做是「程序员意图空间」到「程序代码空间」的映射,其中意图可以是由自然语言描述的信息。如上图所示,这是从一个较为连续的、有着较清晰边界的数据集,向一个更加离散而没有清晰边界的数据集进行映射。 换句话说,尽管代码生成的意图较为清楚,但是实现该意图的代码数据却比较稀疏,而且即便对于相同的意图,其对应的实现代码之间仍存在较大差距,因此这样的任务是非常难学习的。 为此,在 aiXcoder 的实际实现中,对不同应用领域的代码都采用了特定的模型,它们仅使用该领域的数据进行训练。例如,对 TensorFlow 或 PyTorch 等框架也有其特定的代码补全模型。这样做的主要目的就是加强程序分布的稠密性,在特定领域下,代码分布更加接近连续性。可见,根据编程者的「意图」来「直接」生成完整代码是非常困难的,但李戈教授表示,可以用类似的技术来辅助人类程序员来编写代码,我们可以从程序员已经写下的代码中获取程序员的「编程意图」,然后综合分析代码,的结构信息、变量引用信息、API 序列信息、继承关系信息等等,以自动生成后续代码。然而,在这个过程中,只有语言模型是远远不够的,还需要对很多其它代码特征进行分析,才能做好生成式的代码补全。单纯的预训练语言模型又怎么样?提起代码补全,有些人可能会下意识的认为这仅仅是一个普通的语言建模任务,模型只需要根据开发者之前写的代码预测之后的代码即可。因此使用最先进的预训练语言模型,再在代码数据上进行微调说不定是一种好方法。 但是李戈教授表示,这样的想法是远远不够的。预训练语言模型在代码补全任务中效果不佳,主要是因为代码补全任务本身存在诸多不同于自然语言分析任务的挑战。 首先是代码文本中存在的语义抽象性问题。代码的语义(功能语义)与其字面表示之间存在更大的差距。我们无法根据字面确定代码的准确语义。例如,在代码中,只改变一个字符就有可能完全改变整行代码的功能,因此处理代码的语言并准确提取其含义相比自然语言处理任务更棘手。 f = open(word_ids.txt,r)f = open(word_ids.txt,w) 上图所示,在 Python 代码中,打开某个文件时使用「r」和「w」会实现完全不同的功能。 此外,代码的功能语义难以进行具体的表达和刻画,而且代码功能语义的表达方式多种多样。例如,有多种代码的形式文本用于实现某个功能,不能说某一种代码是对的而另一种是错的。 list_a = [] for i in items: result = test(i) list_a.append(result) list_a = [test(i) for i in items]
在获得程序代码的各种特征之后,就该把这些特征输入深度神经网络进行分析了,但这并不容易,因为在输入神经网络之前需要把这些特征进行向量化表示。在研究过程中,北京大学提出了一系列解决程序语言成分相量化的办法,并且在国际上最早发表了相关的论文,这些都为 aiXcoder 的构造打下了基础。