Commit be3dfa50 authored by jerrrrry's avatar jerrrrry
Browse files

Initial commit

parents
Pipeline #2876 failed with stages
in 0 seconds
# 主观评测指引
## 介绍
主观评测旨在评估模型在符合人类偏好的能力上的表现。这种评估的黄金准则是人类喜好,但标注成本很高。
为了探究模型的主观能力,我们采用了JudgeLLM作为人类评估者的替代品([LLM-as-a-Judge](https://arxiv.org/abs/2306.05685))。
流行的评估方法主要有:
- Compare模式:将模型的回答进行两两比较,以计算对战其胜率。
- Score模式:针对单模型的回答进行打分(例如:[Chatbot Arena](https://chat.lmsys.org/))。
我们基于以上方法支持了JudgeLLM用于模型的主观能力评估(目前opencompass仓库里支持的所有模型都可以直接作为JudgeLLM进行调用,此外一些专用的JudgeLLM我们也在计划支持中)。
## 目前已支持的主观评测数据集
1. AlignBench 中文Scoring数据集(https://github.com/THUDM/AlignBench)
2. MTBench 英文Scoring数据集,两轮对话(https://github.com/lm-sys/FastChat)
3. MTBench101 英文Scoring数据集,多轮对话(https://github.com/mtbench101/mt-bench-101)
4. AlpacaEvalv2 英文Compare数据集(https://github.com/tatsu-lab/alpaca_eval)
5. ArenaHard 英文Compare数据集,主要面向coding(https://github.com/lm-sys/arena-hard/tree/main)
6. Fofo 英文Socring数据集(https://github.com/SalesforceAIResearch/FoFo/)
7. Wildbench 英文Score和Compare数据集(https://github.com/allenai/WildBench)
## 启动主观评测
类似于已有的客观评测方式,可以在configs/eval_subjective.py中进行相关配置
### 基本参数models, datasets 和 judgemodels的指定
类似于客观评测的方式,导入需要评测的models和datasets,例如
```
with read_base():
from .datasets.subjective.alignbench.alignbench_judgeby_critiquellm import alignbench_datasets
from .datasets.subjective.alpaca_eval.alpacav2_judgeby_gpt4 import subjective_datasets as alpacav2
from .models.qwen.hf_qwen_7b import models
```
值得注意的是,由于主观评测的模型设置参数通常与客观评测不同,往往需要设置`do_sample`的方式进行推理而不是`greedy`,故可以在配置文件中自行修改相关参数,例如
```
models = [
dict(
type=HuggingFaceChatGLM3,
abbr='chatglm3-6b-hf2',
path='THUDM/chatglm3-6b',
tokenizer_path='THUDM/chatglm3-6b',
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,
run_cfg=dict(num_gpus=1, num_procs=1),
)
]
```
judgemodel通常被设置为GPT4等强力模型,可以直接按照config文件中的配置填入自己的API key,或使用自定义的模型作为judgemodel
### 其他参数的指定
除了基本参数以外,还可以在config中修改`infer``eval`字段里的partitioner,从而设置更合适的分片方式,目前支持的分片方式主要有三种:NaivePartitoner, SizePartitioner和NumberWorkPartitioner
以及可以指定自己的workdir用以保存相关文件。
## 自定义主观数据集评测
主观评测的具体流程包括:
1. 评测数据集准备
2. 使用API模型或者开源模型进行问题答案的推理
3. 使用选定的评价模型(JudgeLLM)对模型输出进行评估
4. 对评价模型返回的预测结果进行解析并计算数值指标
### 第一步:数据准备
这一步需要准备好数据集文件以及在`Opencompass/datasets/subjective/`下实现自己数据集的类,将读取到的数据以`list of dict`的格式return
实际上可以按照自己喜欢的任意格式进行数据准备(csv, json, jsonl)等皆可,不过为了方便上手,推荐按照已有的主观数据集的格式进行构建或按照如下的json格式进行构建。
对于对战模式和打分模式,我们各提供了一个demo测试集如下:
```python
### 对战模式示例
[
{
"question": "如果我在空中垂直抛球,球最初向哪个方向行进?",
"capability": "知识-社会常识",
"others": {
"question": "如果我在空中垂直抛球,球最初向哪个方向行进?",
"evaluating_guidance": "",
"reference_answer": "上"
}
},...]
### 打分模式数据集示例
[
{
"question": "请你扮演一个邮件管家,我让你给谁发送什么主题的邮件,你就帮我扩充好邮件正文,并打印在聊天框里。你需要根据我提供的邮件收件人以及邮件主题,来斟酌用词,并使用合适的敬语。现在请给导师发送邮件,询问他是否可以下周三下午15:00进行科研同步会,大约200字。",
"capability": "邮件通知",
"others": ""
},
```
如果要准备自己的数据集,请按照以下字段进行提供,并整理为一个json文件:
- 'question':问题描述
- 'capability':题目所属的能力维度
- 'others':其他可能需要对题目进行特殊处理的项目
以上三个字段是必要的,用户也可以添加其他字段,如果需要对每个问题的prompt进行单独处理,可以在'others'字段中进行一些额外设置,并在Dataset类中添加相应的字段。
### 第二步:构建评测配置
以Alignbench为例`configs/datasets/subjective/alignbench/alignbench_judgeby_critiquellm.py`
1. 首先需要设置`subjective_reader_cfg`,用以接收从自定义的Dataset类里return回来的相关字段并指定保存文件时的output字段
2. 然后需要指定数据集的根路径`data_path`以及数据集的文件名`subjective_all_sets`,如果有多个子文件,在这个list里进行添加即可
3. 指定`subjective_infer_cfg``subjective_eval_cfg`,配置好相应的推理和评测的prompt
4. 在相应的位置指定`mode`等额外信息,注意,对于不同的主观数据集,所需指定的字段可能不尽相同。
5. 定义后处理与得分统计。例如opencompass/opencompass/datasets/subjective/alignbench下的alignbench_postprocess处理函数
### 第三步 启动评测并输出评测结果
```shell
python run.py configs/eval_subjective.py -r
```
- `-r` 参数支持复用模型推理和评估结果。
JudgeLLM的评测回复会保存在 `output/.../results/timestamp/xxmodel/xxdataset/.json`
评测报告则会输出到 `output/.../summary/timestamp/report.csv`
## 主观多轮对话评测
在OpenCompass中我们同样支持了主观的多轮对话评测,以MT-Bench为例,对MTBench的评测可以参见`configs/datasets/subjective/multiround`
在多轮对话评测中,你需要将数据格式整理为如下的dialogue格式
```
"dialogue": [
{
"role": "user",
"content": "Imagine you are participating in a race with a group of people. If you have just overtaken the second person, what's your current position? Where is the person you just overtook?"
},
{
"role": "assistant",
"content": ""
},
{
"role": "user",
"content": "If the \"second person\" is changed to \"last person\" in the above question, what would the answer be?"
},
{
"role": "assistant",
"content": ""
}
],
```
值得注意的是,由于MTBench各不同的题目类型设置了不同的温度,因此我们需要将原始数据文件按照温度分成三个不同的子集以分别推理,针对不同的子集我们可以设置不同的温度,具体设置参加`configs\datasets\subjective\multiround\mtbench_single_judge_diff_temp.py`
# flake8: noqa
# Configuration file for the Sphinx documentation builder.
#
# This file only contains a selection of the most common options. For a full
# list see the documentation:
# https://www.sphinx-doc.org/en/master/usage/configuration.html
# -- Path setup --------------------------------------------------------------
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
import os
import subprocess
import sys
import pytorch_sphinx_theme
from sphinx.builders.html import StandaloneHTMLBuilder
sys.path.insert(0, os.path.abspath('../../'))
# -- Project information -----------------------------------------------------
project = 'OpenCompass'
copyright = '2023, OpenCompass'
author = 'OpenCompass Authors'
# The full version, including alpha/beta/rc tags
version_file = '../../opencompass/__init__.py'
def get_version():
with open(version_file, 'r') as f:
exec(compile(f.read(), version_file, 'exec'))
return locals()['__version__']
release = get_version()
# -- General configuration ---------------------------------------------------
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
'sphinx.ext.autodoc',
'sphinx.ext.autosummary',
'sphinx.ext.intersphinx',
'sphinx.ext.napoleon',
'sphinx.ext.viewcode',
'myst_parser',
'sphinx_copybutton',
'sphinx_tabs.tabs',
'notfound.extension',
'sphinxcontrib.jquery',
'sphinx_design',
]
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix(es) of source filenames.
# You can specify multiple suffix as a list of string:
#
source_suffix = {
'.rst': 'restructuredtext',
'.md': 'markdown',
}
language = 'cn'
# The master toctree document.
root_doc = 'index'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This pattern also affects html_static_path and html_extra_path.
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
# -- Options for HTML output -------------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
html_theme = 'pytorch_sphinx_theme'
html_theme_path = [pytorch_sphinx_theme.get_html_theme_path()]
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
# yapf: disable
html_theme_options = {
'menu': [
{
'name': 'GitHub',
'url': 'https://github.com/open-compass/opencompass'
},
],
# Specify the language of shared menu
'menu_lang': 'cn',
# Disable the default edit on GitHub
'default_edit_on_github': False,
}
# yapf: enable
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
html_css_files = [
'https://cdn.datatables.net/v/bs4/dt-1.12.1/datatables.min.css',
'css/readthedocs.css'
]
html_js_files = [
'https://cdn.datatables.net/v/bs4/dt-1.12.1/datatables.min.js',
'js/custom.js'
]
# -- Options for HTMLHelp output ---------------------------------------------
# Output file base name for HTML help builder.
htmlhelp_basename = 'opencompassdoc'
# -- Options for LaTeX output ------------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#
# 'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#
# 'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#
# 'preamble': '',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
(root_doc, 'opencompass.tex', 'OpenCompass Documentation', author,
'manual'),
]
# -- Options for manual page output ------------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [(root_doc, 'opencompass', 'OpenCompass Documentation', [author],
1)]
# -- Options for Texinfo output ----------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
(root_doc, 'opencompass', 'OpenCompass Documentation', author,
'OpenCompass Authors', 'AGI evaluation toolbox and benchmark.',
'Miscellaneous'),
]
# -- Options for Epub output -------------------------------------------------
# Bibliographic Dublin Core info.
epub_title = project
# The unique identifier of the text. This can be a ISBN number
# or the project homepage.
#
# epub_identifier = ''
# A unique identification for the text.
#
# epub_uid = ''
# A list of files that should not be packed into the epub file.
epub_exclude_files = ['search.html']
# set priority when building html
StandaloneHTMLBuilder.supported_image_types = [
'image/svg+xml', 'image/gif', 'image/png', 'image/jpeg'
]
# -- Extension configuration -------------------------------------------------
# Ignore >>> when copying code
copybutton_prompt_text = r'>>> |\.\.\. '
copybutton_prompt_is_regexp = True
# Auto-generated header anchors
myst_heading_anchors = 3
# Enable "colon_fence" extension of myst.
myst_enable_extensions = ['colon_fence', 'dollarmath']
# Configuration for intersphinx
intersphinx_mapping = {
'python': ('https://docs.python.org/3', None),
'numpy': ('https://numpy.org/doc/stable', None),
'torch': ('https://pytorch.org/docs/stable/', None),
'mmengine': ('https://mmengine.readthedocs.io/en/latest/', None),
'transformers':
('https://huggingface.co/docs/transformers/main/en/', None),
}
napoleon_custom_sections = [
# Custom sections for data elements.
('Meta fields', 'params_style'),
('Data fields', 'params_style'),
]
# Disable docstring inheritance
autodoc_inherit_docstrings = False
# Mock some imports during generate API docs.
autodoc_mock_imports = ['rich', 'attr', 'einops']
# Disable displaying type annotations, these can be very verbose
autodoc_typehints = 'none'
# The not found page
notfound_template = '404.html'
def builder_inited_handler(app):
subprocess.run(['./cp_origin_docs.sh'])
subprocess.run(['./statis.py'])
def setup(app):
app.connect('builder-inited', builder_inited_handler)
#!/usr/bin/env bash
# Copy *.md files from docs/ if it doesn't have a Chinese translation
for filename in $(find ../en/ -name '*.md' -printf "%P\n");
do
mkdir -p $(dirname $filename)
cp -n ../en/$filename ./$filename
done
[html writers]
table_style: colwidths-auto
# 常见问题
## 通用
### ppl 和 gen 有什么区别和联系?
`ppl` 是困惑度 (perplexity) 的缩写,是一种评价模型进行语言建模能力的指标。在 OpenCompass 的语境下,它一般指一种选择题的做法:给定一个上下文,模型需要从多个备选项中选择一个最合适的。此时,我们会将 n 个选项拼接上上下文后,形成 n 个序列,然后计算模型对这 n 个序列的 perplexity,我们认为其中 perplexity 最低的序列所对应的选项即为模型在这道题上面的推理结果,该种评测方法的后处理简单直接、确定性高。
`gen` 是生成 (generate) 的缩写。在 OpenCompass 的语境下,它指的是在给定上下文的情况下,模型往后续写的结果就是这道题目上的推理结果。一般来说,续写得到的字符串需要结合上比较重的后处理过程,才能进行可靠的答案提取,从而完成评测。
从使用上来说,基座模型的单项选择题和部分具有选择题性质的题目会使用 `ppl`,基座模型的不定项选择和非选择题都会使用 `gen`。而对话模型的所有题目都会使用 `gen`,因为许多商用 API 模型不会暴露 `ppl` 的接口。但也存在例外情况,例如我们希望基座模型输出解题思路过程时 (例如 Let's think step by step),我们同样会使用 `gen`,但总体的使用如下图所示:
| | ppl | gen |
| -------- | ----------- | ------------------ |
| 基座模型 | 仅 MCQ 任务 | MCQ 以外的其他任务 |
| 对话模型 | 无 | 所有任务 |
`ppl` 高度类似地,条件对数概率 `clp` (conditional log probability) 是在给定上下文的情况下,计算下一个 token 的概率。它也仅适用于选择题,考察概率的范围仅限于备选项标号所对应的 token,取其中概率最高的 token 所对应的选项为模型的推理结果。与 ppl 相比,`clp` 的计算更加高效,仅需要推理一次,而 ppl 需要推理 n 次,但坏处是,`clp` 受制于 tokenizer,在例如选项前后有无空格符号时,tokenizer 编码的结果会有变化,导致测试结果不可靠。因此 OpenCompass 中很少使用 `clp`
### OpenCompass 如何控制 few shot 评测的 shot 数目?
在数据集配置文件中,有一个 `retriever` 的字段,该字段表示如何召回数据集中的样本作为上下文样例,其中最常用的是 `FixKRetriever` 表示固定使用某 k 个样本,因此即为 k-shot。另外还有 `ZeroRetriever` 表示不使用任何样本,这在大多数情况下意味着 0-shot。
另一方面,in context 的样本也可以直接在数据集的模板中指定,在该情况下亦会搭配使用 `ZeroRetriever`,但此时的评测并不是 0-shot,而需要根据具体的模板来进行确定。具体请看 [prompt](../prompt/prompt_template.md)
### OpenCompass task 的默认划分逻辑是什么样的?
OpenCompass 默认使用 num_worker_partitioner。OpenCompass 的评测从本质上来说就是有一系列的模型和一系列的数据集,然后两两组合,用每个模型去跑每个数据集。对于同一个模型,OpenCompass 会将其拆分为 `--max-num-workers` (或 config 中的 `infer.runner.max_num_workers`) 个 task,为了保证每个 task 的运行耗时均匀,每个 task 均会所有数据集的一部分。示意图如下:
![num_worker_partitioner](https://github.com/open-compass/opencompass/assets/17680578/68c57a57-0804-4865-a0c6-133e1657b9fc)
### OpenCompass 在 slurm 等方式运行时,为什么会有部分 infer log 不存在?
因为 log 的文件名并不是一个数据集的切分,而是一个 task 的名字。由于 partitioner 有可能会将多个较小的任务合并成一个大的,而 task 的名字往往就是第一个数据集的名字。因此该 task 中后面的数据集的名字对应的 log 都不会出现,而是会直接写在第一个数据集对应的 log 中
### OpenCompass 中的断点继续逻辑是什么样的?
只要使用 --reuse / -r 开关,则会进行断点继续。首先 OpenCompass 会按照最新的 config 文件配置模型和数据集,然后在 partitioner 确定分片大小并切片后,对每个分片依次查找,若该分片已完成,则跳过;若该分片未完成或未启动,则加入待测列表。然后将待测列表中的任务依次进行执行。注意,未完成的任务对应的输出文件名一般是 `tmp_xxx`,此时模型会从该文件中标号最大的一个数据开始往后继续跑,直到完成这个分片。
根据上述过程,有如下推论:
- 在已有输出文件夹的基础上断点继续时,不可以更换 partitioner 的切片方式,或者不可以修改 `--max-num-workers` 的入参。(除非使用了 `tools/prediction_merger.py` 工具)
- 如果数据集有了任何修改,不要断点继续,或者根据需要将原有的输出文件进行删除后,全部重跑。
### OpenCompass 如何分配 GPU?
OpenCompass 使用称为 task (任务) 的单位处理评估请求。每个任务都是模型和数据集的独立组合。任务所需的 GPU 资源完全由正在评估的模型决定,具体取决于 `num_gpus` 参数。
在评估过程中,OpenCompass 部署多个工作器并行执行任务。这些工作器不断尝试获取 GPU 资源直到成功运行任务。因此,OpenCompass 始终努力充分利用所有可用的 GPU 资源。
例如,如果您在配备有 8 个 GPU 的本地机器上使用 OpenCompass,每个任务要求 4 个 GPU,那么默认情况下,OpenCompass 会使用所有 8 个 GPU 同时运行 2 个任务。但是,如果您将 `--max-num-workers` 设置为 1,那么一次只会处理一个任务,只使用 4 个 GPU。
### 我如何控制 OpenCompass 占用的 GPU 数量?
目前,没有直接的方法来指定 OpenCompass 可以使用的 GPU 数量。但以下是一些间接策略:
**如果在本地评估:**
您可以通过设置 `CUDA_VISIBLE_DEVICES` 环境变量来限制 OpenCompass 的 GPU 访问。例如,使用 `CUDA_VISIBLE_DEVICES=0,1,2,3 python run.py ...` 只会向 OpenCompass 暴露前四个 GPU,确保它同时使用的 GPU 数量不超过这四个。
**如果使用 Slurm 或 DLC:**
尽管 OpenCompass 没有直接访问资源池,但您可以调整 `--max-num-workers` 参数以限制同时提交的评估任务数量。这将间接管理 OpenCompass 使用的 GPU 数量。例如,如果每个任务需要 4 个 GPU,您希望分配总共 8 个 GPU,那么应将 `--max-num-workers` 设置为 2。
### 找不到 `libGL.so.1`
opencv-python 依赖一些动态库,但环境中没有,最简单的解决办法是卸载 opencv-python 再安装 opencv-python-headless。
```bash
pip uninstall opencv-python
pip install opencv-python-headless
```
也可以根据报错提示安装对应的依赖库
```bash
sudo apt-get update
sudo apt-get install -y libgl1 libglib2.0-0
```
### 运行报错 Error: mkl-service + Intel(R) MKL
报错全文如下:
```text
Error: mkl-service + Intel(R) MKL: MKL_THREADING_LAYER=INTEL is incompatible with libgomp-a34b3233.so.1 library.
Try to import numpy first or set the threading layer accordingly. Set MKL_SERVICE_FORCE_INTEL to force it.
```
可以通过设置环境变量 `MKL_SERVICE_FORCE_INTEL=1` 来解决这个问题。
## 网络
### 运行报错:`('Connection aborted.', ConnectionResetError(104, 'Connection reset by peer'))` 或 `urllib3.exceptions.MaxRetryError: HTTPSConnectionPool(host='cdn-lfs.huggingface.co', port=443)`
由于 HuggingFace 的实现,OpenCompass 在首次加载某些数据集和模型时需要网络(尤其是与 HuggingFace 的连接)。此外,每次启动时都会连接到 HuggingFace。为了成功运行,您可以:
- 通过指定环境变量 `http_proxy``https_proxy`,挂上代理;
- 使用其他机器的缓存文件。首先在有 HuggingFace 访问权限的机器上运行实验,然后将缓存文件复制 / 软链到离线的机器上。缓存文件默认位于 `~/.cache/huggingface/`[文档](https://huggingface.co/docs/datasets/cache#cache-directory))。当缓存文件准备好时,您可以在离线模式下启动评估:
```python
HF_DATASETS_OFFLINE=1 TRANSFORMERS_OFFLINE=1 HF_EVALUATE_OFFLINE=1 HF_HUB_OFFLINE=1 python run.py ...
```
这样,评估不再需要网络连接。但是,如果缓存中缺少任何数据集或模型的文件,仍然会引发错误。
- 使用中国大陆内的镜像源,例如 [hf-mirror](https://hf-mirror.com/)
```python
HF_ENDPOINT=https://hf-mirror.com python run.py ...
```
### 我的服务器无法连接到互联网,我如何使用 OpenCompass?
[网络-Q1](#运行报错Connection-aborted-ConnectionResetError104-Connection-reset-by-peer-或-urllib3exceptionsMaxRetryError-HTTPSConnectionPoolhostcdn-lfshuggingfaceco-port443) 所述,使用其他机器的缓存文件。
## 效率
### 为什么 OpenCompass 将每个评估请求分割成任务?
鉴于大量的评估时间和大量的数据集,对 LLM 模型进行全面的线性评估可能非常耗时。为了解决这个问题,OpenCompass 将评估请求分为多个独立的 “任务”。然后,这些任务被派发到各种 GPU 组或节点,实现全并行并最大化计算资源的效率。
### 任务分区是如何工作的?
OpenCompass 中的每个任务代表等待评估的特定模型和数据集部分的组合。OpenCompass 提供了各种任务分区策略,每种策略都针对不同的场景。在推理阶段,主要的分区方法旨在平衡任务大小或计算成本。这种成本是从数据集大小和推理类型中启发式地得出的。
### 为什么在 OpenCompass 上评估 LLM 模型需要更多时间?
请检查:
1. 是否有使用 vllm / lmdeploy 等推理后端,这会大大提速测试过程
2. 对于使用原生 huggingface 跑的,`batch_size` 为 1 会大幅拖慢测试过程,可以适当调大 `batch_size`
3. 如果是 huggingface 上下载的模型,是否有大量的时间卡在网络连接或模型下载上面了
4. 模型的推理结果是否会意外地长,尤其是模型是否在尝试再出若干题并尝试进行解答,这在基座模型中会尤其常见。可以通过在数据集中添加 `stopping_criteria` 的方式来解决
如果上述检查项没有解决问题,请考虑给我们报 bug
## 模型
### 如何使用本地已下好的 Huggingface 模型?
如果您已经提前下载好 Huggingface 的模型文件,请手动指定模型路径. 示例如下
```bash
python run.py --datasets siqa_gen winograd_ppl --hf-type base --hf-path /path/to/model
```
## 数据集
### 如何构建自己的评测数据集
- 客观数据集构建参见:[支持新数据集](../advanced_guides/new_dataset.md)
- 主观数据集构建参见:[主观评测指引](../advanced_guides/subjective_evaluation.md)
# 安装
## 基础安装
1. 使用Conda准备 OpenCompass 运行环境:
```bash
conda create --name opencompass python=3.10 -y
# conda create --name opencompass_lmdeploy python=3.10 -y
conda activate opencompass
```
如果你希望自定义 PyTorch 版本,请参考 [官方文档](https://pytorch.org/get-started/locally/) 准备 PyTorch 环境。需要注意的是,OpenCompass 要求 `pytorch>=1.13`
2. 安装 OpenCompass:
- pip安装
```bash
# 支持绝大多数数据集及模型
pip install -U opencompass
# 完整安装(支持更多数据集)
# pip install "opencompass[full]"
# API 测试(例如 OpenAI、Qwen)
# pip install "opencompass[api]"
```
- 如果希望使用 OpenCompass 的最新功能,也可以从源代码构建它:
```bash
git clone https://github.com/open-compass/opencompass opencompass
cd opencompass
pip install -e .
```
## 其他安装
### 推理后端
```bash
# 模型推理后端,由于这些推理后端通常存在依赖冲突,建议使用不同的虚拟环境来管理它们。
pip install "opencompass[lmdeploy]"
# pip install "opencompass[vllm]"
```
- LMDeploy
可以通过下列命令判断推理后端是否安装成功,更多信息请参考 [官方文档](https://lmdeploy.readthedocs.io/zh-cn/latest/get_started.html)
```bash
lmdeploy chat internlm/internlm2_5-1_8b-chat --backend turbomind
```
- vLLM
可以通过下列命令判断推理后端是否安装成功,更多信息请参考 [官方文档](https://docs.vllm.ai/en/latest/getting_started/quickstart.html)
```bash
vllm serve facebook/opt-125m
```
### API
Opencompass支持不同的商业模型API调用,你可以通过pip方式安装,或者参考 [API](https://github.com/open-compass/opencompass/blob/main/requirements/api.txt) 安装对应的API模型依赖
```bash
pip install opencompass[api]
# pip install openai # GPT-3.5-Turbo / GPT-4-Turbo / GPT-4 / GPT-4o (API)
# pip install anthropic # Claude (API)
# pip install dashscope # 通义千问 (API)
# pip install volcengine-python-sdk # 字节豆包 (API)
# ...
```
### 数据集
基础安装可以支持绝大部分基础数据集,针对某些数据集(i.e. Alpaca-eval, Longbench etc.),需要安装额外的依赖。
你可以通过pip方式安装,或者参考 [额外依赖](https://github.com/open-compass/opencompass/blob/main/requirements/extra.txt) 安装对应的依赖
```bash
pip install opencompass[full]
```
针对 HumanEvalX / HumanEval+ / MBPP+ 需要手动clone git仓库进行安装
```bash
git clone --recurse-submodules git@github.com:open-compass/human-eval.git
cd human-eval
pip install -e .
pip install -e evalplus
```
部分智能体评测需要安装大量依赖且可能会与已有运行环境冲突,我们建议创建不同的conda环境来管理
```bash
# T-Eval
pip install lagent==0.1.2
# CIBench
pip install -r requirements/agent.txt
```
## 数据集准备
OpenCompass 支持的数据集主要包括三个部分:
1. Huggingface 数据集: [Huggingface Dataset](https://huggingface.co/datasets) 提供了大量的数据集,这部分数据集运行时会**自动下载**
2. ModelScope 数据集:[ModelScope OpenCompass Dataset](https://modelscope.cn/organization/opencompass) 支持从 ModelScope 自动下载数据集。
要启用此功能,请设置环境变量:`export DATASET_SOURCE=ModelScope`,可用的数据集包括(来源于 OpenCompassData-core.zip):
```plain
humaneval, triviaqa, commonsenseqa, tydiqa, strategyqa, cmmlu, lambada, piqa, ceval, math, LCSTS, Xsum, winogrande, openbookqa, AGIEval, gsm8k, nq, race, siqa, mbpp, mmlu, hellaswag, ARC, BBH, xstory_cloze, summedits, GAOKAO-BENCH, OCNLI, cmnli
```
3. 自建以及第三方数据集:OpenCompass 还提供了一些第三方数据集及自建**中文**数据集。运行以下命令**手动下载解压**
在 OpenCompass 项目根目录下运行下面命令,将数据集准备至 `${OpenCompass}/data` 目录下:
```bash
wget https://github.com/open-compass/opencompass/releases/download/0.2.2.rc1/OpenCompassData-core-20240207.zip
unzip OpenCompassData-core-20240207.zip
```
如果需要使用 OpenCompass 提供的更加完整的数据集 (~500M),可以使用下述命令进行下载和解压:
```bash
wget https://github.com/open-compass/opencompass/releases/download/0.2.2.rc1/OpenCompassData-complete-20240207.zip
unzip OpenCompassData-complete-20240207.zip
cd ./data
find . -name "*.zip" -exec unzip "{}" \;
```
两个 `.zip` 中所含数据集列表如[此处](https://github.com/open-compass/opencompass/releases/tag/0.2.2.rc1)所示。
OpenCompass 已经支持了大多数常用于性能比较的数据集,具体支持的数据集列表请直接在 `configs/datasets` 下进行查找。
接下来,你可以阅读[快速上手](./quick_start.md)了解 OpenCompass 的基本用法。
# 快速开始
![image](https://github.com/open-compass/opencompass/assets/22607038/d063cae0-3297-4fd2-921a-366e0a24890b)
## 概览
在 OpenCompass 中评估一个模型通常包括以下几个阶段:**配置** -> **推理** -> **评估** -> **可视化**
**配置**:这是整个工作流的起点。您需要配置整个评估过程,选择要评估的模型和数据集。此外,还可以选择评估策略、计算后端等,并定义显示结果的方式。
**推理与评估**:在这个阶段,OpenCompass 将会开始对模型和数据集进行并行推理和评估。**推理**阶段主要是让模型从数据集产生输出,而**评估**阶段则是衡量这些输出与标准答案的匹配程度。这两个过程会被拆分为多个同时运行的“任务”以提高效率,但请注意,如果计算资源有限,这种策略可能会使评测变得更慢。如果需要了解该问题及解决方案,可以参考 [FAQ: 效率](faq.md#效率)
**可视化**:评估完成后,OpenCompass 将结果整理成易读的表格,并将其保存为 CSV 和 TXT 文件。你也可以激活飞书状态上报功能,此后可以在飞书客户端中及时获得评测状态报告。
接下来,我们将展示 OpenCompass 的基础用法,展示基座模型模型 [InternLM2-1.8B](https://huggingface.co/internlm/internlm2-1_8b) 和对话模型 [InternLM2-Chat-1.8B](https://huggingface.co/internlm/internlm2-chat-1_8b)[Qwen2-1.5B-Instruct](https://huggingface.co/Qwen/Qwen2-1.5B-Instruct)[GSM8K](https://github.com/openai/grade-school-math)[MATH](https://github.com/hendrycks/math) 下采样数据集上的评估。它们的配置文件可以在 [configs/eval_chat_demo.py](https://github.com/open-compass/opencompass/blob/main/configs/eval_chat_demo.py)[configs/eval_base_demo.py](https://github.com/open-compass/opencompass/blob/main/configs/eval_base_demo.py) 中找到。
在运行此实验之前,请确保您已在本地安装了 OpenCompass。这个例子 (应该) 可以在一台 _GTX-1660-6G_ GPU 下成功运行。
对于参数更大的模型,如 Llama3-8B,请参考 [configs 目录](https://github.com/open-compass/opencompass/tree/main/configs) 中提供的其他示例。
## 配置评估任务
在 OpenCompass 中,每个评估任务由待评估的模型和数据集组成。评估的入口点是 `run.py`。用户可以通过命令行或配置文件选择要测试的模型和数据集。
对于对话模型
`````{tabs}
````{tab} 命令行(自定义 HF 模型)
对于 HuggingFace 模型,用户可以通过命令行直接设置模型参数,无需额外的配置文件。例如,对于 `internlm/internlm2-chat-1_8b` 模型,您可以使用以下命令进行评估:
```bash
python run.py \
--datasets demo_gsm8k_chat_gen demo_math_chat_gen \
--hf-type chat \
--hf-path internlm/internlm2-chat-1_8b \
--debug
```
请注意,通过这种方式,OpenCompass 一次只评估一个模型,而其他方式可以一次评估多个模型。
:::{dropdown} HF 模型完整参数列表
:animate: fade-in-slide-down
| 命令行参数 | 描述 | 样例数值 |
| --- | --- | --- |
| `--hf-type` | HuggingFace 模型类型,可选值为 `chat` 或 `base` | chat |
| `--hf-path` | HuggingFace 模型路径 | internlm/internlm2-chat-1_8b |
| `--model-kwargs` | 构建模型的参数 | device_map='auto' |
| `--tokenizer-path` | HuggingFace tokenizer 路径(如果与模型路径相同,可以省略) | internlm/internlm2-chat-1_8b |
| `--tokenizer-kwargs` | 构建 tokenizer 的参数 | padding_side='left' truncation='left' trust_remote_code=True |
| `--generation-kwargs` | 生成的参数 | do_sample=True top_k=50 top_p=0.95 |
| `--max-seq-len` | 模型可以接受的最大序列长度 | 2048 |
| `--max-out-len` | 生成的最大 token 数 | 100 |
| `--min-out-len` | 生成的最小 token 数 | 1 |
| `--batch-size` | 批量大小 | 64 |
| `--hf-num-gpus` | 运行一个模型实例所需的 GPU 数量 | 1 |
| `--stop-words` | 停用词列表 | '<\|im_end\|>' '<\|im_start\|>' |
| `--pad-token-id` | 填充 token 的 ID | 0 |
| `--peft-path` | (例如) LoRA 模型的路径 | internlm/internlm2-chat-1_8b |
| `--peft-kwargs` | (例如) 构建 LoRA 模型的参数 | trust_remote_code=True |
:::
:::{dropdown} 更复杂的命令样例
:animate: fade-in-slide-down
例如一个占用 2 卡进行测试的 Qwen1.5-14B-Chat, 开启数据采样,模型的命令如下:
```bash
python run.py --datasets demo_gsm8k_chat_gen demo_math_chat_gen \
--hf-type chat \
--hf-path Qwen/Qwen1.5-14B-Chat \
--max-out-len 1024 \
--min-out-len 1 \
--hf-num-gpus 2 \
--generation-kwargs do_sample=True temperature=0.6 \
--stop-words '<|im_end|>' '<|im_start|>' \
--debug
```
:::
````
````{tab} 命令行
用户可以使用 `--models` 和 `--datasets` 结合想测试的模型和数据集。
```bash
python run.py \
--models hf_internlm2_chat_1_8b hf_qwen2_1_5b_instruct \
--datasets demo_gsm8k_chat_gen demo_math_chat_gen \
--debug
```
模型和数据集的配置文件预存于 `configs/models` 和 `configs/datasets` 中。用户可以使用 `tools/list_configs.py` 查看或过滤当前可用的模型和数据集配置。
```bash
# 列出所有配置
python tools/list_configs.py
# 列出与llama和mmlu相关的所有配置
python tools/list_configs.py llama mmlu
```
:::{dropdown} 关于 `list_configs`
:animate: fade-in-slide-down
运行 `python tools/list_configs.py llama mmlu` 将产生如下输出:
```text
+-----------------+-----------------------------------+
| Model | Config Path |
|-----------------+-----------------------------------|
| hf_llama2_13b | configs/models/hf_llama2_13b.py |
| hf_llama2_70b | configs/models/hf_llama2_70b.py |
| ... | ... |
+-----------------+-----------------------------------+
+-------------------+---------------------------------------------------+
| Dataset | Config Path |
|-------------------+---------------------------------------------------|
| cmmlu_gen | configs/datasets/cmmlu/cmmlu_gen.py |
| cmmlu_gen_ffe7c0 | configs/datasets/cmmlu/cmmlu_gen_ffe7c0.py |
| ... | ... |
+-------------------+---------------------------------------------------+
```
用户可以使用第一列中的名称作为 `python run.py` 中 `--models` 和 `--datasets` 的输入参数。对于数据集,同一名称的不同后缀通常表示其提示或评估方法不同。
:::
:::{dropdown} 没有列出的模型?
:animate: fade-in-slide-down
如果您想评估其他模型,请查看 “命令行(自定义 HF 模型)”选项卡,了解无需配置文件自定义 HF 模型的方法,或 “配置文件”选项卡,了解准备模型配置的通用方法。
:::
````
````{tab} 配置文件
除了通过命令行配置实验外,OpenCompass 还允许用户在配置文件中编写实验的完整配置,并通过 `run.py` 直接运行它。配置文件是以 Python 格式组织的,并且必须包括 `datasets` 和 `models` 字段。
本次测试配置在 [configs/eval_chat_demo.py](https://github.com/open-compass/opencompass/blob/main/configs/eval_chat_demo.py) 中。此配置通过 [继承机制](../user_guides/config.md#继承机制) 引入所需的数据集和模型配置,并以所需格式组合 `datasets` 和 `models` 字段。
```python
from mmengine.config import read_base
with read_base():
from .datasets.demo.demo_gsm8k_chat_gen import gsm8k_datasets
from .datasets.demo.demo_math_chat_gen import math_datasets
from .models.qwen.hf_qwen2_1_5b_instruct import models as hf_qwen2_1_5b_instruct_models
from .models.hf_internlm.hf_internlm2_chat_1_8b import models as hf_internlm2_chat_1_8b_models
datasets = gsm8k_datasets + math_datasets
models = hf_qwen2_1_5b_instruct_models + hf_internlm2_chat_1_8b_models
```
运行任务时,我们只需将配置文件的路径传递给 `run.py`:
```bash
python run.py configs/eval_chat_demo.py --debug
```
:::{dropdown} 关于 `models`
:animate: fade-in-slide-down
OpenCompass 提供了一系列预定义的模型配置,位于 `configs/models` 下。以下是与 [InternLM2-Chat-1.8B](https://github.com/open-compass/opencompass/blob/main/configs/models/hf_internlm/hf_internlm2_chat_1_8b.py)(`configs/models/hf_internlm/hf_internlm2_chat_1_8b.py`)相关的配置片段:
```python
# 使用 `HuggingFacewithChatTemplate` 评估由 HuggingFace 的 `AutoModelForCausalLM` 支持的对话模型
from opencompass.models import HuggingFacewithChatTemplate
models = [
dict(
type=HuggingFacewithChatTemplate,
abbr='internlm2-chat-1.8b-hf', # 模型的缩写
path='internlm/internlm2-chat-1_8b', # 模型的 HuggingFace 路径
max_out_len=1024, # 生成的最大 token 数
batch_size=8, # 批量大小
run_cfg=dict(num_gpus=1), # 该模型所需的 GPU 数量
)
]
```
使用配置时,我们可以通过命令行参数 `--models` 指定相关文件,或使用继承机制将模型配置导入到配置文件中的 `models` 列表中。
```{seealso}
有关模型配置的更多信息,请参见 [准备模型](../user_guides/models.md)。
```
:::
:::{dropdown} 关于 `datasets`
:animate: fade-in-slide-down
与模型类似,数据集的配置文件也提供在 `configs/datasets` 下。用户可以在命令行中使用 `--datasets`,或通过继承在配置文件中导入相关配置
下面是来自 `configs/eval_chat_demo.py` 的与数据集相关的配置片段:
```python
from mmengine.config import read_base # 使用 mmengine.read_base() 读取基本配置
with read_base():
# 直接从预设的数据集配置中读取所需的数据集配置
from .datasets.demo.demo_gsm8k_chat_gen import gsm8k_datasets # 读取 GSM8K 配置,使用 4-shot,基于生成式进行评估
from .datasets.demo.demo_math_chat_gen import math_datasets # 读取 MATH 配置,使用 0-shot,基于生成式进行评估
datasets = gsm8k_datasets + math_datasets # 最终的配置需要包含所需的评估数据集列表 'datasets'
```
数据集配置通常有两种类型:`ppl` 和 `gen`,分别指示使用的评估方法。其中 `ppl` 表示辨别性评估,`gen` 表示生成性评估。对话模型仅使用 `gen` 生成式评估。
此外,[configs/datasets/collections](https://github.com/open-compass/opencompass/blob/main/configs/datasets/collections) 收录了各种数据集集合,方便进行综合评估。OpenCompass 通常使用 [`chat_OC15.py`](https://github.com/open-compass/opencompass/blob/main/configs/dataset_collections/chat_OC15.py) 进行全面的模型测试。要复制结果,只需导入该文件,例如:
```bash
python run.py --models hf_internlm2_chat_1_8b --datasets chat_OC15 --debug
```
```{seealso}
您可以从 [配置数据集](../user_guides/datasets.md) 中找到更多信息。
```
:::
````
`````
对于基座模型
`````{tabs}
````{tab} 命令行(自定义 HF 模型)
对于 HuggingFace 模型,用户可以通过命令行直接设置模型参数,无需额外的配置文件。例如,对于 `internlm/internlm2-1_8b` 模型,您可以使用以下命令进行评估:
```bash
python run.py \
--datasets demo_gsm8k_base_gen demo_math_base_gen \
--hf-type base \
--hf-path internlm/internlm2-1_8b \
--debug
```
请注意,通过这种方式,OpenCompass 一次只评估一个模型,而其他方式可以一次评估多个模型。
:::{dropdown} 更复杂的命令样例
:animate: fade-in-slide-down
例如一个占用 2 卡进行测试的 Qwen1.5-14B, 开启数据采样,模型的命令如下:
```bash
python run.py --datasets demo_gsm8k_base_gen demo_math_base_gen \
--hf-type chat \
--hf-path Qwen/Qwen1.5-14B \
--max-out-len 1024 \
--min-out-len 1 \
--hf-num-gpus 2 \
--generation-kwargs do_sample=True temperature=0.6 \
--debug
```
:::
````
````{tab} 命令行
用户可以使用 `--models` 和 `--datasets` 结合想测试的模型和数据集。
```bash
python run.py \
--models hf_internlm2_1_8b hf_qwen2_1_5b \
--datasets demo_gsm8k_base_gen demo_math_base_gen \
--debug
```
````
````{tab} 配置文件
除了通过命令行配置实验外,OpenCompass 还允许用户在配置文件中编写实验的完整配置,并通过 `run.py` 直接运行它。配置文件是以 Python 格式组织的,并且必须包括 `datasets` 和 `models` 字段。
本次测试配置在 [configs/eval_base_demo.py](https://github.com/open-compass/opencompass/blob/main/configs/eval_base_demo.py) 中。此配置通过 [继承机制](../user_guides/config.md#继承机制) 引入所需的数据集和模型配置,并以所需格式组合 `datasets` 和 `models` 字段。
```python
from mmengine.config import read_base
with read_base():
from .datasets.demo.demo_gsm8k_base_gen import gsm8k_datasets
from .datasets.demo.demo_math_base_gen import math_datasets
from .models.qwen.hf_qwen2_1_5b import models as hf_qwen2_1_5b_models
from .models.hf_internlm.hf_internlm2_1_8b import models as hf_internlm2_1_8b_models
datasets = gsm8k_datasets + math_datasets
models = hf_qwen2_1_5b_models + hf_internlm2_1_8b_models
```
运行任务时,我们只需将配置文件的路径传递给 `run.py`:
```bash
python run.py configs/eval_base_demo.py --debug
```
:::{dropdown} 关于 `models`
:animate: fade-in-slide-down
OpenCompass 提供了一系列预定义的模型配置,位于 `configs/models` 下。以下是与 [InternLM2-1.8B](https://github.com/open-compass/opencompass/blob/main/configs/models/hf_internlm/hf_internlm2_1_8b.py)(`configs/models/hf_internlm/hf_internlm2_1_8b.py`)相关的配置片段:
```python
# 使用 `HuggingFaceBaseModel` 评估由 HuggingFace 的 `AutoModelForCausalLM` 支持的基座模型
from opencompass.models import HuggingFaceBaseModel
models = [
dict(
type=HuggingFaceBaseModel,
abbr='internlm2-1.8b-hf', # 模型的缩写
path='internlm/internlm2-1_8b', # 模型的 HuggingFace 路径
max_out_len=1024, # 生成的最大 token 数
batch_size=8, # 批量大小
run_cfg=dict(num_gpus=1), # 该模型所需的 GPU 数量
)
]
```
使用配置时,我们可以通过命令行参数 `--models` 指定相关文件,或使用继承机制将模型配置导入到配置文件中的 `models` 列表中。
```{seealso}
有关模型配置的更多信息,请参见 [准备模型](../user_guides/models.md)。
```
:::
:::{dropdown} 关于 `datasets`
:animate: fade-in-slide-down
与模型类似,数据集的配置文件也提供在 `configs/datasets` 下。用户可以在命令行中使用 `--datasets`,或通过继承在配置文件中导入相关配置
下面是来自 `configs/eval_base_demo.py` 的与数据集相关的配置片段:
```python
from mmengine.config import read_base # 使用 mmengine.read_base() 读取基本配置
with read_base():
# 直接从预设的数据集配置中读取所需的数据集配置
from .datasets.demo.demo_gsm8k_base_gen import gsm8k_datasets # 读取 GSM8K 配置,使用 4-shot,基于生成式进行评估
from .datasets.demo.demo_math_base_gen import math_datasets # 读取 MATH 配置,使用 0-shot,基于生成式进行评估
datasets = gsm8k_datasets + math_datasets # 最终的配置需要包含所需的评估数据集列表 'datasets'
```
数据集配置通常有两种类型:`ppl` 和 `gen`,分别指示使用的评估方法。其中 `ppl` 表示判别性评估,`gen` 表示生成性评估。基座模型对于 "选择题" 类型的数据集会使用 `ppl` 判别性评估,其他则会使用 `gen` 生成式评估。
```{seealso}
您可以从 [配置数据集](../user_guides/datasets.md) 中找到更多信息。
```
:::
````
`````
```{warning}
OpenCompass 通常假定运行环境网络是可用的。如果您遇到网络问题或希望在离线环境中运行 OpenCompass,请参阅 [FAQ - 网络 - Q1](./faq.md#网络) 寻求解决方案。
```
接下来的部分将使用基于配置的方法,评测对话模型,作为示例来解释其他特征。
## 启动评估
由于 OpenCompass 默认并行启动评估过程,我们可以在第一次运行时以 `--debug` 模式启动评估,并检查是否存在问题。包括在前述的所有文档中,我们都使用了 `--debug` 开关。在 `--debug` 模式下,任务将按顺序执行,并实时打印输出。
```bash
python run.py configs/eval_chat_demo.py -w outputs/demo --debug
```
对话默写 'internlm/internlm2-chat-1_8b' 和 'Qwen/Qwen2-1.5B-Instruct' 将在首次运行期间从 HuggingFace 自动下载。
如果一切正常,您应该看到屏幕上显示 “Starting inference process”,且进度条开始前进:
```bash
[2023-07-12 18:23:55,076] [opencompass.openicl.icl_inferencer.icl_gen_inferencer] [INFO] Starting inference process...
```
然后,您可以按 `Ctrl+C` 中断程序,并以正常模式运行以下命令:
```bash
python run.py configs/eval_chat_demo.py -w outputs/demo
```
在正常模式下,评估任务将在后台并行执行,其输出将被重定向到输出目录 `outputs/demo/{TIMESTAMP}`。前端的进度条只指示已完成任务的数量,而不考虑其成功或失败。**任何后端任务失败都只会在终端触发警告消息。**
:::{dropdown} `run.py` 中的更多参数
:animate: fade-in-slide-down
以下是与评估相关的一些参数,可以帮助您根据环境配置更有效的推理任务:
- `-w outputs/demo`:保存评估日志和结果的工作目录。在这种情况下,实验结果将保存到 `outputs/demo/{TIMESTAMP}`
- `-r {TIMESTAMP/latest}`:重用现有的推理结果,并跳过已完成的任务。如果后面跟随时间戳,将重用工作空间路径下该时间戳的结果;若给定 latest 或干脆不指定,将重用指定工作空间路径下的最新结果。
- `--mode all`:指定任务的特定阶段。
- all:(默认)执行完整评估,包括推理和评估。
- infer:在每个数据集上执行推理。
- eval:根据推理结果进行评估。
- viz:仅显示评估结果。
- `--max-num-workers 8`:并行任务的最大数量。在如 Slurm 之类的分布式环境中,此参数指定提交任务的最大数量。在本地环境中,它指定同时执行的任务的最大数量。请注意,实际的并行任务数量取决于可用的 GPU 资源,可能不等于这个数字。
如果您不是在本地机器上执行评估,而是使用 Slurm 集群,您可以指定以下参数:
- `--slurm`:在集群上使用 Slurm 提交任务。
- `--partition(-p) my_part`:Slurm 集群分区。
- `--retry 2`:失败任务的重试次数。
```{seealso}
入口还支持将任务提交到阿里巴巴深度学习中心(DLC),以及更多自定义评估策略。请参考 [评测任务发起](../user_guides/experimentation.md#评测任务发起) 了解详情。
```
:::
## 可视化评估结果
评估完成后,评估结果表格将打印如下:
```text
dataset version metric mode qwen2-1.5b-instruct-hf internlm2-chat-1.8b-hf
---------- --------- -------- ------ ------------------------ ------------------------
demo_gsm8k 1d7fe4 accuracy gen 56.25 32.81
demo_math 393424 accuracy gen 18.75 14.06
```
所有运行输出将定向到 `outputs/demo/` 目录,结构如下:
```text
outputs/default/
├── 20200220_120000
├── 20230220_183030 # 每个实验一个文件夹
│ ├── configs # 用于记录的已转储的配置文件。如果在同一个实验文件夹中重新运行了不同的实验,可能会保留多个配置
│ ├── logs # 推理和评估阶段的日志文件
│ │ ├── eval
│ │ └── infer
│ ├── predictions # 每个任务的推理结果
│ ├── results # 每个任务的评估结果
│ └── summary # 单个实验的汇总评估结果
├── ...
```
打印评测结果的过程可被进一步定制化,用于输出一些数据集的平均分 (例如 MMLU, C-Eval 等)。
关于评测结果输出的更多介绍可阅读 [结果展示](../user_guides/summarizer.md)
## 更多教程
想要更多了解 OpenCompass, 可以点击下列链接学习。
- [配置数据集](../user_guides/datasets.md)
- [准备模型](../user_guides/models.md)
- [任务运行和监控](../user_guides/experimentation.md)
- [如何调 Prompt](../prompt/overview.md)
- [结果展示](../user_guides/summarizer.md)
- [学习配置文件](../user_guides/config.md)
欢迎来到 OpenCompass 中文教程!
==========================================
OpenCompass 上手路线
-------------------------------
为了用户能够快速上手,我们推荐以下流程:
- 对于想要使用 OpenCompass 的用户,我们推荐先阅读 开始你的第一步_ 部分来设置环境,并启动一个迷你实验熟悉流程。
- 对于一些基础使用,我们建议用户阅读 教程_ 。
- 如果您想调整提示词(prompt),您可以浏览 提示词_ 。
- 若您想进行更多模块的自定义,例如增加数据集和模型,我们提供了 进阶教程_ 。
- 还有更多实用的工具,如提示词预览、飞书机器人上报等功能,我们同样提供了 工具_ 教程。
我们始终非常欢迎用户的 PRs 和 Issues 来完善 OpenCompass!
.. _开始你的第一步:
.. toctree::
:maxdepth: 1
:caption: 开始你的第一步
get_started/installation.md
get_started/quick_start.md
get_started/faq.md
.. _教程:
.. toctree::
:maxdepth: 1
:caption: 教程
user_guides/framework_overview.md
user_guides/config.md
user_guides/datasets.md
user_guides/models.md
user_guides/evaluation.md
user_guides/experimentation.md
user_guides/metrics.md
user_guides/deepseek_r1.md
.. _提示词:
.. toctree::
:maxdepth: 1
:caption: 提示词
prompt/overview.md
prompt/prompt_template.md
prompt/meta_template.md
prompt/chain_of_thought.md
.. _进阶教程:
.. toctree::
:maxdepth: 1
:caption: 进阶教程
advanced_guides/new_dataset.md
advanced_guides/custom_dataset.md
advanced_guides/new_model.md
advanced_guides/evaluation_lmdeploy.md
advanced_guides/accelerator_intro.md
advanced_guides/math_verify.md
advanced_guides/llm_judge.md
advanced_guides/code_eval.md
advanced_guides/code_eval_service.md
advanced_guides/subjective_evaluation.md
.. _工具:
.. toctree::
:maxdepth: 1
:caption: 工具
tools.md
.. _数据集列表:
.. toctree::
:maxdepth: 1
:caption: 数据集列表
dataset_statistics.md
.. _其他说明:
.. toctree::
:maxdepth: 1
:caption: 其他说明
notes/contribution_guide.md
索引与表格
==================
* :ref:`genindex`
* :ref:`search`
# 为 OpenCompass 做贡献
- [为 OpenCompass 做贡献](#为-opencompass-做贡献)
- [什么是拉取请求?](#什么是拉取请求)
- [基本的工作流:](#基本的工作流)
- [具体步骤](#具体步骤)
- [1. 获取最新的代码库](#1-获取最新的代码库)
- [2. 从 `main` 分支创建一个新的开发分支](#2-从-main-分支创建一个新的开发分支)
- [3. 提交你的修改](#3-提交你的修改)
- [4. 推送你的修改到复刻的代码库,并创建一个拉取请求](#4-推送你的修改到复刻的代码库并创建一个拉取请求)
- [5. 讨论并评审你的代码](#5-讨论并评审你的代码)
- [6. `拉取请求`合并之后删除该分支](#6-拉取请求合并之后删除该分支)
- [代码风格](#代码风格)
- [Python](#python)
- [关于提交数据集](#关于提交数据集)
感谢你对于OpenCompass的贡献!我们欢迎各种形式的贡献,包括但不限于以下几点。
- 修改错别字或修复bug
- 添加文档或将文档翻译成其它语言
- 添加新功能和组件
## 什么是拉取请求?
`拉取请求` (Pull Request), [GitHub 官方文档](https://docs.github.com/en/github/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/about-pull-requests)定义如下。
```
拉取请求是一种通知机制。你修改了他人的代码,将你的修改通知原来作者,希望他合并你的修改。
```
## 基本的工作流:
1. 获取最新的代码库
2. 从最新的 `main` 分支创建分支进行开发
3. 提交修改 ([不要忘记使用 pre-commit hooks!](#3-提交你的修改))
4. 推送你的修改并创建一个 `拉取请求`
5. 讨论、审核代码
6. 将开发分支合并到 `main` 分支
## 具体步骤
### 1. 获取最新的代码库
- 当你第一次提 PR 时
复刻 OpenCompass 原代码库,点击 GitHub 页面右上角的 **Fork** 按钮即可
![avatar](https://github.com/open-compass/opencompass/assets/22607038/851ed33d-02db-49c9-bf94-7c62eee89eb2)
克隆复刻的代码库到本地
```bash
git clone git@github.com:XXX/opencompass.git
```
添加原代码库为上游代码库
```bash
git remote add upstream git@github.com:InternLM/opencompass.git
```
- 从第二个 PR 起
检出本地代码库的主分支,然后从最新的原代码库的主分支拉取更新。
```bash
git checkout main
git pull upstream main
```
### 2. 从 `main` 分支创建一个新的开发分支
```bash
git checkout main -b branchname
```
### 3. 提交你的修改
- 如果你是第一次尝试贡献,请在 OpenCompass 的目录下安装并初始化 pre-commit hooks。
```bash
pip install -U pre-commit
pre-commit install
```
````{tip}
对于中国地区的用户,由于网络原因,安装 pre-commit hook 可能会失败。可以尝试以下命令切换为国内镜像源:
```bash
pre-commit install -c .pre-commit-config-zh-cn.yaml
pre-commit run –all-files -c .pre-commit-config-zh-cn.yaml
```
````
- 提交修改。在每次提交前,pre-commit hooks 都会被触发并规范化你的代码格式。
```bash
# coding
git add [files]
git commit -m 'messages'
```
```{note}
有时你的文件可能会在提交时被 pre-commit hooks 自动修改。这时请重新添加并提交修改后的文件。
```
### 4. 推送你的修改到复刻的代码库,并创建一个拉取请求
- 推送当前分支到远端复刻的代码库
```bash
git push origin branchname
```
- 创建一个拉取请求
![avatar](https://github.com/open-compass/opencompass/assets/22607038/08feb221-b145-4ea8-8e20-05f143081604)
- 修改拉取请求信息模板,描述修改原因和修改内容。还可以在 PR 描述中,手动关联到相关的议题 (issue),(更多细节,请参考[官方文档](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue))。
- 你同样可以把 PR 关联给相关人员进行评审。
### 5. 讨论并评审你的代码
- 根据评审人员的意见修改代码,并推送修改
### 6. `拉取请求`合并之后删除该分支
- 在 PR 合并之后,你就可以删除该分支了。
```bash
git branch -d branchname # 删除本地分支
git push origin --delete branchname # 删除远程分支
```
## 代码风格
### Python
我们采用[PEP8](https://www.python.org/dev/peps/pep-0008/)作为首选的代码风格。
我们使用以下工具进行linting和格式化:
- [flake8](https://github.com/PyCQA/flake8): 一个围绕一些linter工具的封装器。
- [isort](https://github.com/timothycrosley/isort): 一个用于排序Python导入的实用程序。
- [yapf](https://github.com/google/yapf): 一个Python文件的格式化器。
- [codespell](https://github.com/codespell-project/codespell): 一个Python实用程序,用于修复文本文件中常见的拼写错误。
- [mdformat](https://github.com/executablebooks/mdformat): mdformat是一个有明确定义的Markdown格式化程序,可以用来在Markdown文件中强制执行一致的样式。
- [docformatter](https://github.com/myint/docformatter): 一个格式化docstring的工具。
yapf和isort的样式配置可以在[setup.cfg](https://github.com/OpenCompass/blob/main/setup.cfg)中找到。
## 关于贡献测试数据集
- 提交测试数据集
- 请在代码中实现自动下载数据集的逻辑;或者在 PR 中提供获取数据集的方法,OpenCompass 的维护者会跟进处理。如果数据集尚未公开,亦请注明。
- 提交数据配置文件
- 在数据配置同级目录下提供 README,README 中的内容应该包含,但不局限于:
- 该数据集的简单说明
- 该数据集的官方链接
- 该数据集的一些测试样例
- 该数据集在相关模型上的评测结果
- 该数据集的引用
- (可选) 数据集的 summarizer
- (可选) 如果测试过程无法通过简单拼接数据集和模型配置文件的方式来实现的话,还需要提供进行测试过程的配置文件
- (可选) 如果需要,请在文档相关位置处添加该数据集的说明。这在辅助用户理解该测试方案是非常必要的,可参考 OpenCompass 中该类型的文档:
- [循环评测](../advanced_guides/circular_eval.md)
- [代码评测](../advanced_guides/code_eval.md)
- [污染评估](../advanced_guides/contamination_eval.md)
# 新闻
- **\[2024.05.08\]** 我们支持了以下四个MoE模型的评测配置文件: [Mixtral-8x22B-v0.1](configs/models/mixtral/hf_mixtral_8x22b_v0_1.py), [Mixtral-8x22B-Instruct-v0.1](configs/models/mixtral/hf_mixtral_8x22b_instruct_v0_1.py), [Qwen1.5-MoE-A2.7B](configs/models/qwen/hf_qwen1_5_moe_a2_7b.py), [Qwen1.5-MoE-A2.7B-Chat](configs/models/qwen/hf_qwen1_5_moe_a2_7b_chat.py) 。欢迎试用!
- **\[2024.04.30\]** 我们支持了计算模型在给定[数据集](configs/datasets/llm_compression/README.md)上的压缩率(Bits per Character)的评测方法([官方文献](https://github.com/hkust-nlp/llm-compression-intelligence))。欢迎试用[llm-compression](configs/eval_llm_compression.py)评测集! 🔥🔥🔥
- **\[2024.04.26\]** 我们报告了典型LLM在常用基准测试上的表现,欢迎访问[文档](https://opencompass.readthedocs.io/zh-cn/latest/user_guides/corebench.html)以获取更多信息!🔥🔥🔥.
- **\[2024.04.26\]** 我们废弃了 OpenCompass 进行多模态大模型评测的功能,相关功能转移至 [VLMEvalKit](https://github.com/open-compass/VLMEvalKit),推荐使用!🔥🔥🔥.
- **\[2024.04.26\]** 我们支持了 [ArenaHard评测](configs/eval_subjective_arena_hard.py) 欢迎试用!🔥🔥🔥.
- **\[2024.04.22\]** 我们支持了 [LLaMA3](configs/models/hf_llama/hf_llama3_8b.py)[LLaMA3-Instruct](configs/models/hf_llama/hf_llama3_8b_instruct.py) 的评测,欢迎试用!🔥🔥🔥.
- **\[2024.02.29\]** 我们支持了MT-Bench、AlpacalEval和AlignBench,更多信息可以在[这里](https://opencompass.readthedocs.io/en/latest/advanced_guides/subjective_evaluation.html)找到。
- **\[2024.01.30\]** 我们发布了OpenCompass 2.0。更多信息,请访问[CompassKit](https://github.com/open-compass)[CompassHub](https://hub.opencompass.org.cn/home)[CompassRank](https://rank.opencompass.org.cn/home)
- **\[2024.01.17\]** 我们支持了 [InternLM2](https://github.com/open-compass/opencompass/blob/main/configs/eval_internlm2_chat_keyset.py)[InternLM2-Chat](https://github.com/open-compass/opencompass/blob/main/configs/eval_internlm2_chat_keyset.py) 的相关评测,InternLM2 在这些测试中表现出非常强劲的性能,欢迎试用!.
- **\[2024.01.17\]** 我们支持了多根针版本的大海捞针测试,更多信息见[这里](https://opencompass.readthedocs.io/zh-cn/latest/advanced_guides/needleinahaystack_eval.html#id8).
- **\[2023.12.28\]** 我们支持了对使用[LLaMA2-Accessory](https://github.com/Alpha-VLLM/LLaMA2-Accessory)(一款强大的LLM开发工具箱)开发的所有模型的无缝评估!
- **\[2023.12.22\]** 我们开源了[T-Eval](https://github.com/open-compass/T-Eval)用于评测大语言模型工具调用能力。欢迎访问T-Eval的官方[Leaderboard](https://open-compass.github.io/T-Eval/leaderboard.html)获取更多信息!
- **\[2023.12.10\]** 我们开源了多模评测框架 [VLMEvalKit](https://github.com/open-compass/VLMEvalKit),目前已支持 20+ 个多模态大模型与包括 MMBench 系列在内的 7 个多模态评测集.
- **\[2023.12.10\]** 我们已经支持了Mistral AI的MoE模型 **Mixtral-8x7B-32K**。欢迎查阅[MixtralKit](https://github.com/open-compass/MixtralKit)以获取更多关于推理和评测的详细信息.
- **\[2023.11.22\]** 我们已经支持了多个于API的模型,包括**百度、字节跳动、华为、360**。欢迎查阅[模型](https://opencompass.readthedocs.io/en/latest/user_guides/models.html)部分以获取更多详细信息。
- **\[2023.11.20\]** 感谢[helloyongyang](https://github.com/helloyongyang)支持使用[LightLLM](https://github.com/ModelTC/lightllm)作为后端进行评估。欢迎查阅[使用LightLLM进行评估](https://opencompass.readthedocs.io/en/latest/advanced_guides/evaluation_lightllm.html)以获取更多详细信息。
- **\[2023.11.13\]** 我们很高兴地宣布发布 OpenCompass v0.1.8 版本。此版本支持本地加载评估基准,从而无需连接互联网。请注意,随着此更新的发布,**您需要重新下载所有评估数据集**,以确保结果准确且最新。
- **\[2023.11.06\]** 我们已经支持了多个基于 API 的模型,包括ChatGLM Pro@智谱清言、ABAB-Chat@MiniMax 和讯飞。欢迎查看 [模型](https://opencompass.readthedocs.io/en/latest/user_guides/models.html) 部分以获取更多详细信息。
- **\[2023.10.24\]** 我们发布了一个全新的评测集,BotChat,用于评估大语言模型的多轮对话能力,欢迎查看 [BotChat](https://github.com/open-compass/BotChat) 获取更多信息.
- **\[2023.09.26\]** 我们在评测榜单上更新了[Qwen](https://github.com/QwenLM/Qwen), 这是目前表现最好的开源模型之一, 欢迎访问[官方网站](https://opencompass.org.cn)获取详情.
- **\[2023.09.20\]** 我们在评测榜单上更新了[InternLM-20B](https://github.com/InternLM/InternLM), 欢迎访问[官方网站](https://opencompass.org.cn)获取详情.
- **\[2023.09.19\]** 我们在评测榜单上更新了WeMix-LLaMA2-70B/Phi-1.5-1.3B, 欢迎访问[官方网站](https://opencompass.org.cn)获取详情.
- **\[2023.09.18\]** 我们发布了[长文本评测指引](docs/zh_cn/advanced_guides/longeval.md).
- **\[2023.09.08\]** 我们在评测榜单上更新了Baichuan-2/Tigerbot-2/Vicuna-v1.5, 欢迎访问[官方网站](https://opencompass.org.cn)获取详情。
- **\[2023.09.06\]** 欢迎 [**Baichuan2**](https://github.com/baichuan-inc/Baichuan2) 团队采用OpenCompass对模型进行系统评估。我们非常感谢社区在提升LLM评估的透明度和可复现性上所做的努力。
- **\[2023.09.02\]** 我们加入了[Qwen-VL](https://github.com/QwenLM/Qwen-VL)的评测支持。
- **\[2023.08.25\]** 欢迎 [**TigerBot**](https://github.com/TigerResearch/TigerBot) 团队采用OpenCompass对模型进行系统评估。我们非常感谢社区在提升LLM评估的透明度和可复现性上所做的努力。
- **\[2023.08.21\]** [**Lagent**](https://github.com/InternLM/lagent) 正式发布,它是一个轻量级、开源的基于大语言模型的智能体(agent)框架。我们正与Lagent团队紧密合作,推进支持基于Lagent的大模型工具能力评测 !
- **\[2023.08.18\]** OpenCompass现已支持**多模态评测**,支持10+多模态评测数据集,包括 **MMBench, SEED-Bench, COCO-Caption, Flickr-30K, OCR-VQA, ScienceQA** 等. 多模态评测榜单即将上线,敬请期待!
- **\[2023.08.18\]** [数据集页面](https://opencompass.org.cn/dataset-detail/MMLU) 现已在OpenCompass官网上线,欢迎更多社区评测数据集加入OpenCompass !
- **\[2023.08.11\]** 官网榜单上新增了[模型对比](https://opencompass.org.cn/model-compare/GPT-4,ChatGPT,LLaMA-2-70B,LLaMA-65B)功能,希望该功能可以协助提供更多发现!
- **\[2023.08.11\]** 新增了 [LEval](https://github.com/OpenLMLab/LEval) 评测支持.
- **\[2023.08.10\]** OpenCompass 现已适配 [LMDeploy](https://github.com/InternLM/lmdeploy). 请参考 [评测指南](https://opencompass.readthedocs.io/zh_CN/latest/advanced_guides/evaluation_lmdeploy.html)**Turbomind** 加速后的模型进行评估.
- **\[2023.08.10\]** [Qwen-7B](https://github.com/QwenLM/Qwen-7B)[XVERSE-13B](https://github.com/xverse-ai/XVERSE-13B)的评测结果已更新在 OpenCompass [大语言模型评测榜单](https://opencompass.org.cn/leaderboard-llm)!
- **\[2023.08.09\]** 更新更多评测数据集(**CMMLU, TydiQA, SQuAD2.0, DROP**) ,请登录 [大语言模型评测榜单](https://opencompass.org.cn/leaderboard-llm) 查看更多结果! 欢迎添加你的评测数据集到OpenCompass.
- **\[2023.08.07\]** 新增了 [MMBench 评测脚本](tools/eval_mmbench.py) 以支持用户自行获取 [MMBench](https://opencompass.org.cn/MMBench)-dev 的测试结果.
- **\[2023.08.05\]** [GPT-4](https://openai.com/gpt-4) 的评测结果已更新在 OpenCompass [大语言模型评测榜单](https://opencompass.org.cn/leaderboard-llm)!
- **\[2023.07.27\]** 新增了 [CMMLU](https://github.com/haonan-li/CMMLU)! 欢迎更多的数据集加入 OpenCompass.
# Chain of Thought
## 背景
CoT(思维链)是帮助大型语言模型解决如数学问题和关系推理问题等复杂问题的有效方式,在OpenCompass中,我们支持多种类型的CoT方法。
![image](https://github.com/open-compass/opencompass/assets/28834990/45d60e0e-02a1-49aa-b792-40a1f95f9b9e)
## 1. 零样本思维链
可以通过在数据集配置中简单地添加 “Let's think step by step",来更改数据集配置的 PromptTemplate,从而实现 零样本 CoT prompt 以进行评估:
```python
qa_infer_cfg = dict(
prompt_template=dict(
type=PromptTemplate,
template="Answer the question:\nQ: {question}?\nLet's think step by step:\n"
),
retriever=dict(type=ZeroRetriever)
)
```
## 2. 小样本思维链
小样本思维链可以使大型语言模型更容易跟随预设的指示并得到更好的答案。对于小样本思维链,按照以下配置将思维链模板添加到 `PromptTemplate` 中,可以创建一个 one-shot prompt:
```python
qa_infer_cfg = dict(
prompt_template=dict(
type=PromptTemplate,
template=
'''Question: Mark's basketball team scores 25 2 pointers, 8 3 pointers and 10 free throws. Their opponents score double the 2 pointers but half the 3 pointers and free throws. What's the total number of points scored by both teams added together?
Let's think step by step
Answer:
Mark's team scores 25 2 pointers, meaning they scored 25*2= 50 points in 2 pointers.
His team also scores 6 3 pointers, meaning they scored 8*3= 24 points in 3 pointers
They scored 10 free throws, and free throws count as one point so they scored 10*1=10 points in free throws.
All together his team scored 50+24+10= 84 points
Mark's opponents scored double his team's number of 2 pointers, meaning they scored 50*2=100 points in 2 pointers.
His opponents scored half his team's number of 3 pointers, meaning they scored 24/2= 12 points in 3 pointers.
They also scored half Mark's team's points in free throws, meaning they scored 10/2=5 points in free throws.
All together Mark's opponents scored 100+12+5=117 points
The total score for the game is both team's scores added together, so it is 84+117=201 points
The answer is 201
Question: {question}\nLet's think step by step:\n{answer}
'''),
retriever=dict(type=ZeroRetriever)
)
```
## 3. Self-Consistency
SC (Self-Consistency) 方法是在 [此文章](https://arxiv.org/abs/2203.11171) 中提出的,该方法会为问题生成多条不同的推理路径,并对生成的答案进行众数投票。这种方法在复杂推理任务中表现出了显著的能力,但由于需要推理多次来采样多条推理链,所以可能会消耗很多的时间和资源。在 OpenCompass 中,您可以通过在数据集配置中将 `GenInferencer` 替换为 `SCInferencer` 并设置相应的参数参数来简单地实现 SC 方法,例如:
```python
# 此SC版gsm8k测试配置可以在: opencompass.configs.datasets.gsm8k.gsm8k_gen_a3e34a.py 中找到。
gsm8k_infer_cfg = dict(
inferencer=dict(
type=SCInferencer, # 替换 GenInferencer 为 SCInferencer
generation_kwargs=dict(do_sample=True, temperature=0.7, top_k=40), # 设置采样参数以确保模型生成不同的输出,目前仅适用于从HuggingFace加载的模型。
infer_type='SC',
sc_size = SAMPLE_SIZE
)
)
gsm8k_eval_cfg = dict(sc_size=SAMPLE_SIZE)
```
```{note}
注意,OpenCompass 默认使用 argmax 的方式采样下一个 token,因此若不指定采样参数,模型每次的推理结果将会是完全一致的,多轮评测将会失效。
```
其中 `SAMPLE_SIZE` 是推理路径的数量,较高的值通常会带来更高的性能。SC方法的原论文中展示了不同推理任务间推理路径数量与性能之间的关系:
![image](https://github.com/open-compass/opencompass/assets/28834990/05c7d850-7076-43ca-b165-e6251f9b3001)
从图中可以看出,在不同的推理任务中,随着推理路径数量的增加,性能呈现出增长的趋势。但是,对于某些任务,增加推理路径的数量可能达到一个极限,进一步增加推理路径的数量可能不会带来更多的性能提升。因此,需要在具体任务中进行实验和调整,找到最适合任务的推理路径数量。
## 4. Tree-of-Thoughts
相比一般的CoT方法采样一条推理路径,ToT(Tree-of-Thoughts)允许语言模型同时考虑多种不同的推理路径,通过对推理过程进行自我评估,以及在必要时进行前瞻或回溯以做出全局选择。具体的,分为下面四个阶段:
**1. 问题分解 (Thought Decomposition)**
根据问题的特点,将问题分解成多个中间步骤。每个步骤可以是短语、算式或写作计划,这取决于问题的性质。
**2. 推理过程生成 (Thought Generation)**
假设解决问题需要k个步骤,有两种方法生成推理内容:
- 独立采样:对于每个状态,模型会独立地从CoT提示中完整抽取k个推理内容,不依赖于其他的推理内容。
- 顺序生成:顺序地使用“提示”来逐步引导推理内容生成,每个推理内容都可能依赖于前一个推理内容。
**3. 启发式评估 (Heuristic Evaluation)**
使用启发式方法评估每个生成的推理内容对问题解决的贡献,这种自我评估基于语言模型的自我反馈,如设计Prompt让模型对多个生成结果进行打分。
**4. 选择搜索算法 (Search Algorithm)**
根据生成和评估推理内容的方法,选择适当的搜索算法。例如,可以使用广度优先搜索(BFS)或深度优先搜索(DFS)等算法来系统地探索思考树,并进行前瞻和回溯。
在OpenCompass中,需要根据需要设置ToT参数,以下是[ToT论文](https://arxiv.org/pdf/2305.10601.pdf)中24点游戏的样例配置,目前支持Huggingface模型进行ToT推理:
```python
# 此 ToT Game24 配置可以在以下路径找到:opencompass/configs/datasets/game24/game24_gen_8dfde3.py。
from opencompass.datasets import (Game24Dataset, game24_postprocess,
Game24Evaluator, Game24PromptWrapper)
generation_kwargs = dict(temperature=0.7)
game24_infer_cfg = dict(
prompt_template=dict(
type=PromptTemplate,
template='{input}'), #直接传入input内容,因为Prompt需要分段指定
retriever=dict(type=ZeroRetriever),
inferencer=dict(type=ToTInferencer, # 替换GenInferencer为ToTInferencer
generation_kwargs=generation_kwargs,
method_generate='propose', # 生成推理内容的方法,可以是独立采样(sample)或顺序生成(propose)
method_evaluate='value', # 评估推理内容的方法,可以是投票 (vote)或打分(value)
method_select='greedy', # 选择推理内容的方法,可以是贪心(greedy)或随机(sample)
n_evaluate_sample=3,
n_select_sample=5,
task_wrapper=dict(type=Game24PromptWrapper) # 该Wrapper类包含每个步骤的Prompt和推理内容的生成及评估方法,需要根据任务进行自定义
))
```
如果要在自定义的数据集上使用ToT方法,相比普通评测方式,需要在`opencompass.datasets.YourDataConfig.py`中额外设置`YourDataPromptWrapper`类,以进行ToT中的推理生成和启发式评估。对于类似游戏24点的推理任务,具体可以参考`opencompass/datasets/game24.py`
# Meta Template
## 背景
在 LLM 的 Supervised Fine-Tuning (SFT) 过程中,我们常常会根据实际的要求往对话内注入一些预定义的字符串,以求模型能按照一定的要求输出内容。例如,在一些 `chat` 模型的微调中,我们可能会在每段对话的开头加入系统层级的指令,并约定一套的格式表示用户与模型之间的对话。在一段对话中,模型期望文本的格式可能如下:
```Bash
Meta instruction: You are now a helpful and harmless AI assistant.
HUMAN: Hi!<eoh>\n
Bot: Hello! How may I assist you?<eob>\n
```
在评测时,我们也需要按照约定的格式输入问题,模型才能发挥出其最大的性能。
此外, API 模型也存在着类似的情况。一般 API 的对话模型都允许用户在调用时传入历史对话,还有些模型也允许传入 SYSTEM 层级的指令。为了更好地评测 API 模型的能力,我们希望在评测 API 模型时可以尽量让数据更贴合 API 模型本身的多轮对话模板,而并非把所有内容塞进一段指令当中。
因此,我们需要针对不同模型指定不同的解析模板。在 OpenCompass 中,我们将这套解析模板其称为 **Meta Template**。Meta Template 与模型的配置相绑定,在运行时与数据集的对话式模板相结合,最终产生最适合当前模型的 prompt。
```Python
# 指定时只需要把 meta_template 字段传入模型
models = [
dict(
type='AnyModel',
meta_template = ..., # meta tmplate
)
]
```
接下来,我们会介绍 Meta Template 在两种模型上的配置方法。建议读者在阅读本章前,先了解[对话式模板](./prompt_template.md#对话式-prompt)的基本语法。
```{note}
在某些情况下(例如对基座的测试),我们并不需要在正常对话中注入任何的指令,此时我们可以将 meta template 置空。在这种情况下,模型接收到的 prompt 仅由数据集配置定义,是一个普通的字符串。若数据集配置使用的是对话式模板,不同角色的发言将会由 \n 拼接而成。
```
## 应用在语言模型上
下图展示了在 2-shot learning 的情况下,数据从数据集中经过 prompt template 和 meta template,最终构建出 prompt 的几种情况。读者可以该图为参考,方便理解后续的章节。
![](https://user-images.githubusercontent.com/22607038/251195073-85808807-6359-44df-8a19-9f5d00c591ec.png)
我们将会结合几个例子讲解 meta template 的定义方式。
假设根据数据集的对话式模板,产生了下面的 PromptList:
```python
PromptList([
dict(role='HUMAN', prompt='1+1=?'),
dict(role='BOT', prompt='2'),
dict(role='HUMAN', prompt='2+2=?'),
dict(role='BOT', prompt='4'),
])
```
我们希望把这段对话传到一个已经经过 SFT 的模型。模型约定的对话中不同的角色的发言以`<角色名>:`开头,并固定以一个特殊 token 和 \\n 结尾。以下是模型期望接收到的完整字符串:
```Plain
<HUMAN>: 1+1=?<eoh>
<BOT>: 2<eob>
<HUMAN>: 2+2=?<eoh>
<BOT>: 4<eob>
```
在 meta template 中,我们只需要把每轮对话的格式抽象为如下配置即可:
```Python
# model meta template
meta_template = dict(
round=[
dict(role='HUMAN', begin='<HUMAN>: ', end='<eoh>\n'),
dict(role='BOT', begin='<BOT>: ', end='<eob>\n'),
],
)
```
______________________________________________________________________
有的数据集中可能会引入 SYSTEM 级别的角色:
```python
PromptList([
dict(role='SYSTEM', fallback_role='HUMAN', prompt='Solve the following math questions'),
dict(role='HUMAN', prompt='1+1=?'),
dict(role='BOT', prompt='2'),
dict(role='HUMAN', prompt='2+2=?'),
dict(role='BOT', prompt='4'),
])
```
假设模型同样接受 SYSTEM 这个角色,且期望输入为:
```Bash
<SYSTEM>: Solve the following math questions<eosys>\n
<HUMAN>: 1+1=?<eoh>\n
<BOT>: 2<eob>\n
<HUMAN>: 2+2=?<eoh>\n
<BOT>: 4<eob>\n
end of conversation
```
我们就可以把 SYSTEM 角色的定义放进 `reserved_roles` 中。`reserved_roles` 中的角色不会在常规对话中出现,但允许数据集配置的对话式模板在 `begin` 或者 `end` 中调用。
```Python
# model meta template
meta_template = dict(
round=[
dict(role='HUMAN', begin='<HUMAN>: ', end='<eoh>\n'),
dict(role='BOT', begin='<BOT>: ', end='<eob>\n'),
],
reserved_roles=[dict(role='SYSTEM', begin='<SYSTEM>: ', end='<eosys>\n'),],
),
```
若模型并不接受 SYSTEM 角色,则**不需要**配置此项,也能正常运行。这种情况下,模型会接收到的字符串变成了:
```Python
<HUMAN>: Solve the following math questions<eoh>\n
<HUMAN>: 1+1=?<eoh>\n
<BOT>: 2<eob>\n
<HUMAN>: 2+2=?<eoh>\n
<BOT>: 4<eob>\n
end of conversation
```
这是因为在 OpenCompass 预定义的数据集中,每个 `SYSTEM` 发言都会有一个 `fallback_role='HUMAN'`,即若 meta template 中的 `SYSTEM` 角色不存在,发言者会被切换至 `HUMAN` 角色。
______________________________________________________________________
有的模型还可能需要考虑在对话开始或结束时嵌入其它字符串,如系统指令:
```Bash
Meta instruction: You are now a helpful and harmless AI assistant.
<SYSTEM>: Solve the following math questions<eosys>\n
<HUMAN>: 1+1=?<eoh>\n
<BOT>: 2<eob>\n
<HUMAN>: 2+2=?<eoh>\n
<BOT>: 4<eob>\n
end of conversation
```
此时,我们可以通过指定 `begin``end` 参数指定这些字符串。
```Python
meta_template = dict(
round=[
dict(role='HUMAN', begin='<HUMAN>: ', end='<eoh>\n'),
dict(role='BOT', begin='<BOT>: ', end='<eob>\n'),
],
reserved_roles=[dict(role='SYSTEM', begin='<SYSTEM>: ', end='<eosys>\n'),],
begin="Meta instruction: You are now a helpful and harmless AI assistant.",
end="end of conversion",
),
```
______________________________________________________________________
**生成式**的任务评测中,我们也不会将答案直接输入模型,而是通过截断 prompt,在保留上文的同时,把模型输出的答案留空。
```Bash
Meta instruction: You are now a helpful and harmless AI assistant.
<SYSTEM>: Solve the following math questions<eosys>\n
<HUMAN>: 1+1=?<eoh>\n
<BOT>: 2<eob>\n
<HUMAN>: 2+2=?<eoh>\n
<BOT>:
```
我们只需要把 BOT 的配置中把 `generate` 字段置为 True ,OpenCompass 即会将 BOT 的最后一句话留给模型生成:
```Python
meta_template = dict(
round=[
dict(role='HUMAN', begin='<HUMAN>: ', end='<eoh>\n'),
dict(role='BOT', begin='<BOT>: ', end='<eob>\n', generate=True),
],
reserved_roles=[dict(role='SYSTEM', begin='<SYSTEM>: ', end='<eosys>\n'),],
begin="Meta instruction: You are now a helpful and harmless AI assistant.",
end="end of conversion",
),
```
需要注意的是,`generate` 仅影响生成式推理。在进行判别式推理时,模型接受到的 prompt 仍然是完整的。
### 全量字段介绍
```Bash
models = [
dict(meta_template = dict(
begin="Meta instruction: You are now a helpful and harmless AI assistant.",
round=[
dict(role='HUMAN', begin='HUMAN: ', end='<eoh>\n'), # begin and end can be a list of strings or integers.
dict(role='THOUGHTS', begin='THOUGHTS: ', end='<eot>\n', prompt='None'), # Here we can set the default prompt, which may be overridden by the speicfic dataset
dict(role='BOT', begin='BOT: ', generate=True, end='<eob>\n'),
],
end="end of conversion",
reserved_roles=[dict(role='SYSTEM', begin='SYSTEM: ', end='\n'),],
eos_token_id=10000,
),
)
]
```
meta_template 是一个字典,该字典可以包含以下数个字段:
- `begin``end` :(str,可选) prompt 的开头和结尾,通常是一些系统级别的指令。
- `round`:(list) 每一轮对话的模板格式。每轮对话的 prompt 内容由数据集配置的对话式模板控制。
- `reserved_roles`:(list,可选)指定 `round` 中并未出现,但有可能在数据集配置中用到的的预留角色,例如 `SYSTEM` 角色。
- `eos_token_id`:(int, 可选):指定了该模型的 eos token 的 id。如果不设置,则默认为 tokenizer 中的 eos token id。它的主要作用是在生成式任务中,截取模型的输出结果,因此一般应该被设置为 generate=True 的项所对应的 end 的第一个 token id。
meta_template 的 `round` 指定了一轮对话中每个角色说话的格式,接受一个字典组成的列表,每个字典的关键字如下:
- `role`(str): 参与对话的角色名,该字符串并不影响实际的 prompt。
- `begin`, `end` (str): 指定该角色在说话时的固定开头或结尾。
- `prompt` (str):角色的 prompt。在 meta template 中允许留空,但此时必须在数据集配置的 prompt 中指定。
- `generate` (bool): 指定为 True 时,该角色即为模型扮演的角色。在生成任务中,模型接收到的 prompt 会截止到该角色的 `begin` 处,剩下的内容由模型补全。
## 应用在 API 模型上
API 模型的 meta template 与普通模型的 meta template 类似,但配置更为简单。用户可以根据情况,直接使用下面的两种配置之一,即可以多轮对话的方式评测 API 模型:
```Bash
# 若 API 模型不支持 system 指令
meta_template=dict(
round=[
dict(role='HUMAN', api_role='HUMAN'),
dict(role='BOT', api_role='BOT', generate=True)
],
)
# 若 API 模型支持 system 指令
meta_template=dict(
round=[
dict(role='HUMAN', api_role='HUMAN'),
dict(role='BOT', api_role='BOT', generate=True)
],
reserved_roles=[
dict(role='SYSTEM', api_role='SYSTEM'),
],
)
```
### 原理
尽管不同 API 模型接受的数据结构不一,但总体上不乏共通之处。接受对话历史的接口里通常允许用户传入以下三个角色的 prompt:
- 用户
- 机器人
- 系统 (可选)
据此 OpenCompass 为 API 模型预设了三个 `api_role``HUMAN`, `BOT`, `SYSTEM`,同时约定 API 模型接受的输入除了普通字符串外,还有一种以 `PromptList` 结构表示对话的中间格式。API 模型会将对话重新以多轮对话格式打包,发送至后端。但要激活此功能,需要用户使用上面的 meta template 中把数据集 prompt 模板中的角色 `role` 映射到对应的 `api_role` 中。下图展示了 API 模型接受的输入与 Prompt Template 、Meta Template 之间的关系。
![](https://user-images.githubusercontent.com/22607038/251195872-63aa7d30-045a-4837-84b5-11b09f07fb18.png)
## 调试
如果需要调试 prompt,建议在准备好配置文件后,使用 `tools/prompt_viewer.py` 脚本预览模型实际接收到的 prompt。阅读[这里](../tools.md#prompt-viewer)了解更多。
# Prompt 概括
提示词 (prompt) 是 LLM 的输入,用于让 LLM 往后续写内容或计算困惑度 (ppl),提示词的选取会对被评测模型的精度产生重大影响。如何将数据集转换为一系列的提示词的过程是由模板 (template) 来定义的。
在 OpenCompass 中,我们将 template 拆分为两部分:数据侧的 template 和模型侧的 template。在测评模型时,数据会先后经过数据和模型侧的 template,最终转化为模型所需的输入。
数据侧的 template 被称为 [prompt_template](./prompt_template.md),它表示了把数据集的字段转化成提示词的过程。
模型侧的 template 被称为 [meta_template](./meta_template.md),它表示了模型将这些提示词转化为自身期望的输入的过程。
我们另外还提供了一些 [思维链](./chain_of_thought.md) 的 prompt 示例。
# Prompt 模板
## 背景
在语言模型的评测中,我们常会将原始数据集以一定的规则构造成 prompt,以便模型能够按照要求回答问题。
通常,我们会在 prompt 开头放入指令,几个 in-context example(上下文样例),再在最后放入题目。例如:
```text
Solve the following questions.
1+1=?
2
3+9=?
12
5+6=?
```
大量的实验表明,即便测试的原始题目相同,对于 prompt 的不同构造方式会对模型的表现产生影响。可能影响的因素包括:
- Prompt 本身的构成方式,包括指令、in-context example、题目的写法;
- in-context example 的选择,包括了选择的数量和方式;
- 对 prompt 的使用方式。是让模型基于 prompt 进行补全,还是从候选的 prompt 中选择一个最好的作为答案?
OpenCompass 将 prompt 的构建策略定义在了数据集配置中的 `infer_cfg` 部分。一个典型的 `infer_cfg` 如下所示:
```python
infer_cfg=dict(
ice_template=dict( # 用于构造 In Context Example (ice) 的模板
type=PromptTemplate,
template='{question}\n{answer}'
),
prompt_template=dict( # 用于构造主干 prompt 的模板
type=PromptTemplate,
template='Solve the following questions.\n</E>{question}\n{answer}',
ice_token="</E>"
),
retriever=dict(type=FixKRetriever, fix_id_list=[0, 1]), # 定义 in context example 的获取方式
inferencer=dict(type=GenInferencer), # 使用何种方式推理得到 prediction
)
```
本文档中,我们将会主要介绍 `ice_template``prompt_template``inferencer` 的定义方法。对于 `retriever` 的介绍请参考其他章节。
我们首先介绍 prompt 的基本语法。
## 字符串式 prompt
字符串式的模板是比较经典的模板形式,考虑下面的模板:
```python
prompt_template=dict(
type=PromptTemplate,
template="{anything}\nQuestion: {question}\nAnswer: {answer}"
)
```
运行时,花括号`{}`内的字段会被替换成数据样本内的对应字段。如果数据样本中没有对应的字段,则会保持原样输出。
例如我们有一个数据 example 如下:
```python
example = {
'question': '1+1=?',
'answer': '2', # 假设 answer 被写在了 reader_cfg.output_column 中
'irrelavent_infos': 'blabla',
}
```
则填入模板后的结果为:
```text
{anything}
Question: 1+1=?
Answer:
```
可以看到,问题的实际答案 `answer` 并没有出现在生成的结果中。这是因为 OpenCompass 会遮盖被写在 `reader_cfg.output_column` 中的字段,避免答案泄露。关于 `reader_cfg` 的详细说明,请参考介绍数据集配置的相关文档。
## 对话式 prompt
在实际的测试中,简单的补全式测试并不能很好地测试出对话式的模型的性能,因此我们更希望 prompt 能以对话的格式输入到模型中。另外,不同的模型对对话的格式定义也不一样,因此我们也需要数据集侧产生的 prompt 更加通用,在测试时再结合具体模型生成符合需求的提示词。
因此,OpenCompass 在字符串式模板之上,增加了对对话式模板的支持。对话式模板更加灵活,它可以结合模型侧不同的 [meta_template](./meta_template.md) 生成不同对话形式的提示词,同时适用于基座和对话模型,但定义也相对复杂。
现在,让我们假设有一个数据样本如下:
```python
example = {
'question': '1+1=?',
'answer': '2', # 假设 answer 被写在了 reader_cfg.output_column 中
'irrelavent_infos': 'blabla',
}
```
接下来,我们来展示几个例子:
`````{tabs}
````{tab} 普通对话
```python
prompt_template=dict(
type=PromptTemplate,
template=dict(
round=[
dict(role="HUMAN", prompt="Question: {question}"),
dict(role="BOT", prompt="Answer: {answer}"),
]
)
)
```
OpenCompass 把数据填入模板后得到的中间结果为:
```python
PromptList([
dict(role='HUMAN', prompt='Question: 1+1=?'),
dict(role='BOT', prompt='Answer: '),
])
```
````
````{tab} 多轮对话
```python
prompt_template=dict(
type=PromptTemplate,
template=dict(
round=[
dict(role="HUMAN", prompt="Question: 2+2=?"),
dict(role="BOT", prompt="Answer: 4"),
dict(role="HUMAN", prompt="Question: 3+3=?"),
dict(role="BOT", prompt="Answer: 6"),
dict(role="HUMAN", prompt="Question: {question}"),
dict(role="BOT", prompt="Answer: {answer}"),
]
)
)
```
OpenCompass 把数据填入模板后得到的中间结果为:
```python
PromptList([
dict(role='HUMAN', prompt='Question: 2+2=?'),
dict(role='BOT', prompt='Answer: 4'),
dict(role='HUMAN', prompt='Question: 3+3=?'),
dict(role='BOT', prompt='Answer: 6'),
dict(role='HUMAN', prompt='Question: 1+1=?'),
dict(role='BOT', prompt='Answer: '),
])
```
````
````{tab} 带 SYSTEM 的对话
```python
prompt_template=dict(
type=PromptTemplate,
template=dict(
begin=[
dict(role='SYSTEM', fallback_role='HUMAN', prompt='Solve the following questions.'),
],
round=[
dict(role="HUMAN", prompt="Question: {question}"),
dict(role="BOT", prompt="Answer: {answer}"),
]
)
)
```
OpenCompass 把数据填入模板后得到的中间结果为:
```python
PromptList([
dict(role='SYSTEM', fallback_role='HUMAN', prompt='Solve the following questions.'),
dict(role='HUMAN', prompt='Question: 1+1=?'),
dict(role='BOT', prompt='Answer: '),
])
```
在具体的 meta template 中处理时,如果定义中存在 SYSTEM 角色,则会调用 SYSTEM 的模板进行处理。否则,会调用 fallback_role 角色的模板进行处理,也就是这个例子中的 HUMAN 角色。
````
`````
可以见到,在对话式的模板中,prompt 是以不同角色 `role` 的对话为形式进行组织的。在当前 OpenCompass 的预定义数据集配置中,一个 prompt 中常有的角色有:
- `HUMAN`:人类,通常为提问的一方
- `BOT`:语言模型,通常为回答的一方
- `SYSTEM`:系统,通常用在提示词的开头,负责下达指令。
另外与字符串式的模板不同,经过对话式模板所生成的 prompt 从固定的字符串变成了一个中间结构 PromptList。这个结构会进一步与模型侧的 [meta template](./meta_template.md) 相结合,拼装完成得到最终的提示词。如果不指定 meta template,PromptList 中各项的 prompt 则会直接按行拼接成字符串。
```{note}
上面例子中 PromptList 中的内容并非模型最终的输入,而取决于 meta template 的处理。一个容易产生误解的地方是,在生成式的评测中,最后一个 `BOT` 角色的 prompt `Answer: ` **不会**实际输入到模型。这是由于 API 模型通常并无法自定义模型回复的开头,因此这一设定保持了语言模型与 API 模型在评测上行为的一致。更多信息可以参考 [meta template](./meta_template.md) 的文档。
```
<details>
<summary>点击查看完整参数介绍</summary>
- `begin``end` :(list,可选) prompt 的开头和结尾,通常是一些系统级别的指令。里面的每一项**允许是一个字典或字符串**
- `round`:(list) 对话的模板格式。列表的每一项**只允许是一个字典**
每一个字典的参数如下:
- `role`(str): 参与对话的角色名,用于与 `meta_template` 中的名称进行关联,不会影响实际生成的 prompt。
- `fallback_role` (str) : 缺省角色名,假设 `meta_template` 中找不到 `role`,则会尝试使用 `fallback_role` 进行关联。默认为 `None`
- `prompt` (str) : 角色的对话内容。
</details>
## Prompt 模板 与 `inferencer`
在明白了 prompt 模板的基础定义方式后,我们还要根据 `inferencer` 的类型组织 prompt 模板。
OpenCompass 中主要支持了两种 Infernecer:`GenInferencer``PPLInferencer`,它们对应着两种不同的推理方式。
`GenInferencer` 对应生成式的推理。在推理时,模型被要求以输入的提示词为基准,继续往下续写。此时,`template` 则单一地表示这一句话对应的模板,例如:
`````{tabs}
````{group-tab} 字符串式模板
```python
prompt_template=dict(
type=PromptTemplate,
template='Solve the following questions.\n{question}\n{answer}'
)
```
````
````{group-tab} 对话式模板
```python
prompt_template=dict(
type=PromptTemplate,
template=dict(
begin=[
dict(role='SYSTEM', fallback_role='HUMAN', prompt='Solve the following questions.'),
],
round=[
dict(role="HUMAN", prompt="{question}"),
dict(role="BOT", prompt="{answer}"),
]
)
)
```
````
`````
则模型的推理结果将会是往下续写的字符串。
`PPLInferencer` 对应判别式推理。在推理时,模型被要求计算多个输入字符串各自的混淆度 (PerPLexity / ppl),并将其中 ppl 最小的项作为模型的推理结果。此时 `template` 是一个 `dict`,表示每一句话所对应的模板,例如:
`````{tabs}
````{group-tab} 字符串式模板
```python
prompt_template=dict(
type=PromptTemplate,
template=dict(
"A": "Question: Which is true?\nA. {A}\nB. {B}\nC. {C}\nAnswer: A",
"B": "Question: Which is true?\nA. {A}\nB. {B}\nC. {C}\nAnswer: B",
"C": "Question: Which is true?\nA. {A}\nB. {B}\nC. {C}\nAnswer: C",
"UNK": "Question: Which is true?\nA. {A}\nB. {B}\nC. {C}\nAnswer: None of them is true.",
)
)
```
````
````{group-tab} 对话式模板
```python
prompt_template=dict(
type=PromptTemplate,
template=dict(
"A": dict(
round=[
dict(role="HUMAN", prompt="Question: Which is true?\nA. {A}\nB. {B}\nC. {C}"),
dict(role="BOT", prompt="Answer: A"),
]
),
"B": dict(
round=[
dict(role="HUMAN", prompt="Question: Which is true?\nA. {A}\nB. {B}\nC. {C}"),
dict(role="BOT", prompt="Answer: B"),
]
),
"C": dict(
round=[
dict(role="HUMAN", prompt="Question: Which is true?\nA. {A}\nB. {B}\nC. {C}"),
dict(role="BOT", prompt="Answer: C"),
]
),
"UNK": dict(
round=[
dict(role="HUMAN", prompt="Question: Which is true?\nA. {A}\nB. {B}\nC. {C}"),
dict(role="BOT", prompt="Answer: None of them is true."),
]
),
)
)
```
````
`````
此时模型的推理结果将会是 `template` 的四个 key 之一 ("A" / "B" / "C" / "UNK")
## `ice_template` 与 `prompt_template`
在 OpenCompass 中,对于 0-shot 的评测,我们通常只需要定义 `prompt_template` 字段,即可完成 prompt 的构造。但对于 few shot 的评测,我们还需要定义 `ice_template` 字段,管理上下文学习中样例所对应的 prompt 模板。
`ice_template``prompt_template` 两者遵循的语法和规则一致,完整 prompt 的构造流程可以使用如下的伪代码进行表示:
```python
def build_prompt():
ice = ice_template.format(*ice_example)
prompt = prompt_template.replace(prompt_template.ice_token, ice).format(*prompt_example)
return prompt
```
现在,让我们假设有两个训练数据 (ex1, ex2) 和一个测试数据 (ex3):
```python
ex1 = {
'question': '2+2=?',
'answer': '4',
'irrelavent_infos': 'blabla',
}
ex2 = {
'question': '3+3=?',
'answer': '6',
'irrelavent_infos': 'blabla',
}
ex3 = {
'question': '1+1=?',
'answer': '2', # 假设 answer 被写在了 reader_cfg.output_column 中
'irrelavent_infos': 'blabla',
}
```
接下来,我们看一下不同的 prompt 构造方法对应的实际效果:
`````{tabs}
````{group-tab} 字符串式模板
模板配置如下:
```python
infer_cfg=dict(
ice_template=dict(
type=PromptTemplate,
template='{question}\n{answer}'
),
prompt_template=dict(
type=PromptTemplate,
template='Solve the following questions.\n</E>{question}\n{answer}'
ice_token='</E>',
)
)
```
会得到以下字符串:
```text
Solve the following questions.
2+2=?
4
3+3=?
6
1+1=?
```
````
````{group-tab} 对话式模板
模板配置如下:
```python
infer_cfg=dict(
ice_template=dict(
type=PromptTemplate,
template=dict(
round=[
dict(role="HUMAN", prompt="{question}"),
dict(role="BOT", prompt="{answer}"),
]
)
),
prompt_template=dict(
type=PromptTemplate,
template=dict(
begin=[
dict(role='SYSTEM', fallback_role='HUMAN', prompt='Solve the following questions.'),
'</E>',
],
round=[
dict(role="HUMAN", prompt="{question}"),
dict(role="BOT", prompt="{answer}"),
],
),
ice_token='</E>',
)
)
```
OpenCompass 把数据填入模板后得到的中间结果为:
```python
PromptList([
dict(role='SYSTEM', fallback_role='HUMAN', prompt='Solve the following questions.'),
dict(role='HUMAN', prompt='2+2=?'),
dict(role='BOT', prompt='4'),
dict(role='HUMAN', prompt='3+3=?'),
dict(role='BOT', prompt='6'),
dict(role='HUMAN', prompt='1+1=?'),
dict(role='BOT', prompt=''),
])
```
````
`````
### 省略式使用方法
值得一提的是,为了简便配置文件,`prompt_template` 这一字段是可被省略的。当 `prompt_template` 字段被省略时,`ice_template` 会同时被作为 `prompt_template`,用于拼装得到完整的 prompt。以下两份 `infer_cfg` 是等价的:
<table class="docutils">
<thead>
<tr>
<th>完整写法</th>
<th>省略写法</th>
<tbody>
<tr>
<td>
```python
infer_cfg=dict(
ice_template=dict(
type=PromptTemplate,
template="Q: {question}\nA: {answer}",
),
prompt_template=dict(
type=PromptTemplate,
template="</E>Q: {question}\nA: {answer}",
ice_token="</E>",
),
# ...
)
```
</td>
<td>
```python
infer_cfg=dict(
ice_template=dict(
type=PromptTemplate,
template="</E>Q: {question}\nA: {answer}",
ice_token="</E>",
),
# ...
)
```
</td>
</tr>
</thead>
</table>
更一般地,即便在 0-shot learning 的情况下(即 `retriever``ZeroRetriver`)时,这一机制依然生效。因此以下配置也是合法的:
```python
datasets = [
dict(
infer_cfg=dict(
ice_template=dict(
type=PromptTemplate,
template="Q: {question}\nA: {answer}",
),
retriever=dict(type=ZeroRetriever),
inferencer=dict(type=GenInferencer),
)
),
]
```
## 使用建议
建议使用 [Prompt Viewer](../tools.md) 工具对完成拼装后的 prompt 进行可视化,确认模板是否正确,结果是否符合预期。
#! /usr/bin/env python
from pathlib import Path
import yaml
from tabulate import tabulate
OC_ROOT = Path(__file__).absolute().parents[2]
GITHUB_PREFIX = 'https://github.com/open-compass/opencompass/tree/main/'
DATASETZOO_TEMPLATE = """\
# 数据集统计
在本页面中,我们列举了OpenCompass所支持的所有数据集。
你可以使用排序和搜索功能找到需要的数据集。
"""
with open('dataset_statistics.md', 'w') as f:
f.write(DATASETZOO_TEMPLATE)
load_path = str(OC_ROOT / 'dataset-index.yml')
with open(load_path, 'r') as f2:
data_list = yaml.load(f2, Loader=yaml.FullLoader)
HEADER = ['name', 'category', 'paper', 'configpath']
def table_format(data_list):
table_format_list = []
for i in data_list:
table_format_list_sub = []
for j in i:
for index in HEADER:
if index == 'paper':
table_format_list_sub.append('[链接](' + i[j][index] + ')')
elif index == 'configpath':
if isinstance(i[j][index], list):
sub_list_text = ''
for k in i[j][index]:
sub_list_text += ('[链接](' + GITHUB_PREFIX + k +
') / ')
table_format_list_sub.append(sub_list_text[:-2])
else:
table_format_list_sub.append('[链接](' + GITHUB_PREFIX +
i[j][index] + ')')
else:
table_format_list_sub.append(i[j][index])
table_format_list.append(table_format_list_sub)
return table_format_list
data_format_list = table_format(data_list)
def generate_table(data_list, title=None):
with open('dataset_statistics.md', 'a') as f:
if title is not None:
f.write(f'\n{title}')
f.write("""\n```{table}\n:class: dataset\n""")
header = ['数据集名称', '数据集类型', '原文或资源地址', '配置文件链接']
table_cfg = dict(tablefmt='pipe',
floatfmt='.2f',
numalign='right',
stralign='center')
f.write(tabulate(data_list, header, **table_cfg))
f.write('\n```\n')
generate_table(
data_list=data_format_list,
title='## 支持数据集列表',
)
# 实用工具
## Prompt Viewer
本工具允许你在不启动完整训练流程的情况下,直接查看生成的 prompt。如果传入的配置仅为数据集配置(如 `configs/datasets/nq/nq_gen_3dcea1.py`),则展示数据集配置中定义的原始 prompt。若为完整的评测配置(包含模型和数据集),则会展示所选模型运行时实际接收到的 prompt。
运行方式:
```bash
python tools/prompt_viewer.py CONFIG_PATH [-n] [-a] [-p PATTERN]
```
- `-n`: 不进入交互模式,默认选择第一个 model (如有)和 dataset。
- `-a`: 查看配置中所有模型和所有数据集组合接收到的 prompt。
- `-p PATTERN`: 不进入交互模式,选择所有与传入正则表达式匹配的数据集。
## Case Analyzer
本工具在已有评测结果的基础上,产出推理错误样本以及带有标注信息的全量样本。
运行方式:
```bash
python tools/case_analyzer.py CONFIG_PATH [-w WORK_DIR]
```
- `-w`:工作路径,默认为 `'./outputs/default'`
## Lark Bot
用户可以通过配置飞书机器人,实现任务状态的实时监控。飞书机器人的设置文档请[参考这里](https://open.feishu.cn/document/ukTMukTMukTM/ucTM5YjL3ETO24yNxkjN?lang=zh-CN#7a28964d)
配置方式:
- 打开 `configs/secrets.py` 文件,并在文件中加入以下行:
```python
lark_bot_url = 'YOUR_WEBHOOK_URL'
```
通常, Webhook URL 格式如 https://open.feishu.cn/open-apis/bot/v2/hook/xxxxxxxxxxxxxxxxx 。
- 在完整的评测配置中继承该文件:
```python
_base_ = [
'secrets.py',
...
]
```
实例可见 `configs/eval.py`
- 为了避免机器人频繁发消息形成骚扰,默认运行时状态不会自动上报。有需要时,可以通过 `-l``--lark` 启动状态上报:
```bash
python run.py configs/eval_demo.py -l
```
## API Model Tester
本工具可以快速测试 API 模型的功能是否正常。
运行方式:
```bash
python tools/test_api_model.py [CONFIG_PATH] -n
```
## Prediction Merger
本工具可以合并由于 `partitioner` 而产生的分片推理结果。
运行方式:
```bash
python tools/prediction_merger.py CONFIG_PATH [-w WORK_DIR]
```
- `-w`:工作路径,默认为 `'./outputs/default'`
## List Configs
本工具可以列出或搜索所有可用的模型和数据集配置,且支持模糊搜索,便于结合 `run.py` 使用。
运行方式:
```bash
python tools/list_configs.py [PATTERN1] [PATTERN2] [...]
```
若运行时不加任何参数,则默认列出所有在 `configs/models``configs/dataset` 下的模型配置。
用户同样可以传入任意数量的参数,脚本会列出所有跟传入字符串相关的配置,支持模糊搜索及 * 号匹配。如下面的命令会列出所有跟 `mmlu``llama` 相关的配置:
```bash
python tools/list_configs.py mmlu llama
```
它的输出可以是:
```text
+-----------------+-----------------------------------+
| Model | Config Path |
|-----------------+-----------------------------------|
| hf_llama2_13b | configs/models/hf_llama2_13b.py |
| hf_llama2_70b | configs/models/hf_llama2_70b.py |
| hf_llama2_7b | configs/models/hf_llama2_7b.py |
| hf_llama_13b | configs/models/hf_llama_13b.py |
| hf_llama_30b | configs/models/hf_llama_30b.py |
| hf_llama_65b | configs/models/hf_llama_65b.py |
| hf_llama_7b | configs/models/hf_llama_7b.py |
| llama2_13b_chat | configs/models/llama2_13b_chat.py |
| llama2_70b_chat | configs/models/llama2_70b_chat.py |
| llama2_7b_chat | configs/models/llama2_7b_chat.py |
+-----------------+-----------------------------------+
+-------------------+---------------------------------------------------+
| Dataset | Config Path |
|-------------------+---------------------------------------------------|
| cmmlu_gen | configs/datasets/cmmlu/cmmlu_gen.py |
| cmmlu_gen_ffe7c0 | configs/datasets/cmmlu/cmmlu_gen_ffe7c0.py |
| cmmlu_ppl | configs/datasets/cmmlu/cmmlu_ppl.py |
| cmmlu_ppl_fd1f2f | configs/datasets/cmmlu/cmmlu_ppl_fd1f2f.py |
| mmlu_gen | configs/datasets/mmlu/mmlu_gen.py |
| mmlu_gen_23a9a9 | configs/datasets/mmlu/mmlu_gen_23a9a9.py |
| mmlu_gen_5d1409 | configs/datasets/mmlu/mmlu_gen_5d1409.py |
| mmlu_gen_79e572 | configs/datasets/mmlu/mmlu_gen_79e572.py |
| mmlu_gen_a484b3 | configs/datasets/mmlu/mmlu_gen_a484b3.py |
| mmlu_ppl | configs/datasets/mmlu/mmlu_ppl.py |
| mmlu_ppl_ac766d | configs/datasets/mmlu/mmlu_ppl_ac766d.py |
+-------------------+---------------------------------------------------+
```
## Dataset Suffix Updater
本工具可以快速修改 `configs/dataset` 目录下的配置文件后缀,使其符合提示词哈希命名规范。
运行方式:
```bash
python tools/update_dataset_suffix.py
```
# 学习配置文件
OpenCompass 使用 OpenMMLab 新式风格的配置文件。如果你之前熟悉 OpenMMLab 风格的配置文件,可以直接阅读
[纯 Python 风格的配置文件(Beta)](https://mmengine.readthedocs.io/zh_CN/latest/advanced_tutorials/config.html#python-beta)
了解新式配置文件与原配置文件的区别。如果你之前没有接触过 OpenMMLab 风格的配置文件,
下面我将会用一个简单的例子来介绍配置文件的使用。请确保你安装了最新版本的 MMEngine,以支持新式风格的配置文件。
## 基本格式
OpenCompass 的配置文件都是 Python 格式的,遵从基本的 Python 语法,通过定义变量的形式指定每个配置项。
比如在定义模型时,我们使用如下配置:
```python
# model_cfg.py
from opencompass.models import HuggingFaceCausalLM
models = [
dict(
type=HuggingFaceCausalLM,
path='huggyllama/llama-7b',
model_kwargs=dict(device_map='auto'),
tokenizer_path='huggyllama/llama-7b',
tokenizer_kwargs=dict(padding_side='left', truncation_side='left'),
max_seq_len=2048,
max_out_len=50,
run_cfg=dict(num_gpus=8, num_procs=1),
)
]
```
当读取配置文件时,使用 MMEngine 中的 `Config.fromfile` 进行解析。
```python
>>> from mmengine.config import Config
>>> cfg = Config.fromfile('./model_cfg.py')
>>> print(cfg.models[0])
{'type': HuggingFaceCausalLM, 'path': 'huggyllama/llama-7b', 'model_kwargs': {'device_map': 'auto'}, ...}
```
## 继承机制
OpenCompass 的配置文件使用了 Python 的 import 机制进行配置文件的继承。需要注意的是,
我们需要在继承配置文件时使用 `read_base` 上下文管理器。
```python
# inherit.py
from mmengine.config import read_base
with read_base():
from .model_cfg import models # model_cfg.py 中的 models 被继承到本配置文件
```
使用 `Config.fromfile` 解析配置文件:
```python
>>> from mmengine.config import Config
>>> cfg = Config.fromfile('./inherit.py')
>>> print(cfg.models[0])
{'type': HuggingFaceCausalLM, 'path': 'huggyllama/llama-7b', 'model_kwargs': {'device_map': 'auto'}, ...}
```
## 评测配置文件示例
```python
# configs/llama7b.py
from mmengine.config import read_base
with read_base():
# 直接从预设数据集配置中读取需要的数据集配置
from .datasets.piqa.piqa_ppl import piqa_datasets
from .datasets.siqa.siqa_gen import siqa_datasets
# 将需要评测的数据集拼接成 datasets 字段
datasets = [*piqa_datasets, *siqa_datasets]
# 使用 HuggingFaceCausalLM 评测 HuggingFace 中 AutoModelForCausalLM 支持的模型
from opencompass.models import HuggingFaceCausalLM
models = [
dict(
type=HuggingFaceCausalLM,
# 以下参数为 HuggingFaceCausalLM 的初始化参数
path='huggyllama/llama-7b',
tokenizer_path='huggyllama/llama-7b',
tokenizer_kwargs=dict(padding_side='left', truncation_side='left'),
max_seq_len=2048,
# 以下参数为各类模型都必须设定的参数,非 HuggingFaceCausalLM 的初始化参数
abbr='llama-7b', # 模型简称,用于结果展示
max_out_len=100, # 最长生成 token 数
batch_size=16, # 批次大小
run_cfg=dict(num_gpus=1), # 运行配置,用于指定资源需求
)
]
```
## 数据集配置文件示例
以上示例配置文件中,我们直接以继承的方式获取了数据集相关的配置。接下来,
我们会以 PIQA 数据集配置文件为示例,展示数据集配置文件中各个字段的含义。
如果你不打算修改模型测试的 prompt,或者添加新的数据集,则可以跳过这一节的介绍。
PIQA 数据集 [配置文件](https://github.com/open-compass/opencompass/blob/main/configs/datasets/piqa/piqa_ppl_1cf9f0.py)
如下,这是一个基于 PPL(困惑度)进行评测的配置,并且不使用上下文学习方法(In-Context Learning)。
```python
from opencompass.openicl.icl_prompt_template import PromptTemplate
from opencompass.openicl.icl_retriever import ZeroRetriever
from opencompass.openicl.icl_inferencer import PPLInferencer
from opencompass.openicl.icl_evaluator import AccEvaluator
from opencompass.datasets import HFDataset
# 读取配置
# 加载后的数据集通常以字典形式组织样本,分别指定样本中用于组成 prompt 的输入字段,和作为答案的输出字段
piqa_reader_cfg = dict(
input_columns=['goal', 'sol1', 'sol2'],
output_column='label',
test_split='validation',
)
# 推理配置
piqa_infer_cfg = dict(
# Prompt 生成配置
prompt_template=dict(
type=PromptTemplate,
# Prompt 模板,模板形式与后续指定的 inferencer 类型相匹配
# 这里为了计算 PPL,需要指定每个答案对应的 Prompt 模板
template={
0: 'The following makes sense: \nQ: {goal}\nA: {sol1}\n',
1: 'The following makes sense: \nQ: {goal}\nA: {sol2}\n'
}),
# 上下文样本配置,此处指定 `ZeroRetriever`,即不使用上下文样本
retriever=dict(type=ZeroRetriever),
# 推理方式配置
# - PPLInferencer 使用 PPL(困惑度)获取答案
# - GenInferencer 使用模型的生成结果获取答案
inferencer=dict(type=PPLInferencer))
# 评估配置,使用 Accuracy 作为评估指标
piqa_eval_cfg = dict(evaluator=dict(type=AccEvaluator))
# 数据集配置,以上各个变量均为此配置的参数
# 为一个列表,用于指定一个数据集各个评测子集的配置。
piqa_datasets = [
dict(
type=HFDataset,
path='piqa',
reader_cfg=piqa_reader_cfg,
infer_cfg=piqa_infer_cfg,
eval_cfg=piqa_eval_cfg)
]
```
其中 **Prompt 生成配置** 的详细配置方式,可以参见 [Prompt 模板](../prompt/prompt_template.md)
## 进阶评测配置
在 OpenCompass 中,我们支持了任务划分器(Partitioner)、运行后端(Runner)等配置项,
用于更加灵活、高效的利用计算资源。
默认情况下,我们会使用基于样本数的方式对推理任务进行划分,你可以在启动任务时使用
`--max-partition-size` 指定进行任务划分的样本数阈值。同时,我们默认使用本地资源进行推理和评估任务,
如果你希望使用 Slurm 集群资源,可以在启动任务时使用 `--slurm` 参数和 `--partition` 参数指定 slurm 运行后端。
进一步地,如果以上功能无法满足你的任务划分和运行后端配置需求,你可以在配置文件中进行更详细的配置。
参见[数据分片](./evaluation.md)
# 主要数据集性能
我们选择部分用于评估大型语言模型(LLMs)的知名基准,并提供了主要的LLMs在这些数据集上的详细性能结果。
| Model | Version | Metric | Mode | GPT-4-1106 | GPT-4-0409 | Claude-3-Opus | Llama-3-70b-Instruct(lmdeploy) | Mixtral-8x22B-Instruct-v0.1 |
| -------------------- | ------- | ---------------------------- | ---- | ---------- | ---------- | ------------- | ------------------------------ | --------------------------- |
| MMLU | - | naive_average | gen | 83.6 | 84.2 | 84.6 | 80.5 | 77.2 |
| CMMLU | - | naive_average | gen | 71.9 | 72.4 | 74.2 | 70.1 | 59.7 |
| CEval-Test | - | naive_average | gen | 69.7 | 70.5 | 71.7 | 66.9 | 58.7 |
| GaokaoBench | - | weighted_average | gen | 74.8 | 76.0 | 74.2 | 67.8 | 60.0 |
| Triviaqa_wiki(1shot) | 01cf41 | score | gen | 73.1 | 82.9 | 82.4 | 89.8 | 89.7 |
| NQ_open(1shot) | eaf81e | score | gen | 27.9 | 30.4 | 39.4 | 40.1 | 46.8 |
| Race-High | 9a54b6 | accuracy | gen | 89.3 | 89.6 | 90.8 | 89.4 | 84.8 |
| WinoGrande | 6447e6 | accuracy | gen | 80.7 | 83.3 | 84.1 | 69.7 | 76.6 |
| HellaSwag | e42710 | accuracy | gen | 92.7 | 93.5 | 94.6 | 87.7 | 86.1 |
| BBH | - | naive_average | gen | 82.7 | 78.5 | 78.5 | 80.5 | 79.1 |
| GSM-8K | 1d7fe4 | accuracy | gen | 80.5 | 79.7 | 87.7 | 90.2 | 88.3 |
| Math | 393424 | accuracy | gen | 61.9 | 71.2 | 60.2 | 47.1 | 50 |
| TheoremQA | ef26ca | accuracy | gen | 28.4 | 23.3 | 29.6 | 25.4 | 13 |
| HumanEval | 8e312c | humaneval_pass@1 | gen | 74.4 | 82.3 | 76.2 | 72.6 | 72.0 |
| MBPP(sanitized) | 1e1056 | score | gen | 78.6 | 77.0 | 76.7 | 71.6 | 68.9 |
| GPQA_diamond | 4baadb | accuracy | gen | 40.4 | 48.5 | 46.5 | 38.9 | 36.4 |
| IFEval | 3321a3 | Prompt-level-strict-accuracy | gen | 71.9 | 79.9 | 80.0 | 77.1 | 65.8 |
# 配置数据集
本节教程主要关注如何选择和配置所需要的数据集。请确保你已按照[数据集准备](../get_started/installation.md#数据集准备)中的步骤下载好数据集。
## 数据集配置文件目录结构
首先简单介绍一下 OpenCompass `configs/datasets` 目录下的结构,如下所示:
```text
configs/datasets/
├── agieval
├── apps
├── ARC_c
├── ...
├── CLUE_afqmc # 数据集
│   ├── CLUE_afqmc_gen_901306.py # 不同版本数据集配置文件
│   ├── CLUE_afqmc_gen.py
│   ├── CLUE_afqmc_ppl_378c5b.py
│   ├── CLUE_afqmc_ppl_6507d7.py
│   ├── CLUE_afqmc_ppl_7b0c1e.py
│   └── CLUE_afqmc_ppl.py
├── ...
├── XLSum
├── Xsum
└── z_bench
```
`configs/datasets` 目录结构下,我们直接展平所有数据集,在各个数据集对应的文件夹下存在多个数据集配置。
数据集配置文件名由以下命名方式构成 `{数据集名称}_{评测方式}_{prompt版本号}.py`,以 `CLUE_afqmc/CLUE_afqmc_gen_db509b.py` 为例,该配置文件则为中文通用能力下的 `CLUE_afqmc` 数据集,对应的评测方式为 `gen`,即生成式评测,对应的prompt版本号为 `db509b`;同样的, `CLUE_afqmc_ppl_00b348.py` 指评测方式为`ppl`即判别式评测,prompt版本号为 `00b348`
除此之外,不带版本号的文件,例如: `CLUE_afqmc_gen.py` 则指向该评测方式最新的prompt配置文件,通常来说会是精度最高的prompt。
## 数据集选择
在各个数据集配置文件中,数据集将会被定义在 `{}_datasets` 变量当中,例如下面 `CLUE_afqmc/CLUE_afqmc_gen_db509b.py` 中的 `afqmc_datasets`
```python
afqmc_datasets = [
dict(
abbr="afqmc-dev",
type=AFQMCDatasetV2,
path="./data/CLUE/AFQMC/dev.json",
reader_cfg=afqmc_reader_cfg,
infer_cfg=afqmc_infer_cfg,
eval_cfg=afqmc_eval_cfg,
),
]
```
以及 `CLUE_cmnli/CLUE_cmnli_ppl_b78ad4.py` 中的 `cmnli_datasets`
```python
cmnli_datasets = [
dict(
type=HFDataset,
abbr='cmnli',
path='json',
split='train',
data_files='./data/CLUE/cmnli/cmnli_public/dev.json',
reader_cfg=cmnli_reader_cfg,
infer_cfg=cmnli_infer_cfg,
eval_cfg=cmnli_eval_cfg)
]
```
以上述两个数据集为例, 如果用户想同时评测这两个数据集,可以在 `configs` 目录下新建一个配置文件,我们使用 `mmengine` 配置中直接import的机制来构建数据集部分的参数,如下所示:
```python
from mmengine.config import read_base
with read_base():
from .datasets.CLUE_afqmc.CLUE_afqmc_gen_db509b import afqmc_datasets
from .datasets.CLUE_cmnli.CLUE_cmnli_ppl_b78ad4 import cmnli_datasets
datasets = []
datasets += afqmc_datasets
datasets += cmnli_datasets
```
用户可以根据需要,选择不同能力不同数据集以及不同评测方式的配置文件来构建评测脚本中数据集的部分。
有关如何启动评测任务,以及如何评测自建数据集可以参考相关文档。
### 数据集多次评测
在数据集配置中可以通过设置参数`n`来对同一数据集进行多次评测,最终返回平均指标,例如:
```python
afqmc_datasets = [
dict(
abbr="afqmc-dev",
type=AFQMCDatasetV2,
path="./data/CLUE/AFQMC/dev.json",
n=10, # 进行10次评测
reader_cfg=afqmc_reader_cfg,
infer_cfg=afqmc_infer_cfg,
eval_cfg=afqmc_eval_cfg,
),
]
```
另外,对于二值评测指标(例如accuracy,pass-rate等),还可以通过设置参数`k`配合`n`进行[G-Pass@k](http://arxiv.org/abs/2412.13147)评测。G-Pass@k计算公式为:
```{math}
\text{G-Pass@}k_\tau=E_{\text{Data}}\left[ \sum_{j=\lceil \tau \cdot k \rceil}^c \frac{{c \choose j} \cdot {n - c \choose k - j}}{{n \choose k}} \right],
```
其中 $n$ 为评测次数, $c$ 为 $n$ 次运行中通过或正确的次数。配置例子如下:
```python
aime2024_datasets = [
dict(
abbr='aime2024',
type=Aime2024Dataset,
path='opencompass/aime2024',
k=[2, 4], # 返回 G-Pass@2和G-Pass@4的结果
n=12, # 12次评测
...
)
]
```
# 强推理模型评测教程
OpenCompass提供针对DeepSeek R1系列推理模型的评测教程(数学数据集)。
- 在模型层面,我们建议使用Sampling方式,以减少因为Greedy评测带来的大量重复
- 在数据集层面,我们对数据量较小的评测基准,使用多次评测并取平均的方式。
- 在答案验证层面,为了减少基于规则评测带来的误判,我们统一使用基于LLM验证的方式进行评测。
## 安装和准备
请按OpenCompass安装教程进行安装。
## 构建评测配置
我们在 `example/eval_deepseek_r1.py` 中提供了示例配置,以下对评测配置进行解读
### 评测配置解读
#### 1. 数据集与验证器配置
```python
# 支持多运行次数的数据集配置(示例)
from opencompass.configs.datasets.aime2024.aime2024_llmverify_repeat8_gen_e8fcee import aime2024_datasets
datasets = sum(
(v for k, v in locals().items() if k.endswith('_datasets')),
[],
)
# 设置LLM验证器, 用户需事先通过LMDeploy/vLLM/SGLang等工具启动API 评测服务器,或者直接使用兼容OpenAI标准接口的模型服务
verifier_cfg = dict(
abbr='qwen2-5-32B-Instruct',
type=OpenAISDK,
path='Qwen/Qwen2.5-32B-Instruct', # 需替换实际路径
key='YOUR_API_KEY', # 需替换真实API Key
openai_api_base=['http://your-api-endpoint'], # 需替换API地址
query_per_second=16,
batch_size=1024,
temperature=0.001,
max_out_len=16384
)
# 应用验证器到所有数据集
for item in datasets:
if 'judge_cfg' in item['eval_cfg']['evaluator']:
item['eval_cfg']['evaluator']['judge_cfg'] = verifier_cfg
```
#### 2. 模型配置
我们提供了基于LMDeploy作为推理后端的评测示例,用户可以通过修改path(即HF路径)
```python
# LMDeploy模型配置示例
models = [
dict(
type=TurboMindModelwithChatTemplate,
abbr='deepseek-r1-distill-qwen-7b-turbomind',
path='deepseek-ai/DeepSeek-R1-Distill-Qwen-7B',
engine_config=dict(session_len=32768, max_batch_size=128, tp=1),
gen_config=dict(
do_sample=True,
temperature=0.6,
top_p=0.95,
max_new_tokens=32768
),
max_seq_len=32768,
batch_size=64,
run_cfg=dict(num_gpus=1),
pred_postprocessor=dict(type=extract_non_reasoning_content)
),
# 可扩展14B/32B配置...
]
```
#### 3. 评估流程配置
```python
# 推理配置
infer = dict(
partitioner=dict(type=NumWorkerPartitioner, num_worker=1),
runner=dict(type=LocalRunner, task=dict(type=OpenICLInferTask))
# 评估配置
eval = dict(
partitioner=dict(type=NaivePartitioner, n=8),
runner=dict(type=LocalRunner, task=dict(type=OpenICLEvalTask)))
```
#### 4. 结果汇总配置
```python
# 多运行结果平均配置
summary_groups = [
{
'name': 'AIME2024-Aveage8',
'subsets':[[f'aime2024-run{idx}', 'accuracy'] for idx in range(8)]
},
# 其他数据集平均配置...
]
summarizer = dict(
dataset_abbrs=[
['AIME2024-Aveage8', 'naive_average'],
# 其他数据集指标...
],
summary_groups=summary_groups
)
# 工作目录设置
work_dir = "outputs/deepseek_r1_reasoning"
```
## 执行评测
### 场景1:模型1卡加载,数据1个worker评测,共使用1个GPU
```bash
opencompass example/eval_deepseek_r1.py --debug --dump-eval-details
```
评测日志会在命令行输出。
### 场景2:模型1卡加载,数据8个worker评测,共使用8个GPU
需要修改配置文件中的infer配置,将num_worker设置为8
```python
# 推理配置
infer = dict(
partitioner=dict(type=NumWorkerPartitioner, num_worker=1),
runner=dict(type=LocalRunner, task=dict(type=OpenICLInferTask))
```
同时评测命令去掉`--debug`参数
```bash
opencompass example/eval_deepseek_r1.py --dump-eval-details
```
此模式下,OpenCompass将使用多线程启动`$num_worker`个任务,命令行不展示具体日志,具体的评测日志将会在`$work_dir`下中展示。
### 场景3:模型2卡加载,数据4个worker评测,共使用8个GPU
需要注意模型配置中,`run_cfg`中的`num_gpus`需要设置为2(如使用推理后端,则推理后端的参数也需要同步修改,比如LMDeploy中的tp需要设置为2),同时修改`infer`配置中的`num_worker`为4
```python
models += [
dict(
type=TurboMindModelwithChatTemplate,
abbr='deepseek-r1-distill-qwen-14b-turbomind',
path='deepseek-ai/DeepSeek-R1-Distill-Qwen-14B',
engine_config=dict(session_len=32768, max_batch_size=128, tp=2),
gen_config=dict(
do_sample=True,
temperature=0.6,
top_p=0.95,
max_new_tokens=32768),
max_seq_len=32768,
max_out_len=32768,
batch_size=128,
run_cfg=dict(num_gpus=2),
pred_postprocessor=dict(type=extract_non_reasoning_content)
),
]
```
```python
# 推理配置
infer = dict(
partitioner=dict(type=NumWorkerPartitioner, num_worker=4),
runner=dict(type=LocalRunner, task=dict(type=OpenICLInferTask))
```
### 评测结果
评测结果展示如下:
```bash
dataset version metric mode deepseek-r1-distill-qwen-7b-turbomind ---------------------------------- --------- ------------- ------ --------------------------------------- MATH - - - AIME2024-Aveage8 - naive_average gen 56.25
```
## 性能基线参考
由于模型使用Sampling进行解码,同时AIME数据量较小,使用8次评测取平均情况下,仍会出现1-3分的性能抖动
| 模型 | 数据集 | 指标 | 数值 |
| ---------------------------- | -------- | -------- | ---- |
| DeepSeek-R1-Distill-Qwen-7B | AIME2024 | Accuracy | 56.3 |
| DeepSeek-R1-Distill-Qwen-14B | AIME2024 | Accuracy | 74.2 |
| DeepSeek-R1-Distill-Qwen-32B | AIME2024 | Accuracy | 74.2 |
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment