BigCodeBench:下一代 HumanEval
HumanEval 是评估大型语言模型 (LLM) 代码生成任务的参考基准,因为它简化了对紧凑函数级代码片段的评估。然而,其在评估 LLM 编程能力方面的有效性日益受到关注,主要担忧是 HumanEval 中的任务过于简单,可能无法代表真实世界的编程任务。与 HumanEval 中面向算法的任务相比,真实的软件开发通常涉及多样的库和函数调用。此外,LLM 在 HumanEval 上的表现容易受到污染和过拟合问题的影响,这使其在评估 LLM 的泛化能力方面可靠性较低。
尽管已经有一些努力来解决这些问题,但它们要么是特定领域的、确定性的,要么是面向 Agent 的(抱歉了 DS-1000、ODEX 和 SWE-bench 💔)。我们认为社区仍然缺乏一个易于使用、能够广泛评估 LLM 编程能力的基准,而这正是我们关注的重点。
我们很高兴地宣布发布 BigCodeBench,它可以在无污染的情况下评估 LLM 解决实际且具有挑战性的编程任务的能力。具体来说,BigCodeBench 包含 1140 个函数级任务,挑战 LLM 遵循指令并组合来自 139 个库的多个函数调用作为工具。为了严格评估 LLM,每个编程任务都包含 5.6 个测试用例,平均分支覆盖率达到 99%。
准备好深入了解 BigCodeBench 了吗?让我们开始吧!🚀
BigCodeBench 中的任务是什么样的?🕵️♂️
BigCodeBench 每个任务都具有复杂的、面向用户的指令,包括清晰的功能描述、输入/输出格式、错误处理以及经过验证的交互式示例。我们避免了分步式的任务指令,认为有能力的 LLM 应该能够从用户的角度以开放式的方式理解和解决任务。我们使用测试用例来验证特定功能。
# We elaborate the above task with some test cases:
# Requirements SetUp
import unittest
from unittest.mock import patch
import http.client
import ssl
import socket
# Start the test
class TestCases(unittest.TestCase):
# Mock the successful connection and assess the response content
@patch('http.client.HTTPSConnection')
def test_response_content(self, mock_conn):
""" Test the content of the response. """
mock_conn.return_value.getresponse.return_value.read.return_value = b'Expected Content'
result = task_func('www.example.com', 443, '/content/path')
self.assertEqual(result, 'Expected Content')
# Mock the failed connection and assess the error handling
@patch('socket.create_connection')
@patch('http.client.HTTPSConnection')
def test_ssl_handshake_error_handling(self, mock_conn, mock_socket):
""" Test handling of SSL handshake errors. """
mock_socket.side_effect = ssl.SSLError('SSL handshake failed')
with self.assertRaises(ssl.SSLError):
task_func('badssl.com', 443, '/test/path')
# More test cases...
BigCodeBench 中的任务利用了来自流行库的多种函数调用。我们不限制 LLM 可以使用的函数调用,期望它们能够选择合适的函数并灵活地组合它们来解决任务。测试用例被设计为测试框架,用于在运行时检查预期的程序行为。
为了评估 LLM 的性能,我们使用贪心解码的 Pass@1,通过精心设计的测试用例,衡量模型使用首次生成的代码片段正确解决任务的百分比。这种方法与 HumanEval 和 MBPP 等基准一致。我们通过在 Pass@1 评估期间添加缺失的设置(例如,import 语句、全局常量)来解决 LLM 倾向于跳过长代码提示的问题,我们称之为校准 Pass@1 (calibrated Pass@1)。
为了更好地理解实现复杂性和工具使用的多样性,我们将 BigCodeBench 中的任务与一些代表性基准中的任务进行了比较,包括 APPS、DS-1000、ODEX、APIBench、MBPP、NumpyEval、PandasEval、HumanEval 和 TorchDataEval。我们发现,BigCodeBench 需要更复杂的推理和问题解决能力来实现全面的功能。
如任务图所示,主要目标场景是代码补全(表示为 BigCodeBench-Complete
),其中要求 LLM 根据文档字符串中的详细指令完成函数的实现。然而,考虑到多轮对话等下游应用,用户可能会以更具对话性、更简洁的方式描述需求。这正是指令调优的 LLM 的优势所在,因为它们经过训练可以遵循自然语言指令并相应地生成代码片段。为了测试模型是否能真正理解人类意图并将其转化为代码,我们创建了 BigCodeBench-Instruct
,这是 BigCodeBench 的一个更具挑战性的变体,旨在评估指令调优的 LLM。
这些任务从何而来?🤔
我们通过系统的“人机协作流程”来保证 BigCodeBench 中任务的质量。我们以 ODEX 作为“种子数据集”开始,该数据集包含来自 Stack Overflow 的简短但真实的人类意图和相应的 Python 单行代码。我们使用 GPT-4 将这些单行代码扩展为全面的函数级任务。
接下来,20 位人类专家(其中大多数拥有超过 5 年的 Python 编程经验)自愿在一个基于执行的沙箱中指导 GPT-4。他们不断地指示它优化合成的任务并添加测试用例。然后,这些任务和测试用例在本地环境中进行检查,在其他 LLM 上进行预评估,并由另外 7 位人类专家进行交叉核对,以确保其质量。
为了确保整体质量,作者们抽样了一些任务让 11 位人类专家解决,达到了 97% 的平均人类表现。
大语言模型 (LLM) 在 BigCodeBench 上的表现如何?📊
我们在 Hugging Face Space 和 GitHub Pages 上都托管了 BigCodeBench 排行榜。在这里,我们以 Hugging Face 排行榜为例。
有趣的是,我们观察到像 GPT-4 这样的指令调优 LLM 在 BigCodeBench-Complete
的长提示中会省略必要的 import 语句,导致因缺少模块和常量而任务失败。这种行为被称为“模型懒惰”,在社区中有所讨论。
与人类表现相比,LLM 在 BigCodeBench-Complete
上的表现明显较低,在 BigCodeBench-Instruct
上的表现更低。最好的模型(GPT-4o)在 BigCodeBench-Complete
上实现了 61.1% 的校准 Pass@1,在 BigCodeBench-Instruct
上实现了 51.1%。此外,闭源和开源 LLM 之间存在显著的性能差距。
虽然 Pass@1 是一个衡量整体性能的好指标,但它不够详细,无法直接比较模型。受 Chatbot Arena 的启发,我们使用 Elo 评级来对 BigCodeBench-Complete
上的模型进行排名。这种方法最初用于国际象棋,根据玩家的比赛表现进行排名。我们将其应用于编程任务,将每个任务视为一场比赛,每个模型视为一名玩家。Elo 评级的更新基于比赛结果和预期,使用任务级别的校准 Pass@1(0% 或 100%),并排除平局。我们从 1000 的初始 Elo 评级开始,使用最大似然估计进行拟合,并通过 500 次自举 (bootstrap) 获得最终分数。我们发现 GPT-4o 以较大优势领先于其他模型,而 DeepSeekCoder-V2 处于第二梯队。
为了帮助社区了解模型在每个任务上的表现,我们跟踪了解决率,该解决率通过校准 Pass@1 来衡量。在 BigCodeBench-Complete
上,有 149 个任务仍未被任何模型解决,而有 6 个任务被完全解决。对于 BigCodeBench-Instruct
,有 278 个任务仍未被解决,有 14 个任务被所有模型完全解决。大量未解决的任务和少量完全解决的任务表明,BigCodeBench 对 LLM 来说是一个具有挑战性的基准。
太好了!那么,我该如何在 BigCodeBench 上评估我的模型?🛠️
我们通过提供一个简单且用户友好的评估框架,使社区可以轻松访问 BigCodeBench,该框架可通过 PyPI 下载。该评估框架的原型基于用于 HumanEval+ 和 MBPP+ 基准的 EvalPlus。然而,由于我们的基准测试任务的库依赖性比 EvalPlus 多样得多,我们构建了资源限制较少的执行环境,并将其调整为适用于 BigCodeBench 测试框架中的 unittest
。
为了方便评估,我们为代码生成和代码执行提供了预构建的 Docker 镜像。请查看我们的 GitHub 仓库,了解有关如何使用评估框架的更多详细信息。
设置
# Install to use bigcodebench.evaluate
pip install bigcodebench --upgrade
# If you want to use the evaluate locally, you need to install the requirements
pip install -I -r https://raw.githubusercontent.com/bigcode-project/bigcodebench/main/Requirements/requirements-eval.txt
# Install to use bigcodebench.generate
# You are strongly recommended to install the [generate] dependencies in a separate environment
pip install bigcodebench[generate] --upgrade
代码生成
建议您使用 flash-attn
来生成代码样本。
pip install -U flash-attn
要从模型生成代码样本,您可以使用以下命令:
bigcodebench.generate \
--model [model_name] \
--subset [complete|instruct] \
--greedy \
--bs [bs] \
--temperature [temp] \
--n_samples [n_samples] \
--resume \
--backend [vllm|hf|openai|mistral|anthropic|google] \
--tp [gpu_number] \
[--trust_remote_code] \
[--base_url [base_url]]
生成的代码样本将存储在一个名为 [model_name]--bigcodebench-[instruct|complete]--[backend]-[temp]-[n_samples].jsonl
的文件中。
代码后处理
LLM 生成的文本可能不是可编译的代码,因为它包含自然语言行或不完整的额外代码。我们提供一个名为 bigcodebench.sanitize
的工具来清理代码。
# 💡 If you want to store calibrated code in jsonl:
bigcodebench.sanitize --samples samples.jsonl --calibrate
# Sanitized code will be produced to `samples-sanitized-calibrated.jsonl`
# 💡 If you do without calibration:
bigcodebench.sanitize --samples samples.jsonl
# Sanitized code will be produced to `samples-sanitized.jsonl`
# 💡 If you are storing codes in directories:
bigcodebench.sanitize --samples /path/to/vicuna-[??]b_temp_[??]
# Sanitized code will be produced to `/path/to/vicuna-[??]b_temp_[??]-sanitized`
代码评估
强烈建议您使用沙箱,例如 docker
# Mount the current directory to the container
docker run -v $(pwd):/app bigcodebench/bigcodebench-evaluate:latest --subset [complete|instruct] --samples samples-sanitized-calibrated
# ...Or locally ⚠️
bigcodebench.evaluate --subset [complete|instruct] --samples samples-sanitized-calibrated
# ...If the ground truth is working locally (due to some flaky tests)
bigcodebench.evaluate --subset [complete|instruct] --samples samples-sanitized-calibrated --no-gt
下一步是什么?
我们分享一个长期路线图,以解决 BigCodeBench 的局限性,并与社区一起可持续地建设。我们的目标是为社区提供最开放、可靠和可扩展的评估,以真正了解 LLM 在编程方面的基本能力,并找出释放其潜力的方法。具体来说,我们计划在以下方面增强 BigCodeBench:
多语言性:目前,BigCodeBench 仅支持 Python,无法轻易扩展到其他编程语言。由于函数调用大多是特定于语言的,因此在 Python 以外的语言中找到具有相同功能的包或库具有挑战性。
严谨性:虽然我们在 BigCodeBench 中为基准解决方案实现了高测试覆盖率,但这并不能保证由 LLM 生成的所有代码解决方案都能通过现有测试用例得到正确评估。像 EvalPlus 这样的先前工作已经尝试通过基于 LLM 和突变的策略来扩充输入-输出对,从而扩展有限的测试用例。然而,将 EvalPlus 应用于 BigCodeBench 的测试框架具有挑战性。虽然 EvalPlus 强调输入-输出断言,但 BigCodeBench 中的大多数测试框架都需要非平凡的配置(例如,模拟补丁)来检查运行时的预期程序行为。
泛化性:一个关键问题是,“模型对未见过的工具和任务的泛化能力如何?”目前,BigCodeBench 涵盖了常见的库和日常编程任务。在那些使用新兴库(如 transformers 和 langchain)的编程任务上对模型进行基准测试会更有趣。
演进性:库可能会过时或更新,这意味着用于模型训练的源代码数据将不断演变。模型可能不会记住已弃用库版本的函数调用,这给任何依赖于工具的编程基准带来了挑战,使其难以在没有定期更新的情况下正确检验模型能力。另一个相关问题是由于训练数据的演变而导致的测试集污染。
交互性:最近的兴趣集中在作为智能体的 LLM 这一概念上,这被视为通往通用人工智能的一条路径。具体来说,LLM 将被置于一个限制较少的沙箱环境中,在那里它们可以与 Web 浏览器和终端等应用程序进行交互。这种环境有助于解锁自我调试和自我反思等能力。
我们很高兴看到社区的反馈和贡献,共同长期建设 BigCodeBench 🤗
资源
我们开源了 BigCodeBench 的所有产物,包括任务、测试用例、评估框架和排行榜。您可以通过以下方式找到它们:
如果您有任何问题或建议,请随时在仓库中提出问题,或通过 terry.zhuo@monash.edu 或 contact@bigcode-project.org 与我们联系。
引用
如果我们的评估对您有用,请考虑引用我们的工作:
@article{zhuo2024bigcodebench,
title={BigCodeBench: Benchmarking Code Generation with Diverse Function Calls and Complex Instructions},
author={Zhuo, Terry Yue and Vu, Minh Chien and Chim, Jenny and Hu, Han and Yu, Wenhao and Widyasari, Ratnadira and Yusuf, Imam Nur Bani and Zhan, Haolan and He, Junda and Paul, Indraneil and others},
journal={arXiv preprint arXiv:2406.15877},
year={2024}
}