enerdatasynth 0.4.1__py3-none-any.whl
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.
- enerdatasynth/__init__.py +71 -0
- enerdatasynth/cli.py +214 -0
- enerdatasynth/data/__init__.py +0 -0
- enerdatasynth/data/preprocess.py +447 -0
- enerdatasynth/data/temperature.py +386 -0
- enerdatasynth/diffusion/__init__.py +0 -0
- enerdatasynth/diffusion/ddpm.py +120 -0
- enerdatasynth/diffusion/schedules.py +38 -0
- enerdatasynth/evaluation/__init__.py +0 -0
- enerdatasynth/evaluation/baselines.py +72 -0
- enerdatasynth/evaluation/calibration.py +140 -0
- enerdatasynth/evaluation/failure_analysis.py +192 -0
- enerdatasynth/evaluation/metrics.py +58 -0
- enerdatasynth/evaluation/results_report.py +123 -0
- enerdatasynth/generators/__init__.py +13 -0
- enerdatasynth/generators/base.py +59 -0
- enerdatasynth/generators/load.py +165 -0
- enerdatasynth/models/__init__.py +54 -0
- enerdatasynth/models/denoiser.py +87 -0
- enerdatasynth/models/transformer.py +96 -0
- enerdatasynth/sampling/__init__.py +0 -0
- enerdatasynth/sampling/generate.py +91 -0
- enerdatasynth/sdk.py +281 -0
- enerdatasynth/training/__init__.py +0 -0
- enerdatasynth/training/sweep.py +224 -0
- enerdatasynth/training/train.py +183 -0
- enerdatasynth/utils/__init__.py +0 -0
- enerdatasynth/utils/config.py +183 -0
- enerdatasynth/visualization/__init__.py +0 -0
- enerdatasynth/visualization/plots.py +218 -0
- enerdatasynth-0.4.1.dist-info/METADATA +237 -0
- enerdatasynth-0.4.1.dist-info/RECORD +36 -0
- enerdatasynth-0.4.1.dist-info/WHEEL +5 -0
- enerdatasynth-0.4.1.dist-info/entry_points.txt +2 -0
- enerdatasynth-0.4.1.dist-info/licenses/LICENSE +21 -0
- enerdatasynth-0.4.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"""
|
|
2
|
+
enerdatasynth
|
|
3
|
+
================
|
|
4
|
+
A research SDK for synthetic PJM energy resource profiles. Today that
|
|
5
|
+
means electric load; the public interface is designed so a future
|
|
6
|
+
resource type (e.g. wind) can be added through the same contract —
|
|
7
|
+
see `docs/extending.md`.
|
|
8
|
+
|
|
9
|
+
Primary entry point — you should not need anything else for everyday
|
|
10
|
+
generation:
|
|
11
|
+
|
|
12
|
+
import enerdatasynth
|
|
13
|
+
|
|
14
|
+
load = enerdatasynth.model("pjm_load", zone="PS")
|
|
15
|
+
load.set(month=7, Tmax=86, Tmin=70, weekday=True, holiday=False)
|
|
16
|
+
samples = load.sample(n=100) # (100, 24) array, MW
|
|
17
|
+
|
|
18
|
+
`enerdatasynth.model(...)` never exposes tensors, architecture
|
|
19
|
+
classes, checkpoint paths, or the fact that a DDPM/transformer is
|
|
20
|
+
involved at all. See `docs/api_reference.md` for the full contract.
|
|
21
|
+
|
|
22
|
+
For research/development use — training new checkpoints, computing
|
|
23
|
+
evaluation metrics, running calibration — this top-level namespace
|
|
24
|
+
also re-exports the lower-level building blocks:
|
|
25
|
+
|
|
26
|
+
from enerdatasynth import RunConfig, train_one_config, LoadDiffusionModel
|
|
27
|
+
|
|
28
|
+
For anything not re-exported here, import directly from the relevant
|
|
29
|
+
submodule (`enerdatasynth.data`, `enerdatasynth.models`,
|
|
30
|
+
`enerdatasynth.diffusion`, `enerdatasynth.training`,
|
|
31
|
+
`enerdatasynth.sampling`, `enerdatasynth.evaluation`,
|
|
32
|
+
`enerdatasynth.visualization`, `enerdatasynth.generators`,
|
|
33
|
+
`enerdatasynth.utils`).
|
|
34
|
+
|
|
35
|
+
Production code in this package never imports from `research_history/`
|
|
36
|
+
— that directory exists only for reproducibility/provenance and is
|
|
37
|
+
not installed as part of the package.
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
from enerdatasynth.sdk import model, ResourceModel
|
|
41
|
+
from enerdatasynth.utils.config import RunConfig, set_seed, DEFAULT_ARCHITECTURE
|
|
42
|
+
from enerdatasynth.models import build_denoiser, TransformerDenoiser, SimpleMLPDenoiser
|
|
43
|
+
from enerdatasynth.diffusion.ddpm import DDPM
|
|
44
|
+
from enerdatasynth.data.preprocess import run_preprocessing
|
|
45
|
+
from enerdatasynth.training.train import train_one_config
|
|
46
|
+
from enerdatasynth.sampling.generate import generate_for_run
|
|
47
|
+
from enerdatasynth.evaluation.metrics import compute_metrics
|
|
48
|
+
from enerdatasynth.evaluation.calibration import calibrate_checkpoint
|
|
49
|
+
from enerdatasynth.generators import BaseGenerator, LoadDiffusionModel
|
|
50
|
+
|
|
51
|
+
__version__ = "0.4.1"
|
|
52
|
+
|
|
53
|
+
__all__ = [
|
|
54
|
+
"__version__",
|
|
55
|
+
"model",
|
|
56
|
+
"ResourceModel",
|
|
57
|
+
"BaseGenerator",
|
|
58
|
+
"LoadDiffusionModel",
|
|
59
|
+
"RunConfig",
|
|
60
|
+
"set_seed",
|
|
61
|
+
"DEFAULT_ARCHITECTURE",
|
|
62
|
+
"build_denoiser",
|
|
63
|
+
"TransformerDenoiser",
|
|
64
|
+
"SimpleMLPDenoiser",
|
|
65
|
+
"DDPM",
|
|
66
|
+
"run_preprocessing",
|
|
67
|
+
"train_one_config",
|
|
68
|
+
"generate_for_run",
|
|
69
|
+
"calibrate_checkpoint",
|
|
70
|
+
"compute_metrics",
|
|
71
|
+
]
|
enerdatasynth/cli.py
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
"""
|
|
2
|
+
enerdatasynth.cli
|
|
3
|
+
====================
|
|
4
|
+
Console-script entry point (`enerdatasynth`, installed via
|
|
5
|
+
`[project.scripts]` in pyproject.toml). Thin argparse wrapper around
|
|
6
|
+
the existing pipeline functions — no new logic lives here, only
|
|
7
|
+
argument parsing and dispatch, so behavior matches calling the
|
|
8
|
+
underlying functions directly.
|
|
9
|
+
|
|
10
|
+
Usage:
|
|
11
|
+
enerdatasynth preprocess
|
|
12
|
+
enerdatasynth train [--architecture transformer|mlp] [--diffusion-steps T] [--hidden-dim H] [--n-layers L] ...
|
|
13
|
+
enerdatasynth sweep [--epochs N] [--full-grid]
|
|
14
|
+
enerdatasynth generate --diffusion-steps T --hidden-dim H --n-layers L
|
|
15
|
+
enerdatasynth calibrate --run-id transformer_T1000_H64_L2
|
|
16
|
+
enerdatasynth evaluate --run-id transformer_T1000_H64_L2
|
|
17
|
+
enerdatasynth report
|
|
18
|
+
enerdatasynth pipeline [--epochs N] [--full-grid] [--skip-preprocess]
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
from __future__ import annotations
|
|
22
|
+
import argparse
|
|
23
|
+
|
|
24
|
+
import numpy as np
|
|
25
|
+
|
|
26
|
+
from enerdatasynth.utils.config import (
|
|
27
|
+
RunConfig, PROCESSED_DIR, DEFAULT_ARCHITECTURE,
|
|
28
|
+
DEFAULT_T, DEFAULT_HIDDEN_DIM, DEFAULT_N_LAYERS, DEFAULT_N_HEADS,
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def _add_run_config_args(parser: argparse.ArgumentParser) -> None:
|
|
33
|
+
parser.add_argument("--config", type=str, default=None,
|
|
34
|
+
help="Load a RunConfig from YAML (e.g. configs/transformer.yaml). "
|
|
35
|
+
"Takes precedence over the flags below.")
|
|
36
|
+
parser.add_argument("--architecture", choices=["transformer", "mlp"], default=DEFAULT_ARCHITECTURE)
|
|
37
|
+
parser.add_argument("--diffusion-steps", type=int, default=DEFAULT_T)
|
|
38
|
+
parser.add_argument("--hidden-dim", type=int, default=DEFAULT_HIDDEN_DIM)
|
|
39
|
+
parser.add_argument("--n-layers", type=int, default=DEFAULT_N_LAYERS)
|
|
40
|
+
parser.add_argument("--n-heads", type=int, default=DEFAULT_N_HEADS)
|
|
41
|
+
parser.add_argument("--batch-size", type=int, default=None)
|
|
42
|
+
parser.add_argument("--lr", type=float, default=None)
|
|
43
|
+
parser.add_argument("--max-epochs", type=int, default=None)
|
|
44
|
+
parser.add_argument("--patience", type=int, default=None)
|
|
45
|
+
parser.add_argument("--seed", type=int, default=None)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def _run_config_from_args(args: argparse.Namespace) -> RunConfig:
|
|
49
|
+
if getattr(args, "config", None):
|
|
50
|
+
return RunConfig.from_yaml(args.config)
|
|
51
|
+
|
|
52
|
+
kwargs = dict(
|
|
53
|
+
architecture=args.architecture,
|
|
54
|
+
diffusion_steps=args.diffusion_steps,
|
|
55
|
+
hidden_dim=args.hidden_dim,
|
|
56
|
+
n_layers=args.n_layers,
|
|
57
|
+
n_heads=args.n_heads,
|
|
58
|
+
)
|
|
59
|
+
for field in ("batch_size", "lr", "max_epochs", "patience", "seed"):
|
|
60
|
+
value = getattr(args, field, None)
|
|
61
|
+
if value is not None:
|
|
62
|
+
kwargs[field] = value
|
|
63
|
+
return RunConfig(**kwargs)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def cmd_preprocess(args: argparse.Namespace) -> None:
|
|
67
|
+
from enerdatasynth.data.preprocess import run_preprocessing
|
|
68
|
+
run_preprocessing()
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def cmd_train(args: argparse.Namespace) -> None:
|
|
72
|
+
from enerdatasynth.training.train import train_one_config
|
|
73
|
+
cfg = _run_config_from_args(args)
|
|
74
|
+
X_train = np.load(PROCESSED_DIR / "X_daily_profiles.npy")
|
|
75
|
+
Z_train = np.load(PROCESSED_DIR / "Z_conditions.npy")
|
|
76
|
+
X_val = np.load(PROCESSED_DIR / "X_daily_profiles_val.npy")
|
|
77
|
+
Z_val = np.load(PROCESSED_DIR / "Z_conditions_val.npy")
|
|
78
|
+
train_one_config(X_train, Z_train, X_val, Z_val, cfg)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def cmd_sweep(args: argparse.Namespace) -> None:
|
|
82
|
+
from enerdatasynth.training.sweep import run_sweep
|
|
83
|
+
run_sweep(max_epochs=args.epochs, full_grid=args.full_grid)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def cmd_generate(args: argparse.Namespace) -> None:
|
|
87
|
+
from enerdatasynth.sampling.generate import generate_for_run
|
|
88
|
+
cfg = _run_config_from_args(args)
|
|
89
|
+
generate_for_run(
|
|
90
|
+
run_id=cfg.run_id,
|
|
91
|
+
diffusion_steps=cfg.diffusion_steps,
|
|
92
|
+
hidden_dim=cfg.hidden_dim,
|
|
93
|
+
n_layers=cfg.n_layers,
|
|
94
|
+
architecture=cfg.architecture,
|
|
95
|
+
n_heads=cfg.n_heads,
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def cmd_calibrate(args: argparse.Namespace) -> None:
|
|
100
|
+
from enerdatasynth.evaluation.calibration import calibrate_checkpoint
|
|
101
|
+
result = calibrate_checkpoint(
|
|
102
|
+
run_id=args.run_id,
|
|
103
|
+
architecture=args.architecture,
|
|
104
|
+
diffusion_steps=args.diffusion_steps,
|
|
105
|
+
hidden_dim=args.hidden_dim,
|
|
106
|
+
n_layers=args.n_layers,
|
|
107
|
+
n_heads=args.n_heads,
|
|
108
|
+
)
|
|
109
|
+
print(f"Scalar offset: {result['scalar']:+.5f} (saved to {result['path']})")
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def cmd_evaluate(args: argparse.Namespace) -> None:
|
|
113
|
+
from enerdatasynth.visualization.plots import run_all_validation_plots
|
|
114
|
+
from enerdatasynth.evaluation.failure_analysis import analyze, write_failure_analysis_md
|
|
115
|
+
run_all_validation_plots(args.run_id)
|
|
116
|
+
result = analyze(args.run_id)
|
|
117
|
+
write_failure_analysis_md(result)
|
|
118
|
+
print(f"Issues detected: {len(result['issues'])}")
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def cmd_report(args: argparse.Namespace) -> None:
|
|
122
|
+
from enerdatasynth.evaluation.results_report import generate_results_summary
|
|
123
|
+
path = generate_results_summary()
|
|
124
|
+
print(f"Saved: {path}")
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def cmd_pipeline(args: argparse.Namespace) -> None:
|
|
128
|
+
from enerdatasynth.data.preprocess import run_preprocessing
|
|
129
|
+
from enerdatasynth.training.sweep import run_sweep
|
|
130
|
+
from enerdatasynth.sampling.generate import generate_for_run
|
|
131
|
+
from enerdatasynth.evaluation.calibration import calibrate_checkpoint
|
|
132
|
+
from enerdatasynth.visualization.plots import run_all_validation_plots
|
|
133
|
+
from enerdatasynth.evaluation.failure_analysis import analyze, write_failure_analysis_md
|
|
134
|
+
from enerdatasynth.evaluation.results_report import generate_results_summary
|
|
135
|
+
|
|
136
|
+
if not args.skip_preprocess:
|
|
137
|
+
run_preprocessing()
|
|
138
|
+
|
|
139
|
+
df = run_sweep(max_epochs=args.epochs, full_grid=args.full_grid)
|
|
140
|
+
best_row = df.sort_values("best_val_loss").iloc[0]
|
|
141
|
+
run_id = best_row["run_id"]
|
|
142
|
+
architecture = best_row.get("architecture", DEFAULT_ARCHITECTURE)
|
|
143
|
+
n_heads = int(best_row["n_heads"]) if "n_heads" in best_row else DEFAULT_N_HEADS
|
|
144
|
+
|
|
145
|
+
generate_for_run(
|
|
146
|
+
run_id=run_id,
|
|
147
|
+
diffusion_steps=int(best_row["diffusion_steps"]),
|
|
148
|
+
hidden_dim=int(best_row["hidden_dim"]),
|
|
149
|
+
n_layers=int(best_row["n_layers"]),
|
|
150
|
+
architecture=architecture,
|
|
151
|
+
n_heads=n_heads,
|
|
152
|
+
)
|
|
153
|
+
calibrate_checkpoint(
|
|
154
|
+
run_id=run_id, architecture=architecture,
|
|
155
|
+
diffusion_steps=int(best_row["diffusion_steps"]),
|
|
156
|
+
hidden_dim=int(best_row["hidden_dim"]),
|
|
157
|
+
n_layers=int(best_row["n_layers"]), n_heads=n_heads,
|
|
158
|
+
)
|
|
159
|
+
run_all_validation_plots(run_id)
|
|
160
|
+
result = analyze(run_id)
|
|
161
|
+
write_failure_analysis_md(result)
|
|
162
|
+
generate_results_summary()
|
|
163
|
+
print(f"\nPipeline complete. Best run: {run_id}")
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def build_parser() -> argparse.ArgumentParser:
|
|
167
|
+
parser = argparse.ArgumentParser(prog="enerdatasynth")
|
|
168
|
+
subparsers = parser.add_subparsers(dest="command", required=True)
|
|
169
|
+
|
|
170
|
+
p_preprocess = subparsers.add_parser("preprocess", help="Build X/Z tensors from raw CSVs")
|
|
171
|
+
p_preprocess.set_defaults(func=cmd_preprocess)
|
|
172
|
+
|
|
173
|
+
p_train = subparsers.add_parser("train", help="Train a single model configuration")
|
|
174
|
+
_add_run_config_args(p_train)
|
|
175
|
+
p_train.set_defaults(func=cmd_train)
|
|
176
|
+
|
|
177
|
+
p_sweep = subparsers.add_parser("sweep", help="Run the hyperparameter sweep")
|
|
178
|
+
p_sweep.add_argument("--epochs", type=int, default=60)
|
|
179
|
+
p_sweep.add_argument("--full-grid", action="store_true")
|
|
180
|
+
p_sweep.set_defaults(func=cmd_sweep)
|
|
181
|
+
|
|
182
|
+
p_generate = subparsers.add_parser("generate", help="Generate synthetic profiles from a trained checkpoint")
|
|
183
|
+
_add_run_config_args(p_generate)
|
|
184
|
+
p_generate.set_defaults(func=cmd_generate)
|
|
185
|
+
|
|
186
|
+
p_calibrate = subparsers.add_parser("calibrate", help="Fit the scalar bias correction for a trained checkpoint")
|
|
187
|
+
_add_run_config_args(p_calibrate)
|
|
188
|
+
p_calibrate.add_argument("--run-id", required=True)
|
|
189
|
+
p_calibrate.set_defaults(func=cmd_calibrate)
|
|
190
|
+
|
|
191
|
+
p_evaluate = subparsers.add_parser("evaluate", help="Run validation plots + failure analysis for a run")
|
|
192
|
+
p_evaluate.add_argument("--run-id", required=True)
|
|
193
|
+
p_evaluate.set_defaults(func=cmd_evaluate)
|
|
194
|
+
|
|
195
|
+
p_report = subparsers.add_parser("report", help="Regenerate reports/results_summary.md")
|
|
196
|
+
p_report.set_defaults(func=cmd_report)
|
|
197
|
+
|
|
198
|
+
p_pipeline = subparsers.add_parser("pipeline", help="Run the full pipeline end-to-end")
|
|
199
|
+
p_pipeline.add_argument("--epochs", type=int, default=60)
|
|
200
|
+
p_pipeline.add_argument("--full-grid", action="store_true")
|
|
201
|
+
p_pipeline.add_argument("--skip-preprocess", action="store_true")
|
|
202
|
+
p_pipeline.set_defaults(func=cmd_pipeline)
|
|
203
|
+
|
|
204
|
+
return parser
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
def main(argv: list[str] | None = None) -> None:
|
|
208
|
+
parser = build_parser()
|
|
209
|
+
args = parser.parse_args(argv)
|
|
210
|
+
args.func(args)
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
if __name__ == "__main__":
|
|
214
|
+
main()
|
|
File without changes
|