This is a method-level benchmark for evaluating code generating (synthesis) models, which take natural language as input and code as output, and is primarily used to evaluate the ability of code-generating models. AiXcoder NL2Code Evaluation Benchmark is divided into two datasets:
-
Automated Test Dataset: Each sample in this part of the dataset contains a functionally independent and well-described natural language function description, the Java function signature of the function, and a set of Java unit tests that verify the correctness of this function.
The main use of this dataset is to automatically evaluate the correctness of the code generated by the model.
-
NL Task Description Dataset: Each sample in this part of the data set contains a relatively independent functional description. This part of the data is closer to the real method description in the code, and contains some functional descriptions whose details are not very clear.
The code generated by the model requires human evaluation. Please refer to the detailed introduction for the evaluation criteria described later.
Datasets | Automated Test Dataset | NL Task Description Dataset |
---|---|---|
Test Set Size | 187 | 160 |
Currently, these two datasets only contain Java codes, and the natural language description part contains English and Chinese languages. If you only care about code correctness, you can just use the automated test dataset.
The code in this project uses the MIT open source license.
The data in this project is licensed under the Computational Use of Data Agreement (C-UDA).
If you use code or data from this project, it is recommended that you reference it like this:
Yiyang Hao, Ge Li, Yongqiang Liu, Xiaowei Miao, He Zong, Siyuan Jiang, Yang Liu, & He Wei. (2022, June 17). AiXcoder NL2Code Evaluation DataSet: A Dataset for Evaluating Text-to-Code Generation Model. GitHub. Retrieved June 17, 2022, from https://github.com/aixcoder-plugin/nl2code-dataset
数据文件路径:src/main/resources/samples_all.jsonl
这些数据是从开源的“方法注释-Java方法实现”中人工挑选出的一批“方法注释”的集合。我们挑选的标准是:
- 注释比较好地描述了一个可以实现的功能。
- 函数功能相对独立,不太依赖对项目、业务逻辑等上下文的理解。
- 功能是合理的且在开发者的日常工作中确实会发生的需求。而不是编程竞赛的题目或课程作业。
在这个基础上,我们对描述进行了一些补充,使得:
- 描述里包含了具体的,为了实现功能所必需的信息。比如:
Returns whether or no the JDK version is high enough.
里面并没有明确high enough
的标准。所以我们将它手动补充为Returns whether or no the JDK version is 1.7u40 and above.
。 - 删除了和任务无关的描述。例如删除了原始数据
max() that works on three integers. Like many of the other max() functions in this class
中的后半句。
就像真实场景中的一样,自然语言描述中会包含一定的语法错误或标点服务或大小写不一致。我们保留了这些因为我们认为这些扰动可以测试模型的抗干扰能力。
数据文件路径:src/main/resources/dataset_manual_nl.jsonl
这些数据是从开源的“方法注释-Java方法实现”中人工挑选出的一批“方法注释”的集合。我们挑选的标准是:
- 注释比较好地描述了一个可以实现的功能。
- 函数功能相对独立,不太依赖对项目、业务逻辑等上下文的理解。
- 功能是合理的且在开发者的日常工作中确实会发生的需求。而不是编程竞赛的题目或课程作业。
- 我们允许一定程度的模糊,比如“Read the encoded image data from a JPEG image.”中,我们并没有说明读出来的数据应该如何处理。在评估时,只要模型生成的代码完全实现了描述中的功能,那么正确性上就算满分。
我们从三个维度上对模型生成的代码进行人工评估。
正确性:
- 4分:完全实现了指定的功能。
- 3分:实现了主要的功能。但在部分细节上有缺失,不影响整体的逻辑的正确性。稍作修改就可以满足需求。
- 2分:仅实现了主干功能。大多数要求都没有在代码中得到体现。需要较多的修改才能满足需求。
- 1分:完全没有实现指定的功能。
代码质量:
- 3分:细节处理到位。代码从性能上没有明显的更优解。如果可以,资源有相应的释放。没有明显的Code Smell。
- 2分:有轻微遗漏的细节没有处理。有低严重性的Code Smell。
- 1分:代码从性能上有明显的更优解。有严重的Code Smell。
可维护性:
- 5分:方法实现非常规范,变量命名做到语义直白,方法没有不必要的臃肿,可读性好,代码短小,代码块做到层次分明
- 4分:方法实现比较规范,变量命名基本上做到语义直白,可读性较好
- 3分:方法实现满足了一定的规范,存在部分变量命名无意义,使用了有缺陷的代码及deprecate方法
- 2分:方法实现风格混乱,没有遵照一致的规范,且变量命名存在许多无意义的名称,且存在一定的重复及多余的代码。可读性很差
- 1分:非常混乱,完全没有逻辑,难以读懂代码
该数据集包括186个手工收集的JAVA编程中高频出现的代码例子,每个例子包括如下字段:
{ "task_id": 166, "raw_nl": "通过反射为对象的对应字段注入值", "signature": "public <T> T initByReflect(String name, String value, T t)" }
task_id用于标记是例子序号,raw_nl表示自然语言的描述,signature表示要生成函数的签名,raw_nl和signature共同作为模型的输入。
src/main/java/com/aixcode/autoTest/evaluation/ 存放自动化测试类,用于对每一个例子进行测试 src/main/java/com/aixcode/autoTest/generate/ 存放模型输出的函数级代码,每个例子需要手动创建一个类 src/main/java/com/aixcode/autoTest/Excutor.java 自动化测试执行器 src/main/java/com/aixcode/autoTest/predictionHelper.java 将预测的方法转换为自动化能够测试的类
git clone https://github.com/aixcoder-plugin/nl2code-dataset.git
对每个测试数据,把raw_nl和signature作为输入,获得模型的输出,该输出作为类的唯一方法,类名为prefix+task_id,prefix是用户自定义的。同时该类需要继承GenerateMethodBase类,对于如上的例子,根据模型的预测输出,手动生成如下的类,其中类名为Aixcoder166(Aixcoder+166),同时继承GenerateMethodBase类
public class Aixcoder166 extends GenerateMethodBase { /** * 通过反射为对象的对应字段注入值 */ public<T> T initByReflect(String name, Object value, T t) { if (null == t) { throw new NullPointerException("t can not be null"); } if (null == value) { return null; } Class<?> clazz = t.getClass(); if (!clazz.isAssignableFrom(value.getClass())) { throw new IllegalArgumentException("value must be assignable to" + clazz); } try { Field field = clazz.getDeclaredField(name); field.setAccessible(true); field.set(t, value); } catch (NoSuchFieldException e) { throw new IllegalArgumentException("no such field:" + name); } catch (IllegalAccessException e) { throw new IllegalArgumentException("illegal access:" + name); } return t; } }
上面的过程可以通过批量的方式实现,使用predictionHelper类中的assembleFile方法,即可根据模型的预测输出批量的生成所有的类,每个类需要手动的引入所有要的依赖包。执行如下代码:
public class predictionHelper { public static void main(String[] args) { assembleFile("src/main/resources/prediction.jsonl"); } }
class Excutor{ //com.aixcode.autoTest.Excutor类中方法 private static void evaluationOneExample(String basePackage,String prefix,String fileId){ try { int[] result= evaluationGenerateMethod(fileId,basePackage,prefix); System.out.println(prefix+" result:"+result[0]+"/"+result[1]); }catch (Exception e){ e.printStackTrace(); } } }
执行上面的例子,可以如下执行调用
class Excutor{ public static void main(String[] args) { try { String taskId = "166"; String basePackage = "com.aixcode.autoTest.generate.aixcoder"; String prefix = "Aixcoder"; evaluationOneExample(taskId, basePackage, prefix); } catch (Exception e) { e.printStackTrace(); } } }
class Excutor{ //执行所有的例子,会遍历src/main/java/com/aixcode/autoTest/evaluation下的所有evaluate类 public static double[] runAllTest(String basePackage, String prefix, int minFileId, int maxFileId) { try { List<String> fileNames = listFiles("src/main/java/com/aixcode/autoTest/evaluation"); List<String> fileIds = fileNames.stream().map(fileName -> fileName.substring("Evaluation".length(), fileName.lastIndexOf("."))).collect(Collectors.toList()); double copilot_score = 0; int CopilotExacttCount = 0; int totalCount = 0; for (String fileId : fileIds) { if (!(Integer.parseInt(fileId) >= minFileId && Integer.parseInt(fileId) <= maxFileId)) { continue; } totalCount++; int[] result = evaluationGenerateMethod(fileId, basePackage, prefix); if (result != null && result.length == 2 && result[1] != 0) { copilot_score += (double) result[0] / result[1]; if (result[0] == result[1]) { CopilotExacttCount++; } } } return new double[]{copilot_score, CopilotExacttCount, totalCount}; } catch (Exception e) { e.printStackTrace(); } return new double[]{0, 0, 0}; } }
执行上面的任务,可以如下执行:
class Excutor { public static void main(String[] args) { try { double[] res=runAllTest("com.aixcode.autoTest.generate.aixcoderFirstHalf", "AixcoderAuto", 0, 103); System.out.println("result:"+res[0]+"/"+res[1]+"/"+res[2]); } catch (Exception e) { e.printStackTrace(); } } }
- Fork 本仓库
- 新建 Feat_xxx 分支
- 提交代码
- 新建 Pull Request