ins-pricing 0.4.5__py3-none-any.whl → 0.5.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.
- ins_pricing/README.md +48 -22
- ins_pricing/__init__.py +142 -90
- ins_pricing/cli/BayesOpt_entry.py +58 -46
- ins_pricing/cli/BayesOpt_incremental.py +77 -110
- ins_pricing/cli/Explain_Run.py +42 -23
- ins_pricing/cli/Explain_entry.py +551 -577
- ins_pricing/cli/Pricing_Run.py +42 -23
- ins_pricing/cli/bayesopt_entry_runner.py +51 -16
- ins_pricing/cli/utils/bootstrap.py +23 -0
- ins_pricing/cli/utils/cli_common.py +256 -256
- ins_pricing/cli/utils/cli_config.py +379 -360
- ins_pricing/cli/utils/import_resolver.py +375 -358
- ins_pricing/cli/utils/notebook_utils.py +256 -242
- ins_pricing/cli/watchdog_run.py +216 -198
- ins_pricing/frontend/__init__.py +10 -10
- ins_pricing/frontend/app.py +132 -61
- ins_pricing/frontend/config_builder.py +33 -0
- ins_pricing/frontend/example_config.json +11 -0
- ins_pricing/frontend/example_workflows.py +1 -1
- ins_pricing/frontend/runner.py +340 -388
- ins_pricing/governance/__init__.py +20 -20
- ins_pricing/governance/release.py +159 -159
- ins_pricing/modelling/README.md +1 -1
- ins_pricing/modelling/__init__.py +147 -92
- ins_pricing/modelling/{core/bayesopt → bayesopt}/README.md +31 -13
- ins_pricing/modelling/{core/bayesopt → bayesopt}/__init__.py +64 -102
- ins_pricing/modelling/{core/bayesopt → bayesopt}/config_components.py +12 -0
- ins_pricing/modelling/{core/bayesopt → bayesopt}/config_preprocess.py +589 -552
- ins_pricing/modelling/{core/bayesopt → bayesopt}/core.py +987 -958
- ins_pricing/modelling/{core/bayesopt → bayesopt}/model_explain_mixin.py +296 -296
- ins_pricing/modelling/{core/bayesopt → bayesopt}/model_plotting_mixin.py +488 -548
- ins_pricing/modelling/{core/bayesopt → bayesopt}/models/__init__.py +27 -27
- ins_pricing/modelling/{core/bayesopt → bayesopt}/models/model_ft_components.py +349 -342
- ins_pricing/modelling/{core/bayesopt → bayesopt}/models/model_ft_trainer.py +921 -913
- ins_pricing/modelling/{core/bayesopt → bayesopt}/models/model_gnn.py +794 -785
- ins_pricing/modelling/{core/bayesopt → bayesopt}/models/model_resn.py +454 -446
- ins_pricing/modelling/bayesopt/trainers/__init__.py +19 -0
- ins_pricing/modelling/{core/bayesopt → bayesopt}/trainers/trainer_base.py +1294 -1282
- ins_pricing/modelling/{core/bayesopt → bayesopt}/trainers/trainer_ft.py +64 -56
- ins_pricing/modelling/{core/bayesopt → bayesopt}/trainers/trainer_glm.py +203 -198
- ins_pricing/modelling/{core/bayesopt → bayesopt}/trainers/trainer_gnn.py +333 -325
- ins_pricing/modelling/{core/bayesopt → bayesopt}/trainers/trainer_resn.py +279 -267
- ins_pricing/modelling/{core/bayesopt → bayesopt}/trainers/trainer_xgb.py +515 -313
- ins_pricing/modelling/bayesopt/utils/__init__.py +67 -0
- ins_pricing/modelling/bayesopt/utils/constants.py +21 -0
- ins_pricing/modelling/{core/bayesopt → bayesopt}/utils/distributed_utils.py +193 -186
- ins_pricing/modelling/bayesopt/utils/io_utils.py +7 -0
- ins_pricing/modelling/bayesopt/utils/losses.py +27 -0
- ins_pricing/modelling/bayesopt/utils/metrics_and_devices.py +17 -0
- ins_pricing/modelling/{core/bayesopt → bayesopt}/utils/torch_trainer_mixin.py +636 -623
- ins_pricing/modelling/{core/evaluation.py → evaluation.py} +113 -104
- ins_pricing/modelling/explain/__init__.py +55 -55
- ins_pricing/modelling/explain/metrics.py +27 -174
- ins_pricing/modelling/explain/permutation.py +237 -237
- ins_pricing/modelling/plotting/__init__.py +40 -36
- ins_pricing/modelling/plotting/compat.py +228 -0
- ins_pricing/modelling/plotting/curves.py +572 -572
- ins_pricing/modelling/plotting/diagnostics.py +163 -163
- ins_pricing/modelling/plotting/geo.py +362 -362
- ins_pricing/modelling/plotting/importance.py +121 -121
- ins_pricing/pricing/__init__.py +27 -27
- ins_pricing/pricing/factors.py +67 -56
- ins_pricing/production/__init__.py +35 -25
- ins_pricing/production/{predict.py → inference.py} +140 -57
- ins_pricing/production/monitoring.py +8 -21
- ins_pricing/reporting/__init__.py +11 -11
- ins_pricing/setup.py +1 -1
- ins_pricing/tests/production/test_inference.py +90 -0
- ins_pricing/utils/__init__.py +112 -78
- ins_pricing/utils/device.py +258 -237
- ins_pricing/utils/features.py +53 -0
- ins_pricing/utils/io.py +72 -0
- ins_pricing/utils/logging.py +34 -1
- ins_pricing/{modelling/core/bayesopt/utils → utils}/losses.py +125 -129
- ins_pricing/utils/metrics.py +158 -24
- ins_pricing/utils/numerics.py +76 -0
- ins_pricing/utils/paths.py +9 -1
- ins_pricing/utils/profiling.py +8 -4
- {ins_pricing-0.4.5.dist-info → ins_pricing-0.5.1.dist-info}/METADATA +1 -1
- ins_pricing-0.5.1.dist-info/RECORD +132 -0
- ins_pricing/modelling/core/BayesOpt.py +0 -146
- ins_pricing/modelling/core/__init__.py +0 -1
- ins_pricing/modelling/core/bayesopt/trainers/__init__.py +0 -19
- ins_pricing/modelling/core/bayesopt/utils/__init__.py +0 -86
- ins_pricing/modelling/core/bayesopt/utils/constants.py +0 -183
- ins_pricing/modelling/core/bayesopt/utils/io_utils.py +0 -126
- ins_pricing/modelling/core/bayesopt/utils/metrics_and_devices.py +0 -555
- ins_pricing/modelling/core/bayesopt/utils.py +0 -105
- ins_pricing/modelling/core/bayesopt/utils_backup.py +0 -1503
- ins_pricing/tests/production/test_predict.py +0 -233
- ins_pricing-0.4.5.dist-info/RECORD +0 -130
- {ins_pricing-0.4.5.dist-info → ins_pricing-0.5.1.dist-info}/WHEEL +0 -0
- {ins_pricing-0.4.5.dist-info → ins_pricing-0.5.1.dist-info}/top_level.txt +0 -0
|
@@ -1,184 +1,184 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
import argparse
|
|
4
|
-
import json
|
|
5
|
-
import subprocess
|
|
6
|
-
import sys
|
|
7
|
-
from pathlib import Path
|
|
8
|
-
from typing import Iterable, List, Optional, Sequence, cast
|
|
9
|
-
|
|
10
|
-
try:
|
|
11
|
-
from .cli_config import add_config_json_arg, set_env # type: ignore
|
|
12
|
-
except Exception: # pragma: no cover
|
|
13
|
-
from cli_config import add_config_json_arg, set_env # type: ignore
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
def _find_ins_pricing_dir(cwd: Optional[Path] = None) -> Path:
|
|
17
|
-
cwd = (cwd or Path().resolve()).resolve()
|
|
18
|
-
pkg_root = Path(__file__).resolve().parents[2]
|
|
19
|
-
candidates = [pkg_root, cwd / "ins_pricing", cwd, cwd.parent / "ins_pricing"]
|
|
20
|
-
for cand in candidates:
|
|
21
|
-
cli_entry = cand / "cli" / "BayesOpt_entry.py"
|
|
22
|
-
cli_watchdog = cand / "cli" / "watchdog_run.py"
|
|
23
|
-
if cli_entry.exists() and cli_watchdog.exists():
|
|
24
|
-
return cand
|
|
25
|
-
raise FileNotFoundError(
|
|
26
|
-
"Cannot locate ins_pricing directory (expected cli/BayesOpt_entry.py and "
|
|
27
|
-
"cli/watchdog_run.py). "
|
|
28
|
-
f"cwd={cwd}"
|
|
29
|
-
)
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
def _stringify_cmd(cmd: Sequence[object]) -> List[str]:
|
|
33
|
-
return [str(x) for x in cmd]
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
def build_bayesopt_entry_cmd(
|
|
37
|
-
config_json: str | Path,
|
|
38
|
-
model_keys: Sequence[str],
|
|
39
|
-
*,
|
|
40
|
-
nproc_per_node: int = 1,
|
|
41
|
-
standalone: bool = True,
|
|
42
|
-
entry_script: str | Path = "cli/BayesOpt_entry.py",
|
|
43
|
-
extra_args: Optional[Sequence[str]] = None,
|
|
44
|
-
) -> List[str]:
|
|
45
|
-
"""Build a command to run cli/BayesOpt_entry.py (optional torchrun/DDP)."""
|
|
46
|
-
pkg_dir = _find_ins_pricing_dir()
|
|
47
|
-
entry_script_path = Path(entry_script)
|
|
48
|
-
if entry_script_path.is_absolute():
|
|
49
|
-
entry_path = entry_script_path.resolve()
|
|
50
|
-
else:
|
|
51
|
-
candidate = pkg_dir / entry_script_path
|
|
52
|
-
legacy = pkg_dir / "modelling" / entry_script_path
|
|
53
|
-
entry_path = (
|
|
54
|
-
candidate.resolve()
|
|
55
|
-
if candidate.exists()
|
|
56
|
-
else legacy.resolve()
|
|
57
|
-
if legacy.exists()
|
|
58
|
-
else candidate.resolve()
|
|
59
|
-
)
|
|
60
|
-
config_path = Path(config_json)
|
|
61
|
-
if not config_path.is_absolute():
|
|
62
|
-
config_path = (pkg_dir / config_path).resolve() if (pkg_dir / config_path).exists() else config_path.resolve()
|
|
63
|
-
|
|
64
|
-
cmd: List[object]
|
|
65
|
-
if int(nproc_per_node) > 1:
|
|
66
|
-
cmd = [
|
|
67
|
-
sys.executable,
|
|
68
|
-
"-m",
|
|
69
|
-
"torch.distributed.run",
|
|
70
|
-
*(["--standalone"] if standalone else []),
|
|
71
|
-
f"--nproc_per_node={int(nproc_per_node)}",
|
|
72
|
-
str(entry_path),
|
|
73
|
-
]
|
|
74
|
-
else:
|
|
75
|
-
cmd = [sys.executable, str(entry_path)]
|
|
76
|
-
|
|
77
|
-
cmd += ["--config-json", str(config_path), "--model-keys", *list(model_keys)]
|
|
78
|
-
if extra_args:
|
|
79
|
-
cmd += list(extra_args)
|
|
80
|
-
return _stringify_cmd(cmd)
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
def build_incremental_cmd(
|
|
84
|
-
config_json: str | Path,
|
|
85
|
-
*,
|
|
86
|
-
entry_script: str | Path = "cli/BayesOpt_incremental.py",
|
|
87
|
-
extra_args: Optional[Sequence[str]] = None,
|
|
88
|
-
) -> List[str]:
|
|
89
|
-
"""Build a command to run cli/BayesOpt_incremental.py."""
|
|
90
|
-
pkg_dir = _find_ins_pricing_dir()
|
|
91
|
-
entry_script_path = Path(entry_script)
|
|
92
|
-
if entry_script_path.is_absolute():
|
|
93
|
-
entry_path = entry_script_path.resolve()
|
|
94
|
-
else:
|
|
95
|
-
candidate = pkg_dir / entry_script_path
|
|
96
|
-
legacy = pkg_dir / "modelling" / entry_script_path
|
|
97
|
-
entry_path = (
|
|
98
|
-
candidate.resolve()
|
|
99
|
-
if candidate.exists()
|
|
100
|
-
else legacy.resolve()
|
|
101
|
-
if legacy.exists()
|
|
102
|
-
else candidate.resolve()
|
|
103
|
-
)
|
|
104
|
-
config_path = Path(config_json)
|
|
105
|
-
if not config_path.is_absolute():
|
|
106
|
-
config_path = (pkg_dir / config_path).resolve() if (pkg_dir / config_path).exists() else config_path.resolve()
|
|
107
|
-
|
|
108
|
-
cmd: List[object] = [sys.executable, str(entry_path), "--config-json", str(config_path)]
|
|
109
|
-
if extra_args:
|
|
110
|
-
cmd += list(extra_args)
|
|
111
|
-
return _stringify_cmd(cmd)
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
def build_explain_cmd(
|
|
115
|
-
config_json: str | Path,
|
|
116
|
-
*,
|
|
117
|
-
entry_script: str | Path = "cli/Explain_entry.py",
|
|
118
|
-
extra_args: Optional[Sequence[str]] = None,
|
|
119
|
-
) -> List[str]:
|
|
120
|
-
"""Build a command to run cli/Explain_entry.py."""
|
|
121
|
-
pkg_dir = _find_ins_pricing_dir()
|
|
122
|
-
entry_script_path = Path(entry_script)
|
|
123
|
-
if entry_script_path.is_absolute():
|
|
124
|
-
entry_path = entry_script_path.resolve()
|
|
125
|
-
else:
|
|
126
|
-
candidate = pkg_dir / entry_script_path
|
|
127
|
-
legacy = pkg_dir / "modelling" / entry_script_path
|
|
128
|
-
entry_path = (
|
|
129
|
-
candidate.resolve()
|
|
130
|
-
if candidate.exists()
|
|
131
|
-
else legacy.resolve()
|
|
132
|
-
if legacy.exists()
|
|
133
|
-
else candidate.resolve()
|
|
134
|
-
)
|
|
135
|
-
config_path = Path(config_json)
|
|
136
|
-
if not config_path.is_absolute():
|
|
137
|
-
config_path = (pkg_dir / config_path).resolve() if (pkg_dir / config_path).exists() else config_path.resolve()
|
|
138
|
-
|
|
139
|
-
cmd: List[object] = [sys.executable, str(entry_path), "--config-json", str(config_path)]
|
|
140
|
-
if extra_args:
|
|
141
|
-
cmd += list(extra_args)
|
|
142
|
-
return _stringify_cmd(cmd)
|
|
143
|
-
|
|
144
|
-
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
import json
|
|
5
|
+
import subprocess
|
|
6
|
+
import sys
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import Iterable, List, Optional, Sequence, cast
|
|
9
|
+
|
|
10
|
+
try:
|
|
11
|
+
from ins_pricing.cli.utils.cli_config import add_config_json_arg, set_env # type: ignore
|
|
12
|
+
except Exception: # pragma: no cover
|
|
13
|
+
from cli_config import add_config_json_arg, set_env # type: ignore
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def _find_ins_pricing_dir(cwd: Optional[Path] = None) -> Path:
|
|
17
|
+
cwd = (cwd or Path().resolve()).resolve()
|
|
18
|
+
pkg_root = Path(__file__).resolve().parents[2]
|
|
19
|
+
candidates = [pkg_root, cwd / "ins_pricing", cwd, cwd.parent / "ins_pricing"]
|
|
20
|
+
for cand in candidates:
|
|
21
|
+
cli_entry = cand / "cli" / "BayesOpt_entry.py"
|
|
22
|
+
cli_watchdog = cand / "cli" / "watchdog_run.py"
|
|
23
|
+
if cli_entry.exists() and cli_watchdog.exists():
|
|
24
|
+
return cand
|
|
25
|
+
raise FileNotFoundError(
|
|
26
|
+
"Cannot locate ins_pricing directory (expected cli/BayesOpt_entry.py and "
|
|
27
|
+
"cli/watchdog_run.py). "
|
|
28
|
+
f"cwd={cwd}"
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def _stringify_cmd(cmd: Sequence[object]) -> List[str]:
|
|
33
|
+
return [str(x) for x in cmd]
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def build_bayesopt_entry_cmd(
|
|
37
|
+
config_json: str | Path,
|
|
38
|
+
model_keys: Sequence[str],
|
|
39
|
+
*,
|
|
40
|
+
nproc_per_node: int = 1,
|
|
41
|
+
standalone: bool = True,
|
|
42
|
+
entry_script: str | Path = "cli/BayesOpt_entry.py",
|
|
43
|
+
extra_args: Optional[Sequence[str]] = None,
|
|
44
|
+
) -> List[str]:
|
|
45
|
+
"""Build a command to run cli/BayesOpt_entry.py (optional torchrun/DDP)."""
|
|
46
|
+
pkg_dir = _find_ins_pricing_dir()
|
|
47
|
+
entry_script_path = Path(entry_script)
|
|
48
|
+
if entry_script_path.is_absolute():
|
|
49
|
+
entry_path = entry_script_path.resolve()
|
|
50
|
+
else:
|
|
51
|
+
candidate = pkg_dir / entry_script_path
|
|
52
|
+
legacy = pkg_dir / "modelling" / entry_script_path
|
|
53
|
+
entry_path = (
|
|
54
|
+
candidate.resolve()
|
|
55
|
+
if candidate.exists()
|
|
56
|
+
else legacy.resolve()
|
|
57
|
+
if legacy.exists()
|
|
58
|
+
else candidate.resolve()
|
|
59
|
+
)
|
|
60
|
+
config_path = Path(config_json)
|
|
61
|
+
if not config_path.is_absolute():
|
|
62
|
+
config_path = (pkg_dir / config_path).resolve() if (pkg_dir / config_path).exists() else config_path.resolve()
|
|
63
|
+
|
|
64
|
+
cmd: List[object]
|
|
65
|
+
if int(nproc_per_node) > 1:
|
|
66
|
+
cmd = [
|
|
67
|
+
sys.executable,
|
|
68
|
+
"-m",
|
|
69
|
+
"torch.distributed.run",
|
|
70
|
+
*(["--standalone"] if standalone else []),
|
|
71
|
+
f"--nproc_per_node={int(nproc_per_node)}",
|
|
72
|
+
str(entry_path),
|
|
73
|
+
]
|
|
74
|
+
else:
|
|
75
|
+
cmd = [sys.executable, str(entry_path)]
|
|
76
|
+
|
|
77
|
+
cmd += ["--config-json", str(config_path), "--model-keys", *list(model_keys)]
|
|
78
|
+
if extra_args:
|
|
79
|
+
cmd += list(extra_args)
|
|
80
|
+
return _stringify_cmd(cmd)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def build_incremental_cmd(
|
|
84
|
+
config_json: str | Path,
|
|
85
|
+
*,
|
|
86
|
+
entry_script: str | Path = "cli/BayesOpt_incremental.py",
|
|
87
|
+
extra_args: Optional[Sequence[str]] = None,
|
|
88
|
+
) -> List[str]:
|
|
89
|
+
"""Build a command to run cli/BayesOpt_incremental.py."""
|
|
90
|
+
pkg_dir = _find_ins_pricing_dir()
|
|
91
|
+
entry_script_path = Path(entry_script)
|
|
92
|
+
if entry_script_path.is_absolute():
|
|
93
|
+
entry_path = entry_script_path.resolve()
|
|
94
|
+
else:
|
|
95
|
+
candidate = pkg_dir / entry_script_path
|
|
96
|
+
legacy = pkg_dir / "modelling" / entry_script_path
|
|
97
|
+
entry_path = (
|
|
98
|
+
candidate.resolve()
|
|
99
|
+
if candidate.exists()
|
|
100
|
+
else legacy.resolve()
|
|
101
|
+
if legacy.exists()
|
|
102
|
+
else candidate.resolve()
|
|
103
|
+
)
|
|
104
|
+
config_path = Path(config_json)
|
|
105
|
+
if not config_path.is_absolute():
|
|
106
|
+
config_path = (pkg_dir / config_path).resolve() if (pkg_dir / config_path).exists() else config_path.resolve()
|
|
107
|
+
|
|
108
|
+
cmd: List[object] = [sys.executable, str(entry_path), "--config-json", str(config_path)]
|
|
109
|
+
if extra_args:
|
|
110
|
+
cmd += list(extra_args)
|
|
111
|
+
return _stringify_cmd(cmd)
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def build_explain_cmd(
|
|
115
|
+
config_json: str | Path,
|
|
116
|
+
*,
|
|
117
|
+
entry_script: str | Path = "cli/Explain_entry.py",
|
|
118
|
+
extra_args: Optional[Sequence[str]] = None,
|
|
119
|
+
) -> List[str]:
|
|
120
|
+
"""Build a command to run cli/Explain_entry.py."""
|
|
121
|
+
pkg_dir = _find_ins_pricing_dir()
|
|
122
|
+
entry_script_path = Path(entry_script)
|
|
123
|
+
if entry_script_path.is_absolute():
|
|
124
|
+
entry_path = entry_script_path.resolve()
|
|
125
|
+
else:
|
|
126
|
+
candidate = pkg_dir / entry_script_path
|
|
127
|
+
legacy = pkg_dir / "modelling" / entry_script_path
|
|
128
|
+
entry_path = (
|
|
129
|
+
candidate.resolve()
|
|
130
|
+
if candidate.exists()
|
|
131
|
+
else legacy.resolve()
|
|
132
|
+
if legacy.exists()
|
|
133
|
+
else candidate.resolve()
|
|
134
|
+
)
|
|
135
|
+
config_path = Path(config_json)
|
|
136
|
+
if not config_path.is_absolute():
|
|
137
|
+
config_path = (pkg_dir / config_path).resolve() if (pkg_dir / config_path).exists() else config_path.resolve()
|
|
138
|
+
|
|
139
|
+
cmd: List[object] = [sys.executable, str(entry_path), "--config-json", str(config_path)]
|
|
140
|
+
if extra_args:
|
|
141
|
+
cmd += list(extra_args)
|
|
142
|
+
return _stringify_cmd(cmd)
|
|
143
|
+
|
|
144
|
+
|
|
145
145
|
def wrap_with_watchdog(
|
|
146
146
|
cmd: Sequence[str],
|
|
147
|
-
*,
|
|
148
|
-
idle_seconds: int = 7200,
|
|
149
|
-
max_restarts: int = 50,
|
|
150
|
-
restart_delay_seconds: int = 10,
|
|
151
|
-
stop_on_nonzero_exit: bool = True,
|
|
152
|
-
watchdog_script: str | Path = "cli/watchdog_run.py",
|
|
153
|
-
) -> List[str]:
|
|
154
|
-
"""Wrap a command with watchdog: restart when idle_seconds elapses with no output."""
|
|
155
|
-
pkg_dir = _find_ins_pricing_dir()
|
|
156
|
-
watchdog_script_path = Path(watchdog_script)
|
|
157
|
-
if watchdog_script_path.is_absolute():
|
|
158
|
-
watchdog_path = watchdog_script_path.resolve()
|
|
159
|
-
else:
|
|
160
|
-
candidate = pkg_dir / watchdog_script_path
|
|
161
|
-
legacy = pkg_dir / "modelling" / watchdog_script_path
|
|
162
|
-
watchdog_path = (
|
|
163
|
-
candidate.resolve()
|
|
164
|
-
if candidate.exists()
|
|
165
|
-
else legacy.resolve()
|
|
166
|
-
if legacy.exists()
|
|
167
|
-
else candidate.resolve()
|
|
168
|
-
)
|
|
169
|
-
wd_cmd: List[object] = [
|
|
170
|
-
sys.executable,
|
|
171
|
-
str(watchdog_path),
|
|
172
|
-
"--idle-seconds",
|
|
173
|
-
str(int(idle_seconds)),
|
|
174
|
-
"--max-restarts",
|
|
175
|
-
str(int(max_restarts)),
|
|
176
|
-
"--restart-delay-seconds",
|
|
177
|
-
str(int(restart_delay_seconds)),
|
|
178
|
-
]
|
|
179
|
-
if stop_on_nonzero_exit:
|
|
180
|
-
wd_cmd.append("--stop-on-nonzero-exit")
|
|
181
|
-
wd_cmd.append("--")
|
|
147
|
+
*,
|
|
148
|
+
idle_seconds: int = 7200,
|
|
149
|
+
max_restarts: int = 50,
|
|
150
|
+
restart_delay_seconds: int = 10,
|
|
151
|
+
stop_on_nonzero_exit: bool = True,
|
|
152
|
+
watchdog_script: str | Path = "cli/watchdog_run.py",
|
|
153
|
+
) -> List[str]:
|
|
154
|
+
"""Wrap a command with watchdog: restart when idle_seconds elapses with no output."""
|
|
155
|
+
pkg_dir = _find_ins_pricing_dir()
|
|
156
|
+
watchdog_script_path = Path(watchdog_script)
|
|
157
|
+
if watchdog_script_path.is_absolute():
|
|
158
|
+
watchdog_path = watchdog_script_path.resolve()
|
|
159
|
+
else:
|
|
160
|
+
candidate = pkg_dir / watchdog_script_path
|
|
161
|
+
legacy = pkg_dir / "modelling" / watchdog_script_path
|
|
162
|
+
watchdog_path = (
|
|
163
|
+
candidate.resolve()
|
|
164
|
+
if candidate.exists()
|
|
165
|
+
else legacy.resolve()
|
|
166
|
+
if legacy.exists()
|
|
167
|
+
else candidate.resolve()
|
|
168
|
+
)
|
|
169
|
+
wd_cmd: List[object] = [
|
|
170
|
+
sys.executable,
|
|
171
|
+
str(watchdog_path),
|
|
172
|
+
"--idle-seconds",
|
|
173
|
+
str(int(idle_seconds)),
|
|
174
|
+
"--max-restarts",
|
|
175
|
+
str(int(max_restarts)),
|
|
176
|
+
"--restart-delay-seconds",
|
|
177
|
+
str(int(restart_delay_seconds)),
|
|
178
|
+
]
|
|
179
|
+
if stop_on_nonzero_exit:
|
|
180
|
+
wd_cmd.append("--stop-on-nonzero-exit")
|
|
181
|
+
wd_cmd.append("--")
|
|
182
182
|
wd_cmd.extend(list(cmd))
|
|
183
183
|
return _stringify_cmd(wd_cmd)
|
|
184
184
|
|
|
@@ -189,72 +189,19 @@ def run(cmd: Sequence[str], *, check: bool = True) -> subprocess.CompletedProces
|
|
|
189
189
|
|
|
190
190
|
|
|
191
191
|
def _build_config_parser(description: str) -> argparse.ArgumentParser:
|
|
192
|
-
parser = argparse.ArgumentParser(description=description)
|
|
193
|
-
add_config_json_arg(
|
|
194
|
-
parser,
|
|
195
|
-
help_text="Path to config.json (relative paths are resolved from ins_pricing/ when possible).",
|
|
192
|
+
parser = argparse.ArgumentParser(description=description)
|
|
193
|
+
add_config_json_arg(
|
|
194
|
+
parser,
|
|
195
|
+
help_text="Path to config.json (relative paths are resolved from ins_pricing/ when possible).",
|
|
196
196
|
)
|
|
197
197
|
return parser
|
|
198
198
|
|
|
199
199
|
|
|
200
|
-
def
|
|
201
|
-
|
|
202
|
-
argv: Optional[Sequence[str]] = None,
|
|
203
|
-
) -> subprocess.CompletedProcess:
|
|
204
|
-
parser = _build_config_parser(description)
|
|
205
|
-
args = parser.parse_args(argv)
|
|
206
|
-
return run_from_config(args.config_json)
|
|
207
|
-
|
|
200
|
+
def build_cmd_from_config(config_json: str | Path) -> tuple[List[str], str]:
|
|
201
|
+
"""Build a command list from config.json runner settings.
|
|
208
202
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
config_json: str | Path,
|
|
212
|
-
model_keys: Sequence[str],
|
|
213
|
-
max_evals: int = 50,
|
|
214
|
-
plot_curves: bool = True,
|
|
215
|
-
ft_role: Optional[str] = None,
|
|
216
|
-
nproc_per_node: int = 1,
|
|
217
|
-
use_watchdog: bool = False,
|
|
218
|
-
idle_seconds: int = 7200,
|
|
219
|
-
max_restarts: int = 50,
|
|
220
|
-
restart_delay_seconds: int = 10,
|
|
221
|
-
extra_args: Optional[Sequence[str]] = None,
|
|
222
|
-
) -> subprocess.CompletedProcess:
|
|
223
|
-
"""Convenience wrapper: build and run BayesOpt_entry (optional torchrun + watchdog)."""
|
|
224
|
-
args: List[str] = ["--max-evals", str(int(max_evals))]
|
|
225
|
-
if plot_curves:
|
|
226
|
-
args.append("--plot-curves")
|
|
227
|
-
if ft_role:
|
|
228
|
-
args += ["--ft-role", str(ft_role)]
|
|
229
|
-
if extra_args:
|
|
230
|
-
args += list(extra_args)
|
|
231
|
-
|
|
232
|
-
cmd = build_bayesopt_entry_cmd(
|
|
233
|
-
config_json=config_json,
|
|
234
|
-
model_keys=model_keys,
|
|
235
|
-
nproc_per_node=nproc_per_node,
|
|
236
|
-
extra_args=args,
|
|
237
|
-
)
|
|
238
|
-
if use_watchdog:
|
|
239
|
-
cmd = wrap_with_watchdog(
|
|
240
|
-
cmd,
|
|
241
|
-
idle_seconds=idle_seconds,
|
|
242
|
-
max_restarts=max_restarts,
|
|
243
|
-
restart_delay_seconds=restart_delay_seconds,
|
|
244
|
-
)
|
|
245
|
-
return run(cmd, check=True)
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
def run_from_config(config_json: str | Path) -> subprocess.CompletedProcess:
|
|
249
|
-
"""Notebook entry point: switch execution modes by editing config.json.
|
|
250
|
-
|
|
251
|
-
Convention: config.json may include a `runner` section for notebook control:
|
|
252
|
-
- runner.mode: "entry" (default), "incremental", or "explain"
|
|
253
|
-
- runner.nproc_per_node: >1 enables torchrun/DDP (entry only)
|
|
254
|
-
- runner.model_keys: list of models to run (entry only)
|
|
255
|
-
- runner.max_evals / runner.plot_curves / runner.ft_role (entry only; override config fields)
|
|
256
|
-
- runner.use_watchdog / runner.idle_seconds / runner.max_restarts / runner.restart_delay_seconds
|
|
257
|
-
- runner.incremental_args: List[str] (incremental only; extra args for cli/BayesOpt_incremental.py)
|
|
203
|
+
Returns:
|
|
204
|
+
(cmd, mode) where mode is one of: entry, incremental, explain.
|
|
258
205
|
"""
|
|
259
206
|
pkg_dir = _find_ins_pricing_dir()
|
|
260
207
|
config_path = Path(config_json)
|
|
@@ -266,6 +213,10 @@ def run_from_config(config_json: str | Path) -> subprocess.CompletedProcess:
|
|
|
266
213
|
|
|
267
214
|
mode = str(runner.get("mode") or "entry").strip().lower()
|
|
268
215
|
use_watchdog = bool(runner.get("use_watchdog", False))
|
|
216
|
+
if mode == "watchdog":
|
|
217
|
+
use_watchdog = True
|
|
218
|
+
mode = "entry"
|
|
219
|
+
|
|
269
220
|
idle_seconds = int(runner.get("idle_seconds", 7200))
|
|
270
221
|
max_restarts = int(runner.get("max_restarts", 50))
|
|
271
222
|
restart_delay_seconds = int(runner.get("restart_delay_seconds", 10))
|
|
@@ -282,7 +233,7 @@ def run_from_config(config_json: str | Path) -> subprocess.CompletedProcess:
|
|
|
282
233
|
max_restarts=max_restarts,
|
|
283
234
|
restart_delay_seconds=restart_delay_seconds,
|
|
284
235
|
)
|
|
285
|
-
return
|
|
236
|
+
return cmd, "incremental"
|
|
286
237
|
|
|
287
238
|
if mode == "explain":
|
|
288
239
|
exp_args = runner.get("explain_args") or []
|
|
@@ -296,7 +247,7 @@ def run_from_config(config_json: str | Path) -> subprocess.CompletedProcess:
|
|
|
296
247
|
max_restarts=max_restarts,
|
|
297
248
|
restart_delay_seconds=restart_delay_seconds,
|
|
298
249
|
)
|
|
299
|
-
return
|
|
250
|
+
return cmd, "explain"
|
|
300
251
|
|
|
301
252
|
if mode != "entry":
|
|
302
253
|
raise ValueError(
|
|
@@ -337,4 +288,67 @@ def run_from_config(config_json: str | Path) -> subprocess.CompletedProcess:
|
|
|
337
288
|
max_restarts=max_restarts,
|
|
338
289
|
restart_delay_seconds=restart_delay_seconds,
|
|
339
290
|
)
|
|
291
|
+
return cmd, "entry"
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
def run_from_config_cli(
|
|
295
|
+
description: str,
|
|
296
|
+
argv: Optional[Sequence[str]] = None,
|
|
297
|
+
) -> subprocess.CompletedProcess:
|
|
298
|
+
parser = _build_config_parser(description)
|
|
299
|
+
args = parser.parse_args(argv)
|
|
300
|
+
return run_from_config(args.config_json)
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
def run_bayesopt_entry(
|
|
304
|
+
*,
|
|
305
|
+
config_json: str | Path,
|
|
306
|
+
model_keys: Sequence[str],
|
|
307
|
+
max_evals: int = 50,
|
|
308
|
+
plot_curves: bool = True,
|
|
309
|
+
ft_role: Optional[str] = None,
|
|
310
|
+
nproc_per_node: int = 1,
|
|
311
|
+
use_watchdog: bool = False,
|
|
312
|
+
idle_seconds: int = 7200,
|
|
313
|
+
max_restarts: int = 50,
|
|
314
|
+
restart_delay_seconds: int = 10,
|
|
315
|
+
extra_args: Optional[Sequence[str]] = None,
|
|
316
|
+
) -> subprocess.CompletedProcess:
|
|
317
|
+
"""Convenience wrapper: build and run BayesOpt_entry (optional torchrun + watchdog)."""
|
|
318
|
+
args: List[str] = ["--max-evals", str(int(max_evals))]
|
|
319
|
+
if plot_curves:
|
|
320
|
+
args.append("--plot-curves")
|
|
321
|
+
if ft_role:
|
|
322
|
+
args += ["--ft-role", str(ft_role)]
|
|
323
|
+
if extra_args:
|
|
324
|
+
args += list(extra_args)
|
|
325
|
+
|
|
326
|
+
cmd = build_bayesopt_entry_cmd(
|
|
327
|
+
config_json=config_json,
|
|
328
|
+
model_keys=model_keys,
|
|
329
|
+
nproc_per_node=nproc_per_node,
|
|
330
|
+
extra_args=args,
|
|
331
|
+
)
|
|
332
|
+
if use_watchdog:
|
|
333
|
+
cmd = wrap_with_watchdog(
|
|
334
|
+
cmd,
|
|
335
|
+
idle_seconds=idle_seconds,
|
|
336
|
+
max_restarts=max_restarts,
|
|
337
|
+
restart_delay_seconds=restart_delay_seconds,
|
|
338
|
+
)
|
|
339
|
+
return run(cmd, check=True)
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
def run_from_config(config_json: str | Path) -> subprocess.CompletedProcess:
|
|
343
|
+
"""Notebook entry point: switch execution modes by editing config.json.
|
|
344
|
+
|
|
345
|
+
Convention: config.json may include a `runner` section for notebook control:
|
|
346
|
+
- runner.mode: "entry" (default), "incremental", or "explain"
|
|
347
|
+
- runner.nproc_per_node: >1 enables torchrun/DDP (entry only)
|
|
348
|
+
- runner.model_keys: list of models to run (entry only)
|
|
349
|
+
- runner.max_evals / runner.plot_curves / runner.ft_role (entry only; override config fields)
|
|
350
|
+
- runner.use_watchdog / runner.idle_seconds / runner.max_restarts / runner.restart_delay_seconds
|
|
351
|
+
- runner.incremental_args: List[str] (incremental only; extra args for cli/BayesOpt_incremental.py)
|
|
352
|
+
"""
|
|
353
|
+
cmd, _mode = build_cmd_from_config(config_json)
|
|
340
354
|
return run(cmd, check=True)
|