三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE DETAIL

日记详情

真实记录编程学习的某一天,欢迎挑你感兴趣的翻一翻。

OpenCompass:一站式大模型评测平台实战指南

OpenCompass:一站式大模型评测平台实战指南

1. 项目概述:为什么我们需要一个“模型评测场”?

在人工智能模型,尤其是大语言模型(LLM)飞速发展的今天,我们每天都能看到各种新模型、新版本的发布公告。厂商们通常会宣称自己的模型在某某榜单上取得了“SOTA”(State-of-the-the-Art)成绩,或者在多项任务上“全面领先”。作为一个开发者、研究者,甚至是企业技术决策者,面对这些宣传,我们心里难免会打鼓:这些模型在实际应用中到底表现如何?是名副其实的“千里马”,还是经不起推敲的“纸老虎”?更重要的是,当我们需要为自己的项目选择一个合适的模型时,面对琳琅满目的选项,该如何科学、客观地做出判断?

这就是OpenCompass诞生的背景,也是它核心要解决的问题。你可以把它理解为一个大型、公开、公正的“模型评测场”或“竞技场”。它的目标不是为某个模型站台,而是提供一个标准化的“尺子”和“赛道”,让所有模型都在同一套规则下跑一跑,是骡子是马,拉出来溜溜便知。我最初接触OpenCompass,是因为团队需要评估几个开源模型在特定业务场景下的潜力,手动设计测试集、编写评测脚本不仅耗时费力,而且结果往往缺乏可比性。OpenCompass的出现,极大地简化了这个过程,它把模型评测从一项复杂的工程,变成了一个相对标准化的流程。

简单来说,OpenCompass是一个面向大模型的一站式、开源评测平台。它由上海人工智能实验室(上海AI Lab)发起并开源维护。它的核心价值在于“全面”与“开放”:全面体现在它集成了超过50个评测数据集,覆盖了从知识、推理、语言到长文本、代码、智能体等多个维度;开放则意味着它的评测框架、数据集、工具链都是开源的,任何人都可以复现评测结果,甚至可以基于它定制自己的评测任务。这打破了以往评测黑盒、结果不可复现的困境,让模型能力的评估变得更加透明和可信。

2. OpenCompass的核心架构与工作流拆解

要真正用好OpenCompass,不能只停留在“跑个分”的层面,理解其内部架构和工作流,能帮助我们在遇到问题时快速定位,也能让我们更灵活地定制评测任务。OpenCompass的架构设计清晰地分离了“评测什么”、“如何评测”和“在哪里评测”这几个关键问题。

2.1 核心组件:Dataset, Model, Evaluator 与 Runner

OpenCompass的评测流程围绕四个核心组件展开,它们像流水线上的不同工位,各司其职。

Dataset(数据集):这是评测的“考题”。OpenCompass支持多种格式的数据集,最常见的是通过加载 Hugging Face 数据集或处理本地文件。每个数据集包含若干条样本,每条样本通常有输入(prompt)和预期的输出(ground truth)。OpenCompass内置了海量数据集,从经典的MMLU(大规模多任务语言理解)、C-Eval(中文评估基准),到更专业的HumanEval(代码生成)、GSM8K(数学推理)等。理解数据集的特点至关重要,比如MMLU主要考察世界知识和问题解决能力,而HumanEval则严格测试代码的功能正确性。

Model(模型):这是参加评测的“考生”。OpenCompass支持多种模型接口,包括:

  • HuggingFace 模型:这是最常用的方式,直接通过transformers库加载本地或远程的模型文件。
  • API 模型:例如 OpenAI 的 GPT 系列、 Anthropic 的 Claude 等。通过配置API密钥和端点,可以评测闭源模型。
  • 自定义模型:通过继承基类并实现generate方法,可以接入任何形式的模型服务,比如企业内部部署的模型。

Evaluator(评测器):这是“阅卷老师”。它的职责是根据模型的输出和标准答案,给出一个分数。OpenCompass提供了多种评测器:

  • AccEvaluator(准确率评测器):用于单选题、判断题等,直接比对输出与答案是否一致。
  • CircularEvaluator:处理选项为循环列表(如A, B, C, D, A...)的情况。
  • CodeEvaluator:专门用于代码生成任务,它会动态执行生成的代码,检查其功能是否正确。
  • 自定义Evaluator:你可以实现自己的评分逻辑,比如基于规则的关键词匹配,或者调用另一个LLM作为裁判(LLM-as-a-Judge)。

Runner(运行器):这是“考场调度员”。它负责最繁重的工程工作:将庞大的数据集拆分成小块(partition),并发地提交给模型进行推理,并收集结果。Runner有两种主要类型:

  • 本地Runner:在单机或多卡环境下运行,适合快速验证和小规模评测。
  • Slurm Runner:用于高性能计算(HPC)集群,可以调度海量的计算任务,这是进行大规模、全量评测的必备工具。它负责管理任务队列、资源分配和容错重试。

2.2 一次评测的完整工作流

当你执行一条评测命令时,背后发生了以下事情:

  1. 配置解析:OpenCompass读取你的配置文件(一个.py文件),其中定义了要评测的模型列表、数据集列表以及评测方式。
  2. 任务生成:根据“模型×数据集”的组合,生成所有待执行的任务单元。例如,评测2个模型在5个数据集上,就会生成10个任务。
  3. 任务分区与派发:Runner将每个任务的数据集进一步切分成适合单次推理的批次(batch),然后根据配置(本地或Slurm)派发到相应的计算资源上。
  4. 模型推理:在每个计算节点上,加载指定的模型,对输入的prompt批次进行推理,生成回答。
  5. 结果评估:推理完成后,调用对应的Evaluator对模型的输出进行评分。
  6. 结果汇总与展示:所有任务完成后,OpenCompass会将分散的结果文件收集起来,汇总成一张清晰的表格(通常是CSV或HTML格式),展示每个模型在每个数据集上的得分(如准确率)。

这个流程看似复杂,但OpenCompass通过良好的封装,让用户只需要关注配置文件,大大降低了使用门槛。然而,在实际操作中,每个环节都可能遇到“坑”,尤其是在资源管理、错误处理和结果解读上。

3. 从零开始:手把手运行你的第一次模型评测

理论说得再多,不如亲手跑一遍。下面我将以一个最典型的场景为例:在本地使用单张GPU,评测一个开源的中文大模型(例如 Qwen-7B-Chat)在几个常见基准上的表现。这个过程会涉及环境搭建、配置编写、命令执行和结果解读。

3.1 环境准备与安装

首先,你需要一个具备Python环境和NVIDIA GPU的机器。我强烈建议使用Conda来管理环境,避免依赖冲突。

# 1. 创建并激活一个独立的conda环境 conda create -n opencompass python=3.10 -y conda activate opencompass # 2. 安装PyTorch(请根据你的CUDA版本选择对应命令,这里以CUDA 11.8为例) pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118 # 3. 克隆OpenCompass仓库并安装 git clone https://github.com/open-compass/opencompass.git cd opencompass pip install -e .

安装完成后,可以通过opencompass --version检查是否安装成功。这里有个关键点:如果你的网络环境导致克隆GitHub仓库或安装包缓慢,可以考虑使用国内镜像源。但请注意,所有操作均需在合规的网络环境下进行,严禁使用任何非法手段访问网络资源。

3.2 准备模型与数据

OpenCompass的一大优点是,对于许多热门开源模型和标准数据集,它已经内置了支持,无需手动下载。例如,要评测Qwen-7B-Chat,你通常只需要拥有该模型的HuggingFace格式的权重文件。你可以从ModelScope或HuggingFace Hub下载。

假设你已经将模型权重下载到了本地路径/path/to/qwen-7b-chat。接下来,我们需要一个配置文件来告诉OpenCompass评测什么以及如何评测。

3.3 编写评测配置文件

在OpenCompass目录下创建一个新的Python配置文件,例如configs/qwen_eval.py

from mmengine.config import read_base with read_base(): # 从预定义的配置中继承基础设置,比如数据集的加载方式 from .datasets.collections import piqa, siqa, winogrande, hellaswag # 我们添加几个常见的中文评测集 from .datasets.ceval.ceval_gen import ceval_datasets from .datasets.cmmlu.cmmlu_gen import cmmlu_datasets datasets = [] datasets += piqa datasets += siqa datasets += winogrande datasets += hellaswag datasets += ceval_datasets # 中文知识评测 datasets += cmmlu_datasets # 中文多任务语言理解 # 定义要评测的模型 from opencompass.models import HuggingFaceCausalLM qwen_7b_chat = dict( type=HuggingFaceCausalLM, # 你的模型本地路径 path='/path/to/qwen-7b-chat', tokenizer_path='/path/to/qwen-7b-chat', model_kwargs=dict( device_map='auto', torch_dtype=torch.bfloat16, # 根据你的GPU显存选择精度,bfloat16节省显存 trust_remote_code=True, # Qwen模型需要这个参数 ), tokenizer_kwargs=dict( padding_side='left', truncation_side='left', trust_remote_code=True, ), generation_kwargs=dict( do_sample=False, # 评测时通常使用贪婪解码,保证结果确定性 temperature=0, max_new_tokens=512, ), # 批处理大小,根据你的GPU显存调整 batch_size=8, run_cfg=dict(num_gpus=1), # 指定使用1张GPU ) models = [qwen_7b_chat]

这个配置文件做了几件事:

  1. 组合了多个数据集,包括英文常识推理(PIQA, SIQA等)和中文知识评测(C-Eval, CMMLU)。
  2. 定义了一个基于HuggingFace的Qwen模型,指定了模型路径、加载参数、生成参数和运行资源。
  3. 将模型放入models列表,这意味着一次可以评测多个模型,方便对比。

注意trust_remote_code=True对于许多国产模型是必须的,因为它允许执行模型作者提供的自定义代码。但这会带来安全风险,请确保你信任模型来源。在实际生产环境中,建议在隔离环境中进行此类评测。

3.4 执行评测与解读结果

配置好后,就可以运行评测了。对于本地小规模评测,使用以下命令:

python run.py configs/qwen_eval.py --debug

--debug参数非常有用,它只会运行每个数据集的一小部分数据(默认5条),用于快速验证你的配置、模型加载和数据流水线是否正常。如果一切顺利,你会看到任务被提交、推理进度条滚动,最后在outputs/default/目录下生成时间戳命名的文件夹,里面包含结果文件。

正式运行全量数据评测,使用:

python run.py configs/qwen_eval.py

这个过程可能会持续数小时甚至更久,取决于数据集大小和模型速度。运行结束后,你可以使用OpenCompass提供的工具来总结结果:

# 在结果目录下执行 python tools/summarize.py /path/to/your/output/dir

这个脚本会生成一个清晰的Markdown表格,汇总所有模型在所有数据集上的表现。例如,你可能会看到:

ModelC-Eval (val)MMLUGSM8KHumanEval...
Qwen-7B-Chat62.558.245.122.0...
Some-Baseline-Model55.352.730.515.5...

如何解读这些数字?

  • 不要只看总分或平均分:模型的能力是多维度的。一个在C-Eval(中文知识)上得分很高的模型,可能在代码生成(HumanEval)上表现平平。你需要根据你的应用场景来权衡。比如,如果你要做代码助手,那么HumanEval和MBPP的权重就应该提高。
  • 理解数据集的基准线:关注该数据集上公认的强基线模型(例如GPT-4、Claude-3)的分数,以及同类尺寸模型(其他7B模型)的平均水平,这能帮你判断模型的相对位置。
  • 注意评测的局限性:静态的、选择题形式的评测(如MMLU)无法完全反映模型的对话能力、安全性和指令遵循能力。OpenCompass也支持更复杂的评测,如主观题评测(需要LLM作为裁判),但这需要更复杂的配置和更高的成本。

4. 进阶实战:定制化评测与大规模集群部署

当你熟悉了基础流程后,你可能会遇到更复杂的需求:评测私有模型、使用自定义数据集、或者在拥有上百张GPU的集群上发起一次全面评测。这些才是OpenCompass真正发挥威力的地方。

4.1 集成私有模型与自定义数据集

集成私有模型:如果你的模型不是HuggingFace格式,或者需要通过特定的API访问(比如公司内部的推理服务),你需要编写一个自定义的Model类。

from opencompass.models.base import BaseModel from typing import List class MyCustomAPIModel(BaseModel): """一个调用内部API服务的模型示例""" def __init__(self, endpoint: str, api_key: str, **kwargs): super().__init__(**kwargs) self.endpoint = endpoint self.api_key = api_key # 初始化你的API客户端 # self.client = MyClient(endpoint, api_key) def generate(self, inputs: List[str], **kwargs) -> List[str]: """核心方法:接收一批输入文本,返回一批生成文本""" results = [] for prompt in inputs: # 调用你的内部API # response = self.client.chat(prompt, **kwargs) # results.append(response['text']) # 这里用模拟响应代替 results.append(f"Response to: {prompt[:20]}...") return results

然后在配置文件中,像使用HuggingFace模型一样使用它即可。

使用自定义数据集:假设你有一份JSONL格式的业务问答对,想评测模型在其上的表现。

  1. 准备数据文件my_data.jsonl,每行格式如:{"question": "xxx", "answer": "yyy"}
  2. 创建一个数据集配置文件configs/datasets/my_custom_dataset.py:
from opencompass.datasets import BaseDataset from mmengine.config import read_base with read_base(): from .datasets.my_custom_dataset.my_custom_dataset_gen import MyCustomDataset class MyCustomDataset(BaseDataset): def __init__(self, path: str, **kwargs): super().__init__(**kwargs) self.path = path self.data = self._load_data() def _load_data(self): import json data = [] with open(self.path, 'r', encoding='utf-8') as f: for line in f: item = json.loads(line) # 构建成OpenCompass需要的格式:至少包含'prompt'字段 data.append({ 'prompt': item['question'], 'ground_truth': item['answer'] # 可选,用于有标准答案的评测 }) return data def __getitem__(self, index): return self.data[index] def __len__(self): return len(self.data) # 在配置中引用 my_dataset = dict( type=MyCustomDataset, path='path/to/my_data.jsonl', reader_cfg=dict(...), infer_cfg=dict(...), # 指定生成参数 eval_cfg=dict(evaluator=dict(type=AccEvaluator)) # 指定评测器 )

通过这种方式,你可以将任何格式的业务数据接入OpenCompass的评测体系。

4.2 使用Slurm Runner进行大规模评测

当评测任务量巨大(几十个模型,上百个数据集)时,本地运行是不现实的。OpenCompass与Slurm工作流调度器的深度集成,使得它能够高效利用超算中心或公司内部的GPU集群。

其核心思想是:OpenCompass不再直接调用模型,而是根据你的配置,生成成千上万个独立的、可并行执行的Slurm作业脚本。Slurm集群负责这些作业的排队、调度、资源分配和运行。

你需要准备一个Slurm的配置文件(例如configs/slurm.py),其中需要指定:

  • partition: 使用的计算分区。
  • qos: 服务质量等级。
  • retry: 任务失败重试次数。
  • max_num_workers: 最大并发任务数。

然后在启动命令中指定使用Slurm Runner:

python run.py configs/my_full_eval.py --slurm -p partition_name -q qos_name

这里有几个关键经验:

  • 任务分片策略:OpenCompass会自动将大任务切分成小任务。你需要根据集群单节点GPU数量和模型显存占用,合理配置每个任务使用的GPU数(run_cfg中的num_gpus)和批处理大小(batch_size),以最大化集群利用率和任务吞吐量。
  • 依赖管理:确保所有计算节点都有相同的Python环境、模型文件路径和数据集路径(通常使用共享存储如NFS)。
  • 错误监控:大规模运行时,部分任务失败是常态。OpenCompass会记录失败任务,你需要定期检查日志文件(通常在outputs/下的work_dirs中),排查是资源不足、模型加载错误还是数据问题导致的失败,然后调整配置重新提交。

4.3 主观题评测与LLM-as-a-Judge

对于创意写作、文章摘要、对话质量等开放式任务,没有标准答案,如何评测?OpenCompass支持“以模型为裁判”的模式。你需要配置一个“裁判模型”(通常是能力更强的闭源或开源模型,如GPT-4、Qwen-Max)来为“参赛模型”的生成结果打分。

配置上,你需要定义两个模型:参赛模型和裁判模型。然后在数据集的eval_cfg中,指定使用LLMJudge类的评测器,并传入裁判模型的配置。裁判模型会根据预设的评分规则(例如,从1-10分打分,并给出理由)对每个回答进行评判。这个过程计算和API成本都很高,通常只用于关键场景或研究。

5. 避坑指南:那些我踩过的“坑”与最佳实践

在大量使用OpenCompass进行内部模型评估和选型后,我积累了一些宝贵的经验教训,这些是在官方文档中不一定能找到的“实战心得”。

坑一:显存溢出与批处理大小(Batch Size)的权衡这是新手最容易遇到的问题。在配置模型的batch_size时,如果设置过大,会导致GPU显存(OOM)错误,任务直接失败。如果设置过小,又会严重拖慢评测速度,尤其是在使用Slurm时,每个小任务都会产生固定的调度开销。

  • 最佳实践:先从一个小值(如4或8)开始,在本地用--debug模式跑一个数据集,通过nvidia-smi命令监控显存使用情况。确保峰值显存占用低于GPU总显存的80%(留出一些余量给系统和其他进程)。然后逐步调大batch_size,直到找到稳定运行的极限值。对于不同的模型和输入长度,这个值差异很大,需要分别调优。

坑二:模型生成结果中的“附加文本”污染许多对话模型在生成答案后,会习惯性地加上一些后缀,比如“答案:A”、“所以选A”、“答案是A”。而在像MMLU这样的选择题数据集中,标准答案可能就是单个字母“A”。如果评测器(如AccEvaluator)进行严格的字符串匹配,模型生成的“答案是A”和标准答案“A”就不匹配,导致得分被严重低估。

  • 解决方案:OpenCompass的评测器通常提供了pred_postprocessoranswer_postprocessor参数。你可以配置一个后处理函数,在比对前,从模型的预测输出中提取出核心答案。例如,使用正则表达式提取最后一个大写字母。对于内置数据集,OpenCompass通常已经处理了这个问题,但对于自定义数据集,你必须自己实现。

坑三:Slurm任务挂起与资源死锁在大规模集群上,可能会遇到任务一直处于“PENDING”(挂起)状态,无法开始运行。这通常不是OpenCompass的问题,而是Slurm集群的资源分配问题。

  • 排查步骤
    1. 使用squeue命令查看自己任务的状态和原因(REASON列),常见原因有“Resources”(等待资源)、“Priority”(优先级低)。
    2. 检查你的Slurm配置中请求的资源(GPU数量、内存、CPU)是否超过了分区的限制,或者当前分区是否确实有足够的空闲资源。
    3. 检查是否有其他用户的作业占用了大量资源,导致你的作业需要排队。
    4. 考虑调整--max-num-workers参数,限制并发任务数,避免一次性提交过多作业导致系统调度压力过大。

坑四:结果的可复现性机器学习中的随机性会影响评测结果,比如模型生成时的随机采样(如果你设置了do_sample=True)、数据加载的顺序等。

  • 确保复现性的方法
    1. 固定随机种子:在模型配置的generation_kwargs中设置do_sample=False(贪婪解码)可以消除生成随机性。同时,在Python脚本开头全局设置torch.manual_seed(42)np.random.seed(42)
    2. 保存完整的配置与代码:将最终运行所用的配置文件、OpenCompass的版本号(通过pip list | grep opencompass记录)、模型版本(commit id)和数据集版本全部记录下来。这是复现结果的基石。
    3. 理解波动范围:对于某些任务,即使固定种子,由于硬件、库版本的细微差异,结果也可能有微小波动(例如0.1%-0.5%)。在报告结果时,如果是关键结论,可以考虑多次运行取平均。

最佳实践总结

  1. 从小开始,逐步放大:永远先用--debug模式验证整个流程,再用一个小的数据集子集做测试,最后才进行全量评测。
  2. 日志是你的朋友:OpenCompass会生成详细的日志文件。任务失败时,第一时间查看对应的错误日志(通常在work_dirs/下的任务文件夹里),而不是盲目重试。
  3. 版本控制一切:将评测配置文件、自定义的数据集处理脚本、甚至重要的运行命令都纳入Git管理。这能让你清晰地追踪每一次评测的变更。
  4. 结果分析重于跑分:不要只盯着排行榜上的数字。花时间分析模型在哪里错了,错在什么地方。是知识盲区?是推理步骤错误?还是指令理解有偏差?这些定性分析往往比分数更能揭示模型的真实能力边界,对你的应用选型有直接指导意义。

OpenCompass就像一把强大的瑞士军刀,它为混乱的模型评测领域带来了秩序和标准。掌握它,意味着你拥有了客观评估模型能力的“火眼金睛”。无论是跟踪前沿模型进展,还是为你的产品选择最合适的引擎,这项技能都至关重要。从我个人的经验来看,投入时间学习并搭建起内部的模型评测流程,长远来看节省的决策成本和试错时间,远远超过初期的学习投入。

← 返回列表