书生大模型实训营第4期基础岛第六关:OpenCompass 评测书生大模型实践
0. OpenCompass 介绍
OpenCompass 是一个面向大模型评测的一站式开源平台,由上海人工智能实验室研发推出。它主要由三大核心模块构建而成:CompassKit、CompassHub 以及 CompassRank。其中,CompassKit 提供丰富的评测基准和模型模板;CompassHub 是一个基准社区,用于发布和分享评测基准和排行榜;CompassRank 则提供全面、客观、中立的分数和排名。
OpenCompass 主要具有以下几个特点:
- 开源可复现:OpenCompass 可以为研究者们提供公平、公开、可复现的大模型评测方案
- 全面的能力维度:它盖八个维度,提供 100+ 个数据集约 40 万题的模型评测方案,可以更加全面地评估模型能力
- 丰富的模型支持:OpenCompass 平台广泛支持 40+ HuggingFace 及 API 模型
- 分布式高效评测:一行命令即可实现任务分割和分布式评测,数小时即可完成千亿模型全量评测
- 多样化评测范式:支持零样本、小样本及思维链评测,结合标准型或对话型提示词模板,轻松激发各种模型的最大性能
- 灵活化拓展:可以轻松扩展新模型或数据集、自定义更高级的任务分割策略,甚至接入新的集群管理系统
OpenCompass 评测体系目前已经广泛应用于大模型头部企业和科研机构,是唯一一个获得 Meta 官方推荐的国产大模型评测体系,同时也是开源社区最完善的评测体系之一。
OpenCompass 提供了 API 模式评测和本地直接评测两种方式。其中 API 模式评测针对那些以 API 服务形式部署的模型,而本地直接评测则面向那些可以获取到模型权重文件的情况。
1. API 模式评测
首先创建虚拟环境并安装相关依赖:
conda create -n opencompass python=3.10
conda activate opencompass
cd /root
git clone -b 0.3.3 https://github.com/open-compass/opencompass
cd opencompass
pip install -e .
pip install -r requirements.txt
pip install huggingface_hub==0.25.2
评测通过 API 访问的大语言模型的过程很简单,首先我们需要获取模型的 API Key 和接口地址,然后在评测配置文件中设置好密钥和相应的模型参数就可以开始评测了。评测过程中,评测框架会自动向模型服务发送测试用例,获取模型的回复并进行打分分析。整个过程我们不需要准备任何模型文件,也不用担心本地计算资源是否足够,只要确保网络连接正常即可。
这里我使用的是自己的 浦语 API,大家没申请的可以去官网申请一个,目前每个月有100万免费 Token 的额度。获取到 API Key 之后在开发机终端运行如下命令:
export INTERNLM_API_KEY=xxxxxxxxxxxxxxxxxxxxxxx # 填入你申请的 API Key
这条命令会将你的 API Key 设置成环境变量,后续程序中需要使用 API Key 时可以通过直接调用环境变量获得,这样可以避免你的 API Key 在程序中显式出现,降低 API Key 泄露的风险。
然后在终端运行下面命令,创建一个模型配置文件:
cd /root/opencompass/
touch opencompass/configs/models/openai/puyu_api.py
然后打开该文件,贴入以下代码:
import os
from opencompass.models import OpenAISDK
internlm_url = 'https://internlm-chat.intern-ai.org.cn/puyu/api/v1/' # 你前面获得的 api 服务地址
internlm_api_key = os.getenv('INTERNLM_API_KEY')
models = [
dict(
# abbr='internlm2.5-latest',
type=OpenAISDK,
path='internlm2.5-latest', # 请求服务时的 model name
# 换成自己申请的APIkey
key=internlm_api_key, # API key
openai_api_base=internlm_url, # 服务地址
rpm_verbose=True, # 是否打印请求速率
query_per_second=0.16, # 服务请求速率
max_out_len=1024, # 最大输出长度
max_seq_len=4096, # 最大输入长度
temperature=0.01, # 生成温度
batch_size=1, # 批处理大小
retry=3, # 重试次数
)
]
完成上述两步后还需要配置一下数据集,先在终端运行:
cd /root/opencompass/
touch opencompass/configs/datasets/demo/demo_cmmlu_chat_gen.py
创建好数据集配置文件后在该文件中贴入如下代码:
from mmengine import read_base
with read_base():
from ..cmmlu.cmmlu_gen_c13365 import cmmlu_datasets
# 每个数据集只取前2个样本进行评测
for d in cmmlu_datasets:
d['abbr'] = 'demo_' + d['abbr']
d['reader_cfg']['test_range'] = '[0:1]' # 这里每个数据集只取1个样本, 方便快速评测.
至此我们的准备工作就完成了,接下来在终端运行下面这行命令就能启动评测了:
python run.py --models puyu_api.py --datasets demo_cmmlu_chat_gen.py --debug
大概等个十几二十分钟差不多就评测完了,评测结果如下:
2. 本地直接测评
2.1 环境配置和数据准备
如果想要评测本地部署的模型,首先需要获取到完整的模型权重文件,然后在评测配置文件中指定模型路径和相关参数,评测框架就会自动加载模型并开始评测。这种评测方式虽然前期准备工作相对繁琐,需要考虑硬件资源,但好处是评测过程完全在本地完成,不依赖网络状态,而且可以更灵活地调整模型参数,深入了解模型的性能表现。这种方式特别适合需要深入研究模型性能或进行模型改进的研发人员。
我们下面试着评测一下 InternLM2-Chat-1.8B 在 C-Eval 数据集上的性能。
首先还是配置环境+下载依赖:
cd /root/opencompass
conda activate opencompass
conda install pytorch==2.1.2 torchvision==0.16.2 torchaudio==2.1.2 pytorch-cuda=12.1 -c pytorch -c nvidia -y
apt-get update
apt-get install cmake
pip install protobuf==4.25.3
pip install huggingface-hub==0.23.2
为了方便评测,我们将数据集下载到本地:
cp /share/temp/datasets/OpenCompassData-core-20231110.zip /root/opencompass/
unzip OpenCompassData-core-20231110.zip
2.2 加载本地模型进行评测
打开 opencompass 文件夹下的 configs/models/hf_internlm/的 hf_internlm2_5_1_8b_chat.py
文件,修改如下:
from opencompass.models import HuggingFacewithChatTemplate
models = [
dict(
type=HuggingFacewithChatTemplate,
abbr='internlm2_5-1_8b-chat-hf',
path='/share/new_models/Shanghai_AI_Laboratory/internlm2_5-1_8b-chat/',
max_out_len=2048,
batch_size=8,
run_cfg=dict(num_gpus=1),
)
]
然后运行下面命令就可以开始评测 InternLM2-Chat-1.8B 模型在 C-Eval 数据集上的性能:
python run.py --datasets ceval_gen --models hf_internlm2_5_1_8b_chat --debug
由于 OpenCompass 默认并行启动评估过程,我们可以在第一次运行时以 --debug 模式启动评估,并检查是否存在问题。在 --debug 模式下,任务将按顺序执行,并实时打印输出。
大概20来分钟(我这边跑了25分钟的样子)后就能看到评测结果了:
如果你在这一步运行时碰到类似这样的报错:RuntimeError: Failed to import transformers.pipelines because of the following error (look up to see its traceback):,这大概率是因为你 transformers 库的版本有问题,改成跟 Xtuner 任务中一致即可(pip install transformers==4.39.0)
上面的评测命令中包含了模型和数据集路径,略显繁琐,我们可以通过修改配置文件来指定模型和数据集从而省略这两个参数。比如我们可以运行下面命令在 opencompass/configs/
文件夹下创建一个 touch eval_tutorial_demo.py
配置文件:
cd /root/opencompass/configs/
touch eval_tutorial_demo.py
在配置文件中贴入如下代码:
from mmengine.config import read_base
with read_base():
from .datasets.ceval.ceval_gen import ceval_datasets
from .models.hf_internlm.hf_internlm2_5_1_8b_chat import models as hf_internlm2_5_1_8b_chat_models
datasets = ceval_datasets
models = hf_internlm2_5_1_8b_chat_models
这样我们就在配置文件中指定了评测的模型和数据集,评测命令就可以简化成:
python run.py configs/eval_tutorial_demo.py --debug
3. 将本地模型通过部署成 API 服务再评测
在 OpenCompass 的设计中,它不会真正区分开源模型和 API 模型。因此我们可以使用相同的方式评估这两种模型类型。
首先打开一个终端,安装并部署模型:
pip install lmdeploy==0.6.1 openai==1.52.0
lmdeploy serve api_server /share/new_models/Shanghai_AI_Laboratory/internlm2_5-1_8b-chat/ --server-port 23333
成功部署以后会看到如下输出:
然后新开一个终端,使用以下 Python 代码获取由 LMDeploy 注册的模型名称:
from openai import OpenAI
client = OpenAI(
api_key='sk-123456', # 可以设置成随意的字符串
base_url="http://0.0.0.0:23333/v1"
)
model_name = client.models.list().data[0].id
model_name # 注册的模型名称需要被用于后续配置.
这一步可以不用创建文件,激活 opencompass 环境后在终端输入 python 唤醒 python 编译器,然后直接复制粘贴上面的代码到终端运行即可。
结果显示 /share/new_models/Shanghai_AI_Laboratory/internlm2_5-1_8b-chat/
, 接着,使用 touch
命令创建配置脚本 /root/opencompass/configs/models/hf_internlm/hf_internlm2_5_1_8b_chat_api.py
,在脚本中贴入如下代码:
from opencompass.models import OpenAI
api_meta_template = dict(round=[
dict(role='HUMAN', api_role='HUMAN'),
dict(role='BOT', api_role='BOT', generate=True),
])
models = [
dict(
abbr='InternLM-2.5-1.8B-Chat',
type=OpenAI,
path='/share/new_models/Shanghai_AI_Laboratory/internlm2_5-1_8b-chat/', # 注册的模型名称
key='sk-123456',
openai_api_base='http://0.0.0.0:23333/v1/chat/completions',
meta_template=api_meta_template,
query_per_second=1,
max_out_len=2048,
max_seq_len=4096,
batch_size=8),
]
然后运行命令:opencompass --models hf_internlm2_5_1_8b_chat_api --datasets ceval_gen --debug
即可开始评测。大概20来分钟就能出结果了:
4. InternLM2-Chat-1.8B + LMDeploy + ceval 评测
接第3节,还是先打开一个终端,安装并部署模型:
lmdeploy serve api_server /share/new_models/Shanghai_AI_Laboratory/internlm2_chat_1_8b/ --server-port 23334
看到如下输出说明部署成功:
新开一个终端,激活 opencompass 环境并运行第3节中的代码获取部署的模型名称(记得把代码中的端口改成23334)。然后使用 touch
命令创建配置脚本
/root/opencompass/configs/models/hf_internlm/hf_internlm2-chat-1_8b_api.py
,在脚本中填入如下内容:
from opencompass.models import OpenAI
api_meta_template = dict(round=[
dict(role='HUMAN', api_role='HUMAN'),
dict(role='BOT', api_role='BOT', generate=True),
])
models = [
dict(
abbr='InternLM-2-1.8B-Chat',
type=OpenAI,
path='/share/new_models/Shanghai_AI_Laboratory/internlm2-chat-1_8b/', # 注册的模型名称
key='sk-123456',
openai_api_base='http://0.0.0.0:23334/v1/chat/completions',
meta_template=api_meta_template,
query_per_second=1,
max_out_len=2048,
max_seq_len=4096,
batch_size=8),
]
然后运行 opencompass --models hf_internlm2-chat-1_8b_api --datasets ceval_gen --debug
命令开始评测。最终评测结果如下:
5. 使用 OpenCompass 进行主观评测
5.1 主观评测介绍
OpenCompass 采取客观评测与主观评测相结合的方法。针对具有确定性答案的能力维度和场景,通过构造丰富完善的评测集对模型进行客观评测。而针对体现模型能力的开放式或半开放式的问题、模型安全问题等,采用主客观相结合的评测方式。
通俗来讲,客观评测是指对于有标准答案的客观问题,使用定量指标比较模型的输出与标准答案的差异,并根据结果衡量模型的性能。为了规范模型的输出,OpenCompass 采用提示词工程 (prompt engineering)和语境学习(in-context learning)进行客观评测。 在客观评测的具体实践中,通常采用以下两种方式对模型输出结果进行评测:
- 判别式评测:该评测方式会将问题与候选答案组合在一起,计算模型在所有组合上的困惑度(perplexity),并选择困惑度最小的答案作为模型的最终输出。
- 生成式评测:该评测方式主要用于生成类任务,如语言翻译、程序生成、逻辑分析题等。具体实践时,使用问题作为模型的原始输入,并让模型补全答案。
而主观评测则是指以人的主观感受为主的评测,其更符合大模型的实际使用场景。 OpenCompass 采取的主观评测方案是借助受试者的主观判断对具有对话能力的大语言模型进行能力评测, 在具体开展主观评测时,OpenComapss 采用单模型回复满意度统计和多模型满意度比较两种方式开展具体的评测工作。由于主观测试标注成本很高,具体开展主观评测时我们常常使用性能优异的大语言模型(比如 GPT4)来模拟人类进行主观打分。
目前 OpenCompass 中支持的主观评测数据集有以下这些:
- AlignBench 中文Scoring数据集
- MTBench 英文Scoring数据集,两轮对话
- MTBench101 英文Scoring数据集,多轮对话
- AlpacaEvalv2 英文Compare数据集
- ArenaHard 英文Compare数据集,主要面向 coding
- Fofo 英文Socring数据集
- Wildbench 英文Score和Compare数据集
关于 OpenCompass 中主观评测的更多介绍请前往官网文档了解
5.2 对 InternLM2-Chat-1.8B 进行主观评测
正常来说主观评测需要有一个比较强力的 judgemodel 如 GPT4 等模型对待测评模型的回答进行评判打分,但是毕竟 GPT4 是收费的,充钱还得上某宝,所以这里我尝试了两种方法,一种是调用浦语 API(internlm-20b 模型)对 InternLM2-Chat-1.8B 进行主观测评,另一种是使用本地的 InternLM2.5-1.8B-Chat 对本地的 InternLM2-Chat-1.8B 进行评测。前情提要:我做的这两种主观评测实验受限于 API 和硬件均未成功(后续可能会填坑),想要在自己开发机成功运行主观评测的请谨慎观看下面的内容防止浪费你的时间。
5.2.1 调用浦语 API 对 InternLM2-Chat-1.8B 进行主观评测
类似于已有的客观评测方式,我们可以在 configs/eval_subjective.py
中进行主观评测的相关配置。这里我创建了一个新的 configs/eval_subjective_mine.py
文件存储自己的配置,在文件中贴入如下代码:
from mmengine.config import read_base
from opencompass.models import HuggingFacewithChatTemplate
with read_base():
# from opencompass.configs.datasets.subjective.multiround.mtbench101_judge import mtbench101_datasets
from opencompass.configs.datasets.subjective.fofo.fofo_judge import fofo_datasets
from opencompass.models import HuggingFaceCausalLM, HuggingFace, HuggingFaceChatGLM3, OpenAI
from opencompass.partitioners import NaivePartitioner, SizePartitioner
from opencompass.partitioners.sub_naive import SubjectiveNaivePartitioner
from opencompass.partitioners.sub_size import SubjectiveSizePartitioner
from opencompass.partitioners.sub_num_worker import SubjectiveNumWorkerPartitioner
from opencompass.runners import LocalRunner
from opencompass.runners import SlurmSequentialRunner
from opencompass.tasks import OpenICLInferTask
from opencompass.tasks.subjective_eval import SubjectiveEvalTask
from opencompass.summarizers import SubjectiveSummarizer
api_meta_template = dict(
round=[
dict(role='HUMAN', api_role='HUMAN'),
dict(role='BOT', api_role='BOT', generate=True),
]
)
# -------------Inference Stage ----------------------------------------
# For subjective evaluation, we often set do sample for models
models = [
dict(
type=HuggingFacewithChatTemplate,
abbr='internlm2_5-1_8b-chat-hf',
path='/share/new_models/Shanghai_AI_Laboratory/internlm2_5-1_8b-chat/',
tokenizer_path='/share/new_models/Shanghai_AI_Laboratory/internlm2_5-1_8b-chat/',
model_kwargs=dict(
device_map='auto',
trust_remote_code=True,
),
tokenizer_kwargs=dict(
padding_side='left',
truncation_side='left',
trust_remote_code=True,
),
generation_kwargs=dict(
do_sample=True, #For subjective evaluation, we suggest you do set do_sample when running model inference!
),
meta_template=api_meta_template,
max_out_len=2048,
max_seq_len=4096,
batch_size=8,
run_cfg=dict(num_gpus=1, num_procs=1),
)
]
datasets = [*fofo_datasets] # add datasets you want
infer = dict(
partitioner=dict(type=NaivePartitioner),
runner=dict(type=LocalRunner, max_num_workers=16, task=dict(type=OpenICLInferTask)),
)
# -------------Evalation Stage ----------------------------------------
from opencompass.models import OpenAISDK
internlm_url = 'https://internlm-chat.intern-ai.org.cn/puyu/api/v1/' # 你前面获得的 api 服务地址
## ------------- JudgeLLM Configuration
judge_models = [dict(
abbr='InternLM-2.5-latest',
type=OpenAISDK,
path='internlm2.5-latest', # 请求服务时的 model name
# 换成自己申请的APIkey
key="你的浦语 API Key", # API key
openai_api_base=internlm_url, # 服务地址
meta_template=api_meta_template,
query_per_second=16,
max_out_len=2048,
max_seq_len=2048,
batch_size=8,
temperature=0,
)]
## ------------- Evaluation Configuration
eval = dict(
partitioner=dict(type=SubjectiveNaivePartitioner, models=models, judge_models=judge_models,),
runner=dict(type=LocalRunner, max_num_workers=16, task=dict(type=SubjectiveEvalTask)),
)
summarizer = dict(type=SubjectiveSummarizer, function='subjective')
work_dir = 'outputs/subjective/'
代码中将待评测模型设置为本地的 InternLM2-Chat-1.8B,调用浦语的 API 作为 judgemodel,数据集则选用 Fofo 数据集(来自书生模型推荐,这里我一开始试的是 MTBench-101,预计评测完大概需要 10 来个小时,Fofo 数据集评测起来要快很多)。
最后在 opencompass 文件夹下运行下面这条命令即可开始评测:
python run.py configs/eval_subjective_mine.py
评测日志会保存在 /root/opencompass/outputs/subjective
文件夹下,那几个以时间戳命名的文件夹存储的就是你每次评测的日志。
这里我的 inference 大概花了三个多小时,结果在 judgemodel 进行 eval 时报错了,显示请求过于频繁,这就没办法了,我也懒得去申请调整自己 API 的限流策略(这里可以看到其实评测可以正常进行,但是测了 2% 就提示请求频繁了):
5.2.2 使用本地 InternLM2.5-1.8B-Chat 评测 InternLM2-1.8B-Chat
既然 API 显示请求频繁无法对推断结果进行打分,我想着能不能直接使用本地模型进行评测(反正是做学习用途,能跑起来就行)。所以我修改了 5.2.1 配置文件中推理(待测)模型和评测模型(judgemodel)的配置:
# -------------Inference Stage ----------------------------------------
# For subjective evaluation, we often set do sample for models
models = [
dict(
type=HuggingFacewithChatTemplate,
abbr='internlm2-1_8b-chat-hf',
path='/share/new_models/Shanghai_AI_Laboratory/internlm2-chat-1_8b/',
tokenizer_path='/share/new_models/Shanghai_AI_Laboratory/internlm2-chat-1_8b/',
model_kwargs=dict(
device_map='auto',
trust_remote_code=True,
),
tokenizer_kwargs=dict(
padding_side='left',
truncation_side='left',
trust_remote_code=True,
),
generation_kwargs=dict(
do_sample=True, #For subjective evaluation, we suggest you do set do_sample when running model inference!
),
meta_template=api_meta_template,
max_out_len=2048,
max_seq_len=4096,
batch_size=8,
run_cfg=dict(num_gpus=1, num_procs=1),
)
]
## ------------- JudgeLLM Configuration
judge_models = [
dict(
type=HuggingFacewithChatTemplate,
abbr='InternLM-2.5-1.8B-Chat',
path='/share/new_models/Shanghai_AI_Laboratory/internlm2_5-1_8b-chat/',
tokenizer_path='/share/new_models/Shanghai_AI_Laboratory/internlm2_5-1_8b-chat/',
model_kwargs=dict(
device_map='auto',
trust_remote_code=True,
),
tokenizer_kwargs=dict(
padding_side='left',
truncation_side='left',
trust_remote_code=True,
),
generation_kwargs=dict(
do_sample=True,
),
meta_template=api_meta_template,
max_out_len=2048,
max_seq_len=4096,
batch_size=8,
temperature=0,
run_cfg=dict(num_gpus=1, num_procs=1),
)
]
同样是运行这条命令进行评测:
python run.py configs/eval_subjective_mine.py
这里选 InternLM-2.5-1.8B-Chat 作为 judgemodel 是因为其他模型有点大,我怕 24G 显存吃不消,结果证明我真猜对了hhhc
这次不知道为什么推理时间长了将近一倍,我差不多跑了快7个小时才把 inference 跑完,但是在进行 eval 时又报错了,这次提示我爆显存了…,那就真没办法了,两个 1.8B 的跑不起来那就只能等到时候解锁 50%A100 权限了再看能不能回来填下坑吧。
至此,书生大模型实训营第4期基础岛第六关任务完成~