modelmark 0.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.
- modelmark-0.1.0/LICENSE +21 -0
- modelmark-0.1.0/PKG-INFO +109 -0
- modelmark-0.1.0/README.md +91 -0
- modelmark-0.1.0/pyproject.toml +31 -0
- modelmark-0.1.0/setup.cfg +4 -0
- modelmark-0.1.0/src/modelmark/__init__.py +3 -0
- modelmark-0.1.0/src/modelmark/__main__.py +5 -0
- modelmark-0.1.0/src/modelmark/common/dataset.py +116 -0
- modelmark-0.1.0/src/modelmark/common/downloader.py +88 -0
- modelmark-0.1.0/src/modelmark/common/loader.py +63 -0
- modelmark-0.1.0/src/modelmark/common/logger.py +34 -0
- modelmark-0.1.0/src/modelmark/common/parser.py +134 -0
- modelmark-0.1.0/src/modelmark/common/report.py +734 -0
- modelmark-0.1.0/src/modelmark/common/tester.py +162 -0
- modelmark-0.1.0/src/modelmark/common/utils.py +105 -0
- modelmark-0.1.0/src/modelmark/config.py +97 -0
- modelmark-0.1.0/src/modelmark/constants.py +34 -0
- modelmark-0.1.0/src/modelmark/modelmark.py +206 -0
- modelmark-0.1.0/src/modelmark/models/conv.py +75 -0
- modelmark-0.1.0/src/modelmark/models/gru.py +45 -0
- modelmark-0.1.0/src/modelmark/models/linear.py +65 -0
- modelmark-0.1.0/src/modelmark/models/lstm.py +43 -0
- modelmark-0.1.0/src/modelmark/models/transformer.py +86 -0
- modelmark-0.1.0/src/modelmark.egg-info/PKG-INFO +109 -0
- modelmark-0.1.0/src/modelmark.egg-info/SOURCES.txt +27 -0
- modelmark-0.1.0/src/modelmark.egg-info/dependency_links.txt +1 -0
- modelmark-0.1.0/src/modelmark.egg-info/entry_points.txt +2 -0
- modelmark-0.1.0/src/modelmark.egg-info/requires.txt +7 -0
- modelmark-0.1.0/src/modelmark.egg-info/top_level.txt +1 -0
modelmark-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Andrew Larin
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
modelmark-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: modelmark
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Benchmark framework for neural network models
|
|
5
|
+
Author: Andrew Larin
|
|
6
|
+
License: MIT
|
|
7
|
+
Requires-Python: >=3.12
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Requires-Dist: numpy>=2.4
|
|
11
|
+
Requires-Dist: pandas>=3.0
|
|
12
|
+
Requires-Dist: torch>=2.12
|
|
13
|
+
Requires-Dist: tqdm>=4.67
|
|
14
|
+
Requires-Dist: playwright>=1.62
|
|
15
|
+
Requires-Dist: rich>=15.0
|
|
16
|
+
Requires-Dist: thop>=0.1
|
|
17
|
+
Dynamic: license-file
|
|
18
|
+
|
|
19
|
+
# ModelMark
|
|
20
|
+
This tool will help you to test NN models against each other, and form a detailed report that is easy to embed to a website.
|
|
21
|
+
|
|
22
|
+
**Model evaluation report example:**
|
|
23
|
+
|
|
24
|
+
<img src="result.png" alt="Evaluation result" width="600">
|
|
25
|
+
|
|
26
|
+
## About:
|
|
27
|
+
|
|
28
|
+
At each testing run iteration, modelmark:
|
|
29
|
+
|
|
30
|
+
1) Selects next dataset, context, model and seed
|
|
31
|
+
2) Seeds the generators for reproducibility
|
|
32
|
+
3) Creates the loader, model and tester objects
|
|
33
|
+
4) Trains the model for E epochs, restores the state with the least validation loss
|
|
34
|
+
5) Tracks the GFLOPs, Memory, Time - all AVG over whole test
|
|
35
|
+
5) Evaluates the model on dataset with metrics from configuration file
|
|
36
|
+
6) Stores the mean result over S runs
|
|
37
|
+
|
|
38
|
+
That way, the more seeds you run, the more "fair" the results are.
|
|
39
|
+
Finally, modelmark will form the report with all the testing results, training stats and your machine metadata.
|
|
40
|
+
|
|
41
|
+
More on training stats:
|
|
42
|
+
|
|
43
|
+
Time - average time per epoch
|
|
44
|
+
Params - total number of model params
|
|
45
|
+
GFLOPs - average per batch
|
|
46
|
+
Peak Memory - max per training iteration
|
|
47
|
+
|
|
48
|
+
Test consists of F * C * M * S runs, where:
|
|
49
|
+
|
|
50
|
+
F - number of dataset files in the config (e.g. ["ETTh1" : ..., "Weather" : ...] - means F = 2)
|
|
51
|
+
C - number of context sizes (e.g. [32, 64, 128] - means C = 3)
|
|
52
|
+
M - number of models (e.g. ["Linear" : ..., "LSTM" : ...] - means M = 2)
|
|
53
|
+
S - number of seeds (e.g. [42, 43, 44] - means S = 2)
|
|
54
|
+
|
|
55
|
+
# Requirements:
|
|
56
|
+
|
|
57
|
+
OS: Windows or Linux
|
|
58
|
+
Python: 3.12+
|
|
59
|
+
|
|
60
|
+
# Usage:
|
|
61
|
+
|
|
62
|
+
1) Install the package
|
|
63
|
+
|
|
64
|
+
pip install "modelmark @ git+https://github.com/gloptim77/ModelMark.git"
|
|
65
|
+
|
|
66
|
+
2) Run the initialization in an empty folder
|
|
67
|
+
|
|
68
|
+
modelmark -t init
|
|
69
|
+
|
|
70
|
+
3.1) It will create two folders "modelmark_files" and "models"
|
|
71
|
+
|
|
72
|
+
In modelmark_files/config.py there are 3 main configs:
|
|
73
|
+
|
|
74
|
+
model_config = {...} - Models hyperparameters (number of layers, hidden dim, kernel size, etc.)
|
|
75
|
+
data_config = {...} - Dataset parameters (path to file, input/output features, train/val ratios, etc.)
|
|
76
|
+
test_config = {...} - Testing options (optimizer, loss criterion, metrics, learning rate, etc.)
|
|
77
|
+
|
|
78
|
+
3.2) (Optional) download the ETT dataset files
|
|
79
|
+
|
|
80
|
+
modelmark -t load
|
|
81
|
+
|
|
82
|
+
4) When your config, model and data are ready, you can run the testing
|
|
83
|
+
|
|
84
|
+
modelmark -t run
|
|
85
|
+
|
|
86
|
+
5) When the test is over, report results will be in files "result.html" and "result.png"
|
|
87
|
+
|
|
88
|
+
Example of the model: "src/modelmark/models/linear.py"
|
|
89
|
+
Example of the config: "src/modelmark/config.py"
|
|
90
|
+
|
|
91
|
+
You will find the detailed config example with description at [src/modelmark/config.py](src/modelmark/config.py).
|
|
92
|
+
|
|
93
|
+
Example Linear model with detailed description at [src/modelmark/models/linear.py](src/modelmark/models/linear.py).
|
|
94
|
+
|
|
95
|
+
You can change the config and add your model files to suit your test requirements.
|
|
96
|
+
|
|
97
|
+
(But make sure that config and models are compatible)
|
|
98
|
+
|
|
99
|
+
## Troubleshooting
|
|
100
|
+
|
|
101
|
+
- **If something doesn't work**
|
|
102
|
+
|
|
103
|
+
- Please open an issue and attach your application logs (found at "modelmark_files/modelmark.log") so I can help you troubleshoot.
|
|
104
|
+
- Try to restart
|
|
105
|
+
```python
|
|
106
|
+
modelmark -t restart
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
- Try to manually delete "modelmark_files" and return to Usage->2)
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# ModelMark
|
|
2
|
+
This tool will help you to test NN models against each other, and form a detailed report that is easy to embed to a website.
|
|
3
|
+
|
|
4
|
+
**Model evaluation report example:**
|
|
5
|
+
|
|
6
|
+
<img src="result.png" alt="Evaluation result" width="600">
|
|
7
|
+
|
|
8
|
+
## About:
|
|
9
|
+
|
|
10
|
+
At each testing run iteration, modelmark:
|
|
11
|
+
|
|
12
|
+
1) Selects next dataset, context, model and seed
|
|
13
|
+
2) Seeds the generators for reproducibility
|
|
14
|
+
3) Creates the loader, model and tester objects
|
|
15
|
+
4) Trains the model for E epochs, restores the state with the least validation loss
|
|
16
|
+
5) Tracks the GFLOPs, Memory, Time - all AVG over whole test
|
|
17
|
+
5) Evaluates the model on dataset with metrics from configuration file
|
|
18
|
+
6) Stores the mean result over S runs
|
|
19
|
+
|
|
20
|
+
That way, the more seeds you run, the more "fair" the results are.
|
|
21
|
+
Finally, modelmark will form the report with all the testing results, training stats and your machine metadata.
|
|
22
|
+
|
|
23
|
+
More on training stats:
|
|
24
|
+
|
|
25
|
+
Time - average time per epoch
|
|
26
|
+
Params - total number of model params
|
|
27
|
+
GFLOPs - average per batch
|
|
28
|
+
Peak Memory - max per training iteration
|
|
29
|
+
|
|
30
|
+
Test consists of F * C * M * S runs, where:
|
|
31
|
+
|
|
32
|
+
F - number of dataset files in the config (e.g. ["ETTh1" : ..., "Weather" : ...] - means F = 2)
|
|
33
|
+
C - number of context sizes (e.g. [32, 64, 128] - means C = 3)
|
|
34
|
+
M - number of models (e.g. ["Linear" : ..., "LSTM" : ...] - means M = 2)
|
|
35
|
+
S - number of seeds (e.g. [42, 43, 44] - means S = 2)
|
|
36
|
+
|
|
37
|
+
# Requirements:
|
|
38
|
+
|
|
39
|
+
OS: Windows or Linux
|
|
40
|
+
Python: 3.12+
|
|
41
|
+
|
|
42
|
+
# Usage:
|
|
43
|
+
|
|
44
|
+
1) Install the package
|
|
45
|
+
|
|
46
|
+
pip install "modelmark @ git+https://github.com/gloptim77/ModelMark.git"
|
|
47
|
+
|
|
48
|
+
2) Run the initialization in an empty folder
|
|
49
|
+
|
|
50
|
+
modelmark -t init
|
|
51
|
+
|
|
52
|
+
3.1) It will create two folders "modelmark_files" and "models"
|
|
53
|
+
|
|
54
|
+
In modelmark_files/config.py there are 3 main configs:
|
|
55
|
+
|
|
56
|
+
model_config = {...} - Models hyperparameters (number of layers, hidden dim, kernel size, etc.)
|
|
57
|
+
data_config = {...} - Dataset parameters (path to file, input/output features, train/val ratios, etc.)
|
|
58
|
+
test_config = {...} - Testing options (optimizer, loss criterion, metrics, learning rate, etc.)
|
|
59
|
+
|
|
60
|
+
3.2) (Optional) download the ETT dataset files
|
|
61
|
+
|
|
62
|
+
modelmark -t load
|
|
63
|
+
|
|
64
|
+
4) When your config, model and data are ready, you can run the testing
|
|
65
|
+
|
|
66
|
+
modelmark -t run
|
|
67
|
+
|
|
68
|
+
5) When the test is over, report results will be in files "result.html" and "result.png"
|
|
69
|
+
|
|
70
|
+
Example of the model: "src/modelmark/models/linear.py"
|
|
71
|
+
Example of the config: "src/modelmark/config.py"
|
|
72
|
+
|
|
73
|
+
You will find the detailed config example with description at [src/modelmark/config.py](src/modelmark/config.py).
|
|
74
|
+
|
|
75
|
+
Example Linear model with detailed description at [src/modelmark/models/linear.py](src/modelmark/models/linear.py).
|
|
76
|
+
|
|
77
|
+
You can change the config and add your model files to suit your test requirements.
|
|
78
|
+
|
|
79
|
+
(But make sure that config and models are compatible)
|
|
80
|
+
|
|
81
|
+
## Troubleshooting
|
|
82
|
+
|
|
83
|
+
- **If something doesn't work**
|
|
84
|
+
|
|
85
|
+
- Please open an issue and attach your application logs (found at "modelmark_files/modelmark.log") so I can help you troubleshoot.
|
|
86
|
+
- Try to restart
|
|
87
|
+
```python
|
|
88
|
+
modelmark -t restart
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
- Try to manually delete "modelmark_files" and return to Usage->2)
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project.scripts]
|
|
6
|
+
modelmark = "modelmark.modelmark:run"
|
|
7
|
+
|
|
8
|
+
[project]
|
|
9
|
+
name = "modelmark"
|
|
10
|
+
version = "0.1.0"
|
|
11
|
+
description = "Benchmark framework for neural network models"
|
|
12
|
+
readme = "README.md"
|
|
13
|
+
requires-python = ">=3.12"
|
|
14
|
+
license = { text = "MIT" }
|
|
15
|
+
|
|
16
|
+
authors = [
|
|
17
|
+
{ name = "Andrew Larin" }
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
dependencies = [
|
|
21
|
+
"numpy>=2.4",
|
|
22
|
+
"pandas>=3.0",
|
|
23
|
+
"torch>=2.12",
|
|
24
|
+
"tqdm>=4.67",
|
|
25
|
+
"playwright>=1.62",
|
|
26
|
+
"rich>=15.0",
|
|
27
|
+
"thop>=0.1"
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
[tool.setuptools.packages.find]
|
|
31
|
+
where = ["src"]
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import torch
|
|
4
|
+
from torch.utils.data import Dataset
|
|
5
|
+
|
|
6
|
+
import copy
|
|
7
|
+
import numpy as np
|
|
8
|
+
import pandas as pd
|
|
9
|
+
|
|
10
|
+
from modelmark.common.utils import load_config
|
|
11
|
+
config = load_config()
|
|
12
|
+
|
|
13
|
+
class CausalDataset(Dataset):
|
|
14
|
+
"""
|
|
15
|
+
Sliding-window dataset for ETT.
|
|
16
|
+
|
|
17
|
+
Returns:
|
|
18
|
+
x: [seq_len, num_features]
|
|
19
|
+
y: [pred_len, 1]
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
def __init__(
|
|
23
|
+
self,
|
|
24
|
+
data_config: dict,
|
|
25
|
+
seq_len: int,
|
|
26
|
+
pred_len: int,
|
|
27
|
+
split: str = "train",
|
|
28
|
+
mean: np.ndarray | None = None,
|
|
29
|
+
std: np.ndarray | None = None,
|
|
30
|
+
):
|
|
31
|
+
super().__init__()
|
|
32
|
+
|
|
33
|
+
self.seq_len = seq_len
|
|
34
|
+
self.pred_len = pred_len
|
|
35
|
+
|
|
36
|
+
# Extract config
|
|
37
|
+
data_path = config.data_path + data_config["path"]
|
|
38
|
+
features = copy.deepcopy(data_config["input_features"])
|
|
39
|
+
targets = data_config["output_features"]
|
|
40
|
+
features.extend([item for item in targets if item not in features])
|
|
41
|
+
train_ratio = data_config["train_ratio"]
|
|
42
|
+
val_ratio = data_config["val_ratio"]
|
|
43
|
+
|
|
44
|
+
# Load, extract, convert
|
|
45
|
+
df = pd.read_csv(data_path)
|
|
46
|
+
|
|
47
|
+
df = df[features]
|
|
48
|
+
data = df.values.astype(np.float32)
|
|
49
|
+
self.input_indices = torch.tensor(df.columns.get_indexer(data_config["input_features"]), dtype=torch.int)
|
|
50
|
+
self.output_indices = torch.tensor(df.columns.get_indexer(data_config["output_features"]), dtype=torch.int)
|
|
51
|
+
|
|
52
|
+
n = len(data)
|
|
53
|
+
|
|
54
|
+
train_end = int(n * train_ratio)
|
|
55
|
+
val_end = int(n * (train_ratio + val_ratio))
|
|
56
|
+
|
|
57
|
+
if split == "train":
|
|
58
|
+
start = 0
|
|
59
|
+
end = train_end
|
|
60
|
+
elif split == "val":
|
|
61
|
+
start = train_end
|
|
62
|
+
end = val_end
|
|
63
|
+
elif split == "test":
|
|
64
|
+
start = val_end
|
|
65
|
+
end = n
|
|
66
|
+
else:
|
|
67
|
+
raise ValueError(f"Unknown split: {split}")
|
|
68
|
+
|
|
69
|
+
# Save scaling information
|
|
70
|
+
if split == "train":
|
|
71
|
+
self.mean = data[start:train_end].mean(axis=0)
|
|
72
|
+
self.std = data[start:train_end].std(axis=0)
|
|
73
|
+
|
|
74
|
+
# Prevent division by zero
|
|
75
|
+
self.std[self.std < 1e-8] = 1.0
|
|
76
|
+
else:
|
|
77
|
+
if mean is None or std is None:
|
|
78
|
+
raise ValueError(
|
|
79
|
+
"Validation/test datasets need training mean and std."
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
self.mean = mean
|
|
83
|
+
self.std = std
|
|
84
|
+
|
|
85
|
+
# Scale using TRAIN statistics
|
|
86
|
+
data = (data - self.mean) / self.std
|
|
87
|
+
|
|
88
|
+
# Keep only the split region
|
|
89
|
+
self.data = data[start:end]
|
|
90
|
+
|
|
91
|
+
# Number of valid windows
|
|
92
|
+
self.length = len(self.data) - seq_len - pred_len + 1
|
|
93
|
+
|
|
94
|
+
if self.length <= 0:
|
|
95
|
+
raise ValueError(
|
|
96
|
+
f"Split '{split}' is too short for "
|
|
97
|
+
f"seq_len={seq_len}, pred_len={pred_len}"
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
def __len__(self):
|
|
101
|
+
return self.length
|
|
102
|
+
|
|
103
|
+
def __getitem__(self, idx):
|
|
104
|
+
x_start = idx
|
|
105
|
+
x_end = x_start + self.seq_len
|
|
106
|
+
|
|
107
|
+
y_start = x_end
|
|
108
|
+
y_end = y_start + self.pred_len
|
|
109
|
+
|
|
110
|
+
x = self.data[x_start:x_end, self.input_indices]
|
|
111
|
+
y = self.data[y_start:y_end, self.output_indices]
|
|
112
|
+
|
|
113
|
+
return (
|
|
114
|
+
torch.from_numpy(x),
|
|
115
|
+
torch.from_numpy(y),
|
|
116
|
+
)
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"""Download time-series datasets to a local directory.
|
|
2
|
+
|
|
3
|
+
Supports:
|
|
4
|
+
- ETT (ETTh1, ETTh2, ETTm1, ETTm2) — from the ETDataset GitHub repo
|
|
5
|
+
- Air Quality (UCI Repository)
|
|
6
|
+
- Weather (Max Planck Institute / Jena climate dataset)
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import argparse
|
|
10
|
+
import shutil
|
|
11
|
+
import urllib.request
|
|
12
|
+
import zipfile
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
|
|
15
|
+
import logging
|
|
16
|
+
logger = logging.getLogger(__name__)
|
|
17
|
+
from rich.console import Console
|
|
18
|
+
console = Console()
|
|
19
|
+
|
|
20
|
+
DATASETS = {
|
|
21
|
+
"ett": {
|
|
22
|
+
"dir": "data/ett",
|
|
23
|
+
"kind": "multi_csv",
|
|
24
|
+
"base_url": "https://raw.githubusercontent.com/zhouhaoyi/ETDataset/main/ETT-small",
|
|
25
|
+
"files": ["ETTh1", "ETTh2", "ETTm1", "ETTm2"],
|
|
26
|
+
},
|
|
27
|
+
"air_quality": {
|
|
28
|
+
"dir": "data/air_quality",
|
|
29
|
+
"kind": "zip",
|
|
30
|
+
"url": "https://archive.ics.uci.edu/static/public/360/air+quality.zip",
|
|
31
|
+
"zip_name": "AirQualityUCI.zip",
|
|
32
|
+
},
|
|
33
|
+
"weather": {
|
|
34
|
+
"dir": "data/weather",
|
|
35
|
+
"kind": "zip",
|
|
36
|
+
"url": "https://storage.googleapis.com/tensorflow/tf-keras-datasets/jena_climate_2009_2016.csv.zip",
|
|
37
|
+
"zip_name": "jena_climate_2009_2016.csv.zip",
|
|
38
|
+
},
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def download_ett(cfg: dict, out_dir: Path) -> None:
|
|
43
|
+
out_dir.mkdir(parents=True, exist_ok=True)
|
|
44
|
+
for name in cfg["files"]:
|
|
45
|
+
url = f"{cfg['base_url']}/{name}.csv"
|
|
46
|
+
path = out_dir / f"{name}.csv"
|
|
47
|
+
if path.exists():
|
|
48
|
+
logger.info(f"{name}.csv already exists, skipping.")
|
|
49
|
+
continue
|
|
50
|
+
logger.info(f"Downloading {name}...")
|
|
51
|
+
console.print(f"Downloading {name}...")
|
|
52
|
+
urllib.request.urlretrieve(url, path)
|
|
53
|
+
logger.info(f"Saved to {path}")
|
|
54
|
+
console.print(f"Saved to {path}", style="green")
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def download_zip_dataset(cfg: dict, out_dir: Path) -> None:
|
|
58
|
+
out_dir.mkdir(parents=True, exist_ok=True)
|
|
59
|
+
zip_path = out_dir / cfg["zip_name"]
|
|
60
|
+
|
|
61
|
+
if not zip_path.exists():
|
|
62
|
+
logger.info(f"Downloading {cfg['zip_name']}...")
|
|
63
|
+
console.print(f"Downloading {cfg['zip_name']}...")
|
|
64
|
+
urllib.request.urlretrieve(cfg["url"], zip_path)
|
|
65
|
+
logger.info(f"Saved to {zip_path}")
|
|
66
|
+
console.print(f"Saved to {zip_path}", style="green")
|
|
67
|
+
else:
|
|
68
|
+
logger.info(f"{cfg['zip_name']} already exists, skipping download.")
|
|
69
|
+
console.print(f"{cfg['zip_name']} already exists, skipping download.", style="yellow")
|
|
70
|
+
|
|
71
|
+
logger.info(f"Extracting {zip_path.name}...")
|
|
72
|
+
console.print(f"Extracting {zip_path.name}...")
|
|
73
|
+
with zipfile.ZipFile(zip_path) as zf:
|
|
74
|
+
zf.extractall(out_dir)
|
|
75
|
+
console.print(f"Extracted to {out_dir}", color="green")
|
|
76
|
+
|
|
77
|
+
def download_dataset(name: str) -> None:
|
|
78
|
+
if name not in DATASETS:
|
|
79
|
+
valid = ", ".join(DATASETS)
|
|
80
|
+
raise ValueError(f"Unknown dataset '{name}'. Choose from: {valid}")
|
|
81
|
+
|
|
82
|
+
cfg = DATASETS[name]
|
|
83
|
+
out_dir = Path(cfg["dir"])
|
|
84
|
+
|
|
85
|
+
if cfg["kind"] == "multi_csv":
|
|
86
|
+
download_ett(cfg, out_dir)
|
|
87
|
+
elif cfg["kind"] == "zip":
|
|
88
|
+
download_zip_dataset(cfg, out_dir)
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from modelmark.common.dataset import CausalDataset
|
|
4
|
+
from torch.utils.data import DataLoader
|
|
5
|
+
|
|
6
|
+
import logging
|
|
7
|
+
logger = logging.getLogger(__name__)
|
|
8
|
+
from modelmark.common.utils import load_config
|
|
9
|
+
config = load_config()
|
|
10
|
+
|
|
11
|
+
class Loader:
|
|
12
|
+
|
|
13
|
+
def __init__(self, file_config : dict, context_size : int):
|
|
14
|
+
|
|
15
|
+
self.get_dataloaders(file_config, context_size)
|
|
16
|
+
logger.debug(f"Dataset len stats: train={len(self.train_loader)} val={len(self.val_loader)} test={len(self.test_loader)}")
|
|
17
|
+
|
|
18
|
+
def get_dataloaders(self, file_config : dict, context_size : int) -> tuple[DataLoader, DataLoader, DataLoader]:
|
|
19
|
+
"""Load the data, pack to datasets, create the loaders and return them"""
|
|
20
|
+
|
|
21
|
+
train_ds = CausalDataset(data_config = file_config,
|
|
22
|
+
seq_len = context_size,
|
|
23
|
+
pred_len = context_size,
|
|
24
|
+
split = "train")
|
|
25
|
+
|
|
26
|
+
val_ds = CausalDataset(data_config = file_config,
|
|
27
|
+
seq_len = context_size,
|
|
28
|
+
pred_len = context_size,
|
|
29
|
+
split = "val",
|
|
30
|
+
mean = train_ds.mean,
|
|
31
|
+
std = train_ds.std)
|
|
32
|
+
|
|
33
|
+
test_ds = CausalDataset(data_config = file_config,
|
|
34
|
+
seq_len = context_size,
|
|
35
|
+
pred_len = context_size,
|
|
36
|
+
split = "test",
|
|
37
|
+
mean = train_ds.mean,
|
|
38
|
+
std = train_ds.std)
|
|
39
|
+
|
|
40
|
+
self.train_loader = DataLoader(
|
|
41
|
+
train_ds,
|
|
42
|
+
batch_size = config.test_config["optim"]["batch_size"],
|
|
43
|
+
shuffle = True,
|
|
44
|
+
num_workers = 0,
|
|
45
|
+
pin_memory = True,
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
self.val_loader = DataLoader(
|
|
49
|
+
val_ds,
|
|
50
|
+
batch_size = config.test_config["optim"]["batch_size"],
|
|
51
|
+
shuffle = False,
|
|
52
|
+
num_workers = 0,
|
|
53
|
+
pin_memory = True,
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
self.test_loader = DataLoader(
|
|
57
|
+
test_ds,
|
|
58
|
+
batch_size = config.test_config["optim"]["batch_size"],
|
|
59
|
+
shuffle = False,
|
|
60
|
+
num_workers = 0,
|
|
61
|
+
pin_memory = True,
|
|
62
|
+
)
|
|
63
|
+
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import sys
|
|
3
|
+
from typing import Optional
|
|
4
|
+
|
|
5
|
+
def setup_logging(log_format: Optional[str] = None) -> None:
|
|
6
|
+
"""
|
|
7
|
+
Configure logging for the entire application.
|
|
8
|
+
|
|
9
|
+
Args:
|
|
10
|
+
log_format: Optional custom format string. If None, a default format is used.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
if log_format is None:
|
|
14
|
+
log_format = "%(asctime)s [%(levelname)s] [%(name)s] - %(message)s"
|
|
15
|
+
|
|
16
|
+
logging.basicConfig(
|
|
17
|
+
level = logging.DEBUG,
|
|
18
|
+
filemode = 'w',
|
|
19
|
+
filename='modelmark_files/modelmark.log',
|
|
20
|
+
format = log_format,
|
|
21
|
+
datefmt = '%H:%M:%S',
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
def get_logger(name: str) -> logging.Logger:
|
|
25
|
+
"""
|
|
26
|
+
Convenience function to get a logger for a module.
|
|
27
|
+
|
|
28
|
+
Args:
|
|
29
|
+
name: Usually __name__.
|
|
30
|
+
|
|
31
|
+
Returns:
|
|
32
|
+
A configured logger instance.
|
|
33
|
+
"""
|
|
34
|
+
return logging.getLogger(name)
|