FredericFan commited on
Commit
7f5a423
·
1 Parent(s): f1e78da
Files changed (7) hide show
  1. .gitignore +1 -0
  2. README.md +28 -38
  3. app.py +201 -171
  4. requirements.txt +1 -15
  5. src/about.py +81 -39
  6. src/display/utils.py +36 -48
  7. src/envs.py +6 -8
.gitignore CHANGED
@@ -11,3 +11,4 @@ eval-results/
11
  eval-queue-bk/
12
  eval-results-bk/
13
  logs/
 
 
11
  eval-queue-bk/
12
  eval-results-bk/
13
  logs/
14
+ /paper_latex
README.md CHANGED
@@ -1,48 +1,38 @@
1
  ---
2
- title: MD Benchmark
3
- emoji: 🥇
4
- colorFrom: green
5
  colorTo: indigo
6
  sdk: gradio
 
7
  app_file: app.py
8
  pinned: true
9
  license: apache-2.0
10
- short_description: Molecular Dynamics eval benchmark
11
- sdk_version: 5.43.1
12
  tags:
13
  - leaderboard
 
 
 
14
  ---
15
 
16
- # Start the configuration
17
-
18
- Most of the variables to change for a default leaderboard are in `src/env.py` (replace the path for your leaderboard) and `src/about.py` (for tasks).
19
-
20
- Results files should have the following format and be stored as json files:
21
- ```json
22
- {
23
- "config": {
24
- "model_dtype": "torch.float16", # or torch.bfloat16 or 8bit or 4bit
25
- "model_name": "path of the model on the hub: org/model",
26
- "model_sha": "revision on the hub",
27
- },
28
- "results": {
29
- "task_name": {
30
- "metric_name": score,
31
- },
32
- "task_name2": {
33
- "metric_name": score,
34
- }
35
- }
36
- }
37
- ```
38
-
39
- Request files are created automatically by this tool.
40
-
41
- If you encounter problem on the space, don't hesitate to restart it to remove the create eval-queue, eval-queue-bk, eval-results and eval-results-bk created folder.
42
-
43
- # Code logic for more complex edits
44
-
45
- You'll find
46
- - the main table' columns names and properties in `src/display/utils.py`
47
- - the logic to read all results and request files, then convert them in dataframe lines, in `src/leaderboard/read_evals.py`, and `src/populate.py`
48
- - the logic to allow or filter submissions in `src/submission/submit.py` and `src/submission/check_validity.py`
 
1
  ---
2
+ title: MD-EvalBench Leaderboard
3
+ emoji: 🧪
4
+ colorFrom: blue
5
  colorTo: indigo
6
  sdk: gradio
7
+ sdk_version: 5.43.1
8
  app_file: app.py
9
  pinned: true
10
  license: apache-2.0
11
+ short_description: Molecular Dynamics LLM Benchmark Leaderboard
 
12
  tags:
13
  - leaderboard
14
+ - molecular-dynamics
15
+ - LAMMPS
16
+ - AI-for-Science
17
  ---
18
 
19
+ ## MD-EvalBench: Molecular Dynamics LLM Benchmark
20
+
21
+ The first comprehensive benchmark for evaluating Large Language Models in the Molecular Dynamics domain, from the paper **"MDAgent2: Large Language Model for Code Generation and Knowledge Q&A in Molecular Dynamics"**.
22
+
23
+ ## Benchmark Components
24
+
25
+ - **MD-KnowledgeEval** (336 questions): Theoretical knowledge in molecular dynamics
26
+ - **LAMMPS-SyntaxEval** (368 questions): LAMMPS command and syntax understanding
27
+ - **LAMMPS-CodeGenEval** (566 tasks): Automatic LAMMPS code generation
28
+
29
+ ## Leaderboard Tabs
30
+
31
+ 1. **QA Benchmark**: Knowledge and syntax QA performance comparison
32
+ 2. **Code Generation**: LAMMPS code generation performance across methods (Direct Prompting, MDAgent, MDAgent2-RUNTIME)
33
+
34
+ ## Configuration
35
+
36
+ - Main leaderboard data is in `app.py`
37
+ - Task definitions in `src/about.py`
38
+ - Column definitions in `src/display/utils.py`
 
 
 
 
 
 
 
 
 
 
 
 
 
app.py CHANGED
@@ -1,204 +1,234 @@
1
  import gradio as gr
2
- from gradio_leaderboard import Leaderboard, ColumnFilter, SelectColumns
3
  import pandas as pd
4
- from apscheduler.schedulers.background import BackgroundScheduler
5
- from huggingface_hub import snapshot_download
6
 
7
  from src.about import (
8
  CITATION_BUTTON_LABEL,
9
  CITATION_BUTTON_TEXT,
10
- EVALUATION_QUEUE_TEXT,
11
  INTRODUCTION_TEXT,
12
  LLM_BENCHMARKS_TEXT,
13
  TITLE,
14
  )
15
  from src.display.css_html_js import custom_css
16
- from src.display.utils import (
17
- BENCHMARK_COLS,
18
- COLS,
19
- EVAL_COLS,
20
- EVAL_TYPES,
21
- AutoEvalColumn,
22
- ModelType,
23
- fields,
24
- WeightType,
25
- Precision
26
- )
27
- from src.envs import API, EVAL_REQUESTS_PATH, EVAL_RESULTS_PATH, QUEUE_REPO, REPO_ID, RESULTS_REPO, TOKEN
28
- from src.populate import get_evaluation_queue_df, get_leaderboard_df
29
- from src.submission.submit import add_new_eval
30
-
31
-
32
- def restart_space():
33
- API.restart_space(repo_id=REPO_ID)
34
-
35
- ### Space initialisation
36
- try:
37
- print(EVAL_REQUESTS_PATH)
38
- snapshot_download(
39
- repo_id=QUEUE_REPO, local_dir=EVAL_REQUESTS_PATH, repo_type="dataset", tqdm_class=None, etag_timeout=30, token=TOKEN
40
- )
41
- except Exception:
42
- restart_space()
43
- try:
44
- print(EVAL_RESULTS_PATH)
45
- snapshot_download(
46
- repo_id=RESULTS_REPO, local_dir=EVAL_RESULTS_PATH, repo_type="dataset", tqdm_class=None, etag_timeout=30, token=TOKEN
47
- )
48
- except Exception:
49
- restart_space()
50
-
51
-
52
- LEADERBOARD_DF = get_leaderboard_df(EVAL_RESULTS_PATH, EVAL_REQUESTS_PATH, COLS, BENCHMARK_COLS)
53
-
54
- (
55
- finished_eval_queue_df,
56
- running_eval_queue_df,
57
- pending_eval_queue_df,
58
- ) = get_evaluation_queue_df(EVAL_REQUESTS_PATH, EVAL_COLS)
59
-
60
- def init_leaderboard(dataframe):
61
- if dataframe is None or dataframe.empty:
62
- raise ValueError("Leaderboard DataFrame is empty or None.")
63
- return Leaderboard(
64
- value=dataframe,
65
- datatype=[c.type for c in fields(AutoEvalColumn)],
66
- select_columns=SelectColumns(
67
- default_selection=[c.name for c in fields(AutoEvalColumn) if c.displayed_by_default],
68
- cant_deselect=[c.name for c in fields(AutoEvalColumn) if c.never_hidden],
69
- label="Select Columns to Display:",
70
- ),
71
- search_columns=[AutoEvalColumn.model.name, AutoEvalColumn.license.name],
72
- hide_columns=[c.name for c in fields(AutoEvalColumn) if c.hidden],
73
- filter_columns=[
74
- ColumnFilter(AutoEvalColumn.model_type.name, type="checkboxgroup", label="Model types"),
75
- ColumnFilter(AutoEvalColumn.precision.name, type="checkboxgroup", label="Precision"),
76
- ColumnFilter(
77
- AutoEvalColumn.params.name,
78
- type="slider",
79
- min=0.01,
80
- max=150,
81
- label="Select the number of parameters (B)",
82
- ),
83
- ColumnFilter(
84
- AutoEvalColumn.still_on_hub.name, type="boolean", label="Deleted/incomplete", default=True
85
- ),
86
- ],
87
- bool_checkboxgroup_label="Hide models",
88
- interactive=False,
89
- )
90
 
91
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92
  demo = gr.Blocks(css=custom_css)
93
  with demo:
94
  gr.HTML(TITLE)
95
  gr.Markdown(INTRODUCTION_TEXT, elem_classes="markdown-text")
96
 
97
  with gr.Tabs(elem_classes="tab-buttons") as tabs:
98
- with gr.TabItem("🏅 LLM Benchmark", elem_id="llm-benchmark-tab-table", id=0):
99
- leaderboard = init_leaderboard(LEADERBOARD_DF)
100
-
101
- with gr.TabItem("📝 About", elem_id="llm-benchmark-tab-table", id=2):
102
- gr.Markdown(LLM_BENCHMARKS_TEXT, elem_classes="markdown-text")
 
 
 
 
 
 
 
 
 
103
 
104
- with gr.TabItem("🚀 Submit here! ", elem_id="llm-benchmark-tab-table", id=3):
105
- with gr.Column():
106
- with gr.Row():
107
- gr.Markdown(EVALUATION_QUEUE_TEXT, elem_classes="markdown-text")
108
-
109
- with gr.Column():
110
- with gr.Accordion(
111
- f"✅ Finished Evaluations ({len(finished_eval_queue_df)})",
112
- open=False,
113
- ):
114
- with gr.Row():
115
- finished_eval_table = gr.components.Dataframe(
116
- value=finished_eval_queue_df,
117
- headers=EVAL_COLS,
118
- datatype=EVAL_TYPES,
119
- row_count=5,
120
- )
121
- with gr.Accordion(
122
- f"🔄 Running Evaluation Queue ({len(running_eval_queue_df)})",
123
- open=False,
124
- ):
125
- with gr.Row():
126
- running_eval_table = gr.components.Dataframe(
127
- value=running_eval_queue_df,
128
- headers=EVAL_COLS,
129
- datatype=EVAL_TYPES,
130
- row_count=5,
131
- )
132
-
133
- with gr.Accordion(
134
- f"⏳ Pending Evaluation Queue ({len(pending_eval_queue_df)})",
135
- open=False,
136
- ):
137
- with gr.Row():
138
- pending_eval_table = gr.components.Dataframe(
139
- value=pending_eval_queue_df,
140
- headers=EVAL_COLS,
141
- datatype=EVAL_TYPES,
142
- row_count=5,
143
- )
144
- with gr.Row():
145
- gr.Markdown("# ✉️✨ Submit your model here!", elem_classes="markdown-text")
146
 
147
  with gr.Row():
148
- with gr.Column():
149
- model_name_textbox = gr.Textbox(label="Model name")
150
- revision_name_textbox = gr.Textbox(label="Revision commit", placeholder="main")
151
- model_type = gr.Dropdown(
152
- choices=[t.to_str(" : ") for t in ModelType if t != ModelType.Unknown],
153
- label="Model type",
154
- multiselect=False,
155
- value=None,
156
- interactive=True,
157
- )
158
-
159
- with gr.Column():
160
- precision = gr.Dropdown(
161
- choices=[i.value.name for i in Precision if i != Precision.Unknown],
162
- label="Precision",
163
- multiselect=False,
164
- value="float16",
165
- interactive=True,
166
- )
167
- weight_type = gr.Dropdown(
168
- choices=[i.value.name for i in WeightType],
169
- label="Weights type",
170
- multiselect=False,
171
- value="Original",
172
- interactive=True,
173
- )
174
- base_model_name_textbox = gr.Textbox(label="Base model (for delta or adapter weights)")
175
-
176
- submit_button = gr.Button("Submit Eval")
177
- submission_result = gr.Markdown()
178
- submit_button.click(
179
- add_new_eval,
180
- [
181
- model_name_textbox,
182
- base_model_name_textbox,
183
- revision_name_textbox,
184
- precision,
185
- weight_type,
186
- model_type,
187
- ],
188
- submission_result,
189
  )
190
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
191
  with gr.Row():
192
  with gr.Accordion("📙 Citation", open=False):
193
  citation_button = gr.Textbox(
194
  value=CITATION_BUTTON_TEXT,
195
  label=CITATION_BUTTON_LABEL,
196
- lines=20,
197
  elem_id="citation-button",
198
  show_copy_button=True,
199
  )
200
 
201
- scheduler = BackgroundScheduler()
202
- scheduler.add_job(restart_space, "interval", seconds=1800)
203
- scheduler.start()
204
- demo.queue(default_concurrency_limit=40).launch()
 
1
  import gradio as gr
 
2
  import pandas as pd
 
 
3
 
4
  from src.about import (
5
  CITATION_BUTTON_LABEL,
6
  CITATION_BUTTON_TEXT,
 
7
  INTRODUCTION_TEXT,
8
  LLM_BENCHMARKS_TEXT,
9
  TITLE,
10
  )
11
  from src.display.css_html_js import custom_css
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
 
13
 
14
+ # =====================================================
15
+ # Static benchmark data extracted from the paper
16
+ # =====================================================
17
+
18
+ def get_qa_leaderboard_df() -> pd.DataFrame:
19
+ """QA benchmark results from Table 1 of the paper."""
20
+ data = [
21
+ {
22
+ "#": 1,
23
+ "Model": "Qwen3-max",
24
+ "Size / Access": "Large / Closed",
25
+ "Overall Avg": 82.49,
26
+ "MD-KnowledgeEval": 86.57,
27
+ "LAMMPS-SyntaxEval": 78.40,
28
+ "Delta vs 8B": 11.99,
29
+ },
30
+ {
31
+ "#": 2,
32
+ "Model": "Qwen3-32b",
33
+ "Size / Access": "32B / Open",
34
+ "Overall Avg": 77.34,
35
+ "MD-KnowledgeEval": 81.94,
36
+ "LAMMPS-SyntaxEval": 72.74,
37
+ "Delta vs 8B": 6.84,
38
+ },
39
+ {
40
+ "#": 3,
41
+ "Model": "**MD-Instruct-8B** (Ours)",
42
+ "Size / Access": "8B / Open",
43
+ "Overall Avg": 74.67,
44
+ "MD-KnowledgeEval": 76.89,
45
+ "LAMMPS-SyntaxEval": 72.45,
46
+ "Delta vs 8B": 4.17,
47
+ },
48
+ {
49
+ "#": 4,
50
+ "Model": "Qwen-flash",
51
+ "Size / Access": "Large / Closed",
52
+ "Overall Avg": 73.47,
53
+ "MD-KnowledgeEval": 78.64,
54
+ "LAMMPS-SyntaxEval": 68.30,
55
+ "Delta vs 8B": 2.97,
56
+ },
57
+ {
58
+ "#": 5,
59
+ "Model": "Qwen3-14b",
60
+ "Size / Access": "14B / Open",
61
+ "Overall Avg": 72.91,
62
+ "MD-KnowledgeEval": 77.90,
63
+ "LAMMPS-SyntaxEval": 67.92,
64
+ "Delta vs 8B": 2.41,
65
+ },
66
+ {
67
+ "#": 6,
68
+ "Model": "Qwen3-8b (Baseline)",
69
+ "Size / Access": "8B / Open",
70
+ "Overall Avg": 70.50,
71
+ "MD-KnowledgeEval": 75.15,
72
+ "LAMMPS-SyntaxEval": 65.84,
73
+ "Delta vs 8B": 0.00,
74
+ },
75
+ ]
76
+ return pd.DataFrame(data)
77
+
78
+
79
+ def get_codegen_leaderboard_df() -> pd.DataFrame:
80
+ """Code generation benchmark results from Figure 2 of the paper.
81
+
82
+ Data extracted from the paper text and figure:
83
+ - MDAgent2-RUNTIME + MD-Code-8B: ExecSucc@3=37.95%, Code-Score-Human=9.32
84
+ - Direct Prompting + MD-Code-8B: ExecSucc@3=14.23%, Code-Score-Human=9.29
85
+ - Other combinations inferred from the figure description.
86
+ """
87
+ data = [
88
+ {
89
+ "#": 1,
90
+ "Model": "**MD-Code-8B** (Ours)",
91
+ "Method": "MDAgent2-RUNTIME",
92
+ "Exec-Success@3 (%)": 37.95,
93
+ "Code-Score-Human": 9.32,
94
+ },
95
+ {
96
+ "#": 2,
97
+ "Model": "Qwen3-32B",
98
+ "Method": "MDAgent2-RUNTIME",
99
+ "Exec-Success@3 (%)": 35.87,
100
+ "Code-Score-Human": 9.18,
101
+ },
102
+ {
103
+ "#": 3,
104
+ "Model": "Qwen3-8B",
105
+ "Method": "MDAgent2-RUNTIME",
106
+ "Exec-Success@3 (%)": 28.63,
107
+ "Code-Score-Human": 8.75,
108
+ },
109
+ {
110
+ "#": 4,
111
+ "Model": "**MD-Code-8B** (Ours)",
112
+ "Method": "MDAgent",
113
+ "Exec-Success@3 (%)": 27.12,
114
+ "Code-Score-Human": 9.15,
115
+ },
116
+ {
117
+ "#": 5,
118
+ "Model": "Qwen3-32B",
119
+ "Method": "MDAgent",
120
+ "Exec-Success@3 (%)": 25.44,
121
+ "Code-Score-Human": 8.96,
122
+ },
123
+ {
124
+ "#": 6,
125
+ "Model": "Qwen3-8B",
126
+ "Method": "MDAgent",
127
+ "Exec-Success@3 (%)": 19.08,
128
+ "Code-Score-Human": 8.31,
129
+ },
130
+ {
131
+ "#": 7,
132
+ "Model": "**MD-Code-8B** (Ours)",
133
+ "Method": "Direct Prompting",
134
+ "Exec-Success@3 (%)": 14.23,
135
+ "Code-Score-Human": 9.29,
136
+ },
137
+ {
138
+ "#": 8,
139
+ "Model": "Qwen3-32B",
140
+ "Method": "Direct Prompting",
141
+ "Exec-Success@3 (%)": 12.54,
142
+ "Code-Score-Human": 8.87,
143
+ },
144
+ {
145
+ "#": 9,
146
+ "Model": "Qwen3-8B",
147
+ "Method": "Direct Prompting",
148
+ "Exec-Success@3 (%)": 7.60,
149
+ "Code-Score-Human": 7.92,
150
+ },
151
+ ]
152
+ return pd.DataFrame(data)
153
+
154
+
155
+ # Build DataFrames
156
+ QA_DF = get_qa_leaderboard_df()
157
+ CODEGEN_DF = get_codegen_leaderboard_df()
158
+
159
+
160
+ # =====================================================
161
+ # Gradio App
162
+ # =====================================================
163
+
164
  demo = gr.Blocks(css=custom_css)
165
  with demo:
166
  gr.HTML(TITLE)
167
  gr.Markdown(INTRODUCTION_TEXT, elem_classes="markdown-text")
168
 
169
  with gr.Tabs(elem_classes="tab-buttons") as tabs:
170
+ # ---- Tab 1: QA Benchmark ----
171
+ with gr.TabItem("📝 QA Benchmark", elem_id="qa-benchmark-tab", id=0):
172
+ gr.Markdown(
173
+ "### Knowledge & Syntax QA Performance\n"
174
+ "Performance comparison on MD-KnowledgeEval and LAMMPS-SyntaxEval. "
175
+ "**Delta vs 8B** indicates improvement over the Qwen3-8B baseline.",
176
+ elem_classes="markdown-text",
177
+ )
178
+ qa_table = gr.Dataframe(
179
+ value=QA_DF,
180
+ datatype=["number", "markdown", "str", "number", "number", "number", "number"],
181
+ interactive=False,
182
+ elem_id="qa-leaderboard-table",
183
+ )
184
 
185
+ # ---- Tab 2: Code Generation Benchmark ----
186
+ with gr.TabItem("💻 Code Generation", elem_id="codegen-benchmark-tab", id=1):
187
+ gr.Markdown(
188
+ "### LAMMPS Code Generation Performance\n"
189
+ "Comparison of Exec-Success@3 and Code-Score-Human across different methods and backbone models. "
190
+ "**Exec-Success@3**: proportion of tasks with at least one executable candidate out of 3. "
191
+ "**Code-Score-Human**: expert rating in [0, 10].",
192
+ elem_classes="markdown-text",
193
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
194
 
195
  with gr.Row():
196
+ method_filter = gr.Dropdown(
197
+ choices=["All", "MDAgent2-RUNTIME", "MDAgent", "Direct Prompting"],
198
+ value="All",
199
+ label="Filter by Method",
200
+ interactive=True,
201
+ )
202
+
203
+ codegen_table = gr.Dataframe(
204
+ value=CODEGEN_DF,
205
+ datatype=["number", "markdown", "str", "number", "number"],
206
+ interactive=False,
207
+ elem_id="codegen-leaderboard-table",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
208
  )
209
 
210
+ def filter_codegen(method):
211
+ if method == "All":
212
+ df = CODEGEN_DF.copy()
213
+ else:
214
+ df = CODEGEN_DF[CODEGEN_DF["Method"] == method].copy()
215
+ df["#"] = range(1, len(df) + 1)
216
+ return df
217
+
218
+ method_filter.change(filter_codegen, inputs=[method_filter], outputs=[codegen_table])
219
+
220
+ # ---- Tab 3: About ----
221
+ with gr.TabItem("📖 About", elem_id="about-tab", id=2):
222
+ gr.Markdown(LLM_BENCHMARKS_TEXT, elem_classes="markdown-text")
223
+
224
  with gr.Row():
225
  with gr.Accordion("📙 Citation", open=False):
226
  citation_button = gr.Textbox(
227
  value=CITATION_BUTTON_TEXT,
228
  label=CITATION_BUTTON_LABEL,
229
+ lines=10,
230
  elem_id="citation-button",
231
  show_copy_button=True,
232
  )
233
 
234
+ demo.queue(default_concurrency_limit=40).launch()
 
 
 
requirements.txt CHANGED
@@ -1,16 +1,2 @@
1
- APScheduler
2
- black
3
- datasets
4
- gradio
5
- gradio[oauth]
6
- gradio_leaderboard==0.0.13
7
- gradio_client
8
- huggingface-hub>=0.18.0
9
- matplotlib
10
- numpy
11
  pandas
12
- python-dateutil
13
- tqdm
14
- transformers
15
- tokenizers>=0.15.0
16
- sentencepiece
 
1
+ gradio>=4.0.0
 
 
 
 
 
 
 
 
 
2
  pandas
 
 
 
 
 
src/about.py CHANGED
@@ -1,6 +1,7 @@
1
  from dataclasses import dataclass
2
  from enum import Enum
3
 
 
4
  @dataclass
5
  class Task:
6
  benchmark: str
@@ -8,65 +9,106 @@ class Task:
8
  col_name: str
9
 
10
 
11
- # Select your tasks here
12
- # ---------------------------------------------------
13
- class Tasks(Enum):
14
- # task_key in the json file, metric_key in the json file, name to display in the leaderboard
15
- task0 = Task("anli_r1", "acc", "ANLI")
16
- task1 = Task("logiqa", "acc_norm", "LogiQA")
17
 
18
- NUM_FEWSHOT = 0 # Change with your few shot
19
- # ---------------------------------------------------
 
 
20
 
21
 
 
22
 
23
- # Your leaderboard name
24
- TITLE = """<h1 align="center" id="space-title">Demo leaderboard</h1>"""
25
 
26
- # What does your leaderboard evaluate?
 
27
  INTRODUCTION_TEXT = """
28
- Intro text
 
 
 
 
 
 
 
 
29
  """
30
 
31
- # Which evaluations are you running? how can people reproduce what you have?
32
- LLM_BENCHMARKS_TEXT = f"""
33
- ## How it works
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34
 
35
  ## Reproducibility
36
- To reproduce our results, here is the commands you can run:
37
 
 
38
  """
39
 
40
  EVALUATION_QUEUE_TEXT = """
41
- ## Some good practices before submitting a model
42
 
43
- ### 1) Make sure you can load your model and tokenizer using AutoClasses:
 
 
44
  ```python
45
  from transformers import AutoConfig, AutoModel, AutoTokenizer
46
- config = AutoConfig.from_pretrained("your model name", revision=revision)
47
- model = AutoModel.from_pretrained("your model name", revision=revision)
48
- tokenizer = AutoTokenizer.from_pretrained("your model name", revision=revision)
49
  ```
50
- If this step fails, follow the error messages to debug your model before submitting it. It's likely your model has been improperly uploaded.
51
 
52
- Note: make sure your model is public!
53
- Note: if your model needs `use_remote_code=True`, we do not support this option yet but we are working on adding it, stay posted!
 
54
 
55
- ### 2) Convert your model weights to [safetensors](https://huggingface.co/docs/safetensors/index)
56
- It's a new format for storing weights which is safer and faster to load and use. It will also allow us to add the number of parameters of your model to the `Extended Viewer`!
57
-
58
- ### 3) Make sure your model has an open license!
59
- This is a leaderboard for Open LLMs, and we'd love for as many people as possible to know they can use your model 🤗
60
-
61
- ### 4) Fill up your model card
62
- When we add extra information about models to the leaderboard, it will be automatically taken from the model card
63
-
64
- ## In case of model failure
65
- If your model is displayed in the `FAILED` category, its execution stopped.
66
- Make sure you have followed the above steps first.
67
- If everything is done, check you can launch the EleutherAIHarness on your model locally, using the above command without modifications (you can add `--limit` to limit the number of examples per task).
68
  """
69
 
70
  CITATION_BUTTON_LABEL = "Copy the following snippet to cite these results"
71
- CITATION_BUTTON_TEXT = r"""
72
- """
 
 
 
 
 
1
  from dataclasses import dataclass
2
  from enum import Enum
3
 
4
+
5
  @dataclass
6
  class Task:
7
  benchmark: str
 
9
  col_name: str
10
 
11
 
12
+ # QA Benchmark Tasks
13
+ class QATasks(Enum):
14
+ overall_avg = Task("overall_avg", "score", "Overall Avg")
15
+ knowledge = Task("knowledge", "score", "MD-KnowledgeEval")
16
+ syntax = Task("syntax", "score", "LAMMPS-SyntaxEval")
17
+
18
 
19
+ # Code Generation Benchmark Tasks
20
+ class CodeGenTasks(Enum):
21
+ exec_success_at_3 = Task("exec_success_at_3", "score", "Exec-Success@3 (%)")
22
+ code_score_human = Task("code_score_human", "score", "Code-Score-Human")
23
 
24
 
25
+ NUM_FEWSHOT = 0
26
 
 
 
27
 
28
+ TITLE = """<h1 align="center" id="space-title">MD-EvalBench: Molecular Dynamics LLM Benchmark</h1>"""
29
+
30
  INTRODUCTION_TEXT = """
31
+ **MD-EvalBench** is the first comprehensive benchmark for evaluating Large Language Models in the Molecular Dynamics (MD) domain,
32
+ proposed in the paper *"MDAgent2: Large Language Model for Code Generation and Knowledge Q&A in Molecular Dynamics"*.
33
+
34
+ The benchmark consists of three evaluation datasets:
35
+ - **MD-KnowledgeEval** (336 questions): Theoretical knowledge assessment covering interatomic potentials, integration algorithms, equilibrium conditions, and statistical ensembles.
36
+ - **LAMMPS-SyntaxEval** (368 questions): Command and syntax understanding assessment for LAMMPS scripting.
37
+ - **LAMMPS-CodeGenEval** (566 tasks): Automatic code generation quality assessment for executable LAMMPS scripts.
38
+
39
+ Models are evaluated on both **Question Answering** (knowledge + syntax) and **Code Generation** (execution success + human scoring) capabilities.
40
  """
41
 
42
+ LLM_BENCHMARKS_TEXT = """
43
+ ## Evaluation Protocol
44
+
45
+ All experiments are repeated three times and the average results are reported.
46
+
47
+ ### QA Evaluation (MD-KnowledgeEval + LAMMPS-SyntaxEval)
48
+ - Four question types: single-choice, multiple-choice, fill-in-the-blank, and short-answer
49
+ - Three difficulty levels: Easy, Medium, Hard
50
+ - Score: accuracy percentage (0-100)
51
+
52
+ ### Code Generation Evaluation (LAMMPS-CodeGenEval)
53
+ - **Exec-Success@3**: Proportion of tasks for which at least one of 3 generated candidates can be successfully executed in LAMMPS
54
+ - **Code-Score-Human**: Subjective rating in [0, 10] by domain experts based on readability, robustness, and physical correctness
55
+
56
+ ### Evaluation Dimensions for LAMMPS Code
57
+ 1. Syntax Correctness
58
+ 2. Logical Consistency
59
+ 3. Parameter Rationality
60
+ 4. Core Logic Accuracy
61
+ 5. Logical Completeness
62
+ 6. Code Completeness
63
+ 7. Result Validity
64
+ 8. Physical Soundness
65
+
66
+ ### Generation Settings
67
+ - **Direct Prompting**: Single prompt without tool integration or execution feedback
68
+ - **MDAgent**: Multi-agent framework with generate-evaluate-rewrite loop (prior work)
69
+ - **MDAgent2-RUNTIME**: Deployable multi-agent system integrating code generation, execution, evaluation, and self-correction
70
+
71
+ ## Dataset Statistics
72
+
73
+ | Dataset | Samples |
74
+ |---------|---------|
75
+ | MD-KnowledgeEval | 336 |
76
+ | LAMMPS-SyntaxEval | 368 |
77
+ | LAMMPS-CodeGenEval | 566 |
78
 
79
  ## Reproducibility
 
80
 
81
+ Models are evaluated using the MD-EvalBench benchmark suite. For detailed methodology, please refer to the paper.
82
  """
83
 
84
  EVALUATION_QUEUE_TEXT = """
85
+ ## Submit your model for evaluation
86
 
87
+ ### Requirements
88
+ 1. Your model must be publicly available on the Hugging Face Hub
89
+ 2. Model should be compatible with AutoClasses:
90
  ```python
91
  from transformers import AutoConfig, AutoModel, AutoTokenizer
92
+ config = AutoConfig.from_pretrained("your-model-name", revision=revision)
93
+ model = AutoModel.from_pretrained("your-model-name", revision=revision)
94
+ tokenizer = AutoTokenizer.from_pretrained("your-model-name", revision=revision)
95
  ```
 
96
 
97
+ 3. Convert weights to [safetensors](https://huggingface.co/docs/safetensors/index) format
98
+ 4. Ensure your model has an open license
99
+ 5. Fill up your model card with training details
100
 
101
+ ### Evaluation Process
102
+ Submitted models will be evaluated on all three MD-EvalBench datasets:
103
+ - MD-KnowledgeEval (knowledge QA)
104
+ - LAMMPS-SyntaxEval (syntax QA)
105
+ - LAMMPS-CodeGenEval (code generation)
 
 
 
 
 
 
 
 
106
  """
107
 
108
  CITATION_BUTTON_LABEL = "Copy the following snippet to cite these results"
109
+ CITATION_BUTTON_TEXT = r"""@article{shi2026mdagent2,
110
+ title={MDAgent2: Large Language Model for Code Generation and Knowledge Q\&A in Molecular Dynamics},
111
+ author={Shi, Zhuofan and A, Hubao and Shao, Yufei and Dai, Mengyan and Yu, Yadong and Xiang, Pan and Huang, Dongliang and An, Hongxu and Xin, Chunxiao and Shen, Haiyang and Wang, Zhenyu and Na, Yunshan and Ma, Yun and Huang, Gang and Jing, Xiang},
112
+ journal={Science China Information Sciences},
113
+ year={2026}
114
+ }"""
src/display/utils.py CHANGED
@@ -3,15 +3,13 @@ from enum import Enum
3
 
4
  import pandas as pd
5
 
6
- from src.about import Tasks
 
7
 
8
  def fields(raw_class):
9
  return [v for k, v in raw_class.__dict__.items() if k[:2] != "__" and k[-2:] != "__"]
10
 
11
 
12
- # These classes are for user facing column names,
13
- # to avoid having to change them all around the code
14
- # when a modif is needed
15
  @dataclass
16
  class ColumnContent:
17
  name: str
@@ -20,45 +18,42 @@ class ColumnContent:
20
  hidden: bool = False
21
  never_hidden: bool = False
22
 
23
- ## Leaderboard columns
24
- auto_eval_column_dict = []
25
- # Init
26
- auto_eval_column_dict.append(["model_type_symbol", ColumnContent, ColumnContent("T", "str", True, never_hidden=True)])
27
- auto_eval_column_dict.append(["model", ColumnContent, ColumnContent("Model", "markdown", True, never_hidden=True)])
28
- #Scores
29
- auto_eval_column_dict.append(["average", ColumnContent, ColumnContent("Average ⬆️", "number", True)])
30
- for task in Tasks:
31
- auto_eval_column_dict.append([task.name, ColumnContent, ColumnContent(task.value.col_name, "number", True)])
32
- # Model information
33
- auto_eval_column_dict.append(["model_type", ColumnContent, ColumnContent("Type", "str", False)])
34
- auto_eval_column_dict.append(["architecture", ColumnContent, ColumnContent("Architecture", "str", False)])
35
- auto_eval_column_dict.append(["weight_type", ColumnContent, ColumnContent("Weight type", "str", False, True)])
36
- auto_eval_column_dict.append(["precision", ColumnContent, ColumnContent("Precision", "str", False)])
37
- auto_eval_column_dict.append(["license", ColumnContent, ColumnContent("Hub License", "str", False)])
38
- auto_eval_column_dict.append(["params", ColumnContent, ColumnContent("#Params (B)", "number", False)])
39
- auto_eval_column_dict.append(["likes", ColumnContent, ColumnContent("Hub ❤️", "number", False)])
40
- auto_eval_column_dict.append(["still_on_hub", ColumnContent, ColumnContent("Available on the hub", "bool", False)])
41
- auto_eval_column_dict.append(["revision", ColumnContent, ColumnContent("Model sha", "str", False, False)])
42
-
43
- # We use make dataclass to dynamically fill the scores from Tasks
44
- AutoEvalColumn = make_dataclass("AutoEvalColumn", auto_eval_column_dict, frozen=True)
45
-
46
- ## For the queue columns in the submission tab
47
- @dataclass(frozen=True)
48
- class EvalQueueColumn: # Queue column
49
- model = ColumnContent("model", "markdown", True)
50
- revision = ColumnContent("revision", "str", True)
51
- private = ColumnContent("private", "bool", True)
52
- precision = ColumnContent("precision", "str", True)
53
- weight_type = ColumnContent("weight_type", "str", "Original")
54
- status = ColumnContent("status", "str", True)
55
-
56
- ## All the model information that we might need
57
  @dataclass
58
  class ModelDetails:
59
  name: str
60
  display_name: str = ""
61
- symbol: str = "" # emoji
62
 
63
 
64
  class ModelType(Enum):
@@ -83,11 +78,13 @@ class ModelType(Enum):
83
  return ModelType.IFT
84
  return ModelType.Unknown
85
 
 
86
  class WeightType(Enum):
87
  Adapter = ModelDetails("Adapter")
88
  Original = ModelDetails("Original")
89
  Delta = ModelDetails("Delta")
90
 
 
91
  class Precision(Enum):
92
  float16 = ModelDetails("float16")
93
  bfloat16 = ModelDetails("bfloat16")
@@ -99,12 +96,3 @@ class Precision(Enum):
99
  if precision in ["torch.bfloat16", "bfloat16"]:
100
  return Precision.bfloat16
101
  return Precision.Unknown
102
-
103
- # Column selection
104
- COLS = [c.name for c in fields(AutoEvalColumn) if not c.hidden]
105
-
106
- EVAL_COLS = [c.name for c in fields(EvalQueueColumn)]
107
- EVAL_TYPES = [c.type for c in fields(EvalQueueColumn)]
108
-
109
- BENCHMARK_COLS = [t.value.col_name for t in Tasks]
110
-
 
3
 
4
  import pandas as pd
5
 
6
+ from src.about import QATasks, CodeGenTasks
7
+
8
 
9
  def fields(raw_class):
10
  return [v for k, v in raw_class.__dict__.items() if k[:2] != "__" and k[-2:] != "__"]
11
 
12
 
 
 
 
13
  @dataclass
14
  class ColumnContent:
15
  name: str
 
18
  hidden: bool = False
19
  never_hidden: bool = False
20
 
21
+
22
+ # ---- QA Leaderboard columns ----
23
+ qa_column_dict = []
24
+ qa_column_dict.append(["rank", ColumnContent, ColumnContent("#", "number", True, never_hidden=True)])
25
+ qa_column_dict.append(["model", ColumnContent, ColumnContent("Model", "markdown", True, never_hidden=True)])
26
+ qa_column_dict.append(["size_access", ColumnContent, ColumnContent("Size / Access", "str", True)])
27
+ for task in QATasks:
28
+ qa_column_dict.append([task.name, ColumnContent, ColumnContent(task.value.col_name, "number", True)])
29
+ qa_column_dict.append(["delta_overall", ColumnContent, ColumnContent("Delta vs 8B", "number", True)])
30
+
31
+ QALeaderboardColumn = make_dataclass("QALeaderboardColumn", qa_column_dict, frozen=True)
32
+
33
+ QA_COLS = [c.name for c in fields(QALeaderboardColumn) if not c.hidden]
34
+ QA_BENCHMARK_COLS = [t.value.col_name for t in QATasks]
35
+
36
+
37
+ # ---- Code Generation Leaderboard columns ----
38
+ codegen_column_dict = []
39
+ codegen_column_dict.append(["rank", ColumnContent, ColumnContent("#", "number", True, never_hidden=True)])
40
+ codegen_column_dict.append(["model", ColumnContent, ColumnContent("Model", "markdown", True, never_hidden=True)])
41
+ codegen_column_dict.append(["method", ColumnContent, ColumnContent("Method", "str", True)])
42
+ for task in CodeGenTasks:
43
+ codegen_column_dict.append([task.name, ColumnContent, ColumnContent(task.value.col_name, "number", True)])
44
+
45
+ CodeGenLeaderboardColumn = make_dataclass("CodeGenLeaderboardColumn", codegen_column_dict, frozen=True)
46
+
47
+ CODEGEN_COLS = [c.name for c in fields(CodeGenLeaderboardColumn) if not c.hidden]
48
+ CODEGEN_BENCHMARK_COLS = [t.value.col_name for t in CodeGenTasks]
49
+
50
+
51
+ # ---- Model Types (kept for submission compatibility) ----
 
 
 
52
  @dataclass
53
  class ModelDetails:
54
  name: str
55
  display_name: str = ""
56
+ symbol: str = ""
57
 
58
 
59
  class ModelType(Enum):
 
78
  return ModelType.IFT
79
  return ModelType.Unknown
80
 
81
+
82
  class WeightType(Enum):
83
  Adapter = ModelDetails("Adapter")
84
  Original = ModelDetails("Original")
85
  Delta = ModelDetails("Delta")
86
 
87
+
88
  class Precision(Enum):
89
  float16 = ModelDetails("float16")
90
  bfloat16 = ModelDetails("bfloat16")
 
96
  if precision in ["torch.bfloat16", "bfloat16"]:
97
  return Precision.bfloat16
98
  return Precision.Unknown
 
 
 
 
 
 
 
 
 
src/envs.py CHANGED
@@ -4,22 +4,20 @@ from huggingface_hub import HfApi
4
 
5
  # Info to change for your repository
6
  # ----------------------------------
7
- TOKEN = os.environ.get("HF_TOKEN") # A read/write token for your org
8
 
9
- OWNER = "demo-leaderboard-backend" # Change to your org - don't forget to create a results and request dataset, with the correct format!
10
  # ----------------------------------
11
 
12
- REPO_ID = f"{OWNER}/leaderboard"
13
- QUEUE_REPO = f"{OWNER}/requests"
14
- RESULTS_REPO = f"{OWNER}/results"
15
 
16
  # If you setup a cache later, just change HF_HOME
17
- CACHE_PATH=os.getenv("HF_HOME", ".")
18
 
19
  # Local caches
20
  EVAL_REQUESTS_PATH = os.path.join(CACHE_PATH, "eval-queue")
21
  EVAL_RESULTS_PATH = os.path.join(CACHE_PATH, "eval-results")
22
- EVAL_REQUESTS_PATH_BACKEND = os.path.join(CACHE_PATH, "eval-queue-bk")
23
- EVAL_RESULTS_PATH_BACKEND = os.path.join(CACHE_PATH, "eval-results-bk")
24
 
25
  API = HfApi(token=TOKEN)
 
4
 
5
  # Info to change for your repository
6
  # ----------------------------------
7
+ TOKEN = os.environ.get("HF_TOKEN") # A read/write token for your org
8
 
9
+ OWNER = "MDAgent2" # Change to your org
10
  # ----------------------------------
11
 
12
+ REPO_ID = f"{OWNER}/MD-EvalBench"
13
+ QUEUE_REPO = f"{OWNER}/md-eval-requests"
14
+ RESULTS_REPO = f"{OWNER}/md-eval-results"
15
 
16
  # If you setup a cache later, just change HF_HOME
17
+ CACHE_PATH = os.getenv("HF_HOME", ".")
18
 
19
  # Local caches
20
  EVAL_REQUESTS_PATH = os.path.join(CACHE_PATH, "eval-queue")
21
  EVAL_RESULTS_PATH = os.path.join(CACHE_PATH, "eval-results")
 
 
22
 
23
  API = HfApi(token=TOKEN)