【ASE模型组】Hint::neural 模型与case study
模型
基于搜索的提示系统
我们的系统用Pycee针对语法错误给出提示。然而,对于语法正确、结果错误的代码,我们需要另外的解决方式。因此,我们维护一些 (错误代码, 相应提示) 的数据,该数据可以由我们预先给定,也会在网站运行过程中请用户标注。当用户出现错误时,搜索与用户错误代码相似的已有错误代码,并给出相应提示。
为了计算代码之间的相似度,我们需要采用code embedding技术,即将一段代码编码为高维空间中的向量。
CodeSearchNet
今年,GitHub和Weights&Biases携手推出了一项新赛事 CodeSearchNet,旨在推动语义代码搜索的相关研究。CodeSearchNet语料库的数据取自GitHub上的开源项目,经过了充分的预处理。其中包含了约600万种函数,取自Go,Java,JavaScript,PHP,Python和Ruby这六种编程语言的开源代码,以及大量用于查询的自然语言及其标注。其中,用于查询的自然语言获取自Bing搜索引擎的常见搜索语句,标注由专家人工标注所得。
为了更好地评判不同的code searching方法,CodeSearchNet还公开了baseline模型代码 repo,并设立了leaderboard,其中包含大量预训练模型。因此,我们可以采用表现良好的预训练模型对代码计算embedding,从而计算相似度并进行匹配。
Baseline模型
Baseline模型包含code encoder \(E_c\)与query encoder \(E_q\)两部分,将代码与查询文本投射到同一个高维向量空间中。
训练过程中,训练数据包括大量code and text pair: \((c_i, q_i)\)。通过最大化\(E_c(c_i)\)与\(E_q(q_i)\)的余弦相似度,使得代码\(c_i\)与文本\(q_i\)的embedding尽可能相似。
Code Encoder
由于我们只使用code encoder部分,因此下面只讲解code encoder。
首先,模型将代码转换为token序列。为了避免空格、空白换行等问题对tokenize产生影响,模型利用parso]()解析代码的AST,并遍历AST、将各个叶子结点对应的值结合为token序列。如下列代码:
n = int(input())
d = dict()
for i in range(1, n + 1):
d[i] = i*i
print(d)
被tokenize为如下序列:'n', '=', 'int', '(', 'input', '(', ')', ')', 'd', '=', 'dict', '(', ')', 'for', 'i', 'in', 'range', '(', '1', ',', 'n', '+', '1', ')', ':', 'd', '[', 'i', ']', '=', 'i', '*', 'i', 'print', '(', 'd', ')';token序列经过BPE编码得到BPE code序列。
接着,模型对序列中的每个BPE code计算一个embedding。Embedding计算方法包括:
- Neural Bag of Words:每个BPE code被投影到一个embedding上
- Bidirectional RNN
- 1D Convolutional Neural Network
- Self-Attention:使用multi-head attention
最后,通过pooling方式将embedding序列合并为一个embedding;可用的pooling方法包括max / mean pooling与weighted sum pooling。
我们使用的模型为leaderboard第一个模型,即Neural Bag of Words + weighted sum pooling。我们用模型的code encoder计算用户错误代码embedding \(\vec{x}\)与已有错误代码的embedding \(\vec{c}_i, i=1,2,...,N\),选择与用户错误代码cosine similarity最大的已有错误代码,返回相应提示。
Case study
Code Embedding
模型的vocabulary大小为10000,其中包括5000个单词和5000个BPE code。计算vocabulary中,部分单词之间cosine similarity如下:
word 1 | word 2 | cosine similarity |
---|---|---|
for | while | 0.1801 |
try | except | 0.1785 |
open | while | -0.2296 |
可以看出,含义相似的单词(如for和while都表示循环)embedding较为相似。而try、except虽然含义不相似,但功能十分相关,因此相似度也较高。而基本无关的单词(如open和while)相似度很低。
代码相似度计算
考虑以下四段代码,分别为题目的正确解法1、正确解法2、与解法2类似的错误3、与错误3相同的错误4.计算其两两cosine similarity:
def fact(x):
if x == 0:
return 1
return x * fact(x - 1)
x = int(input())
print(fact(x))
x = int(input())
out = 1
for xx in range(1, x + 1):
out *= xx
print(out)
x = input()
out = 1
for xx in range(1, x + 1):
out *= xx
print(out)
inp = input()
out = 1
for i in range(1, inp + 1):
out *= i
print(out)
计算得cosine similarity如下:
code 1 | code 2 | code 3 | code 4 | |
---|---|---|---|---|
code 1 | - | 0.9854 | 0.9835 | 0.9716 |
code 2 | - | - | 0.9995 | 0.9861 |
code 3 | - | - | - | 0.9859 |
code 4 | - | - | - | - |
由于各个代码片段较短,各个code embedding都比较相似。