benchscope 1.0.6__tar.gz → 1.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {benchscope-1.0.6 → benchscope-1.1.0}/PKG-INFO +9 -4
- {benchscope-1.0.6 → benchscope-1.1.0}/README.md +3 -3
- {benchscope-1.0.6 → benchscope-1.1.0}/benchscope/__init__.py +2 -2
- benchscope-1.1.0/benchscope/accuracy/__init__.py +15 -0
- benchscope-1.1.0/benchscope/accuracy/baselines.py +160 -0
- benchscope-1.1.0/benchscope/accuracy/compare.py +112 -0
- benchscope-1.1.0/benchscope/accuracy/datasets.py +619 -0
- benchscope-1.1.0/benchscope/accuracy/engines.py +93 -0
- benchscope-1.1.0/benchscope/accuracy/estimator.py +167 -0
- benchscope-1.1.0/benchscope/accuracy/executor.py +541 -0
- benchscope-1.1.0/benchscope/accuracy/metrics.py +152 -0
- benchscope-1.1.0/benchscope/accuracy/native_runner.py +130 -0
- benchscope-1.1.0/benchscope/accuracy/scorers/__init__.py +24 -0
- benchscope-1.1.0/benchscope/accuracy/scorers/base.py +52 -0
- benchscope-1.1.0/benchscope/accuracy/scorers/choice.py +83 -0
- benchscope-1.1.0/benchscope/accuracy/scorers/code.py +115 -0
- benchscope-1.1.0/benchscope/accuracy/scorers/judge.py +106 -0
- benchscope-1.1.0/benchscope/accuracy/scorers/math.py +123 -0
- benchscope-1.1.0/benchscope/accuracy/task_manager.py +365 -0
- benchscope-1.1.0/benchscope/bench_params.py +70 -0
- {benchscope-1.0.6 → benchscope-1.1.0}/benchscope/benches/base.py +8 -3
- benchscope-1.1.0/benchscope/benches/builtin_bench.py +805 -0
- {benchscope-1.0.6 → benchscope-1.1.0}/benchscope/benches/runner.py +20 -11
- benchscope-1.1.0/benchscope/benchs.py +673 -0
- benchscope-1.1.0/benchscope/cli.py +515 -0
- {benchscope-1.0.6 → benchscope-1.1.0}/benchscope/config.py +127 -8
- {benchscope-1.0.6 → benchscope-1.1.0}/benchscope/constants.py +7 -0
- {benchscope-1.0.6 → benchscope-1.1.0}/benchscope/env_info.py +78 -7
- benchscope-1.1.0/benchscope/server/api_accuracy.py +290 -0
- benchscope-1.1.0/benchscope/server/api_benchs.py +344 -0
- {benchscope-1.0.6 → benchscope-1.1.0}/benchscope/server/api_config.py +95 -29
- {benchscope-1.0.6 → benchscope-1.1.0}/benchscope/server/api_dashboard.py +11 -3
- {benchscope-1.0.6 → benchscope-1.1.0}/benchscope/server/api_logs.py +18 -0
- {benchscope-1.0.6 → benchscope-1.1.0}/benchscope/server/api_sessions.py +20 -1
- benchscope-1.1.0/benchscope/server/api_skills.py +285 -0
- {benchscope-1.0.6 → benchscope-1.1.0}/benchscope/server/api_tasks.py +12 -0
- {benchscope-1.0.6 → benchscope-1.1.0}/benchscope/server/app.py +11 -1
- {benchscope-1.0.6 → benchscope-1.1.0}/benchscope/server/state.py +3 -0
- {benchscope-1.0.6 → benchscope-1.1.0}/benchscope/server/test_manager.py +94 -2
- {benchscope-1.0.6 → benchscope-1.1.0}/benchscope/session_manager.py +105 -7
- {benchscope-1.0.6 → benchscope-1.1.0}/benchscope/task_manager.py +285 -15
- benchscope-1.1.0/benchscope/webui/assets/AccuracyCreateView-CdDahriB.js +1 -0
- benchscope-1.1.0/benchscope/webui/assets/AccuracyCreateView-Cm-Ff5Vs.css +1 -0
- benchscope-1.1.0/benchscope/webui/assets/AccuracyView-4I9IZUHM.css +1 -0
- benchscope-1.1.0/benchscope/webui/assets/AccuracyView-N9nvvEV_.js +1 -0
- benchscope-1.1.0/benchscope/webui/assets/DashboardView-C7cqOnf2.css +1 -0
- benchscope-1.1.0/benchscope/webui/assets/DashboardView-CNWdkbvp.js +1 -0
- benchscope-1.1.0/benchscope/webui/assets/DatasAnalysisView-NPF80jch.css +1 -0
- benchscope-1.1.0/benchscope/webui/assets/DatasAnalysisView-QhBG9WIV.js +1 -0
- benchscope-1.0.6/benchscope/webui/assets/DatasPerfsView-CiHoLV4u.js → benchscope-1.1.0/benchscope/webui/assets/DatasPerfsView-CATOCvAY.js +4 -4
- benchscope-1.1.0/benchscope/webui/assets/DatasPerfsView-C_AW0Lau.css +1 -0
- benchscope-1.1.0/benchscope/webui/assets/DatasView-BHAhBwJ9.css +1 -0
- benchscope-1.1.0/benchscope/webui/assets/DatasView-CBIJT2l1.js +1 -0
- benchscope-1.1.0/benchscope/webui/assets/LivePanels-BjhVg5vH.css +1 -0
- benchscope-1.1.0/benchscope/webui/assets/LivePanels-Dl-vSRIz.js +1 -0
- benchscope-1.1.0/benchscope/webui/assets/PerfCreateView-BRlIW2Y5.js +5 -0
- benchscope-1.1.0/benchscope/webui/assets/PerfCreateView-D6cVjWaE.css +1 -0
- benchscope-1.1.0/benchscope/webui/assets/PerformanceView-BaW-rr6g.css +1 -0
- benchscope-1.1.0/benchscope/webui/assets/PerformanceView-CXlPEqtA.js +2 -0
- benchscope-1.1.0/benchscope/webui/assets/SessionsView-BSPe9Y12.css +1 -0
- benchscope-1.1.0/benchscope/webui/assets/SessionsView-DNx-KNFK.js +70 -0
- benchscope-1.1.0/benchscope/webui/assets/SettingsView-CjM63YKU.css +1 -0
- benchscope-1.1.0/benchscope/webui/assets/SettingsView-NGoJGdrx.js +1 -0
- benchscope-1.0.6/benchscope/webui/assets/antd-CEH7kT1R.js → benchscope-1.1.0/benchscope/webui/assets/antd-C1UY0_xE.js +83 -83
- benchscope-1.0.6/benchscope/webui/assets/index-BOkjDk-W.css → benchscope-1.1.0/benchscope/webui/assets/index-PunnEio_.css +1 -1
- benchscope-1.1.0/benchscope/webui/assets/index-_MKlNAIp.js +8 -0
- benchscope-1.0.6/benchscope/webui/assets/vue-q1XafS6H.js → benchscope-1.1.0/benchscope/webui/assets/vue-CFDjioJX.js +1 -1
- {benchscope-1.0.6 → benchscope-1.1.0}/benchscope/webui/index.html +4 -4
- {benchscope-1.0.6 → benchscope-1.1.0}/benchscope.egg-info/PKG-INFO +9 -4
- benchscope-1.1.0/benchscope.egg-info/SOURCES.txt +91 -0
- {benchscope-1.0.6 → benchscope-1.1.0}/benchscope.egg-info/requires.txt +6 -0
- {benchscope-1.0.6 → benchscope-1.1.0}/pyproject.toml +6 -1
- benchscope-1.0.6/benchscope/cli.py +0 -66
- benchscope-1.0.6/benchscope/webui/assets/AccuracyView-BjuVpuFU.css +0 -1
- benchscope-1.0.6/benchscope/webui/assets/AccuracyView-DuYXlzdF.js +0 -1
- benchscope-1.0.6/benchscope/webui/assets/DashboardView-B9NSQxgY.js +0 -1
- benchscope-1.0.6/benchscope/webui/assets/DashboardView-efxhNbZA.css +0 -1
- benchscope-1.0.6/benchscope/webui/assets/DatasAnalysisView-D4kMXxJP.css +0 -1
- benchscope-1.0.6/benchscope/webui/assets/DatasAnalysisView-Dq2PU74U.js +0 -1
- benchscope-1.0.6/benchscope/webui/assets/DatasEvalsView-CKDm5d0o.js +0 -1
- benchscope-1.0.6/benchscope/webui/assets/DatasEvalsView-Dw2s8Caq.css +0 -1
- benchscope-1.0.6/benchscope/webui/assets/DatasPerfsView-iOsgANDF.css +0 -1
- benchscope-1.0.6/benchscope/webui/assets/DatasView-CelHF7nF.js +0 -1
- benchscope-1.0.6/benchscope/webui/assets/DatasView-RZvG0ZHh.css +0 -1
- benchscope-1.0.6/benchscope/webui/assets/MetricsTable-BqMrqOR7.css +0 -1
- benchscope-1.0.6/benchscope/webui/assets/MetricsTable-CnuI6iCF.js +0 -1
- benchscope-1.0.6/benchscope/webui/assets/PerfCreateView-CuS38i63.js +0 -5
- benchscope-1.0.6/benchscope/webui/assets/PerfCreateView-snqxkmyk.css +0 -1
- benchscope-1.0.6/benchscope/webui/assets/PerformanceView-CHLBhiQ5.css +0 -1
- benchscope-1.0.6/benchscope/webui/assets/PerformanceView-KOF5Mglm.js +0 -2
- benchscope-1.0.6/benchscope/webui/assets/SessionsView-DD5s41VZ.js +0 -4
- benchscope-1.0.6/benchscope/webui/assets/SessionsView-M3-edhM0.css +0 -1
- benchscope-1.0.6/benchscope/webui/assets/SettingsView-8-rKWxWv.css +0 -1
- benchscope-1.0.6/benchscope/webui/assets/SettingsView-zpGCDV5m.js +0 -1
- benchscope-1.0.6/benchscope/webui/assets/index-DN0xzMJ_.js +0 -2
- benchscope-1.0.6/benchscope.egg-info/SOURCES.txt +0 -69
- {benchscope-1.0.6 → benchscope-1.1.0}/LICENSE +0 -0
- {benchscope-1.0.6 → benchscope-1.1.0}/benchscope/__main__.py +0 -0
- {benchscope-1.0.6 → benchscope-1.1.0}/benchscope/benches/__init__.py +0 -0
- {benchscope-1.0.6 → benchscope-1.1.0}/benchscope/benches/sglang_bench.py +0 -0
- {benchscope-1.0.6 → benchscope-1.1.0}/benchscope/benches/vllm_bench.py +0 -0
- {benchscope-1.0.6 → benchscope-1.1.0}/benchscope/builtin_datasets.py +0 -0
- {benchscope-1.0.6 → benchscope-1.1.0}/benchscope/datasets.py +0 -0
- {benchscope-1.0.6 → benchscope-1.1.0}/benchscope/gpu.py +0 -0
- {benchscope-1.0.6 → benchscope-1.1.0}/benchscope/parser.py +0 -0
- {benchscope-1.0.6 → benchscope-1.1.0}/benchscope/server/__init__.py +0 -0
- {benchscope-1.0.6 → benchscope-1.1.0}/benchscope/server/api_test.py +0 -0
- {benchscope-1.0.6 → benchscope-1.1.0}/benchscope/server/status.py +0 -0
- {benchscope-1.0.6 → benchscope-1.1.0}/benchscope/server/ws.py +0 -0
- {benchscope-1.0.6 → benchscope-1.1.0}/benchscope/summary.py +0 -0
- {benchscope-1.0.6 → benchscope-1.1.0}/benchscope/webui/assets/echarts-52vywGac.js +0 -0
- {benchscope-1.0.6 → benchscope-1.1.0}/benchscope/webui/blue_logo.png +0 -0
- {benchscope-1.0.6 → benchscope-1.1.0}/benchscope/webui/bs-logo.png +0 -0
- {benchscope-1.0.6 → benchscope-1.1.0}/benchscope.egg-info/dependency_links.txt +0 -0
- {benchscope-1.0.6 → benchscope-1.1.0}/benchscope.egg-info/entry_points.txt +0 -0
- {benchscope-1.0.6 → benchscope-1.1.0}/benchscope.egg-info/top_level.txt +0 -0
- {benchscope-1.0.6 → benchscope-1.1.0}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: benchscope
|
|
3
|
-
Version: 1.0
|
|
3
|
+
Version: 1.1.0
|
|
4
4
|
Summary: LLM inference performance testing tool. Supports vLLM, SGLang, and any OpenAI-compatible API.
|
|
5
5
|
Author-email: benchscope <labelnet@foxmail.com>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -29,8 +29,13 @@ Requires-Dist: openpyxl>=3.1
|
|
|
29
29
|
Requires-Dist: pydantic>=2
|
|
30
30
|
Requires-Dist: python-multipart>=0.0.9
|
|
31
31
|
Requires-Dist: pyyaml>=6.0
|
|
32
|
+
Requires-Dist: aiohttp>=3.9
|
|
32
33
|
Provides-Extra: modelscope
|
|
33
34
|
Requires-Dist: modelscope>=1.15; extra == "modelscope"
|
|
35
|
+
Provides-Extra: accuracy-native
|
|
36
|
+
Requires-Dist: torch>=2.0; extra == "accuracy-native"
|
|
37
|
+
Requires-Dist: transformers>=4.40; extra == "accuracy-native"
|
|
38
|
+
Requires-Dist: peft>=0.10; extra == "accuracy-native"
|
|
34
39
|
Dynamic: license-file
|
|
35
40
|
|
|
36
41
|
<div align="center">
|
|
@@ -41,9 +46,9 @@ Dynamic: license-file
|
|
|
41
46
|
|
|
42
47
|
<p align="center"><strong>English</strong> | <a href="README.zh-CN.md">简体中文</a></p>
|
|
43
48
|
|
|
44
|
-
BenchScope is an open‑source LLM inference benchmarking platform built with
|
|
49
|
+
BenchScope is an open‑source LLM inference benchmarking platform built with ~~Vibe Coding~~ Harness Coding.
|
|
45
50
|
|
|
46
|
-
A visualization testing platform for LLM model **performance & accuracy**, supporting models
|
|
51
|
+
A visualization testing platform for LLM model **performance & accuracy**, supporting models inference with vLLM / SGLang and any OpenAI‑compatible API.
|
|
47
52
|
|
|
48
53
|
<div align="center">
|
|
49
54
|
<img src="asserts/main-performance.png" width="72%" alt="BenchScope main performance screenshot" />
|
|
@@ -55,7 +60,7 @@ A visualization testing platform for LLM model **performance & accuracy**, suppo
|
|
|
55
60
|
|
|
56
61
|
- **Easy to install** — `pip install` and one command starts the whole web platform.
|
|
57
62
|
- **Performance testing dual mode** — Concurrency Mode (multi-level concurrency load) and Threshold Mode (auto-search the max concurrency meeting the threshold).
|
|
58
|
-
- **Accuracy testing dual mode** —
|
|
63
|
+
- **Accuracy testing dual mode** — Native(local model weights)/ Serving(API)double model tasks。
|
|
59
64
|
- **Real-time data feedback** — every concurrency result streams into tables, charts and progress in real time.
|
|
60
65
|
- **Visualization curves** — multi-dimensional charts for throughput / TTFT / TPOT / ITL.
|
|
61
66
|
- **Log cache & download** — run logs, mean/P99 summaries and Excel export with online preview & download.
|
|
@@ -6,9 +6,9 @@
|
|
|
6
6
|
|
|
7
7
|
<p align="center"><strong>English</strong> | <a href="README.zh-CN.md">简体中文</a></p>
|
|
8
8
|
|
|
9
|
-
BenchScope is an open‑source LLM inference benchmarking platform built with
|
|
9
|
+
BenchScope is an open‑source LLM inference benchmarking platform built with ~~Vibe Coding~~ Harness Coding.
|
|
10
10
|
|
|
11
|
-
A visualization testing platform for LLM model **performance & accuracy**, supporting models
|
|
11
|
+
A visualization testing platform for LLM model **performance & accuracy**, supporting models inference with vLLM / SGLang and any OpenAI‑compatible API.
|
|
12
12
|
|
|
13
13
|
<div align="center">
|
|
14
14
|
<img src="asserts/main-performance.png" width="72%" alt="BenchScope main performance screenshot" />
|
|
@@ -20,7 +20,7 @@ A visualization testing platform for LLM model **performance & accuracy**, suppo
|
|
|
20
20
|
|
|
21
21
|
- **Easy to install** — `pip install` and one command starts the whole web platform.
|
|
22
22
|
- **Performance testing dual mode** — Concurrency Mode (multi-level concurrency load) and Threshold Mode (auto-search the max concurrency meeting the threshold).
|
|
23
|
-
- **Accuracy testing dual mode** —
|
|
23
|
+
- **Accuracy testing dual mode** — Native(local model weights)/ Serving(API)double model tasks。
|
|
24
24
|
- **Real-time data feedback** — every concurrency result streams into tables, charts and progress in real time.
|
|
25
25
|
- **Visualization curves** — multi-dimensional charts for throughput / TTFT / TPOT / ITL.
|
|
26
26
|
- **Log cache & download** — run logs, mean/P99 summaries and Excel export with online preview & download.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"""精度测试模块(Accuracy):与性能模块彻底解耦的独立评测闭环。
|
|
2
|
+
|
|
3
|
+
子模块:
|
|
4
|
+
- engines.py 精度引擎适配(bench 引擎注册表 eval 能力过滤 + 环境校验)
|
|
5
|
+
- datasets.py 评测数据集(datasets.yaml 注册表 + 下载/标准化/抽样/统计)
|
|
6
|
+
- executor.py 推理执行器(Serving/Native/Mock 统一接口;benchscope eval 实现体)
|
|
7
|
+
- metrics.py 指标汇总(accuracy/pass_rate/分学科/Token 统计/结论)
|
|
8
|
+
- estimator.py Token 预估(常量表 > 实测统计 > 字符估算)
|
|
9
|
+
- baselines.py 开源基线库与对标计算
|
|
10
|
+
- task_manager.py EvalTaskManager(独立调度 + 三件套落库 + WS 推送)
|
|
11
|
+
- compare.py 多任务对比 / Native vs Serving 一致性差值
|
|
12
|
+
- scorers/ 判分器(choice / math / code / judge)
|
|
13
|
+
|
|
14
|
+
设计文档:docs/rules/AccuracyEngine.md
|
|
15
|
+
"""
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
"""开源模型基准对标(平台核心新增能力)。
|
|
2
|
+
|
|
3
|
+
每次评测结束后自动横向对标内置基线池(configs/baselines.yaml,静态固化公开测评
|
|
4
|
+
分数 + 来源标注),生成:
|
|
5
|
+
1. 同数据集差值百分点(当前模型 vs 最接近尺寸基线 / 最优基线)
|
|
6
|
+
2. 能力档位评级 S / A / B / C(相对最优基线:≥0 → S;≥-5pp → A;≥-15pp → B;否则 C)
|
|
7
|
+
3. 同尺寸段排名百分比(段内基线中被当前模型超越的比例)
|
|
8
|
+
4. 能力雷达(知识 / 数学 / 代码 / 对话维度,单数据集任务取该维度得分)
|
|
9
|
+
5. 自动结论:优于同尺寸开源基线 / 持平基线 / 明显劣于基线(风险预警)
|
|
10
|
+
"""
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import logging
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
|
|
16
|
+
import yaml
|
|
17
|
+
|
|
18
|
+
log = logging.getLogger("benchscope.accuracy.baselines")
|
|
19
|
+
|
|
20
|
+
CONFIGS_DIR = Path(__file__).resolve().parent.parent / "configs"
|
|
21
|
+
BASELINES_YAML = CONFIGS_DIR / "baselines.yaml"
|
|
22
|
+
|
|
23
|
+
# 同尺寸段划分(B):[0, 4) / [4, 15) / [15, 40) / [40, +∞)
|
|
24
|
+
_SIZE_SEGMENTS = ((0, 4), (4, 15), (15, 40), (40, float("inf")))
|
|
25
|
+
|
|
26
|
+
# 档位阈值(相对最优基线差值,百分点)
|
|
27
|
+
_GRADE_RULES = (
|
|
28
|
+
(0.0, "S"),
|
|
29
|
+
(-5.0, "A"),
|
|
30
|
+
(-15.0, "B"),
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
RADAR_DIMS = ("知识", "数学", "代码", "对话")
|
|
34
|
+
_DIM_BY_CATEGORY = {
|
|
35
|
+
"accuracy-knowledge": "知识",
|
|
36
|
+
"accuracy-math": "数学",
|
|
37
|
+
"accuracy-code": "代码",
|
|
38
|
+
"accuracy-chat": "对话",
|
|
39
|
+
"accuracy-mix": "综合",
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def load_baselines() -> dict:
|
|
44
|
+
"""读取基线库(原文 + 解析结果,供 API 展示与更新)。"""
|
|
45
|
+
content = BASELINES_YAML.read_text(encoding="utf-8") if BASELINES_YAML.exists() else ""
|
|
46
|
+
try:
|
|
47
|
+
data = yaml.safe_load(content) or {}
|
|
48
|
+
except Exception:
|
|
49
|
+
log.exception("解析 baselines.yaml 失败")
|
|
50
|
+
data = {}
|
|
51
|
+
return {
|
|
52
|
+
"version": data.get("version") or "",
|
|
53
|
+
"models": data.get("models") or [],
|
|
54
|
+
"content": content,
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def save_baselines(content: str) -> dict:
|
|
59
|
+
"""管理员更新基线库(YAML 校验后写盘)。"""
|
|
60
|
+
data = yaml.safe_load(content or "")
|
|
61
|
+
if not isinstance(data, dict) or not isinstance(data.get("models"), list) or not data["models"]:
|
|
62
|
+
raise ValueError("基线库必须是含非空 models 列表的对象")
|
|
63
|
+
for m in data["models"]:
|
|
64
|
+
if not isinstance(m, dict) or not m.get("name") or not isinstance(m.get("scores"), dict):
|
|
65
|
+
raise ValueError("基线模型必须含 name 与 scores 字典")
|
|
66
|
+
BASELINES_YAML.write_text(content, encoding="utf-8")
|
|
67
|
+
return load_baselines()
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def _segment(params_b: float) -> int:
|
|
71
|
+
for i, (lo, hi) in enumerate(_SIZE_SEGMENTS):
|
|
72
|
+
if lo <= params_b < hi:
|
|
73
|
+
return i
|
|
74
|
+
return len(_SIZE_SEGMENTS) - 1
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def _grade(diff_vs_best: float) -> str:
|
|
78
|
+
for threshold, grade in _GRADE_RULES:
|
|
79
|
+
if diff_vs_best >= threshold:
|
|
80
|
+
return grade
|
|
81
|
+
return "C"
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def _conclusion(diff_vs_segment: float) -> str:
|
|
85
|
+
if diff_vs_segment >= 0:
|
|
86
|
+
return "优于同尺寸开源基线"
|
|
87
|
+
if diff_vs_segment >= -5.0:
|
|
88
|
+
return "持平基线"
|
|
89
|
+
return "明显劣于基线(风险预警)"
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def compute_benchmark(meta: dict, result: dict) -> dict | None:
|
|
93
|
+
"""由数据集元数据与评测结果计算基线对标。
|
|
94
|
+
|
|
95
|
+
返回 None 表示该数据集无任何基线分数可对标。
|
|
96
|
+
"""
|
|
97
|
+
dataset_id = meta.get("id") or ""
|
|
98
|
+
library = load_baselines()
|
|
99
|
+
models = [m for m in library["models"] if isinstance(m.get("scores"), dict)]
|
|
100
|
+
|
|
101
|
+
# 当前模型该数据集主指标(百分制)
|
|
102
|
+
main_metric = (meta.get("eval") or {}).get("metrics") or "accuracy"
|
|
103
|
+
score = None
|
|
104
|
+
if main_metric == "accuracy":
|
|
105
|
+
score = result.get("accuracy")
|
|
106
|
+
elif main_metric == "exact_match":
|
|
107
|
+
score = (result.get("dataset_metrics") or {}).get("exact_match")
|
|
108
|
+
elif main_metric == "pass@1":
|
|
109
|
+
score = (result.get("dataset_metrics") or {}).get("pass_at_1")
|
|
110
|
+
elif main_metric == "mt_bench":
|
|
111
|
+
score = (result.get("dataset_metrics") or {}).get("mt_bench_score")
|
|
112
|
+
if score is None:
|
|
113
|
+
return None
|
|
114
|
+
|
|
115
|
+
scored = [
|
|
116
|
+
{"name": m.get("name"), "params_b": float(m.get("params_b") or 0),
|
|
117
|
+
"group": m.get("group") or "general", "source": m.get("source") or "",
|
|
118
|
+
"score": float(m["scores"][dataset_id])}
|
|
119
|
+
for m in models if dataset_id in m["scores"]
|
|
120
|
+
]
|
|
121
|
+
if not scored:
|
|
122
|
+
return None
|
|
123
|
+
|
|
124
|
+
best = max(scored, key=lambda m: m["score"])
|
|
125
|
+
# 尺寸最接近的基线(参数量差最小)
|
|
126
|
+
nearest = min(scored, key=lambda m: abs(m["params_b"] - float(result.get("_params_b") or 0) or 0))
|
|
127
|
+
current_seg = _segment(nearest["params_b"])
|
|
128
|
+
segment_models = [m for m in scored if _segment(m["params_b"]) == current_seg]
|
|
129
|
+
seg_best = max(segment_models, key=lambda m: m["score"])
|
|
130
|
+
better_count = sum(1 for m in segment_models if score >= m["score"])
|
|
131
|
+
|
|
132
|
+
diff_best = round(score - best["score"], 2)
|
|
133
|
+
diff_nearest = round(score - nearest["score"], 2)
|
|
134
|
+
diff_segment = round(score - seg_best["score"], 2)
|
|
135
|
+
|
|
136
|
+
# 能力雷达:单数据集任务仅该维度有值(综合类全维空)
|
|
137
|
+
dim = _DIM_BY_CATEGORY.get(meta.get("category") or "")
|
|
138
|
+
radar = {d: None for d in RADAR_DIMS}
|
|
139
|
+
if dim in radar:
|
|
140
|
+
radar[dim] = round(float(score), 2)
|
|
141
|
+
|
|
142
|
+
return {
|
|
143
|
+
"dataset_id": dataset_id,
|
|
144
|
+
"metric": main_metric,
|
|
145
|
+
"score": round(float(score), 2),
|
|
146
|
+
"baselines": scored,
|
|
147
|
+
"baseline_used": {"name": nearest["name"], "score": nearest["score"], "params_b": nearest["params_b"],
|
|
148
|
+
"source": nearest["source"]},
|
|
149
|
+
"diff_pp": diff_nearest,
|
|
150
|
+
"diff_vs_best_pp": diff_best,
|
|
151
|
+
"best_baseline": {"name": best["name"], "score": best["score"]},
|
|
152
|
+
"grade": _grade(diff_best),
|
|
153
|
+
"rank_pct": round(better_count / len(segment_models) * 100.0, 1) if segment_models else None,
|
|
154
|
+
"segment": {"range_b": [segment_models[0]["params_b"], segment_models[-1]["params_b"]] if segment_models else [],
|
|
155
|
+
"count": len(segment_models), "best": seg_best["name"], "best_score": seg_best["score"]},
|
|
156
|
+
"diff_vs_segment_pp": diff_segment,
|
|
157
|
+
"radar": radar,
|
|
158
|
+
"conclusion": _conclusion(diff_segment),
|
|
159
|
+
"baseline_version": library.get("version") or "",
|
|
160
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
"""多任务对比 / Native vs Serving 训推一致性差值(P15)。
|
|
2
|
+
|
|
3
|
+
对比口径:
|
|
4
|
+
- 横向对比:多任务按「模型+数据集」分组,逐指标(accuracy / exact_match / pass@1 /
|
|
5
|
+
mt_bench_score)列出;
|
|
6
|
+
- 一致性:同组内同时存在 native 与 serving 任务时计算逐指标差值
|
|
7
|
+
(|diff| ≤ 2pp 训推一致;≤ 5pp 存在偏差;> 5pp 显著偏差)。
|
|
8
|
+
"""
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
CONSISTENT = "训推一致"
|
|
12
|
+
DEVIATED = "存在偏差"
|
|
13
|
+
SIGNIFICANT = "显著偏差"
|
|
14
|
+
|
|
15
|
+
# 参与对比的主指标(按数据集判分器取值)
|
|
16
|
+
_MAIN_METRICS = (
|
|
17
|
+
("accuracy", "accuracy"),
|
|
18
|
+
("exact_match", "dataset_metrics.exact_match"),
|
|
19
|
+
("pass@1", "dataset_metrics.pass_at_1"),
|
|
20
|
+
("mt_bench_score", "dataset_metrics.mt_bench_score"),
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _main_metric(result: dict | None) -> tuple[str, float | None]:
|
|
25
|
+
"""任务的主指标取值(按数据集判分器选择)。"""
|
|
26
|
+
if not result:
|
|
27
|
+
return "accuracy", None
|
|
28
|
+
dm = result.get("dataset_metrics") or {}
|
|
29
|
+
if dm.get("pass_at_1") is not None:
|
|
30
|
+
return "pass@1", dm.get("pass_at_1")
|
|
31
|
+
if dm.get("exact_match") is not None:
|
|
32
|
+
return "exact_match", dm.get("exact_match")
|
|
33
|
+
if dm.get("mt_bench_score") is not None:
|
|
34
|
+
return "mt_bench_score", dm.get("mt_bench_score")
|
|
35
|
+
return "accuracy", result.get("accuracy")
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def _deviation_label(diff_pp: float) -> str:
|
|
39
|
+
diff = abs(diff_pp)
|
|
40
|
+
if diff <= 2.0:
|
|
41
|
+
return CONSISTENT
|
|
42
|
+
if diff <= 5.0:
|
|
43
|
+
return DEVIATED
|
|
44
|
+
return SIGNIFICANT
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def compare_tasks(task_snapshots: list[dict]) -> dict:
|
|
48
|
+
"""对比多任务结果。
|
|
49
|
+
|
|
50
|
+
task_snapshots:[{task_id, name, mode, model, lora_name/lora_path, dataset_id,
|
|
51
|
+
dataset_name, engine_id, result}]
|
|
52
|
+
返回 {items, groups}:items 为任务主指标表,groups 按「模型+数据集」分组,
|
|
53
|
+
组内含 native vs serving 一致性差值。
|
|
54
|
+
"""
|
|
55
|
+
items = []
|
|
56
|
+
for t in task_snapshots:
|
|
57
|
+
result = t.get("result") or {}
|
|
58
|
+
metric_name, metric_value = _main_metric(result)
|
|
59
|
+
items.append({
|
|
60
|
+
"task_id": t.get("task_id"),
|
|
61
|
+
"name": t.get("name") or t.get("task_id"),
|
|
62
|
+
"mode": t.get("mode"),
|
|
63
|
+
"engine_id": t.get("engine_id"),
|
|
64
|
+
"model": t.get("model"),
|
|
65
|
+
"lora_name": t.get("lora_name") or "",
|
|
66
|
+
"lora_path": t.get("lora_path") or "",
|
|
67
|
+
"dataset_id": t.get("dataset_id"),
|
|
68
|
+
"dataset_name": t.get("dataset_name"),
|
|
69
|
+
"status": t.get("status"),
|
|
70
|
+
"metric": metric_name,
|
|
71
|
+
"metric_value": metric_value,
|
|
72
|
+
"total_samples": result.get("total_samples"),
|
|
73
|
+
"correct_samples": result.get("correct_samples"),
|
|
74
|
+
"invalid_samples": result.get("invalid_samples"),
|
|
75
|
+
"pass_rate": result.get("pass_rate"),
|
|
76
|
+
"conclusion": result.get("conclusion"),
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
# 按「模型 + 数据集」分组,组内做模式对比
|
|
80
|
+
groups: dict[str, list[dict]] = {}
|
|
81
|
+
for item in items:
|
|
82
|
+
key = f"{item.get('model')}|{item.get('lora_path') or ''}|{item.get('dataset_id')}"
|
|
83
|
+
groups.setdefault(key, []).append(item)
|
|
84
|
+
|
|
85
|
+
group_outputs = []
|
|
86
|
+
for key, members in groups.items():
|
|
87
|
+
native = next((m for m in members if m.get("mode") == "native"), None)
|
|
88
|
+
serving = next((m for m in members if m.get("mode") == "serving"), None)
|
|
89
|
+
consistency = None
|
|
90
|
+
if native and serving and native.get("metric_value") is not None and serving.get("metric_value") is not None:
|
|
91
|
+
diff = round(float(native["metric_value"]) - float(serving["metric_value"]), 2)
|
|
92
|
+
consistency = {
|
|
93
|
+
"native_task_id": native["task_id"],
|
|
94
|
+
"serving_task_id": serving["task_id"],
|
|
95
|
+
"metric": native["metric"],
|
|
96
|
+
"native_value": native["metric_value"],
|
|
97
|
+
"serving_value": serving["metric_value"],
|
|
98
|
+
"diff_pp": diff,
|
|
99
|
+
"conclusion": _deviation_label(diff),
|
|
100
|
+
}
|
|
101
|
+
group_outputs.append({
|
|
102
|
+
"key": key,
|
|
103
|
+
"model": members[0].get("model"),
|
|
104
|
+
"lora_path": members[0].get("lora_path") or "",
|
|
105
|
+
"dataset_id": members[0].get("dataset_id"),
|
|
106
|
+
"tasks": [m["task_id"] for m in members],
|
|
107
|
+
"items": members,
|
|
108
|
+
"consistency": consistency,
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
group_outputs.sort(key=lambda g: g["key"])
|
|
112
|
+
return {"items": items, "groups": group_outputs}
|