Skip to content

Commit 8349098

Browse files
committed
Update docs, timelines bug fix
1 parent 70b4201 commit 8349098

9 files changed

Lines changed: 449 additions & 71 deletions

File tree

README.md

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,32 +2,73 @@
22

33
A Python toolkit for [ML.ENERGY](https://ml.energy) datasets: loading raw results, filtering and analyzing runs, fitting models, and building data packages.
44

5-
Actual data are stored in Hugging Face Hub: [ml-energy/benchmark-v3](https://huggingface.co/datasets/ml-energy/benchmark-v3). This repository contains code for working with the data, not the data itself.
5+
We currently have [The ML.ENERGY Benchmark v3.0](https://github.com/ml-energy/benchmark) dataset, which includes LLM and diffusion inference runs on NVIDIA H100 and B200 GPUs.
6+
Actual data are stored in Hugging Face Hub: [`ml-energy/benchmark-v3`](https://huggingface.co/datasets/ml-energy/benchmark-v3).
7+
This repository contains the toolkit code, not the data itself.
8+
9+
## What the toolkit does
10+
11+
- **Load and filter benchmark runs** with typed, immutable collection classes (`LLMRuns`, `DiffusionRuns`).
12+
- **Extract bulk data** — power timelines, ITL samples, output lengths — as DataFrames.
13+
- **Fit models** — logistic power/latency curves, ITL latency distributions.
14+
- **Build data packages** for publishing to Hugging Face Hub.
615

716
## Installation
817

918
```bash
10-
pip install -e .
19+
pip install mlenergy-data
1120
```
1221

1322
## Quick example
1423

1524
```python
1625
from mlenergy_data.records import LLMRuns
1726

18-
runs = LLMRuns.from_directory("/path/to/compiled/data")
27+
runs = LLMRuns.from_hf()
1928

2029
# Find the most energy-efficient model on GPQA
2130
best = min(runs.task("gpqa"), key=lambda r: r.energy_per_token_joules)
22-
print(f"{best.nickname}: {best.energy_per_token_joules:.3f} J/tok")
31+
print(f"{best.nickname}: {best.energy_per_token_joules:.3f} J/tok on {best.gpu_model}")
2332

2433
# Column access via .data
2534
energies = runs.data.energy_per_token_joules # list[float]
2635
```
2736

37+
Filter, group, and compare across GPU generations and model architectures:
38+
39+
```python
40+
# Compare GPU generations: best energy efficiency per model on GPQA
41+
for gpu, group in runs.task("gpqa").group_by("gpu_model").items():
42+
best = min(group, key=lambda r: r.energy_per_token_joules)
43+
print(f"{gpu}: {best.nickname} @ {best.energy_per_token_joules:.3f} J/tok, "
44+
f"{best.output_throughput_tokens_per_sec:.0f} tok/s")
45+
46+
# MoE, Dense, Hybrid: who's more energy-efficient?
47+
for arch, group in runs.task("gpqa").gpu("B200").group_by("architecture").items():
48+
best = min(group, key=lambda r: r.energy_per_token_joules)
49+
print(f"{arch}: {best.nickname} @ {best.energy_per_token_joules:.3f} J/tok")
50+
```
51+
52+
## Who uses it
53+
54+
- [**The ML.ENERGY Leaderboard v3.0**](https://ml.energy/leaderboard): Benchmark results are loaded and compiled into the leaderboard web app data format.
55+
- [**OpenG2G**](TODO): Datacenter-grid coordination simulation framework; loads benchmark data and fits models.
56+
- [**The ML.ENERGY blog**](https://ml.energy/blog): Analysis scripts for blog posts.
57+
2858
## Documentation
2959

3060
See the full [documentation site](https://ml-energy.github.io/mlenergy-data/) for:
3161

3262
- [Usage guide](https://ml-energy.github.io/mlenergy-data/guide/) — progressive walkthrough from loading data to fitting models.
3363
- [API reference](https://ml-energy.github.io/mlenergy-data/api/records/) — auto-generated from docstrings.
64+
65+
## Citation
66+
67+
```bibtex
68+
@inproceedings{mlenergy-neuripsdb25,
69+
title={The {ML.ENERGY Benchmark}: Toward Automated Inference Energy Measurement and Optimization},
70+
author={Jae-Won Chung and Jeff J. Ma and Ruofan Wu and Jiachen Liu and Oh Jun Kweon and Yuxuan Xia and Zhiyu Wu and Mosharaf Chowdhury},
71+
year={2025},
72+
booktitle={NeurIPS Datasets and Benchmarks},
73+
}
74+
```

data_publishing/DATASET_CARD.md

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# The ML.ENERGY Benchmark V3 Dataset
22

3-
This dataset contains benchmark results from [The ML.ENERGY Benchmark](https://github.com/ml-energy/benchmark).
3+
This dataset contains benchmark results from [The ML.ENERGY Benchmark](https://github.com/ml-energy/benchmark), which includes LLM and diffusion inference runs on NVIDIA H100 and B200 GPUs.
44
You can use [The ML.ENERGY Leaderboard](https://ml.energy) to explore the benchmarking results.
55

66
## Subsets
@@ -10,7 +10,7 @@ You can use [The ML.ENERGY Leaderboard](https://ml.energy) to explore the benchm
1010

1111
## Usage
1212

13-
You can programmatically utilize the dataset using the ML.ENERGY data toolkit.
13+
You can programmatically work with the dataset using the [ML.ENERGY data toolkit](https://github.com/ml-energy/data).
1414

1515
```bash
1616
pip install mlenergy-data
@@ -20,14 +20,36 @@ pip install mlenergy-data
2020
from mlenergy_data.records import LLMRuns, DiffusionRuns
2121

2222
# Load (fast, parquet only ~few MB)
23-
llm = LLMRuns.from_hf()
23+
runs = LLMRuns.from_hf()
2424

25-
# Filter and analyze (parquet only, no download)
26-
for r in llm.task("gpqa").gpu("B200"):
27-
print(r.nickname, r.energy_per_token_joules)
25+
# Find the most energy-efficient model on GPQA
26+
best = min(runs.task("gpqa"), key=lambda r: r.energy_per_token_joules)
27+
print(f"{best.nickname}: {best.energy_per_token_joules:.3f} J/tok on {best.gpu_model}")
2828

29-
# Bulk data methods auto-download raw files as needed
30-
out = llm.task("gpqa").output_lengths()
29+
# Column access via .data
30+
energies = runs.data.energy_per_token_joules # list[float]
31+
```
32+
33+
Filter, group, and compare across GPU generations and model architectures:
34+
35+
```python
36+
# Compare GPU generations: best energy efficiency per model on GPQA
37+
for gpu, group in runs.task("gpqa").group_by("gpu_model").items():
38+
best = min(group, key=lambda r: r.energy_per_token_joules)
39+
print(f"{gpu}: {best.nickname} @ {best.energy_per_token_joules:.3f} J/tok, "
40+
f"{best.output_throughput_tokens_per_sec:.0f} tok/s")
41+
42+
# MoE, Dense, Hybrid: who's more energy-efficient?
43+
for arch, group in runs.task("gpqa").gpu("B200").group_by("architecture").items():
44+
best = min(group, key=lambda r: r.energy_per_token_joules)
45+
print(f"{arch}: {best.nickname} @ {best.energy_per_token_joules:.3f} J/tok")
46+
```
47+
48+
Bulk data methods auto-download raw files as needed:
49+
50+
```python
51+
# Power timelines, output lengths, etc.
52+
power_tl = runs.timelines(metric="power.device_instant")
3153
```
3254

3355
## Schema
@@ -74,7 +96,7 @@ Please direct any issues, questions, or discussions to [The ML.ENERGY Data Toolk
7496

7597
```bibtex
7698
@inproceedings{mlenergy-neuripsdb25,
77-
title={The {ML.ENERGY Benchmark}: Toward Automated Inference Energy Measurement and Optimization},
99+
title={The {ML.ENERGY Benchmark}: Toward Automated Inference Energy Measurement and Optimization},
78100
author={Jae-Won Chung and Jeff J. Ma and Ruofan Wu and Jiachen Liu and Oh Jun Kweon and Yuxuan Xia and Zhiyu Wu and Mosharaf Chowdhury},
79101
year={2025},
80102
booktitle={NeurIPS Datasets and Benchmarks},

docs/guide.md

Lines changed: 56 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,19 @@
44

55
For full working examples of the toolkit in production, see:
66

7-
- [ML.ENERGY Leaderboard data build](https://github.com/ml-energy/leaderboard/blob/main/scripts/build_data.py) -- builds the leaderboard JSON data from benchmark runs
8-
- [ML.ENERGY Blog analysis scripts](https://github.com/ml-energy/data/blob/main/blog_analysis_scripts.py) -- generates figures for the ML.ENERGY blog
9-
- [OpenG2G simulation data build](TODO) -- builds power traces, logistic fits, and latency fits for grid simulation
7+
- ML.ENERGY Leaderboard data build
8+
- Builds the leaderboard JSON data from benchmark runs
9+
- [The ML.ENERGY Leaderboard](https://ml.energy/leaderboard)
10+
- [Data build script](https://github.com/ml-energy/leaderboard/blob/main/scripts/build_data.py)
11+
- ML.ENERGY Blog analysis scripts
12+
- Generates figures for the ML.ENERGY blog post on the V3 benchmark results
13+
- [Blog post](https://ml.energy/blog/measurement/energy/diagnosing-inference-energy-consumption-with-the-mlenergy-leaderboard-v30/)
14+
- [Analysis script](TODO)
15+
- OpenG2G simulation data build
16+
- Builds power traces, logistic fits, and latency distributions for datacenter--grid coordination simulation
17+
- [OpenG2G](TODO)
18+
- [Data build script](TODO)
19+
1020

1121
## Loading benchmark runs
1222

@@ -17,7 +27,8 @@ Each run is a frozen dataclass (`LLMRun` / `DiffusionRun`) with IDE autocomplete
1727
from mlenergy_data.records import LLMRuns, DiffusionRuns
1828

1929
# Load all stable LLM runs from a compiled data directory
20-
runs = LLMRuns.from_directory("/path/to/compiled/data")
30+
root = "/path/to/compiled/data"
31+
runs = LLMRuns.from_directory(root)
2132

2233
# Include unstable runs
2334
runs = LLMRuns.from_directory(root, stable_only=False)
@@ -30,6 +41,9 @@ runs = LLMRuns.from_hf()
3041
diff = DiffusionRuns.from_hf()
3142
```
3243

44+
!!! Note
45+
A "compiled data directory" is one built by `data_publishing/build_hf_data.py` (or downloaded from HF Hub). It contains parquet summary files under `runs/`, raw result files under `llm/` and `diffusion/`, and benchmark config files under `configs/`.
46+
3347
## Filtering
3448

3549
All filter methods return a new collection — chain freely:
@@ -49,6 +63,9 @@ chat_or_gpqa = runs.task("gpqa", "lm-arena-chat")
4963
# By nickname
5064
deepseek = runs.nickname("DeepSeek R1")
5165

66+
# Architecture (LLM only)
67+
moe_models = runs.architecture("MoE")
68+
5269
# Batch size: exact values or range
5370
batch_128 = runs.batch(128)
5471
large_batch = runs.batch(min=64)
@@ -58,6 +75,11 @@ mid_batch = runs.batch(min=16, max=128)
5875
single_gpu = runs.num_gpus(1)
5976
multi_gpu = runs.num_gpus(min=2)
6077

78+
# Stability
79+
# Relevant when you explicitly set stable_only=False at load time to include unstable runs. By default, only stable runs are loaded.
80+
stable_only = runs.stable()
81+
unstable_only = runs.unstable()
82+
6183
# Arbitrary predicate
6284
big_models = runs.where(lambda r: r.total_params_billions > 70)
6385
```
@@ -95,6 +117,17 @@ plt.xlabel("Batch size")
95117
plt.ylabel("Energy per token (J)")
96118
```
97119

120+
**Indexing and concatenation:**
121+
122+
```python
123+
first_run = runs[0]
124+
125+
# Concatenate collections
126+
h100 = runs.gpu("H100")
127+
b200 = runs.gpu("B200")
128+
combined = h100 + b200
129+
```
130+
98131
## Grouping
99132

100133
```python
@@ -113,12 +146,12 @@ for (model, batch), g in runs.group_by("model_id", "max_num_seqs").items():
113146
Python is the analysis layer — no special helper functions needed:
114147

115148
```python
116-
# Best energy per token for each model on a task
117-
for model_id, group in runs.task("gpqa").group_by("model_id").items():
118-
best = min(group, key=lambda r: r.energy_per_token_joules)
119-
print(f"{best.nickname}: {best.energy_per_token_joules:.3f} J/tok")
149+
# Compare GPU generations on a task
150+
for gpu, group in runs.task("lm-arena-chat").group_by("gpu_model").items():
151+
best = min(group, key=lambda r: r.output_throughput_tokens_per_sec)
152+
print(f"{gpu}: {best.nickname} @ {best.output_throughput_tokens_per_sec:.0f} tok/s")
120153

121-
# Comparing GPUs
154+
# Comparing GPUs for a specific model
122155
llama70b = runs.model("meta-llama/Llama-3.1-70B-Instruct")
123156
for gpu, g in llama70b.group_by("gpu_model").items():
124157
plt.scatter(g.data.max_num_seqs, g.data.energy_per_token_joules, label=gpu)
@@ -130,6 +163,14 @@ plt.legend()
130163
These methods return pandas DataFrames for numerical analysis.
131164
When loaded from HF Hub (`from_hf()`), they automatically download only the raw files needed for the current collection. The download scope is determined by your filters. HF Hub caches files locally, so repeated calls are instant.
132165

166+
To eagerly download all raw files upfront, use `prefetch()`:
167+
168+
```python
169+
# Eagerly download all raw files for a filtered collection
170+
runs = LLMRuns.from_hf().task("gpqa").prefetch()
171+
power_tl = runs.timelines(metric="power.device_instant") # no download delay
172+
```
173+
133174
```python
134175
# Power timelines (long-form)
135176
power_tl = runs.timelines(metric="power.device_instant")
@@ -158,6 +199,12 @@ t2i = diff.task("text-to-image")
158199
best = min(t2i, key=lambda r: r.energy_per_generation_joules)
159200
print(f"{best.nickname}: {best.energy_per_generation_joules:.3f} J/image")
160201

202+
# Task field and convenience properties
203+
r = diff[0]
204+
r.task # "text-to-image" or "text-to-video"
205+
r.is_text_to_image # True for text-to-image tasks
206+
r.is_text_to_video # True for text-to-video tasks
207+
161208
# Available filters: task(), model(), gpu(), nickname(), batch(),
162209
# num_gpus(), precision(), where()
163210
```
@@ -206,15 +253,3 @@ avg_itl = model.sample_avg(n_replicas=180, rng=rng)
206253
d = model.to_dict()
207254
model2 = ITLMixtureModel.from_dict(d)
208255
```
209-
210-
## Building a Hugging Face data package
211-
212-
```bash
213-
python data_publishing/build_hf_data.py \
214-
--results-dir /path/to/llm/h100/current/run \
215-
--results-dir /path/to/diffusion/h100/current/run \
216-
--out-dir /tmp/hf_pkg
217-
218-
# Upload to Hugging Face Hub
219-
hf upload-large-folder ml-energy/benchmark-v3 /tmp/hf_pkg --repo-type dataset
220-
```

docs/index.md

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
To aid in working with these datasets, we also provide a Python toolkit: `mlenergy-data`.
55

66
We currently have [The ML.ENERGY Benchmark v3.0](https://github.com/ml-energy/benchmark) dataset, which includes LLM and diffusion inference runs on NVIDIA H100 and B200 GPUs.
7-
Actual data are currently stored in Hugging Face Hub: [`ml-energy/benchmark-v3`](https://huggingface.co/datasets/ml-energy/benchmark-v3).
7+
Actual data are stored in Hugging Face Hub: [`ml-energy/benchmark-v3`](https://huggingface.co/datasets/ml-energy/benchmark-v3).
88

99
## What the toolkit does
1010

@@ -29,6 +29,24 @@ runs = LLMRuns.from_hf()
2929
# Find the most energy-efficient model on GPQA
3030
best = min(runs.task("gpqa"), key=lambda r: r.energy_per_token_joules)
3131
print(f"{best.nickname}: {best.energy_per_token_joules:.3f} J/tok on {best.gpu_model}")
32+
33+
# Column access via .data
34+
energies = runs.data.energy_per_token_joules # list[float]
35+
```
36+
37+
Filter, group, and compare across GPU generations and model architectures:
38+
39+
```python
40+
# Compare GPU generations: best energy efficiency per model on GPQA
41+
for gpu, group in runs.task("gpqa").group_by("gpu_model").items():
42+
best = min(group, key=lambda r: r.energy_per_token_joules)
43+
print(f"{gpu}: {best.nickname} @ {best.energy_per_token_joules:.3f} J/tok, "
44+
f"{best.output_throughput_tokens_per_sec:.0f} tok/s")
45+
46+
# MoE, Dense, Hybrid: who's more energy-efficient?
47+
for arch, group in runs.task("gpqa").gpu("B200").group_by("architecture").items():
48+
best = min(group, key=lambda r: r.energy_per_token_joules)
49+
print(f"{arch}: {best.nickname} @ {best.energy_per_token_joules:.3f} J/tok")
3250
```
3351

3452
## Who uses it
@@ -41,3 +59,14 @@ print(f"{best.nickname}: {best.energy_per_token_joules:.3f} J/tok on {best.gpu_m
4159

4260
- [Guide](guide.md): Progressive walkthrough from loading data to fitting models.
4361
- [API Reference](api/records.md): Auto-generated from docstrings.
62+
63+
## Citation
64+
65+
```bibtex
66+
@inproceedings{mlenergy-neuripsdb25,
67+
title={The {ML.ENERGY Benchmark}: Toward Automated Inference Energy Measurement and Optimization},
68+
author={Jae-Won Chung and Jeff J. Ma and Ruofan Wu and Jiachen Liu and Oh Jun Kweon and Yuxuan Xia and Zhiyu Wu and Mosharaf Chowdhury},
69+
year={2025},
70+
booktitle={NeurIPS Datasets and Benchmarks},
71+
}
72+
```

mlenergy_data/modeling/latency.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,11 @@ def _lognormal_mean_var(self, sigma: float, scale: float) -> tuple[float, float]
3838
return ey, vy
3939

4040
def mean_var(self) -> tuple[float, float]:
41-
"""Compute mean and variance of the two-component mixture."""
41+
"""Compute analytical mean and variance of the two-component mixture.
42+
43+
Returns:
44+
Tuple of (mean, variance) in seconds.
45+
"""
4246
p1 = float(self.pi_steady)
4347
p2 = float(self.pi_stall)
4448
ps = max(p1 + p2, 1e-12)
@@ -56,7 +60,14 @@ def mean_var(self) -> tuple[float, float]:
5660
return mx, vx
5761

5862
def sample_one(self, rng: np.random.Generator) -> float:
59-
"""Draw a single sample from the mixture."""
63+
"""Draw a single ITL sample from the mixture.
64+
65+
Args:
66+
rng: NumPy random generator.
67+
68+
Returns:
69+
Sampled ITL value in seconds.
70+
"""
6071
p1 = float(self.pi_steady)
6172
p2 = float(self.pi_stall)
6273
ps = max(p1 + p2, 1e-12)

mlenergy_data/modeling/logistic.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ class LogisticModel:
2828
b0: float
2929

3030
def eval_x(self, x: float) -> float:
31-
"""Evaluate at continuous x (= log2(batch_size))."""
31+
"""Evaluate at continuous x (typically log2(batch_size))."""
3232
a = self.k * (float(x) - self.x0)
3333
if a >= 0:
3434
ea = math.exp(-a)
@@ -39,7 +39,7 @@ def eval_x(self, x: float) -> float:
3939
return float(self.b0 + self.L * s)
4040

4141
def deriv_wrt_x(self, x: float) -> float:
42-
"""dy/dx for y = b0 + L * sigmoid(k*(x - x0))."""
42+
"""Derivative dy/dx at continuous x."""
4343
a = self.k * (float(x) - self.x0)
4444
if a >= 0:
4545
ea = math.exp(-a)

0 commit comments

Comments
 (0)