ml-dash 0.6.2__py3-none-any.whl → 0.6.2rc1__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.
- ml_dash/__init__.py +64 -36
- ml_dash/auth/token_storage.py +226 -267
- ml_dash/auto_start.py +15 -28
- ml_dash/cli.py +2 -16
- ml_dash/cli_commands/download.py +667 -757
- ml_dash/cli_commands/list.py +13 -146
- ml_dash/cli_commands/login.py +183 -190
- ml_dash/cli_commands/upload.py +1141 -1291
- ml_dash/client.py +6 -79
- ml_dash/config.py +119 -119
- ml_dash/experiment.py +1034 -1234
- ml_dash/files.py +224 -339
- ml_dash/log.py +7 -7
- ml_dash/metric.py +100 -359
- ml_dash/params.py +6 -6
- ml_dash/remote_auto_start.py +17 -20
- ml_dash/run.py +65 -211
- ml_dash/storage.py +1081 -1051
- {ml_dash-0.6.2.dist-info → ml_dash-0.6.2rc1.dist-info}/METADATA +14 -12
- ml_dash-0.6.2rc1.dist-info/RECORD +30 -0
- {ml_dash-0.6.2.dist-info → ml_dash-0.6.2rc1.dist-info}/WHEEL +1 -1
- ml_dash/cli_commands/api.py +0 -165
- ml_dash/cli_commands/profile.py +0 -92
- ml_dash/snowflake.py +0 -173
- ml_dash-0.6.2.dist-info/RECORD +0 -33
- {ml_dash-0.6.2.dist-info → ml_dash-0.6.2rc1.dist-info}/entry_points.txt +0 -0
ml_dash/remote_auto_start.py
CHANGED
|
@@ -9,18 +9,18 @@ IMPORTANT: Before using rdxp, you must authenticate with the ML-Dash server:
|
|
|
9
9
|
python -m ml_dash.cli login
|
|
10
10
|
|
|
11
11
|
Usage:
|
|
12
|
-
from ml_dash
|
|
12
|
+
from ml_dash import rdxp
|
|
13
13
|
|
|
14
14
|
# Use with statement (recommended)
|
|
15
15
|
with rdxp.run:
|
|
16
|
-
rdxp.log("Hello from rdxp!"
|
|
16
|
+
rdxp.log().info("Hello from rdxp!")
|
|
17
17
|
rdxp.params.set(lr=0.001)
|
|
18
|
-
rdxp.metrics("
|
|
18
|
+
rdxp.metrics("loss").append(step=0, value=0.5)
|
|
19
19
|
# Automatically completes on exit from with block
|
|
20
20
|
|
|
21
21
|
# Or start/complete manually
|
|
22
22
|
rdxp.run.start()
|
|
23
|
-
rdxp.log("Training..."
|
|
23
|
+
rdxp.log().info("Training...")
|
|
24
24
|
rdxp.run.complete()
|
|
25
25
|
|
|
26
26
|
Configuration:
|
|
@@ -30,28 +30,25 @@ Configuration:
|
|
|
30
30
|
"""
|
|
31
31
|
|
|
32
32
|
import atexit
|
|
33
|
+
from .experiment import Experiment
|
|
33
34
|
|
|
34
35
|
# Create pre-configured singleton experiment for remote mode
|
|
35
36
|
# Uses remote API server - token auto-loaded from storage
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
_owner = getpass.getuser()
|
|
42
|
-
rdxp = Experiment(prefix=f"{_owner}/scratch/rdxp", dash_url="https://api.dash.ml")
|
|
43
|
-
|
|
37
|
+
rdxp = Experiment(
|
|
38
|
+
name="rdxp",
|
|
39
|
+
project="scratch",
|
|
40
|
+
remote="https://api.dash.ml"
|
|
41
|
+
)
|
|
44
42
|
|
|
45
43
|
# Register cleanup handler to complete experiment on Python exit (if still open)
|
|
46
44
|
def _cleanup():
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
45
|
+
"""Complete the rdxp experiment on exit if still open."""
|
|
46
|
+
if rdxp._is_open:
|
|
47
|
+
try:
|
|
48
|
+
rdxp.run.complete()
|
|
49
|
+
except Exception:
|
|
50
|
+
# Silently ignore errors during cleanup
|
|
51
|
+
pass
|
|
55
52
|
|
|
56
53
|
atexit.register(_cleanup)
|
|
57
54
|
|
ml_dash/run.py
CHANGED
|
@@ -1,231 +1,85 @@
|
|
|
1
1
|
"""
|
|
2
|
-
RUN - Global
|
|
2
|
+
RUN - Global run configuration object for ML-Dash.
|
|
3
3
|
|
|
4
4
|
This module provides a global RUN object that serves as the single source
|
|
5
|
-
of truth for experiment metadata. Uses params-proto for configuration.
|
|
5
|
+
of truth for run/experiment metadata. Uses params-proto for configuration.
|
|
6
6
|
|
|
7
7
|
Usage:
|
|
8
8
|
from ml_dash import RUN
|
|
9
9
|
|
|
10
|
-
# Configure
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
# Or set directly
|
|
14
|
-
RUN.PREFIX = "ge/myproject/experiments/exp1"
|
|
10
|
+
# Configure the run
|
|
11
|
+
RUN.name = "my-experiment"
|
|
12
|
+
RUN.project = "my-project"
|
|
15
13
|
|
|
16
14
|
# Use in templates
|
|
17
|
-
|
|
15
|
+
folder = "/experiments/{RUN.name}".format(RUN=RUN)
|
|
18
16
|
|
|
19
|
-
# With
|
|
20
|
-
from ml_dash import
|
|
21
|
-
with
|
|
22
|
-
|
|
17
|
+
# With dxp singleton (RUN is auto-populated)
|
|
18
|
+
from ml_dash import dxp
|
|
19
|
+
with dxp.run:
|
|
20
|
+
# RUN.name, RUN.project, RUN.id, RUN.timestamp are set
|
|
21
|
+
dxp.log().info(f"Running {RUN.name}")
|
|
23
22
|
"""
|
|
24
23
|
|
|
25
|
-
import os
|
|
26
|
-
import sys
|
|
27
24
|
from datetime import datetime
|
|
28
|
-
from
|
|
29
|
-
from typing import Union
|
|
30
|
-
|
|
31
|
-
from params_proto import EnvVar, proto
|
|
32
|
-
|
|
33
|
-
PROJECT_ROOT_FILES = ("pyproject.toml", "requirements.txt", "setup.py", "setup.cfg")
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
def find_project_root(
|
|
37
|
-
start: Union[str, Path] = None,
|
|
38
|
-
verbose: bool = False,
|
|
39
|
-
) -> str:
|
|
40
|
-
"""Find the nearest project root by looking for common project files.
|
|
41
|
-
|
|
42
|
-
Walks up the directory tree from `start` until it finds a directory
|
|
43
|
-
containing pyproject.toml, requirements.txt, setup.py, or setup.cfg.
|
|
44
|
-
|
|
45
|
-
Args:
|
|
46
|
-
start: Starting directory or file path. Defaults to cwd.
|
|
47
|
-
verbose: If True, print search progress.
|
|
48
|
-
|
|
49
|
-
Returns:
|
|
50
|
-
String path to the project root directory, or cwd if not found.
|
|
51
|
-
"""
|
|
52
|
-
if start is None:
|
|
53
|
-
start = Path.cwd()
|
|
54
|
-
else:
|
|
55
|
-
start = Path(start)
|
|
56
|
-
|
|
57
|
-
if start.is_file():
|
|
58
|
-
start = start.parent
|
|
59
|
-
|
|
60
|
-
if verbose:
|
|
61
|
-
print(f"Searching for project root from: {start}")
|
|
62
|
-
|
|
63
|
-
for parent in [start, *start.parents]:
|
|
64
|
-
if verbose:
|
|
65
|
-
print(f" Checking: {parent}")
|
|
66
|
-
for filename in PROJECT_ROOT_FILES:
|
|
67
|
-
if (parent / filename).exists():
|
|
68
|
-
if verbose:
|
|
69
|
-
print(f" Found: {parent / filename}")
|
|
70
|
-
return str(parent)
|
|
71
|
-
|
|
72
|
-
if verbose:
|
|
73
|
-
print(f" No project root found, using cwd: {Path.cwd()}")
|
|
74
|
-
return str(Path.cwd())
|
|
25
|
+
from params_proto import proto
|
|
75
26
|
|
|
76
27
|
|
|
77
28
|
@proto.prefix
|
|
78
29
|
class RUN:
|
|
79
|
-
"""
|
|
80
|
-
Global Experiment Run Configuration.
|
|
81
|
-
|
|
82
|
-
This class is the single source of truth for experiment metadata.
|
|
83
|
-
Configure it before starting an experiment, or through the Experiment
|
|
84
|
-
constructor.
|
|
85
|
-
|
|
86
|
-
Default prefix template:
|
|
87
|
-
{project}/{now:%Y/%m-%d}/{path_stem}/{job_name}
|
|
88
|
-
|
|
89
|
-
Example:
|
|
90
|
-
# Set prefix via environment variable
|
|
91
|
-
# export ML_DASH_PREFIX="ge/myproject/exp1"
|
|
92
|
-
|
|
93
|
-
# Or configure directly
|
|
94
|
-
from ml_dash.run import RUN
|
|
95
|
-
|
|
96
|
-
RUN.project = "my-project"
|
|
97
|
-
RUN.prefix = "{username}/{project}/{now:%Y-%m-%d}/{entry}"
|
|
98
|
-
|
|
99
|
-
Auto-detection:
|
|
100
|
-
project_root is auto-detected by searching for pyproject.toml,
|
|
101
|
-
requirements.txt, setup.py, or setup.cfg in parent directories.
|
|
102
|
-
"""
|
|
103
|
-
|
|
104
|
-
user: str = EnvVar @ "ML_DASH_USER" @ "USER"
|
|
105
|
-
|
|
106
|
-
api_url: str = EnvVar @ "ML_DASH_API_URL" | "https://api.dash.ml"
|
|
107
|
-
"""Remote API server URL"""
|
|
108
|
-
|
|
109
|
-
### Experiment and project information
|
|
110
|
-
project = "{user}/scratch" # default project name
|
|
111
|
-
|
|
112
|
-
prefix: str = (
|
|
113
|
-
EnvVar @ "ML_DASH_PREFIX" | "{project}/{now:%Y/%m-%d}/{path_stem}/{job_name}"
|
|
114
|
-
)
|
|
115
|
-
"""Full experiment path: {owner}/{project}/path.../[name]"""
|
|
116
|
-
|
|
117
|
-
readme = None
|
|
118
|
-
|
|
119
|
-
id: int = None
|
|
120
|
-
"""Unique experiment ID (snowflake, auto-generated at run start)"""
|
|
121
|
-
|
|
122
|
-
now = datetime.now()
|
|
123
|
-
"""Timestamp at import time. Does not change during the session."""
|
|
124
|
-
|
|
125
|
-
timestamp: str = None
|
|
126
|
-
"""Timestamp created at instantiation"""
|
|
127
|
-
|
|
128
|
-
### file properties
|
|
129
|
-
project_root: str = None
|
|
130
|
-
"""Root directory for experiment hierarchy (for auto-detection)"""
|
|
131
|
-
|
|
132
|
-
entry: Union[Path, str] = None
|
|
133
|
-
"""Entry point file/directory path"""
|
|
134
|
-
|
|
135
|
-
path_stem: str = None
|
|
136
|
-
|
|
137
|
-
job_counter: int = 1 # Default to 0. Use True to increment by 1.
|
|
138
|
-
|
|
139
|
-
job_name: str = "{now:%H.%M.%S}/{job_counter:03d}"
|
|
140
|
-
|
|
141
|
-
"""
|
|
142
|
-
Default to '{now:%H.%M.%S}'. use '{now:%H.%M.%S}/{job_counter:03d}'
|
|
143
|
-
|
|
144
|
-
for multiple launches. You can do so by setting:
|
|
145
|
-
|
|
146
|
-
```python
|
|
147
|
-
RUN.job_name += "/{job_counter}"
|
|
148
|
-
|
|
149
|
-
for params in sweep:
|
|
150
|
-
thunk = instr(main)
|
|
151
|
-
jaynes.run(thun)
|
|
152
|
-
jaynes.listen()
|
|
153
|
-
```
|
|
154
|
-
"""
|
|
155
|
-
|
|
156
|
-
debug = "pydevd" in sys.modules
|
|
157
|
-
"set to True automatically for pyCharm"
|
|
158
|
-
|
|
159
|
-
def __post_init__(self):
|
|
160
30
|
"""
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
Args:
|
|
164
|
-
entry: Path to entry file/directory (e.g., __file__ or directory
|
|
165
|
-
containing sweep.jsonl). If not provided, uses caller's
|
|
166
|
-
__file__ automatically.
|
|
167
|
-
|
|
168
|
-
Computes prefix as relative path from project_root to entry's directory.
|
|
169
|
-
|
|
170
|
-
Example:
|
|
171
|
-
# experiments/__init__.py
|
|
172
|
-
from ml_dash import RUN
|
|
31
|
+
Global run configuration.
|
|
173
32
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
# experiments/vision/resnet/train.py
|
|
177
|
-
from ml_dash import RUN
|
|
178
|
-
|
|
179
|
-
RUN.__post_init__(entry=__file__)
|
|
180
|
-
# Result: RUN.prefix = "vision/resnet", RUN.name = "resnet"
|
|
33
|
+
This class is the single source of truth for run metadata.
|
|
34
|
+
Configure it before starting an experiment, or let dxp auto-configure.
|
|
181
35
|
"""
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
36
|
+
# Core identifiers
|
|
37
|
+
name: str = "untitled" # Run/experiment name
|
|
38
|
+
project: str = "scratch" # Project name
|
|
39
|
+
|
|
40
|
+
# Auto-generated identifiers (populated at run.start())
|
|
41
|
+
id: str = None # Unique run ID (auto-generated)
|
|
42
|
+
timestamp: str = None # Run timestamp (same as id)
|
|
43
|
+
|
|
44
|
+
# Optional configuration
|
|
45
|
+
folder: str = None # Folder path with optional templates
|
|
46
|
+
description: str = None # Run description
|
|
47
|
+
|
|
48
|
+
@classmethod
|
|
49
|
+
def _generate_id(cls) -> str:
|
|
50
|
+
"""Generate a unique run ID based on current timestamp."""
|
|
51
|
+
return datetime.utcnow().strftime("%Y%m%d_%H%M%S")
|
|
52
|
+
|
|
53
|
+
@classmethod
|
|
54
|
+
def _init_run(cls) -> None:
|
|
55
|
+
"""Initialize run ID and timestamp if not already set."""
|
|
56
|
+
if cls.id is None:
|
|
57
|
+
cls.id = cls._generate_id()
|
|
58
|
+
cls.timestamp = cls.id
|
|
59
|
+
|
|
60
|
+
@classmethod
|
|
61
|
+
def _format(cls, template: str) -> str:
|
|
62
|
+
"""
|
|
63
|
+
Format a template string with RUN values.
|
|
64
|
+
|
|
65
|
+
Args:
|
|
66
|
+
template: String with {RUN.attr} placeholders
|
|
67
|
+
|
|
68
|
+
Returns:
|
|
69
|
+
Formatted string with placeholders replaced
|
|
70
|
+
|
|
71
|
+
Example:
|
|
72
|
+
RUN._format("/experiments/{RUN.name}_{RUN.id}")
|
|
73
|
+
# -> "/experiments/my-exp_20241219_143022"
|
|
74
|
+
"""
|
|
75
|
+
return template.format(RUN=cls)
|
|
76
|
+
|
|
77
|
+
@classmethod
|
|
78
|
+
def _reset(cls) -> None:
|
|
79
|
+
"""Reset RUN to defaults (for testing or new runs)."""
|
|
80
|
+
cls.name = "untitled"
|
|
81
|
+
cls.project = "scratch"
|
|
82
|
+
cls.id = None
|
|
83
|
+
cls.timestamp = None
|
|
84
|
+
cls.folder = None
|
|
85
|
+
cls.description = None
|