PhysiQuanty commited on
Commit
50a4e60
·
verified ·
1 Parent(s): d56ed3c

Upload bench.py

Browse files
Files changed (1) hide show
  1. bench.py +266 -0
bench.py ADDED
@@ -0,0 +1,266 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ import argparse
3
+ import json
4
+ import os
5
+ import subprocess
6
+ import sys
7
+ from pathlib import Path
8
+
9
+
10
+ MODEL_ID = "bench_fr_native1.py"
11
+ BENCHMARK_NAME = "MTEB(fra, v1)"
12
+ OUTPUT_ROOT = "results_mteb_french_native"
13
+ SUMMARY_JSONL = "results_mteb_french_native_summary.jsonl"
14
+
15
+
16
+ TASK_NAMES = [
17
+ "AlloProfClusteringP2P",
18
+ "AlloProfClusteringS2S",
19
+ "HALClusteringS2S",
20
+ "AlloprofReranking",
21
+ "SyntecReranking",
22
+ "AlloprofRetrieval",
23
+ "BSARDRetrieval",
24
+ "SyntecRetrieval",
25
+ "SICKFr",
26
+ "SummEvalFr",
27
+ ]
28
+
29
+
30
+ def find_task_result_json(task_name):
31
+ root = Path(OUTPUT_ROOT)
32
+ files = list(root.rglob(f"{task_name}.json"))
33
+ if not files:
34
+ return None
35
+ return files[0]
36
+
37
+
38
+ def read_main_score(task_name):
39
+ path = find_task_result_json(task_name)
40
+ if path is None:
41
+ return None
42
+
43
+ with open(path, "r", encoding="utf-8") as f:
44
+ data = json.load(f)
45
+
46
+ scores = data.get("scores", {})
47
+ test = scores.get("test", [])
48
+
49
+ if not test:
50
+ return {
51
+ "task_name": task_name,
52
+ "main_score": None,
53
+ "json_path": str(path),
54
+ }
55
+
56
+ first = test[0]
57
+
58
+ return {
59
+ "task_name": task_name,
60
+ "main_score": first.get("main_score"),
61
+ "cosine_spearman": first.get("cosine_spearman"),
62
+ "cosine_pearson": first.get("cosine_pearson"),
63
+ "spearman": first.get("spearman"),
64
+ "pearson": first.get("pearson"),
65
+ "ndcg_at_10": first.get("ndcg_at_10"),
66
+ "map_at_10": first.get("map_at_10"),
67
+ "recall_at_10": first.get("recall_at_10"),
68
+ "json_path": str(path),
69
+ }
70
+
71
+
72
+ def run_worker(task_name, batch_size):
73
+ import torch
74
+ import mteb
75
+ from mteb import MTEB
76
+ from sentence_transformers import SentenceTransformer
77
+
78
+ if not torch.cuda.is_available():
79
+ raise RuntimeError("CUDA non disponible. Vérifie avec: nvidia-smi")
80
+
81
+ print("[WORKER] GPU:", torch.cuda.get_device_name(0))
82
+ print("[WORKER] Task:", task_name)
83
+
84
+ benchmark = mteb.get_benchmark(BENCHMARK_NAME)
85
+
86
+ tasks = [
87
+ task for task in benchmark.tasks
88
+ if task.metadata.name == task_name
89
+ ]
90
+
91
+ if len(tasks) != 1:
92
+ names = [task.metadata.name for task in benchmark.tasks]
93
+ raise RuntimeError(f"Tâche introuvable: {task_name}. Disponibles: {names}")
94
+
95
+ model = SentenceTransformer(
96
+ MODEL_ID,
97
+ device="cuda",
98
+ trust_remote_code=True,
99
+ )
100
+
101
+ evaluation = MTEB(tasks=tasks)
102
+
103
+ results = evaluation.run(
104
+ model,
105
+ output_folder=OUTPUT_ROOT,
106
+ eval_splits=["test"],
107
+ batch_size=batch_size,
108
+ )
109
+
110
+ print("[WORKER DONE]", task_name)
111
+ print("[RAW RESULT]", results)
112
+
113
+ score = read_main_score(task_name)
114
+
115
+ print("")
116
+ print("=" * 80)
117
+ print("[TASK SCORE]")
118
+ print("=" * 80)
119
+
120
+ if score is None:
121
+ print("task_name:", task_name)
122
+ print("main_score: None")
123
+ else:
124
+ for k, v in score.items():
125
+ print(f"{k}: {v}")
126
+
127
+
128
+ def run_parent(batch_size):
129
+ if Path(SUMMARY_JSONL).exists():
130
+ print("[INFO] Existing summary found:", SUMMARY_JSONL)
131
+ print("[INFO] New rows will be appended.")
132
+
133
+ print("[INFO] French-native tasks only:", len(TASK_NAMES))
134
+ print("[INFO] Output:", OUTPUT_ROOT)
135
+
136
+ for i, task_name in enumerate(TASK_NAMES, start=1):
137
+ print("")
138
+ print("#" * 100)
139
+ print(f"[TASK {i}/{len(TASK_NAMES)}] {task_name}")
140
+ print("#" * 100)
141
+
142
+ env = os.environ.copy()
143
+ env["CUDA_VISIBLE_DEVICES"] = env.get("CUDA_VISIBLE_DEVICES", "0")
144
+ env["PYTHONUNBUFFERED"] = "1"
145
+
146
+ cmd = [
147
+ sys.executable,
148
+ __file__,
149
+ "--worker",
150
+ "--task",
151
+ task_name,
152
+ "--batch-size",
153
+ str(batch_size),
154
+ ]
155
+
156
+ proc = subprocess.run(cmd, env=env, text=True)
157
+
158
+ status = "ok" if proc.returncode == 0 else "failed"
159
+ score = read_main_score(task_name) if status == "ok" else None
160
+
161
+ row = {
162
+ "task_name": task_name,
163
+ "status": status,
164
+ "returncode": proc.returncode,
165
+ "main_score": None if score is None else score.get("main_score"),
166
+ "cosine_spearman": None if score is None else score.get("cosine_spearman"),
167
+ "cosine_pearson": None if score is None else score.get("cosine_pearson"),
168
+ "spearman": None if score is None else score.get("spearman"),
169
+ "pearson": None if score is None else score.get("pearson"),
170
+ "ndcg_at_10": None if score is None else score.get("ndcg_at_10"),
171
+ "map_at_10": None if score is None else score.get("map_at_10"),
172
+ "recall_at_10": None if score is None else score.get("recall_at_10"),
173
+ "json_path": None if score is None else score.get("json_path"),
174
+ }
175
+
176
+ with open(SUMMARY_JSONL, "a", encoding="utf-8") as f:
177
+ f.write(json.dumps(row, ensure_ascii=False) + "\n")
178
+
179
+ print("")
180
+ print("[SUMMARY ROW]")
181
+ print(json.dumps(row, ensure_ascii=False, indent=2))
182
+
183
+ print_final_summary()
184
+
185
+
186
+ def print_final_summary():
187
+ path = Path(SUMMARY_JSONL)
188
+
189
+ if not path.exists():
190
+ print("[ERROR] No summary found.")
191
+ return
192
+
193
+ rows = []
194
+
195
+ with open(path, "r", encoding="utf-8") as f:
196
+ for line in f:
197
+ line = line.strip()
198
+ if line:
199
+ rows.append(json.loads(line))
200
+
201
+ latest = {}
202
+ for row in rows:
203
+ latest[row["task_name"]] = row
204
+
205
+ final_rows = list(latest.values())
206
+
207
+ ok_rows = [
208
+ r for r in final_rows
209
+ if r.get("status") == "ok" and isinstance(r.get("main_score"), (int, float))
210
+ ]
211
+
212
+ failed_rows = [
213
+ r for r in final_rows
214
+ if r.get("status") != "ok"
215
+ ]
216
+
217
+ mean_score = None
218
+ if ok_rows:
219
+ mean_score = sum(r["main_score"] for r in ok_rows) / len(ok_rows)
220
+
221
+ print("")
222
+ print("=" * 100)
223
+ print("[FINAL SUMMARY]")
224
+ print("=" * 100)
225
+ print("tasks_total:", len(final_rows))
226
+ print("tasks_ok:", len(ok_rows))
227
+ print("tasks_failed:", len(failed_rows))
228
+ print("mean_main_score:", mean_score)
229
+
230
+ print("")
231
+ print("[OK]")
232
+ for r in ok_rows:
233
+ print(f'{r["task_name"]}: {r["main_score"]}')
234
+
235
+ print("")
236
+ print("[FAILED]")
237
+ for r in failed_rows:
238
+ print(f'{r["task_name"]}: returncode={r["returncode"]}')
239
+
240
+
241
+ def parse_args():
242
+ parser = argparse.ArgumentParser()
243
+ parser.add_argument("--worker", action="store_true")
244
+ parser.add_argument("--task", default=None)
245
+ parser.add_argument("--batch-size", type=int, default=1)
246
+ parser.add_argument("--summary-only", action="store_true")
247
+ return parser.parse_args()
248
+
249
+
250
+ def main():
251
+ args = parse_args()
252
+
253
+ if args.summary_only:
254
+ print_final_summary()
255
+ return
256
+
257
+ if args.worker:
258
+ if args.task is None:
259
+ raise RuntimeError("--task requis avec --worker")
260
+ run_worker(args.task, args.batch_size)
261
+ else:
262
+ run_parent(args.batch_size)
263
+
264
+
265
+ if __name__ == "__main__":
266
+ main()