type
status
date
slug
summary
tags
category
icon
password
AI summary
TL;DR
该文章介绍了一个用于评估 CodeLLMs 在代码翻译任务上的功能性和安全性的自动化框架,旨在通过指定模型名称,实现自动化评估模型的表现。框架支持模型推理、输入处理、输出处理、模板设置、批量运行、指标计算及可视化分析,并提供了一个易用且美观的前端UI界面。同时对评估结果进行了深入的分析和可视化。
✍️Introduction
代码翻译 (Code Translation)
代码翻译(Code Translation)指的是将一种编程语言编写的源代码转换成另一种编程语言同时保持相同功能的过程。如图为将Python代码翻译为功能一致的Java代码示例。这种转换可以是从低级语言到高级语言,也可以是在同等级别的语言之间转换,例如从Python2转换到Python3,从Java转换到Python等。
代码翻译的目的通常是为了利用目标语言的特定优势,如更好的性能、更广泛的库支持或更适合特定应用的语言特性或者是为了维护遗留系统等。代码翻译不仅仅是简单的语法替换,还需要处理不同编程语言之间的语义差异,确保转换后的代码在功能和性能上与原代码等效,生成的代码必须语法正确,且不引入错误。因此,这是一个复杂且技术要求高的过程,通常需要专门的工具和深入的语言知识来实现。
CodeLLMs
代码生成模型是一种人工智能模型,它可以根据给定的输入生成代码。这种模型通常使用机器学习和自然语言处理技术,通过学习大量的代码样本和规则,来理解代码的结构和语法,并能够根据用户的需求生成相应的代码,能够完成诸如代码生成、代码补全、代码翻译等多种编程任务。
意义
在实际的生产环境中,我们不仅希望模型生成的代码在功能上正确无误,同时也需保证代码的安全性。功能性评估关注代码是否正确实现了预定功能,包括其逻辑正确性和满足特定需求的能力。安全性评估则着重于市场的代码是否存在可能导致数据泄露或引入漏洞等安全隐患。
为什么要评估安全性?LLMs 的训练通常包括两个阶段:预训练和微调。在预训练阶段,模型通常在大规模的语料数据集上训练,比如 Github 仓库的代码,这就难免会引入包含漏洞的相关代码,导致模型在生成相关代码时输出具有漏洞 🐞的代码。Pearce 的开创性研究首次对 GitHub Copilot 在程序生成过程中的安全性进行了系统评估。研究结果表明,在约 40% 的测试场景中,Copilot 生成的代码存在可被利用的安全漏洞。
重复性工作 ❓ ❓❓
功能性评估 ☑️
目前已经有较多的权威 Benchmarks 大多针对的是代码生成和补全任务,评估模型输出的代码在测试用例上的 Pass@k 等指标,比如 EvalPlus Leaderboard,LiveBench,Big Code Models Leaderboard 等,具有全面的模型和不受污染的实时数据集、具有区分度的高难度题目等。
但是对于代码翻译任务上的功能性评估,目前的权威 Benchmarks 较少,只有几个相关的数据集,XLCoST,G-TransEval,CodeTransOcean,CodeXGLUE,xCodeEval 等,而且这些数据集普遍存在一些局限性。首先,大多数数据集倾向于包含简单的编程问题,如基本算法实现或简单的代码片段,缺乏对复杂数据结构和算法的覆盖。这与现实生产环境中开发人员面临的复杂工程和算法问题形成鲜明对比,限制了这些数据集在评估模型处理复杂算法和编程任务能力方面的有效性。其次,现有数据集中的测试用例数量通常较为有限,且案例设计较为简单,往往未能涵盖大范围的边界值和异常情况。评估代码大模型的功能性正确需要丰富多样的测试用例,以模拟实际应用场景中的各种输入和约束条件。
安全性评估 🐞
目前对于代码翻译任务上的安全性评估是没有相关研究的 🤗(我来当第一人bushi 🙈)。因此需要自己构建评估数据集、评估方法和评估框架。 考虑源代码不存在漏洞时,翻译成另一种语言的结果是否出现漏洞?源代码存在漏洞时,翻译成另一种语言的结果是否仍保留这些漏洞?
Contribution✨
- 引入了一个功能性评估数据集,共100条,数据的选取日期在2023年之后(因为数据收集部分是在23年末),每个数据有五个测试用例,覆盖不同的测试用例范围,100条数据中含有各个难度的题目,相较之前研究提供的简单数据,该数据集有二叉树算法,图算法,递归等复杂算法和高级数据结构。同时每个问题都提供了Python, Java, C++三种编程语言的结构基本一致的标准答案,每个答案都通过全部的测试用例。
- 引入了一个安全性评估数据集,该数据集通过搜集已有的公开数据集和安全网站提供的示例漏洞样本组合而成,经过滤后共50条。区别于之前的安全数据集,本项目的评估任务是代码翻译任务,所以对于将包含漏洞的Python代码翻译为Java代码,需要保证Python中的漏洞类型在Java中同样存在,且可以翻译为对应的Java代码。因此首先需要人工确定该Python代码包含的漏洞在Java中也有对应的漏洞,然后确定该Python代码可以翻译为Java代码。
- 引入了一个自动化的评估框架,只需指定模型名称即可实现自动化评估模型的表现,框架包含模型推理,输入处理,输出处理,模板设置,批量运行,指标计算,可视化分析等。并且提供了一个易用且美观的前端UI界面,可以浏览数据集,提交任务,查看任务状态,查看模型输出结果以及分析模型输出指标值等,将框架的部分脚本整合为API,为前端提供调用服务。
- 对实验的评估结果进行了数据分析,全面的横向和纵向对比模型的表现。
💫Method
数据集构建🔢
功能性评估数据集
- 数据收集:从 LeetCode、HackerRank 以及洛谷三个平台收集不同类型和不同难度的算法题目,每个题目需要收集对应的description、tag、difficulty、params 以及三种编程语言的标准答案。100条数据中,简单(easy)级别有37题,中等(medium)级别有53题,困难(difficulty)级别有10题。
- 数据审查:由于本评估任务为代码翻译任务,所以特别强调三种语言的参考解答在结构上的一致性,这对于确保CodeBLEU评估指标的有效性至关重要。对于那些难以在结构上保持一致的标准解答的题目,将进行必要的修订或剔除,以维持数据集的标准化和一致性。
安全性评估数据集
- 数据收集:从 CodeQL 官方仓库、SVEN 研究公开的数据集以及 SecurityEval 研究公开的数据集收集相关的具有 Python 漏洞的代码片段,共五十条数据。
- 数据审查:
- 使用 CodeQL 对收集的Python漏洞代码样本进行了全面验证,确保其包含预定的漏洞类型。
- 跨语言漏洞的对比分析:验证Python和Java两种语言中的安全漏洞一致性,依据CodeQL官方提供的CWE漏洞类型清单,对Python代码样本中的漏洞进行了系统审查,确保Java版本中存在相同类型的漏洞。例如,如果存在特定于Python Flask框架的漏洞(如flask-debug),而Java中无对应实现,则应从数据集中移除该样本。
评估框架构建 ⚒️
目前全部的代码已经开源,这也算是我第一个完整的项目,期间经历了一次电脑宕机 push 我尝试将代码同步到 github 中,并使用 git 管理我的整个 project。
CodeTransEval
huhusmang • Updated Jul 23, 2024
说明:该框架流程图将功能性评估和安全性评估进行了统一,两种评估在流程上基本一致,对于输入处理和模型调用模块也是共用的,区别可能在于输出处理和测试执行模块,因为安全性的评估是调用外部第三方工具分析整个文件,所以较为简单。因此下面的每个模块分析都已功能性为主。
输入处理模块 📄
因为数据集只是提供了单纯的代码片段,不能直接输入给 LLM,需要指明具体的要求和任务等,因此需要设计 Prompt 模板,然后对其进行拼接作为 LLM 的输入。
下面为功能性评估的 prompt 模板,四个可替换参数为:
SL
,TL
,SC
,PARAMS
。可以看到下面的 prompt 大致分为三个层次:必要的要求即翻译任务;数据的相关信息;返回代码片段应遵循的要求。其中有四个要求是关于返回代码片段的,因为在实际的实验过程中发现有些模型,特笔是模型本身能力较差,指令遵循能力不好的模型,总是会输出一些上下文(比如相关的代码解释等)和代码注释等,以及输出的代码格式不符合标准的 md 语法没,导致后续无法自动化解析。这里并没有尝试让模型输出 json
格式的数据,感觉应该是个不错的选择,因为之后看到其他 repo 使用了 json output parser。下面是安全性评估的 prompt 模板,其中的要求更多了,主要是因为漏洞评估的数据集涉及到了很多 web 服务的代码,因此在
java
代码中需要引入标准库或者第三方库。由于使用 CodeQL 进行漏洞检测,需要提供的 java
代码能够通过编译,所以需要实际的调用库,从下面的要求可以看出,我首先明确大多数情况下先使用内置的标准库,在标准库无法实现对应功能情况下,使用一些常见的、相关依赖较少的库。然后如果引用了第三方库,需要提供 pom.xml
,以为 CodeQL 可以自动编译 maven 管理的项目。这些要求和方法也是我自己尝试了几个可能的编译方法之后,在自动化优先的情况下所提出来的,肯定还有更好的方法,毕竟我对 java 项目不是很熟悉~
模型调用模块 🤙
目前也有成熟的模型统一接口调用的 repo 比如 ,但当时编写项目最初版本的时候,是先对一两个模型进行测试,而且都是有 API 提供商的,所以就直接翻阅官方文档调用对应的 API 了。期间这个模块经历了几次迭代:抽象出统一的调用接口、添加
litellm
BerriAI • Updated Aug 1, 2024
Pydantic
库作为前置的参数传入验证以及统一的 API key 管理。 输出处理模块 🧰
从上一个模块的示例图可以看到,即使模型的输入要求了输出的格式,但是在返回的结果中仍有文字描述等信息,所以需要从模型的输出中提取出需要的代码片段,具体的需求如下:
- 提取出模型输出中所有的代码片段,基于正则表达式匹配 md 的 code blcok
- 去除代码块中的所有注释,因为对于后续的 CodeBLEU 指标会有影响
- 去除相关的定义数据结构的代码,比如定义
TreeNode
等,因为这些已经在模板文件中定义,防止运行时发生冲突。(这里可能会有一些潜在的问题,因为如果模型输出的代码中定义的数据结构和已经定义好的不一致,就会导致对应的代码无法运行,原本可能正确的代码判为错误的。但是由于在输入的 prompt 中传入了params
,其中包含了数据结构的Name
,且经过观察模型能够与传入params
中的数据结构保持一致,暂未发现由此引发的误判)。
- 去除代码块中包含
main
函数等调用函数,因为嵌入到模板中会造成目标函数多次调用或者造成冲突等其他影响。
- 提取出源代码对应的翻译后的代码。这里的步骤可能令人匪夷所思,认为有些多余,因为经过上述四 个步骤处理后的代码就应该是目标代码了。但实际测试会发现一些问题(提前说明一下,因为在后续的自动化测试运行模块中,为每种语言都定义了一个模板文件,只需传入相关的代码片段即可,也就是翻译后的
n
个函数以及entry point
。比如一个搜索相关的算法有两个函数count
和dfs
,其中dfs
函数是被调用的递归函数,所以entry point
就是count
): - 源代码的
entry point
翻译为目标语言代码后,entry point
发生了改变,即使代码可能功能正确的,也会导致模板文件中运行测试用例的部分因为找不到对应函数,导致无法调用函数进行测试。比如lengthOfLongestSubsequence
翻译后可能会变为length_of_longest_subsequence
所以问题的难点就抽象转化为:给定
n
个函数,如何找到整体的 entry point
方法一:正则表达式提取
整个大致的提取流程如下:
- 将代码片段转化为 code lines
- 遍历所有的 code lines,基于正则表达式提取出定义的 function name
- 将所有 function 转化为由 name 和 body 构成的一个字典
- 遍历每个 function body,识别出被调用的 function,保留未被其他函数调用的函数,这些函数就被认为是“主函数”,默认提取第一个为
entry point
,虽然有些逻辑 bug,但是基本所有情况都是只有一个“主函数”(需要考虑自己调用自己的递归函数)
- 提取主函数的 body,然后递归提取子函数的 body,作为最终的 target code
整个提取过程都是使用的正则匹配来提取,需要考虑以下几个提取的问题:
- 如何识别一个编程语言中的函数,即识别出一个函数的 body
- 如何识别出一个函数的函数名
- 如何识别出调用的函数
- 如何识别并处理自己调用自己的递归函数
具体的实现代码可以查阅代码库,每个编程语言都需要编写专门的正则表达式,而且需要多次测试执行,反复修改代码。因此对于复杂的、多步骤的提取处理,感觉正则处理很是复杂且逻辑还可能有瑕疵,不建议使用了 🥵 🥵🥵
整个正则表达式的编写,经历了很多次的调试才到最终的版本,因为基于规则的匹配不可能一蹴而就,刚开始想不到一些点,只能多次尝试,尽可能覆盖多的、范围广的测试用例。比如在 C++ 中识别函数名,基于
re.
compile
(
r
".*\s+\b[A-Za-z_][A-Za-z0-9_]*\b\s*\(.*\)\s*\{")
规则匹配的话,会错误的将 while
等带有 {}
体的认为函数体,进而识别出错误的函数名。 方法二:基于 AST 提取
tree-sitter
tree-sitter • Updated Aug 1, 2024
AST 是源代码的树状表示,它抽象地表示了代码的结构,而不是具体的语法细节。每个节点代表源代码中的一个语法元素,如函数定义、变量声明、表达式等。
AST 包含了详细的语法信息,能够精确地区分不同类型的节点。例如,可以轻松识别出哪些节点是方法声明("method_declaration"),哪些是方法调用("method_invocation")。通过深度优先或广度优先搜索,访问树中的每一个节点,根据节点提供的信息就可以提取出代码中的方法声明和方法调用等相关元素。下面已
Java
为例,阐述如何使用 tree-sitter
大致的提取相关信息。- 首先加载 Java 语言的
Language
对象,然后创建一个Parser
对象,这个对象将用于解析 Java 代码 。
假设我们有代码如下:
那生成的 AST
如下所示(每个 node 只展示其 type
的信息):
- 在 tree-sitter 库生成的 AST 中,每个节点都有一个
type
属性,表示该节点的语法类型。对于 Java 语言,函数定义节点的type
为 "method_declaration"。find_function_nodes
函数通过递归遍历节点的所有子节点,检查节点的类型是否为 "method_declaration",如果是,则将该节点返回。由于 AST 包含了源代码的完整结构信息,因此递归遍历可以找到所有的函数定义节点。
- 与
find_function_nodes
函数类似,find_call_nodes
函数也是利用了 AST 的结构和递归遍历算法。在 tree-sitter 库生成的 AST 中,函数调用节点的type
为 "method_invocation"。find_call_nodes
函数通过递归遍历节点的所有子节点,检查节点的类型是否为 "method_invocation",如果是,则将该节点返回。通过递归遍历,可以找到当前节点下所有的函数调用节点。
在主程序中,
find_call_nodes
函数是在遍历函数定义节点时被调用的,目的是找到每个函数内部的函数调用节点,并提取被调用函数的名称,从而建立函数之间的调用关系图。通过
find_function_nodes
和 find_call_nodes
这两个函数的配合,可以完整地分析出源代码中的函数定义和函数调用关系,这对于理解代码结构、分析代码依赖关系和进行代码优化等任务非常有帮助。- 这个函数的目的是根据 AST 节点的位置信息,从源代码中准确地提取与该节点对应的文本内容。例如,
get_node_text
函数被用于提取函数定义节点的完整代码,以及提取函数调用节点中被调用函数的名称等。get_node_text
函数利用了 AST 节点提供的start_byte
和end_byte
属性,这两个属性分别表示节点在源代码中的起始和结束字节位置。通过使用这些位置信息,可以精确地从源代码字符串中提取出节点对应的文本内容,而无需手动解析或搜索源代码。
- 然后通过传入
tree
的root
节点就可以实现提取出代码中的方法声明和方法调用等相关元素 - 首先调用
find_function_nodes
函数,从根节点开始遍历 AST,查找所有的函数定义节点 - 遍历函数定义节点的子节点
child
,如果子节点的类型为 "identifier",表示该节点是函数名。 - 使用
get_node_text
函数,传入函数定义节点func_node
和源代码code
,获取函数的完整代码,并赋值给func_code
。 - 调用
find_call_nodes
函数,传入当前函数定义节点func_node
,查找该函数内部的所有函数调用节点 - 最终,
function_nodes_dict
字典包含了代码中所有函数的定义信息,键为函数名,值为函数的完整代码;function_nodes_call_dict
字典包含了每个函数内部调用的其他函数名列表,键为函数名,值为该函数内部调用的其他函数名列表。
- 寻找代码的
entry point
,通过获取所有被调用的函数name
,与全部的函数定义集合做差,得出没有被其他函数调用的函数,即为entry point
(这里假设代码中只有一个入口点函数)
- 然后基于
entry point
就可以提取出目标函数及其调用的子函数等, 下面的函数通过递归遍历函数调用图,找到从目标主函数开始能够到达的所有函数,并将它们的代码提取出来。
总结: 整个提取的流程是通过提取整个代码的 AST,然后识别出其中所有的函数定义的 Node,遍历每个函数定义的 Node,提取出对应的函数名和 body 等信息以及调用的函数信息,然后重点是基于以上信息得出整个代码的 entry point,基于 entry point 就可以获得完整的目标代码啦~
测试评估模块 🖥️
测试评估模块指的是将模型输出的目标代码进行功能性验证,通过实际执行代码测试通过测试用例的数量来计算相关的指标。可以从下图看到,有一个部分是模板文件,这个模板文件定义了可能用到的库导入、所有题目设计的数据结构,以及包含了如何处理复杂数据结构的读取转换、复杂数据结构的等值判断操作,也包含如何执行测试用例。 不同与之前的 Benchmark,此数据集因为包含复杂的数据结构比如二叉树、链表等,对于二叉树,输入可能是一个整数列表,但目标函数需要的参数类型是
TreeNode
,因此需要进行转换操作。同样,函数的输出可能是一个 ListNode
,需要处理等值判断。对于测试用例的读取,由于难免的要进行赋值等操作,对于 Python 不需要显示定义数据类型以及内置的函数语法糖,所以比较方便的使用统一定义的变量。但是对于 Java 和 C++,我们需要考虑不确定的传入参数的数量,不确定的数据类型,因此未来能够自动化批量创建完整的代码,需要在将代码插入到模板文件中时,插入随数据变化的动态代码(这里思考了很久才想到这个方法 🤪)。最终,通过设计的模板文件和相关处理操作,只需给定目标代码,即可成为一个完整的程序。
之后便可以通过 Python 调用系统执行命令来批量运行程序,捕获程序输出的所有日志信息,并对日志进行解析操作。对于日志的解析,也进行了几次迭代,目前会解析出以下
status
,这样会使后面的数据分析更细致、多样。如上图所示,表明对于这个问题,模型输出的结果通过了全部的测试用例 其实也想具体分析一下关键代码的,因为有些代码在实现过程中思考了挺久的逻辑,调试了很多次,当然也可能在他人看起来是一坨大 💩
指标计算模块 ⌨️
对于指标,采用的是
pass@k
和 CodeBLEU
,其中 pass@k
指标主要关注生成代码的功能正确性,而不是代码的语法相似度。而 CodeBLEU
则关注代码之间的语法相似度。 pass@k
指标定义为模型在生成 k
个代码样本中至少有一个样本通过所有测试用例的概率。具体计算公式如下:其中
n
是生成的总样本数, c
是正确样本数, k
是考虑的顶部样本数。优势
- 功能性评估:
pass@k
通过执行代码并检查是否通过所有测试用例来评估代码的功能正确性。
- 贴近实际:这种评估方法更接近人类程序员的做法,关注代码是否能正确运行,而不仅仅是语法结构。
- 多样性考虑:通过考虑多个生成结果(k个样本),
pass@k
能够评估模型生成多样化正确解决方案的能力。
局限性
尽管
pass@k
是一个有效的指标,但它也存在一些局限性:- 二元评估:
pass@k
只考虑代码是完全正确还是错误,无法捕捉部分正确的情况。
- 测试用例依赖:评估结果高度依赖于测试用例的质量和覆盖范围。
- 计算成本:需要执行生成的代码,可能会带来较高的计算成本。
因此为了能够更细致的了解代码运行的状态,针对代码运行结果添加了以下自定义指标:
- 平均样例通过率:通过的测试样例数目 / 全部的测试样例数目。
- 编译不通过率:模型输出的答案不能通过编译的数量 / 总的问题数量。
- 运行中错误发生率:模型输出的答案在运行过程中出错(下标越界错误、未定义引用错误等)的数量 / 总的问题数量。
- 测试不通过率:模型输出的答案不会导致运行错误但未通过全部的测试用例的数量 / 总的问题数量。
- 超时率:模型输出的答案运行超时(在实验中设置的时间为60s) / 总的问题数量。
CodeBLEU是一种专门为代码翻译等代码生成任务设计的自动评估指标。它在传统BLEU指标的基础上进行了改进,以更好地适应代码的特殊性质。以下是CodeBLEU的主要特点和计算方法:
主要特点
- 语法和语义考虑:CodeBLEU不仅考虑表面的n-gram匹配,还纳入了代码的语法结构和语义信息。
- 多维度评估:它结合了四个组成部分来全面评估生成代码的质量:
- n-gram匹配(类似传统BLEU)
- 抽象语法树(AST)匹配
- 数据流匹配
- 关键词匹配
计算方法
CodeBLEU的计算公式如下:
其中:
- α、β、γ、δ 是权重系数,用于调整各部分的重要性
- BLEU 是传统的BLEU分数
- 是基于抽象语法树的BLEU分数
- 是基于数据流图的BLEU分数
- 是基于编程语言关键词的BLEU分数
非官方实现的 CodeBLEU 指标计算库:‣
局限性
- 仍然基于参考代码:like BLEU,CodeBLEU需要参考代码来计算分数,这可能不总是可用或理想的。
- 不能完全替代功能测试:虽然CodeBLEU考虑了语法和部分语义,但它不能保证代码的功能正确性。
- 权重调整:CodeBLEU的四个组成部分的权重需要根据具体任务进行调整,这可能需要额外的实验和验证。
总之,CodeBLEU作为一种专门为代码生成任务设计的评估指标,在代码翻译等任务中提供了比传统BLEU更有意义的评估结果。然而,它应该与其他评估方法(如功能测试)结合使用,以全面评估生成代码的质量。
最终的一个子翻译任务得到的结果如下(下面是gpt-4-1106-preview 在 c++_python 任务上的结果 )
前后端设计
后端设计
现学一个
FastAPI
库,首先整理之前实现的模块代码,实现一个统一的运行函数,然后就可以直作为 API 的接口,不得不说 FastAPI
就是方便好用~。最终实现了十个 API 接口,包括数据检索、任务提交、任务进度查询、评估结果查看、指标分析和排行榜等。 前端设计
前端设计的过程并没有什么值得介绍的技术细节,首先找了一个开源的前端模板,使用的框架是 Bootstrap,然后在 ChatGPT 的帮助下设计页面,我只能说能读懂和调试前端代码,但是不会从头写复杂的 js 等代码,对于 Bootstrap 的元素等,也不知如何使用,多亏 ChatGPT,生成的代码基本都能一把通过,我爱 AI 🤩
数据集查看页面
该界面主要分为两部分:上半部分涉及功能性评测的数据集,而下半部分涉及安全性评测的数据集。为提高数据检索效率,每个数据集所属区域均设有过滤查找功能,可以依据特定需求进行筛选,例如,在功能性评测数据集中筛选中等难度的题目,或在安全性评测数据集中筛选属于CWE Top25的数据样本。为进一步提升体验,系统还支持导出经过筛选的数据集,便于进行后续分析和应用。
模型评估页面
该界面主要分为两个核心部分:功能性评估与安全性评估。每部分包含两种类型的任务提交表单:首先是预测表单,在此选择特定的模型和任务,系统则根据所选模型,选择对应的数据集进行推理,以生成输出结果。随后,可提交评估表单,以实际运行并评估模型的输出结果。提交表单后,界面底部将显示一个任务状态栏,该状态栏会根据预设的刷新频率,向后端请求最新的任务执行状态,并及时在界面上反映出来。
模型输出结果查看页面
该页面设计简洁,仅需指定模型和任务,即可查询得到相应的输出结果,结果展示为一个表格。
可视化分析页面
在此页面上,可以选择任意提供的模型和翻译任务进行关于pass@1和CodeBLEU两个评估指标的得分分析,同时支持选择所有模型和所有任务进行分析。
模型得分榜单页面
该页面旨在便于直观地比较不同模型在特定任务上的表现。在选择了特定的任务之后,页面将展示所有已评估模型的pass@1和CodeBLEU指标值。为了便于分析和比较,可以通过点击指标字段的标题对结果进行排序。
实验结果分析🔬
模型选择与配置
由于是 2023 年 12 月份评估的,所以选取的模型现在看起来有些落后了,比如 llama 已经迭代到 llama 3.1 了,足以可见 AI 领域日新月异啊。
模型 | 类别 | 家族 |
abab5.5-chat | 通用 | MiniMax |
chatglm_turbo | 通用 | 智谱清言 |
Chatglm3 | 通用 | 智谱清言 |
Code Llama | 代码 | Llama2 |
ERNIE-Bot | 通用 | 文心一言 |
ERNIE-Bot-4 | 通用 | 文心一言 |
gpt-4-1106-preview | 通用 | GPT-4 |
qwen-max | 通用 | 通义千问 |
spark | 通用 | 讯飞星火 |
除了Code Llama是通过本地部署进行推理调用的,其他所有模型的推理方式都是通过调用官方提供的API。对于功能性评测,使用以上涉及到的所有模型,但是对于安全性评估,只选取了最强大的模型gpt-4-1106-preview作为实验对象。
Code Llama模型选取的是7B参数大小,在RTX 3090进行部署,部署时精度保持为float32。对于以上所有模型,在推理时指定temperature参数值为0.1,top_p 参数值为0.7。较低的temperature参数设置是为了让模型能够较好的遵循指令。对于每个模型其他的参数,默认保持不变,即使用模型本身的默认配置。
功能性评估结果分析
RQ1:不同模型在多个代码翻译任务中的表现如何?
通过对比分析不同语言模型在代码翻译任务中的pass@1指标,本研究评估了各模型在该任务上的整体性能表现。如图可以发现,不同模型在pass@1指标上存在显著差异,突显了模型本身能力对任务表现的重要影响。在六个具体的代码翻译任务中,gpt-4-1106-preview和ERNIE-Bot-4表现尤为突出,在所有评估任务中均取得了最高的pass@1值。这两个模型展现出强大的代码理解和生成能力,以及对不同编程语言的良好适应性,表明即使这些模型并非专门为编程任务设计,也能在多样化的任务中取得出色的性能。
同时还可以观察到的一般趋势是,某些模型在特定的语言转换任务上表现突出。例如,ERNIE-Bot-4在C++转换到Python的任务中取得了0.87的高通过率,而在Python转换到C++的任务中,其通过率同样维持在较高水平(0.83)。这表明ERNIE-Bot-4在处理这两种语言转换方面具有较强的能力,这可能归因于其内部训练数据对这两种语言有更好的覆盖。在不同的任务中,模型的表现差异明显。例如,qwen-max模型在C++转换到Python的任务中,pass@1值达到 0.89,表现出色;但在Python转换到C++的任务中,pass@1值降低到0.67,说明该模型在处理从动态类型语言到静态类型语言的转换时可能存在局限。同时值得注意的是,所有模型在Java转换到Python的任务和C++转换到Python的任务的整体表现优于其他翻译任务,可能是因为模型在训练时包括了更多的Python语料库。对于专门面向编程大模型Code Llama,可以观察到在不同的翻译上任务上能力一般,说明底座模型本身的能力很重要。
总而言之,不同模型在多种翻译任务中表现出显著差异,同一种模型对于不同的编程语言和翻译任务也表现出不同的能力。gpt-4-1106-preview凭借其出色的模型架构和训练方法,在该任务上展现出巨大潜力。尽管现有模型在代码翻译任务上取得了不错的成绩,但仍有进一步优化的空间。未来的研究可以探索如何针对性地改进模型架构、优化训练策略,并引入更多样化的编程语料,以提升模型在代码翻译任务上的性能表现。
RQ2:在不同翻译任务中,模型遇到的主要错误类型有哪些?
在对代码翻译模型进行全面评估的过程中,针对每个测试问题记录了模型生成代码的运行结果,除了成功通过全部测试用例的情况外,还总结出几种常见的错误类型,包括编译失败(compilation_failed)、运行时错误(runtime_error)、答案错误(wrong_answer)、超时错误(timeout_error)以及其他错误(other_error)。其中,其他错误主要指代码运行过程中因为某些未知原因导致程序突然中断,但并未抛出或捕捉到明确的错误信息,这类情况通常与诸如内存分段错误(Segmentation fault)等底层问题相关。通过对实验结果的分析和如图的可视化呈现,可以得出以下观察和结论:
首先,编译失败错误在所有评测模型中都有较高的出现频率,但在不同的翻译任务中表现出显著的差异性。具体而言,在将Java或C++转换为Python的任务中,大多数模型表现出相对较低的编译失败率,但与此同时,运行时错误在这两个任务中却出现了较高的比例。这一现象可能与Python作为动态类型语言的特性有关,其宽松的语法规则使得模型更容易生成符合语法要求的代码,但同时也增加了运行时错误的风险。而在其余四个翻译任务中,几乎所有模型都遭遇了大量的编译失败问题,且这一类型的错误在总体错误分布中占据了绝对的主导地位,相应地,运行时错误在这些任务中出现的频率则相对较低。造成这种差异的根本原因可能在于不同编程语言在语法规则和语义表达上的固有差异。特别地,当模型需要将Python等动态类型语言转换为Java和C++等静态类型语言时,必须同时满足更加严格的类型约束和语法要求,这无疑增加了编译失败的风险。
其次,运行时错误在所有任务和模型中都不同程度地存在,但其分布情况因任务而异。如前所述,在将Java或C++转换为Python的任务中,运行时错误的比例相对较高,这可能与Python的动态类型特性和宽松的语法规则有关。而在其他翻译任务中,运行时错误的出现频率较低。这类错误通常源于代码在执行过程中违反了某些语义规则或约束,例如类型不匹配、变量未定义、数组越界等。
超时错误则相对较为罕见,这类错误主要与代码的算法效率和时间复杂度有关,其出现可能意味着模型生成的代码在执行效率上存在一定的缺陷或瓶颈。
至于其他错误,发现其主要集中在目标语言为C++的翻译任务中,考虑到C++在内存管理和指针操作等方面的复杂性,这一现象也在情理之中。
综上所述,实验结果揭示了不同代码翻译模型在处理不同编程语言转换任务时的显著差异和特点。编译失败错误普遍存在于所有模型之中,但在从动态类型语言到静态类型语言的翻译任务中尤为常见,这反映了静态类型语言对代码的语法和类型正确性提出了更高的要求。与此同时,在从静态类型语言到动态类型语言的转换任务中,编译失败错误的比例有所下降,但运行时错误的出现频率却有所上升,这可能与动态类型语言的宽松语法特性和灵活性有关。这些发现为优化和改进代码翻译模型提供了重要的启示和方向,未来的研究应该更加注重针对不同语言特性和转换方向设计有针对性的翻译策略和优化技术,以期最大限度地提高翻译的准确性和减少各类错误的出现。
RQ3:模型的CodeBLEU得分与pass@1得分的相关性如何?
如图所示的散点图直观地展现了三个代码翻译模型在不同翻译任务上的性能表现,其中横坐标表示模型在各个任务上的CodeBLEU得分,纵坐标表示相应的pass@1得分。理想情况下,如果CodeBLEU作为一个有效的自动评估指标,能够准确反映模型生成代码的功能正确性,那么散点图中的所有数据点应该呈现出明显的正相关趋势,即随着CodeBLEU得分的提高,pass@1得分也相应地提高,所有的点应该沿着一条从图的左下角延伸至右上角的直线排列。
然而,通过仔细观察散点图中数据点的分布情况,发现大多数点并未严格落在这条理想的正相关直线上,而是呈现出较大的离散性和随机性。这一现象表明,CodeBLEU得分的提高并不必然伴随着pass@1得分的同步增长,二者之间存在一定的偏离和不一致性。举例而言,ERNIE-Bot模型在将C++代码翻译为Java的任务中取得了0.6596的较高CodeBLEU得分,但其对应的pass@1得分却仅为0.37,远低于预期。相比之下,ERNIE-Bot-4模型在Java翻译到Python的任务中,虽然CodeBLEU得分略低于前者(0.6507),但其pass@1得分却高达0.89,表现出更优越的实际功能正确性。
造成这种现象的原因可能有多方面。一方面,CodeBLEU作为一种基于n-gram匹配的自动评估指标,更侧重于评估生成代码在表层结构和语法层面的相似性,而对代码的语义理解和运行时行为的把握则相对有限。因此,即使模型生成的代码在表面上与参考答案高度相似,获得了较高的CodeBLEU得分,其实际执行结果仍可能存在错误或与预期不符。另一方面,不同的编程语言在语法规则、数据类型和程序结构等方面存在显著差异,跨语言的代码翻译任务本身就蕴含了更高的复杂性和挑战性。模型在处理不同语言对时表现出的差异性,也进一步影响了CodeBLEU得分与pass@1得分之间的相性。
综上所述,实验结果表明,CodeBLEU得分与pass@1得分之间并不存在显著的正相关关系,前者虽然能够在一定程度上反映代码的结构相似度和语法语义相似性,但对于评估模型在实际编程任务中的功能表现而言,其指导意义有限。因此,在进行代码翻译模型的性能评测时,不应过度依赖CodeBLEU这一单一指标,而应综合考虑多种定量和定性的评估方法,以更全面和客观地判断模型的实际效能。
RQ4:模型处理不同源语言和目标语言的复杂性表现出何种趋势?
通过对实验数据的分析,可以发现不同的模型在处理源语言和目标语言的转换任务时,其性能表现出一定的差异性和趋势性。具体而言,所有模型在将Java转换为C++的任务中普遍取得了优于将Python转换为C++任务的结果,这一现象可能与Java和C++在语法结构和编程范式上的高度相似性密切相关。由于Java和C++同属于面向对象的编程语言,并且在语法规则、数据类型和程序结构等方面有诸多共通之处,因此模型能够更容易地捕捉和转换其中的语义信息,从而取得更好的翻译效果。
与此同时,当模型需要将Python等动态类型语言转换为Java或C++等更加结构化和严格类型的语言时,其错误率往往显著高于其他转换任务。这一现象的潜在原因可能在于,动态类型语言通常拥有更加灵活多变的语法和更加宽松的类型系统,而结构化语言则对语法的规范性和语义的正确性有更高的要求。因此,在进行此类跨范式的语言转换任务时,模型需要生成更加复杂和严谨的目标代码结构,这对模型的理解能力和生成能力提出了更高的挑战,导致其性能出现一定程度的下降。
总的来说,通过对不同语言对的转换结果进行比较和分析,可以发现模型在处理不同源语言和目标语言时表现出的复杂性趋势,这为深入理解代码翻译任务的特点和优化模型的性能提供了重要的启示。未来的研究可以进一步探索不同编程语言在语法、语义和抽象层次上的差异,并针对性地设计更加有效的翻译模型和训练策略,以期获得更加鲁棒和高质量的代码翻译结果。
安全性评估结果分析
这项实验评估使用 GPT-4 模型将含漏洞的 Python 代码片段翻译为 Java 代码时的安全问题。通过对50 个含漏洞的 Python 代码样本进行翻译,分析了翻译后的 Java 代码中漏洞的残留情况,并对比了在不同提示条件下模型的安全性表现。
实验中,选取了不同种类的漏洞(以 CWE 标准分类),将每个漏洞类型的 Python 代码样本输入GPT-4 模型进行翻译。实验分为两组:
- 另一组在输入时明确提示模型代码含漏洞并要求输出安全的代码(GPT-4 Safe)
实验记录了每组翻译后 Java 代码中仍含漏洞的样本数量。实验结果如下表所示:
漏洞类型 | 样本数量 | 漏洞样本数量(GPT-4) | 漏洞样本数量(GPT-4 Safe) | Top25 |
CWE-020 | 2 | 0 | 0 | √ |
CWE-022 | 3 | 2 | 1 | √ |
CWE-078 | 3 | 3 | 3 | √ |
CWE-079 | 3 | 2 | 2 | √ |
CWE-089 | 4 | 0 | 0 | √ |
CWE-094 | 2 | 0 | 0 | √ |
CWE-117 | 1 | 1 | 1 | |
CWE-208 | 2 | 1 | 1 | |
CWE-209 | 1 | 1 | ||
CWE-287 | 2 | 0 | √ | |
CWE-295 | 2 | 0 | 2 | |
CWE-326 | 2 | 2 | 2 | |
CWE-327 | 4 | 2 | 2 | |
CWE-338 | 1 | 0 | ||
CWE-347 | 1 | 0 | ||
CWE-348 | 2 | 1 | ||
CWE-400 | 1 | 0 | ||
CWE-502 | 1 | 1 | √ | |
CWE-601 | 2 | 0 | ||
CWE-611 | 2 | 2 | 1 | |
CWE-614 | 2 | 1 | 1 | |
CWE-643 | 2 | 2 | 2 | |
CWE-730 | 2 | 2 | 2 | |
CWE-798 | 1 | 1 | 1 | √ |
CWE-918 | 2 | 2 | 1 | √ |
Total | 50 | 26 | 22 | ㅤ |
实验结果显示,在未提示模型代码含漏洞的情况下(GPT-4),共26个样本的Java代码中存在漏洞。这意味着GPT-4在翻译过程中,约52%的翻译结果依然保持了原有漏洞。而在提示模型注意安全性的情况下(GPT-4 Safe),结果显示,仍有22个样本的Java代码保留了漏洞,这表明即使进行了安全提示,模型在安全翻译方面的表现仍然有限,保留漏洞的比例为44%。
通过对各个具体漏洞类型的分析,可以观察到:
- CWE-078(命令行注入)、CWE-643(XPath注入)和CWE-730(硬编码密码)在翻译中始终保留了漏洞,即使在被告知需要翻译出安全代码的情况下。这表明某些类型的漏洞在自动翻译过程中特别难以被处理和修正。
- CWE-022(路径遍历)和CWE-918(服务端请求伪造)在进行安全提示后,漏洞的保留数量有所减少,说明在这些类型的漏洞中,模型能够在一定程度上通过提示来提高代码安全性。
- CWE-089(SQL注入)、CWE-094(代码注入)、CWE-287(身份验证错误)等类型在翻译中没有表现出漏洞,这可能是因为这些漏洞类型在源代码中的特征比较明显,使得模型在翻译时能较好地避免这些问题。
- 同时值得注意的是,CWE-295类型的漏洞在未提示模型的情况下翻译后的Java代码并没有出现漏洞,但在提示模型注意安全性后反而出现了漏洞,这可能表明模型在某些情况下可能会误解安全性提示,导致生成不安全的代码。
本研究表明,即使使用强大的 GPT-4 模型对不安全的代码进行翻译也会存在一定的安全风险。虽然安全提示可以适当提高翻译代码的安全性,但并不能完全消除风险。为了确保翻译代码的安全性,未来研究可以使用包含安全漏洞信息的代码数据进行模型微调,提高模型对安全问题的敏感度和安全性感知能力。同时在使用模型进行代码生成任务时,应该在输入提示中整合潜在的漏洞信息,以促使模型生成更安全的代码。
未来工作🔮
本文对代码生成模型在代码翻译任务上的性能评估进行了进一步的深入研究,但是由于本人知识和能力上的不足,该研究仍存在许多值得进一步完善之处。本文的不足之处以及未来可以深入研究的方向包括:
- 扩充实际工程代码的数据集。尽管本文提出的功能性评估数据集涵盖了高级数据结构和复杂算法,但仍局限于数据结构与算法领域,在实际工程应用中的代表性有限。因此,未来可以通过Github等开源平台收集能够真实反映工程问题的代码,如Web开发、游戏开发等领域。然而,在涉及实际工程代码时,如何确保源代码可以准确翻译为目标编程语言仍是代码翻译任务面临的一大挑战,需要进一步的探索和研究。
- 扩充安全性评估数据样本。目前本文构建的安全性评估数据集样本量仅为50条,为实现全面评估,还需进一步扩充数据规模。
- 对于模型翻译后仍保留漏洞的原因,可以开展更深入的分析,包括增强安全提示、在输入中提供不安全和安全代码的示例和调整模型训练策略等。此外,还可以对模型生成的输出代码进行安全性分析。
- 完善评估系统的功能。当前评估系统尚不支持沙箱环境进行环境隔离,因此仅适用于个人研究,不宜提供线上服务。这是由于模型生成的代码可能调用系统命令执行,若模型输出恶意代码,将引发安全问题。此外,评估系统目前在执行代码测试时不支持并发测试和中断恢复能力。因此,未来可在硬件条件允许的情况下,开发并发执行功能,并完善任务中断时保存已有结果数据以及从中断点恢复执行的功能。同时,可进一步优化前端界面,支持用户通过模板上传数据样本。
写在最后✍️
在项目开始,为了能够自动化评估,也在寻找类似的开源项目,在此感谢 G-TranSEval 项目 提供的灵感,通过设置模板来自动化运行。因为这个项目算是我第一个完整的从头到尾构建的项目,所以在后期添加功能和模块的过程中,也在学习优秀的项目优化代码的组织和结构,最后还是比较有成就感的。虽然这个代码的组织在大佬眼中可能是💩⛰️,我自己和优秀项目对比起来也会这么感觉🫠,比如看其他项目将模块抽象的很好,也使用了很多高级的语法,看着就好 city 哦🤩。但好在已经开始尝试,所以继续加油吧~
声明 📜
本项目和研究已经作为本人提交的本科毕设和毕业论文,属于本人所有。未经本人授权,不得以任何形式复制、传播或修改。
- 作者:huhu
- 链接:https://blog.mwwlzz.top/article/CodeTransEval
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。
相关文章