xrtm-train 0.2.2__tar.gz → 0.2.4__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.
- {xrtm_train-0.2.2 → xrtm_train-0.2.4}/PKG-INFO +3 -3
- {xrtm_train-0.2.2 → xrtm_train-0.2.4}/pyproject.toml +3 -8
- {xrtm_train-0.2.2 → xrtm_train-0.2.4}/src/xrtm/train/cli/__init__.py +42 -19
- {xrtm_train-0.2.2 → xrtm_train-0.2.4}/src/xrtm/train/version.py +1 -1
- {xrtm_train-0.2.2 → xrtm_train-0.2.4}/src/xrtm_train.egg-info/PKG-INFO +3 -3
- {xrtm_train-0.2.2 → xrtm_train-0.2.4}/src/xrtm_train.egg-info/requires.txt +2 -2
- {xrtm_train-0.2.2 → xrtm_train-0.2.4}/tests/test_cli.py +45 -1
- {xrtm_train-0.2.2 → xrtm_train-0.2.4}/LICENSE +0 -0
- {xrtm_train-0.2.2 → xrtm_train-0.2.4}/README.md +0 -0
- {xrtm_train-0.2.2 → xrtm_train-0.2.4}/setup.cfg +0 -0
- {xrtm_train-0.2.2 → xrtm_train-0.2.4}/src/xrtm/train/__init__.py +0 -0
- {xrtm_train-0.2.2 → xrtm_train-0.2.4}/src/xrtm/train/core/__init__.py +0 -0
- {xrtm_train-0.2.2 → xrtm_train-0.2.4}/src/xrtm/train/core/eval/__init__.py +0 -0
- {xrtm_train-0.2.2 → xrtm_train-0.2.4}/src/xrtm/train/core/eval/calibration.py +0 -0
- {xrtm_train-0.2.2 → xrtm_train-0.2.4}/src/xrtm/train/kit/__init__.py +0 -0
- {xrtm_train-0.2.2 → xrtm_train-0.2.4}/src/xrtm/train/kit/builders/__init__.py +0 -0
- {xrtm_train-0.2.2 → xrtm_train-0.2.4}/src/xrtm/train/kit/memory/__init__.py +0 -0
- {xrtm_train-0.2.2 → xrtm_train-0.2.4}/src/xrtm/train/kit/memory/learner.py +0 -0
- {xrtm_train-0.2.2 → xrtm_train-0.2.4}/src/xrtm/train/kit/optimization/__init__.py +0 -0
- {xrtm_train-0.2.2 → xrtm_train-0.2.4}/src/xrtm/train/kit/optimization/compiler.py +0 -0
- {xrtm_train-0.2.2 → xrtm_train-0.2.4}/src/xrtm/train/kit/projectors/__init__.py +0 -0
- {xrtm_train-0.2.2 → xrtm_train-0.2.4}/src/xrtm/train/kit/trainers/__init__.py +0 -0
- {xrtm_train-0.2.2 → xrtm_train-0.2.4}/src/xrtm/train/metrics.py +0 -0
- {xrtm_train-0.2.2 → xrtm_train-0.2.4}/src/xrtm/train/providers/__init__.py +0 -0
- {xrtm_train-0.2.2 → xrtm_train-0.2.4}/src/xrtm/train/real_e2e.py +0 -0
- {xrtm_train-0.2.2 → xrtm_train-0.2.4}/src/xrtm/train/simulation/backtester.py +0 -0
- {xrtm_train-0.2.2 → xrtm_train-0.2.4}/src/xrtm/train/simulation/replayer.py +0 -0
- {xrtm_train-0.2.2 → xrtm_train-0.2.4}/src/xrtm/train/simulation/runner.py +0 -0
- {xrtm_train-0.2.2 → xrtm_train-0.2.4}/src/xrtm_train.egg-info/SOURCES.txt +0 -0
- {xrtm_train-0.2.2 → xrtm_train-0.2.4}/src/xrtm_train.egg-info/dependency_links.txt +0 -0
- {xrtm_train-0.2.2 → xrtm_train-0.2.4}/src/xrtm_train.egg-info/entry_points.txt +0 -0
- {xrtm_train-0.2.2 → xrtm_train-0.2.4}/src/xrtm_train.egg-info/top_level.txt +0 -0
- {xrtm_train-0.2.2 → xrtm_train-0.2.4}/tests/test_backtester.py +0 -0
- {xrtm_train-0.2.2 → xrtm_train-0.2.4}/tests/test_real_benchmark_script.py +0 -0
- {xrtm_train-0.2.2 → xrtm_train-0.2.4}/tests/test_real_e2e.py +0 -0
- {xrtm_train-0.2.2 → xrtm_train-0.2.4}/tests/test_replayer.py +0 -0
- {xrtm_train-0.2.2 → xrtm_train-0.2.4}/tests/test_runner.py +0 -0
- {xrtm_train-0.2.2 → xrtm_train-0.2.4}/tests/test_sample_builder.py +0 -0
- {xrtm_train-0.2.2 → xrtm_train-0.2.4}/tests/test_single_node_trainer.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: xrtm-train
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.4
|
|
4
4
|
Summary: The Learning/Optimization layer for XRTM.
|
|
5
5
|
Author-email: XRTM Team <moy@xrtm.org>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -14,8 +14,8 @@ Requires-Dist: click>=8.0.0
|
|
|
14
14
|
Requires-Dist: rich>=13.0.0
|
|
15
15
|
Requires-Dist: pyyaml>=6.0.0
|
|
16
16
|
Requires-Dist: xrtm-data>=0.2.2
|
|
17
|
-
Requires-Dist: xrtm-eval>=0.2.
|
|
18
|
-
Requires-Dist: xrtm-forecast>=0.6.
|
|
17
|
+
Requires-Dist: xrtm-eval>=0.2.3
|
|
18
|
+
Requires-Dist: xrtm-forecast>=0.6.3
|
|
19
19
|
Provides-Extra: dev
|
|
20
20
|
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
21
21
|
Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "xrtm-train"
|
|
7
|
-
version = "0.2.
|
|
7
|
+
version = "0.2.4"
|
|
8
8
|
description = "The Learning/Optimization layer for XRTM."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.11"
|
|
@@ -20,8 +20,8 @@ dependencies = [
|
|
|
20
20
|
"rich>=13.0.0",
|
|
21
21
|
"pyyaml>=6.0.0",
|
|
22
22
|
"xrtm-data>=0.2.2",
|
|
23
|
-
"xrtm-eval>=0.2.
|
|
24
|
-
"xrtm-forecast>=0.6.
|
|
23
|
+
"xrtm-eval>=0.2.3",
|
|
24
|
+
"xrtm-forecast>=0.6.3",
|
|
25
25
|
]
|
|
26
26
|
|
|
27
27
|
[project.optional-dependencies]
|
|
@@ -46,11 +46,6 @@ xrtm-train = "xrtm.train.cli:main"
|
|
|
46
46
|
package-dir = {"" = "src"}
|
|
47
47
|
packages = {find = {where = ["src"], include = ["xrtm*"], namespaces = true}}
|
|
48
48
|
|
|
49
|
-
[tool.uv.sources]
|
|
50
|
-
xrtm-data = { workspace = true }
|
|
51
|
-
xrtm-eval = { workspace = true }
|
|
52
|
-
xrtm-forecast = { workspace = true }
|
|
53
|
-
|
|
54
49
|
[tool.pytest.ini_options]
|
|
55
50
|
testpaths = ["tests"]
|
|
56
51
|
asyncio_mode = "strict"
|
|
@@ -33,6 +33,7 @@ Example:
|
|
|
33
33
|
"""
|
|
34
34
|
|
|
35
35
|
import json
|
|
36
|
+
from copy import deepcopy
|
|
36
37
|
from datetime import datetime, timedelta, timezone
|
|
37
38
|
from pathlib import Path
|
|
38
39
|
from typing import Any, Dict, Optional
|
|
@@ -86,22 +87,29 @@ DEFAULT_CONFIG = {
|
|
|
86
87
|
|
|
87
88
|
def load_config(config_path: Optional[str]) -> Dict[str, Any]:
|
|
88
89
|
r"""Load configuration from YAML file, merged with defaults."""
|
|
89
|
-
config: Dict[str, Any] = DEFAULT_CONFIG
|
|
90
|
+
config: Dict[str, Any] = deepcopy(DEFAULT_CONFIG)
|
|
90
91
|
|
|
91
92
|
if config_path:
|
|
92
93
|
with open(config_path) as f:
|
|
93
|
-
user_config = yaml.safe_load(f)
|
|
94
|
+
user_config = yaml.safe_load(f) or {}
|
|
95
|
+
if not isinstance(user_config, dict):
|
|
96
|
+
raise ValueError("Training config must be a YAML mapping")
|
|
94
97
|
|
|
95
|
-
|
|
96
|
-
for key, value in user_config.items():
|
|
97
|
-
if isinstance(value, dict) and key in config and isinstance(config[key], dict):
|
|
98
|
-
config[key].update(value)
|
|
99
|
-
else:
|
|
100
|
-
config[key] = value
|
|
98
|
+
_deep_merge(config, user_config)
|
|
101
99
|
|
|
102
100
|
return config
|
|
103
101
|
|
|
104
102
|
|
|
103
|
+
def _deep_merge(base: Dict[str, Any], overrides: Dict[str, Any]) -> Dict[str, Any]:
|
|
104
|
+
r"""Recursively merge overrides into base."""
|
|
105
|
+
for key, value in overrides.items():
|
|
106
|
+
if isinstance(value, dict) and isinstance(base.get(key), dict):
|
|
107
|
+
_deep_merge(base[key], value)
|
|
108
|
+
else:
|
|
109
|
+
base[key] = value
|
|
110
|
+
return base
|
|
111
|
+
|
|
112
|
+
|
|
105
113
|
# =============================================================================
|
|
106
114
|
# CLI Group
|
|
107
115
|
# =============================================================================
|
|
@@ -228,6 +236,7 @@ def prepare(
|
|
|
228
236
|
@click.option("--epochs", type=int, default=None, help="Number of epochs (overrides config)")
|
|
229
237
|
@click.option("--batch-size", type=int, default=None, help="Batch size (overrides config)")
|
|
230
238
|
@click.option("--dry-run", is_flag=True, help="Validate config without training")
|
|
239
|
+
@click.option("--allow-mock", is_flag=True, help="Run the legacy mock training loop for demos only.")
|
|
231
240
|
def train(
|
|
232
241
|
config: Optional[str],
|
|
233
242
|
data_dir: str,
|
|
@@ -238,16 +247,16 @@ def train(
|
|
|
238
247
|
epochs: Optional[int],
|
|
239
248
|
batch_size: Optional[int],
|
|
240
249
|
dry_run: bool,
|
|
250
|
+
allow_mock: bool,
|
|
241
251
|
):
|
|
242
252
|
r"""
|
|
243
|
-
|
|
253
|
+
Validate training configuration for prior-injected models.
|
|
244
254
|
|
|
245
|
-
|
|
246
|
-
|
|
255
|
+
Full model training is not wired into the product path yet. Use --dry-run
|
|
256
|
+
to validate configuration or --allow-mock for the legacy demo loop.
|
|
247
257
|
|
|
248
258
|
Example:
|
|
249
|
-
xrtm-train train -c config.yaml -d samples/ -
|
|
250
|
-
xrtm-train train -d samples/ -m Qwen/Qwen2.5-1.5B --epochs 3
|
|
259
|
+
xrtm-train train -c config.yaml -d samples/ --dry-run
|
|
251
260
|
"""
|
|
252
261
|
# Load and merge config
|
|
253
262
|
cfg = load_config(config)
|
|
@@ -290,6 +299,12 @@ def train(
|
|
|
290
299
|
console.print("\n[yellow]Dry run complete. No training performed.[/yellow]")
|
|
291
300
|
return
|
|
292
301
|
|
|
302
|
+
if not allow_mock:
|
|
303
|
+
raise click.ClickException(
|
|
304
|
+
"Real model training is not implemented in this CLI yet. Use --dry-run to validate config, "
|
|
305
|
+
"or pass --allow-mock to run the legacy demo loop intentionally."
|
|
306
|
+
)
|
|
307
|
+
|
|
293
308
|
# Check for GPU dependencies
|
|
294
309
|
try:
|
|
295
310
|
import torch
|
|
@@ -393,14 +408,16 @@ def _run_training(cfg: dict, data_dir: str, output: str, resume: Optional[str])
|
|
|
393
408
|
@click.option("--model", "-m", required=True, type=click.Path(exists=True), help="Model directory")
|
|
394
409
|
@click.option("--data", "-d", "data_path", required=True, type=click.Path(exists=True), help="Test data file")
|
|
395
410
|
@click.option("--output", "-o", type=click.Path(), help="Output file for results (.json)")
|
|
396
|
-
|
|
411
|
+
@click.option("--allow-mock", is_flag=True, help="Emit the legacy mock metrics for demos only.")
|
|
412
|
+
def eval(model: str, data_path: str, output: Optional[str], allow_mock: bool):
|
|
397
413
|
r"""
|
|
398
|
-
|
|
414
|
+
Validate evaluation inputs for a trained model.
|
|
399
415
|
|
|
400
|
-
|
|
416
|
+
Full model evaluation is not wired into the product path yet. Use --allow-mock
|
|
417
|
+
only when intentionally exercising the legacy demo metrics.
|
|
401
418
|
|
|
402
419
|
Example:
|
|
403
|
-
xrtm-train eval -m models/final -d samples/test.jsonl
|
|
420
|
+
xrtm-train eval -m models/final -d samples/test.jsonl --allow-mock
|
|
404
421
|
"""
|
|
405
422
|
console.print(Panel(
|
|
406
423
|
f"[bold blue]Evaluating Model[/bold blue]\n"
|
|
@@ -423,8 +440,14 @@ def eval(model: str, data_path: str, output: Optional[str]):
|
|
|
423
440
|
test_samples = _load_jsonl(Path(data_path))
|
|
424
441
|
console.print(f"\nLoaded {len(test_samples)} test samples")
|
|
425
442
|
|
|
443
|
+
if not allow_mock:
|
|
444
|
+
raise click.ClickException(
|
|
445
|
+
"Real model evaluation is not implemented in this CLI yet. Pass --allow-mock to emit "
|
|
446
|
+
"the legacy demo metrics intentionally."
|
|
447
|
+
)
|
|
448
|
+
|
|
426
449
|
# Mock evaluation
|
|
427
|
-
console.print("\n[yellow]⚠
|
|
450
|
+
console.print("\n[yellow]⚠ Using legacy mock metrics because --allow-mock was provided.[/yellow]")
|
|
428
451
|
|
|
429
452
|
metrics = {
|
|
430
453
|
"brier_score": 0.15,
|
|
@@ -469,7 +492,7 @@ def init_config(output: str, model: str, strategy: str):
|
|
|
469
492
|
Example:
|
|
470
493
|
xrtm-train init-config -o config.yaml -m Qwen/Qwen2.5-7B
|
|
471
494
|
"""
|
|
472
|
-
config: Dict[str, Any] = DEFAULT_CONFIG
|
|
495
|
+
config: Dict[str, Any] = deepcopy(DEFAULT_CONFIG)
|
|
473
496
|
config["model"]["name"] = model # type: ignore[index]
|
|
474
497
|
config["model"]["strategy"] = strategy # type: ignore[index]
|
|
475
498
|
|
|
@@ -21,7 +21,7 @@ This module provides the single source of truth for the package version.
|
|
|
21
21
|
|
|
22
22
|
__all__ = ["__version__", "__author__", "__contact__", "__license__", "__copyright__"]
|
|
23
23
|
|
|
24
|
-
__version__ = "0.2.
|
|
24
|
+
__version__ = "0.2.4"
|
|
25
25
|
__author__ = "XRTM Team"
|
|
26
26
|
__contact__ = "moy@xrtm.org"
|
|
27
27
|
__license__ = "Apache-2.0"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: xrtm-train
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.4
|
|
4
4
|
Summary: The Learning/Optimization layer for XRTM.
|
|
5
5
|
Author-email: XRTM Team <moy@xrtm.org>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -14,8 +14,8 @@ Requires-Dist: click>=8.0.0
|
|
|
14
14
|
Requires-Dist: rich>=13.0.0
|
|
15
15
|
Requires-Dist: pyyaml>=6.0.0
|
|
16
16
|
Requires-Dist: xrtm-data>=0.2.2
|
|
17
|
-
Requires-Dist: xrtm-eval>=0.2.
|
|
18
|
-
Requires-Dist: xrtm-forecast>=0.6.
|
|
17
|
+
Requires-Dist: xrtm-eval>=0.2.3
|
|
18
|
+
Requires-Dist: xrtm-forecast>=0.6.3
|
|
19
19
|
Provides-Extra: dev
|
|
20
20
|
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
21
21
|
Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
|
|
@@ -18,7 +18,7 @@ from pathlib import Path
|
|
|
18
18
|
|
|
19
19
|
from click.testing import CliRunner
|
|
20
20
|
|
|
21
|
-
from xrtm.train.cli import main
|
|
21
|
+
from xrtm.train.cli import DEFAULT_CONFIG, load_config, main
|
|
22
22
|
|
|
23
23
|
|
|
24
24
|
def test_data_prepare_builds_jsonl_samples() -> None:
|
|
@@ -102,3 +102,47 @@ def test_data_prepare_can_derive_news_and_priors_from_trade_records() -> None:
|
|
|
102
102
|
assert rows[0]["current_news"] == "Market probability update: 0.400"
|
|
103
103
|
assert rows[0]["prior_alpha"] == 4.0
|
|
104
104
|
assert rows[0]["target_alpha"] == 6.0
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def test_load_config_deep_merge_does_not_mutate_defaults() -> None:
|
|
108
|
+
runner = CliRunner()
|
|
109
|
+
|
|
110
|
+
with runner.isolated_filesystem():
|
|
111
|
+
config_path = Path("config.yaml")
|
|
112
|
+
config_path.write_text("model:\n name: custom-model\n")
|
|
113
|
+
|
|
114
|
+
config = load_config(str(config_path))
|
|
115
|
+
|
|
116
|
+
assert config["model"]["name"] == "custom-model"
|
|
117
|
+
assert config["model"]["family"] == DEFAULT_CONFIG["model"]["family"]
|
|
118
|
+
assert DEFAULT_CONFIG["model"]["name"] == "Qwen/Qwen2.5-0.5B"
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def test_train_command_does_not_run_mock_training_by_default() -> None:
|
|
122
|
+
runner = CliRunner()
|
|
123
|
+
|
|
124
|
+
with runner.isolated_filesystem():
|
|
125
|
+
samples = Path("samples")
|
|
126
|
+
samples.mkdir()
|
|
127
|
+
(samples / "train.jsonl").write_text("{}\n")
|
|
128
|
+
(samples / "val.jsonl").write_text("{}\n")
|
|
129
|
+
|
|
130
|
+
result = runner.invoke(main, ["train", "--data", str(samples)])
|
|
131
|
+
|
|
132
|
+
assert result.exit_code != 0
|
|
133
|
+
assert "Real model training is not implemented" in result.output
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def test_eval_command_does_not_emit_mock_metrics_by_default() -> None:
|
|
137
|
+
runner = CliRunner()
|
|
138
|
+
|
|
139
|
+
with runner.isolated_filesystem():
|
|
140
|
+
model = Path("model")
|
|
141
|
+
model.mkdir()
|
|
142
|
+
data = Path("test.jsonl")
|
|
143
|
+
data.write_text("{}\n")
|
|
144
|
+
|
|
145
|
+
result = runner.invoke(main, ["eval", "--model", str(model), "--data", str(data)])
|
|
146
|
+
|
|
147
|
+
assert result.exit_code != 0
|
|
148
|
+
assert "Real model evaluation is not implemented" in result.output
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|