zeromodel-analysis 1.1.0__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.
- zeromodel/analysis/__init__.py +219 -0
- zeromodel/analysis/adapters/__init__.py +29 -0
- zeromodel/analysis/adapters/common.py +207 -0
- zeromodel/analysis/adapters/jsonl.py +52 -0
- zeromodel/analysis/adapters/tensorboard.py +52 -0
- zeromodel/analysis/adapters/trackio.py +40 -0
- zeromodel/analysis/adapters/wandb.py +45 -0
- zeromodel/analysis/compare.py +55 -0
- zeromodel/analysis/compose.py +68 -0
- zeromodel/analysis/controller.py +317 -0
- zeromodel/analysis/critic.py +471 -0
- zeromodel/analysis/domains/__init__.py +1 -0
- zeromodel/analysis/edge.py +60 -0
- zeromodel/analysis/hierarchy.py +81 -0
- zeromodel/analysis/learning.py +290 -0
- zeromodel/analysis/manifold.py +365 -0
- zeromodel/analysis/patterns.py +565 -0
- zeromodel/analysis/phos.py +168 -0
- zeromodel/analysis/policy_diagnostics.py +93 -0
- zeromodel/analysis/policy_properties.py +472 -0
- zeromodel/analysis/spatial.py +350 -0
- zeromodel/analysis/training.py +373 -0
- zeromodel_analysis-1.1.0.dist-info/METADATA +133 -0
- zeromodel_analysis-1.1.0.dist-info/RECORD +26 -0
- zeromodel_analysis-1.1.0.dist-info/WHEEL +5 -0
- zeromodel_analysis-1.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
"""ZeroModel analysis public API."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from .adapters.common import (
|
|
6
|
+
checkpoints_from_export,
|
|
7
|
+
load_tracker_records,
|
|
8
|
+
records_to_checkpoints,
|
|
9
|
+
)
|
|
10
|
+
from .adapters.jsonl import (
|
|
11
|
+
checkpoints_from_csv,
|
|
12
|
+
checkpoints_from_json,
|
|
13
|
+
checkpoints_from_jsonl,
|
|
14
|
+
)
|
|
15
|
+
from .adapters.tensorboard import (
|
|
16
|
+
TENSORBOARD_DEFAULT_ALIASES,
|
|
17
|
+
checkpoints_from_tensorboard_scalars,
|
|
18
|
+
)
|
|
19
|
+
from .adapters.trackio import (
|
|
20
|
+
TRACKIO_DEFAULT_ALIASES,
|
|
21
|
+
checkpoints_from_trackio_export,
|
|
22
|
+
)
|
|
23
|
+
from .adapters.wandb import (
|
|
24
|
+
WANDB_DEFAULT_ALIASES,
|
|
25
|
+
checkpoints_from_wandb_export,
|
|
26
|
+
)
|
|
27
|
+
from .compare import (
|
|
28
|
+
VPMComparison,
|
|
29
|
+
compare_fields,
|
|
30
|
+
)
|
|
31
|
+
from .compose import (
|
|
32
|
+
as_field,
|
|
33
|
+
vpm_add,
|
|
34
|
+
vpm_and,
|
|
35
|
+
vpm_not,
|
|
36
|
+
vpm_or,
|
|
37
|
+
vpm_subtract,
|
|
38
|
+
vpm_xor,
|
|
39
|
+
)
|
|
40
|
+
from .controller import (
|
|
41
|
+
Decision,
|
|
42
|
+
Policy,
|
|
43
|
+
Signal,
|
|
44
|
+
Thresholds,
|
|
45
|
+
VPMController,
|
|
46
|
+
VPMRow,
|
|
47
|
+
default_controller,
|
|
48
|
+
)
|
|
49
|
+
from .critic import (
|
|
50
|
+
CriticAssessment,
|
|
51
|
+
CriticObservation,
|
|
52
|
+
build_critic_vpm,
|
|
53
|
+
critic_recipe,
|
|
54
|
+
observations_from_critic_lines,
|
|
55
|
+
)
|
|
56
|
+
from .edge import (
|
|
57
|
+
TopLeftGate,
|
|
58
|
+
TopLeftGateResult,
|
|
59
|
+
)
|
|
60
|
+
from .hierarchy import (
|
|
61
|
+
HierarchyLevel,
|
|
62
|
+
build_pyramid,
|
|
63
|
+
reduce_blocks,
|
|
64
|
+
)
|
|
65
|
+
from .learning import (
|
|
66
|
+
LearningAssessment,
|
|
67
|
+
LearningObservation,
|
|
68
|
+
VALID_SPLITS,
|
|
69
|
+
build_learning_vpm,
|
|
70
|
+
learning_recipe,
|
|
71
|
+
)
|
|
72
|
+
from .manifold import (
|
|
73
|
+
DecisionManifold,
|
|
74
|
+
ManifoldFrame,
|
|
75
|
+
ManifoldSummary,
|
|
76
|
+
ManifoldTransition,
|
|
77
|
+
build_decision_manifold,
|
|
78
|
+
find_inflection_points,
|
|
79
|
+
)
|
|
80
|
+
from .patterns import (
|
|
81
|
+
MatrixPatternDetector,
|
|
82
|
+
OBJECTIVE_IDS,
|
|
83
|
+
ObjectiveResult,
|
|
84
|
+
PATTERN_CHECKER_VERSION,
|
|
85
|
+
PATTERN_METHOD,
|
|
86
|
+
PatternAnalysisSpec,
|
|
87
|
+
PatternDiscoveryArtifacts,
|
|
88
|
+
PatternReport,
|
|
89
|
+
REPORT_METRICS,
|
|
90
|
+
build_discovered_view,
|
|
91
|
+
detect_patterns,
|
|
92
|
+
)
|
|
93
|
+
from .phos import (
|
|
94
|
+
PHOSResult,
|
|
95
|
+
guarded_pack_artifact,
|
|
96
|
+
image_entropy,
|
|
97
|
+
pack_artifact,
|
|
98
|
+
phos_sort_pack,
|
|
99
|
+
robust01,
|
|
100
|
+
to_square,
|
|
101
|
+
top_left_concentration,
|
|
102
|
+
)
|
|
103
|
+
from .policy_diagnostics import (
|
|
104
|
+
CRITICALITY_METRIC_ID,
|
|
105
|
+
DECISION_MARGIN_METRIC_ID,
|
|
106
|
+
with_q_diagnostics,
|
|
107
|
+
)
|
|
108
|
+
from .policy_properties import (
|
|
109
|
+
CHECKER_VERSION,
|
|
110
|
+
PolicyPropertyChecker,
|
|
111
|
+
PolicyPropertyResult,
|
|
112
|
+
PolicyPropertySpec,
|
|
113
|
+
PolicyPropertyViolation,
|
|
114
|
+
PolicyVerificationReport,
|
|
115
|
+
VERIFICATION_METRICS,
|
|
116
|
+
decode_key_value_row_id,
|
|
117
|
+
)
|
|
118
|
+
from .spatial import (
|
|
119
|
+
SpatialOptimizationResult,
|
|
120
|
+
SpatialOptimizer,
|
|
121
|
+
build_optimized_view,
|
|
122
|
+
optimize_view_profile,
|
|
123
|
+
)
|
|
124
|
+
from .training import (
|
|
125
|
+
TrainingCheckpoint,
|
|
126
|
+
TrainingProgressAssessment,
|
|
127
|
+
build_training_progress_vpm,
|
|
128
|
+
training_progress_recipe,
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
__all__ = [
|
|
132
|
+
"CHECKER_VERSION",
|
|
133
|
+
"CRITICALITY_METRIC_ID",
|
|
134
|
+
"CriticAssessment",
|
|
135
|
+
"CriticObservation",
|
|
136
|
+
"DECISION_MARGIN_METRIC_ID",
|
|
137
|
+
"Decision",
|
|
138
|
+
"DecisionManifold",
|
|
139
|
+
"HierarchyLevel",
|
|
140
|
+
"LearningAssessment",
|
|
141
|
+
"LearningObservation",
|
|
142
|
+
"ManifoldFrame",
|
|
143
|
+
"ManifoldSummary",
|
|
144
|
+
"ManifoldTransition",
|
|
145
|
+
"MatrixPatternDetector",
|
|
146
|
+
"OBJECTIVE_IDS",
|
|
147
|
+
"ObjectiveResult",
|
|
148
|
+
"PATTERN_CHECKER_VERSION",
|
|
149
|
+
"PATTERN_METHOD",
|
|
150
|
+
"PHOSResult",
|
|
151
|
+
"PatternAnalysisSpec",
|
|
152
|
+
"PatternDiscoveryArtifacts",
|
|
153
|
+
"PatternReport",
|
|
154
|
+
"Policy",
|
|
155
|
+
"PolicyPropertyChecker",
|
|
156
|
+
"PolicyPropertyResult",
|
|
157
|
+
"PolicyPropertySpec",
|
|
158
|
+
"PolicyPropertyViolation",
|
|
159
|
+
"PolicyVerificationReport",
|
|
160
|
+
"REPORT_METRICS",
|
|
161
|
+
"Signal",
|
|
162
|
+
"SpatialOptimizationResult",
|
|
163
|
+
"SpatialOptimizer",
|
|
164
|
+
"TENSORBOARD_DEFAULT_ALIASES",
|
|
165
|
+
"TRACKIO_DEFAULT_ALIASES",
|
|
166
|
+
"Thresholds",
|
|
167
|
+
"TopLeftGate",
|
|
168
|
+
"TopLeftGateResult",
|
|
169
|
+
"TrainingCheckpoint",
|
|
170
|
+
"TrainingProgressAssessment",
|
|
171
|
+
"VALID_SPLITS",
|
|
172
|
+
"VERIFICATION_METRICS",
|
|
173
|
+
"VPMComparison",
|
|
174
|
+
"VPMController",
|
|
175
|
+
"VPMRow",
|
|
176
|
+
"WANDB_DEFAULT_ALIASES",
|
|
177
|
+
"as_field",
|
|
178
|
+
"build_critic_vpm",
|
|
179
|
+
"build_decision_manifold",
|
|
180
|
+
"build_discovered_view",
|
|
181
|
+
"build_learning_vpm",
|
|
182
|
+
"build_optimized_view",
|
|
183
|
+
"build_pyramid",
|
|
184
|
+
"build_training_progress_vpm",
|
|
185
|
+
"checkpoints_from_csv",
|
|
186
|
+
"checkpoints_from_export",
|
|
187
|
+
"checkpoints_from_json",
|
|
188
|
+
"checkpoints_from_jsonl",
|
|
189
|
+
"checkpoints_from_tensorboard_scalars",
|
|
190
|
+
"checkpoints_from_trackio_export",
|
|
191
|
+
"checkpoints_from_wandb_export",
|
|
192
|
+
"compare_fields",
|
|
193
|
+
"critic_recipe",
|
|
194
|
+
"decode_key_value_row_id",
|
|
195
|
+
"default_controller",
|
|
196
|
+
"detect_patterns",
|
|
197
|
+
"find_inflection_points",
|
|
198
|
+
"guarded_pack_artifact",
|
|
199
|
+
"image_entropy",
|
|
200
|
+
"learning_recipe",
|
|
201
|
+
"load_tracker_records",
|
|
202
|
+
"observations_from_critic_lines",
|
|
203
|
+
"optimize_view_profile",
|
|
204
|
+
"pack_artifact",
|
|
205
|
+
"phos_sort_pack",
|
|
206
|
+
"records_to_checkpoints",
|
|
207
|
+
"reduce_blocks",
|
|
208
|
+
"robust01",
|
|
209
|
+
"to_square",
|
|
210
|
+
"top_left_concentration",
|
|
211
|
+
"training_progress_recipe",
|
|
212
|
+
"vpm_add",
|
|
213
|
+
"vpm_and",
|
|
214
|
+
"vpm_not",
|
|
215
|
+
"vpm_or",
|
|
216
|
+
"vpm_subtract",
|
|
217
|
+
"vpm_xor",
|
|
218
|
+
"with_q_diagnostics",
|
|
219
|
+
]
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"""Dependency-light adapters from tracker exports to ZeroModel checkpoints."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from zeromodel.analysis.adapters.common import (
|
|
6
|
+
checkpoints_from_export,
|
|
7
|
+
load_tracker_records,
|
|
8
|
+
records_to_checkpoints,
|
|
9
|
+
)
|
|
10
|
+
from zeromodel.analysis.adapters.jsonl import (
|
|
11
|
+
checkpoints_from_csv,
|
|
12
|
+
checkpoints_from_json,
|
|
13
|
+
checkpoints_from_jsonl,
|
|
14
|
+
)
|
|
15
|
+
from zeromodel.analysis.adapters.tensorboard import checkpoints_from_tensorboard_scalars
|
|
16
|
+
from zeromodel.analysis.adapters.trackio import checkpoints_from_trackio_export
|
|
17
|
+
from zeromodel.analysis.adapters.wandb import checkpoints_from_wandb_export
|
|
18
|
+
|
|
19
|
+
__all__ = [
|
|
20
|
+
"checkpoints_from_csv",
|
|
21
|
+
"checkpoints_from_export",
|
|
22
|
+
"checkpoints_from_json",
|
|
23
|
+
"checkpoints_from_jsonl",
|
|
24
|
+
"checkpoints_from_tensorboard_scalars",
|
|
25
|
+
"checkpoints_from_trackio_export",
|
|
26
|
+
"checkpoints_from_wandb_export",
|
|
27
|
+
"load_tracker_records",
|
|
28
|
+
"records_to_checkpoints",
|
|
29
|
+
]
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
"""Common helpers for converting tracker exports into training checkpoints.
|
|
2
|
+
|
|
3
|
+
The adapters in this package intentionally parse exported files rather than live
|
|
4
|
+
tracker APIs. That keeps ZeroModel dependency-light and makes the resulting
|
|
5
|
+
training progress artifacts reproducible from checked-in fixtures.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import csv
|
|
11
|
+
import json
|
|
12
|
+
from collections import OrderedDict
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
from typing import Any, Iterable, Mapping, Sequence
|
|
15
|
+
|
|
16
|
+
from zeromodel.core.artifact import VPMValidationError
|
|
17
|
+
from zeromodel.analysis.training import TrainingCheckpoint
|
|
18
|
+
|
|
19
|
+
_DEFAULT_IGNORE_KEYS = {
|
|
20
|
+
"step",
|
|
21
|
+
"global_step",
|
|
22
|
+
"_step",
|
|
23
|
+
"checkpoint_id",
|
|
24
|
+
"metadata",
|
|
25
|
+
"wall_time",
|
|
26
|
+
"timestamp",
|
|
27
|
+
"time",
|
|
28
|
+
"epoch",
|
|
29
|
+
"tag",
|
|
30
|
+
"name",
|
|
31
|
+
"value",
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _as_number(value: Any) -> float | None:
|
|
36
|
+
if isinstance(value, bool) or value is None:
|
|
37
|
+
return None
|
|
38
|
+
try:
|
|
39
|
+
number = float(value)
|
|
40
|
+
except (TypeError, ValueError):
|
|
41
|
+
return None
|
|
42
|
+
if number != number or number in (float("inf"), float("-inf")):
|
|
43
|
+
return None
|
|
44
|
+
return number
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _load_json(path: Path) -> list[Mapping[str, Any]]:
|
|
48
|
+
payload = json.loads(path.read_text(encoding="utf-8"))
|
|
49
|
+
if isinstance(payload, list):
|
|
50
|
+
records = payload
|
|
51
|
+
elif isinstance(payload, dict):
|
|
52
|
+
for key in ("records", "history", "checkpoints", "rows", "data"):
|
|
53
|
+
if isinstance(payload.get(key), list):
|
|
54
|
+
records = payload[key]
|
|
55
|
+
break
|
|
56
|
+
else:
|
|
57
|
+
records = [payload]
|
|
58
|
+
else:
|
|
59
|
+
raise VPMValidationError(
|
|
60
|
+
"JSON tracker export must be an object or list of objects"
|
|
61
|
+
)
|
|
62
|
+
if not all(isinstance(item, Mapping) for item in records):
|
|
63
|
+
raise VPMValidationError("Tracker export records must be objects")
|
|
64
|
+
return [dict(item) for item in records]
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def _load_jsonl(path: Path) -> list[Mapping[str, Any]]:
|
|
68
|
+
records: list[Mapping[str, Any]] = []
|
|
69
|
+
for line_number, line in enumerate(
|
|
70
|
+
path.read_text(encoding="utf-8").splitlines(), start=1
|
|
71
|
+
):
|
|
72
|
+
text = line.strip()
|
|
73
|
+
if not text:
|
|
74
|
+
continue
|
|
75
|
+
item = json.loads(text)
|
|
76
|
+
if not isinstance(item, Mapping):
|
|
77
|
+
raise VPMValidationError(
|
|
78
|
+
"JSONL tracker record on line %s must be an object" % line_number
|
|
79
|
+
)
|
|
80
|
+
records.append(dict(item))
|
|
81
|
+
return records
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def _load_csv(path: Path) -> list[Mapping[str, Any]]:
|
|
85
|
+
with path.open("r", encoding="utf-8", newline="") as handle:
|
|
86
|
+
return [dict(row) for row in csv.DictReader(handle)]
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def load_tracker_records(path: str | Path) -> list[Mapping[str, Any]]:
|
|
90
|
+
"""Load JSON, JSONL, or CSV tracker records from ``path``."""
|
|
91
|
+
source = Path(path)
|
|
92
|
+
suffix = source.suffix.lower()
|
|
93
|
+
if suffix == ".json":
|
|
94
|
+
return _load_json(source)
|
|
95
|
+
if suffix in {".jsonl", ".ndjson"}:
|
|
96
|
+
return _load_jsonl(source)
|
|
97
|
+
if suffix == ".csv":
|
|
98
|
+
return _load_csv(source)
|
|
99
|
+
raise VPMValidationError("Unsupported tracker export format: %s" % suffix)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def _first_present(record: Mapping[str, Any], keys: Sequence[str]) -> str | None:
|
|
103
|
+
for key in keys:
|
|
104
|
+
if key in record:
|
|
105
|
+
return key
|
|
106
|
+
return None
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def _metric_name(name: str, aliases: Mapping[str, str]) -> str:
|
|
110
|
+
return str(aliases.get(name, name)).replace("/", "_").replace(" ", "_")
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def _metadata_for_record(
|
|
114
|
+
record: Mapping[str, Any], metadata_keys: Iterable[str]
|
|
115
|
+
) -> dict[str, Any]:
|
|
116
|
+
return {key: record[key] for key in metadata_keys if key in record}
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def records_to_checkpoints(
|
|
120
|
+
records: Sequence[Mapping[str, Any]],
|
|
121
|
+
*,
|
|
122
|
+
step_keys: Sequence[str] = ("step", "global_step", "_step"),
|
|
123
|
+
metrics_key: str = "metrics",
|
|
124
|
+
tag_key: str | None = None,
|
|
125
|
+
value_key: str | None = None,
|
|
126
|
+
checkpoint_id_key: str = "checkpoint_id",
|
|
127
|
+
metric_aliases: Mapping[str, str] | None = None,
|
|
128
|
+
metadata_keys: Sequence[str] = ("wall_time", "timestamp", "time", "epoch"),
|
|
129
|
+
ignore_keys: Iterable[str] = _DEFAULT_IGNORE_KEYS,
|
|
130
|
+
) -> list[TrainingCheckpoint]:
|
|
131
|
+
"""Convert tracker records into ordered ``TrainingCheckpoint`` objects.
|
|
132
|
+
|
|
133
|
+
Two export shapes are supported:
|
|
134
|
+
|
|
135
|
+
1. one row per checkpoint, with either a nested ``metrics`` object or flat
|
|
136
|
+
numeric columns;
|
|
137
|
+
2. one row per scalar, with ``tag`` and ``value`` columns that are grouped by
|
|
138
|
+
step, as in TensorBoard scalar CSV exports.
|
|
139
|
+
"""
|
|
140
|
+
if not records:
|
|
141
|
+
raise VPMValidationError("Tracker export contained no records")
|
|
142
|
+
|
|
143
|
+
aliases = {
|
|
144
|
+
str(key): str(value) for key, value in dict(metric_aliases or {}).items()
|
|
145
|
+
}
|
|
146
|
+
ignored = {str(key) for key in ignore_keys}
|
|
147
|
+
by_step: "OrderedDict[int, dict[str, Any]]" = OrderedDict()
|
|
148
|
+
|
|
149
|
+
for record in records:
|
|
150
|
+
step_key = _first_present(record, step_keys)
|
|
151
|
+
if step_key is None:
|
|
152
|
+
raise VPMValidationError(
|
|
153
|
+
"Tracker record is missing a step key; tried %r" % (tuple(step_keys),)
|
|
154
|
+
)
|
|
155
|
+
step_number = _as_number(record[step_key])
|
|
156
|
+
if step_number is None:
|
|
157
|
+
raise VPMValidationError("Tracker step value must be numeric")
|
|
158
|
+
step = int(step_number)
|
|
159
|
+
if step not in by_step:
|
|
160
|
+
by_step[step] = {"metrics": {}, "metadata": {}}
|
|
161
|
+
bucket = by_step[step]
|
|
162
|
+
|
|
163
|
+
if tag_key and value_key and tag_key in record and value_key in record:
|
|
164
|
+
value = _as_number(record[value_key])
|
|
165
|
+
if value is not None:
|
|
166
|
+
bucket["metrics"][_metric_name(str(record[tag_key]), aliases)] = value
|
|
167
|
+
elif isinstance(record.get(metrics_key), Mapping):
|
|
168
|
+
for key, value in record[metrics_key].items():
|
|
169
|
+
number = _as_number(value)
|
|
170
|
+
if number is not None:
|
|
171
|
+
bucket["metrics"][_metric_name(str(key), aliases)] = number
|
|
172
|
+
else:
|
|
173
|
+
for key, value in record.items():
|
|
174
|
+
if key in ignored:
|
|
175
|
+
continue
|
|
176
|
+
number = _as_number(value)
|
|
177
|
+
if number is not None:
|
|
178
|
+
bucket["metrics"][_metric_name(str(key), aliases)] = number
|
|
179
|
+
|
|
180
|
+
bucket["metadata"].update(_metadata_for_record(record, metadata_keys))
|
|
181
|
+
if checkpoint_id_key in record:
|
|
182
|
+
bucket["checkpoint_id"] = str(record[checkpoint_id_key])
|
|
183
|
+
|
|
184
|
+
checkpoints: list[TrainingCheckpoint] = []
|
|
185
|
+
for step, payload in by_step.items():
|
|
186
|
+
metrics = payload["metrics"]
|
|
187
|
+
if not metrics:
|
|
188
|
+
continue
|
|
189
|
+
checkpoints.append(
|
|
190
|
+
TrainingCheckpoint(
|
|
191
|
+
step=step,
|
|
192
|
+
checkpoint_id=payload.get("checkpoint_id") or "step_%s" % step,
|
|
193
|
+
metrics=metrics,
|
|
194
|
+
metadata=payload.get("metadata", {}),
|
|
195
|
+
)
|
|
196
|
+
)
|
|
197
|
+
if not checkpoints:
|
|
198
|
+
raise VPMValidationError("Tracker export contained no numeric metrics")
|
|
199
|
+
return sorted(checkpoints, key=lambda checkpoint: checkpoint.step)
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
def checkpoints_from_export(
|
|
203
|
+
path: str | Path,
|
|
204
|
+
**kwargs: Any,
|
|
205
|
+
) -> list[TrainingCheckpoint]:
|
|
206
|
+
"""Load records from a tracker export and convert them to checkpoints."""
|
|
207
|
+
return records_to_checkpoints(load_tracker_records(path), **kwargs)
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"""Generic JSON/JSONL/CSV training telemetry adapters."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Any, Mapping, Sequence
|
|
7
|
+
|
|
8
|
+
from zeromodel.analysis.training import TrainingCheckpoint
|
|
9
|
+
|
|
10
|
+
from zeromodel.analysis.adapters.common import checkpoints_from_export
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def checkpoints_from_jsonl(
|
|
14
|
+
path: str | Path,
|
|
15
|
+
*,
|
|
16
|
+
step_keys: Sequence[str] = ("step", "global_step", "_step"),
|
|
17
|
+
metric_aliases: Mapping[str, str] | None = None,
|
|
18
|
+
) -> list[TrainingCheckpoint]:
|
|
19
|
+
"""Load checkpoint telemetry from a JSONL export.
|
|
20
|
+
|
|
21
|
+
Each line may contain a nested ``metrics`` object or flat numeric metric
|
|
22
|
+
columns. The return value can be passed directly to
|
|
23
|
+
``build_training_progress_vpm``.
|
|
24
|
+
"""
|
|
25
|
+
return checkpoints_from_export(
|
|
26
|
+
path, step_keys=step_keys, metric_aliases=metric_aliases
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def checkpoints_from_json(
|
|
31
|
+
path: str | Path,
|
|
32
|
+
*,
|
|
33
|
+
step_keys: Sequence[str] = ("step", "global_step", "_step"),
|
|
34
|
+
metric_aliases: Mapping[str, str] | None = None,
|
|
35
|
+
) -> list[TrainingCheckpoint]:
|
|
36
|
+
"""Load checkpoint telemetry from a JSON export."""
|
|
37
|
+
return checkpoints_from_export(
|
|
38
|
+
path, step_keys=step_keys, metric_aliases=metric_aliases
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def checkpoints_from_csv(
|
|
43
|
+
path: str | Path,
|
|
44
|
+
*,
|
|
45
|
+
step_keys: Sequence[str] = ("step", "global_step", "_step"),
|
|
46
|
+
metric_aliases: Mapping[str, str] | None = None,
|
|
47
|
+
**kwargs: Any,
|
|
48
|
+
) -> list[TrainingCheckpoint]:
|
|
49
|
+
"""Load checkpoint telemetry from a CSV export."""
|
|
50
|
+
return checkpoints_from_export(
|
|
51
|
+
path, step_keys=step_keys, metric_aliases=metric_aliases, **kwargs
|
|
52
|
+
)
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"""TensorBoard scalar export adapter.
|
|
2
|
+
|
|
3
|
+
This adapter parses exported scalar CSV/JSON/JSONL files. It deliberately does not
|
|
4
|
+
parse TensorBoard event protobufs directly, keeping ZeroModel free of TensorBoard
|
|
5
|
+
runtime dependencies.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
from typing import Mapping, Sequence
|
|
12
|
+
|
|
13
|
+
from zeromodel.analysis.training import TrainingCheckpoint
|
|
14
|
+
|
|
15
|
+
from zeromodel.analysis.adapters.common import checkpoints_from_export
|
|
16
|
+
|
|
17
|
+
TENSORBOARD_DEFAULT_ALIASES = {
|
|
18
|
+
"train/loss": "train_loss",
|
|
19
|
+
"loss/train": "train_loss",
|
|
20
|
+
"eval/loss": "eval_loss",
|
|
21
|
+
"validation/loss": "eval_loss",
|
|
22
|
+
"eval/accuracy": "heldout_score",
|
|
23
|
+
"validation/accuracy": "heldout_score",
|
|
24
|
+
"eval/reward": "heldout_score",
|
|
25
|
+
"tokens/sec": "tokens_per_second",
|
|
26
|
+
"tokens_per_second": "tokens_per_second",
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def checkpoints_from_tensorboard_scalars(
|
|
31
|
+
path: str | Path,
|
|
32
|
+
*,
|
|
33
|
+
step_keys: Sequence[str] = ("step", "global_step"),
|
|
34
|
+
tag_key: str = "tag",
|
|
35
|
+
value_key: str = "value",
|
|
36
|
+
metric_aliases: Mapping[str, str] | None = None,
|
|
37
|
+
) -> list[TrainingCheckpoint]:
|
|
38
|
+
"""Load checkpoints from TensorBoard scalar exports.
|
|
39
|
+
|
|
40
|
+
TensorBoard's scalar dashboard can export rows shaped like
|
|
41
|
+
``wall_time,step,tag,value``. Those rows are grouped into one checkpoint per
|
|
42
|
+
step.
|
|
43
|
+
"""
|
|
44
|
+
aliases = dict(TENSORBOARD_DEFAULT_ALIASES)
|
|
45
|
+
aliases.update(dict(metric_aliases or {}))
|
|
46
|
+
return checkpoints_from_export(
|
|
47
|
+
path,
|
|
48
|
+
step_keys=step_keys,
|
|
49
|
+
tag_key=tag_key,
|
|
50
|
+
value_key=value_key,
|
|
51
|
+
metric_aliases=aliases,
|
|
52
|
+
)
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"""Trackio training telemetry export adapter.
|
|
2
|
+
|
|
3
|
+
Supports JSON/JSONL/CSV metric exports shaped as flat rows or rows with nested
|
|
4
|
+
``metrics`` dictionaries. No Trackio runtime dependency is required.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
from typing import Mapping, Sequence
|
|
11
|
+
|
|
12
|
+
from zeromodel.analysis.training import TrainingCheckpoint
|
|
13
|
+
|
|
14
|
+
from zeromodel.analysis.adapters.common import checkpoints_from_export
|
|
15
|
+
|
|
16
|
+
TRACKIO_DEFAULT_ALIASES = {
|
|
17
|
+
"train/loss": "train_loss",
|
|
18
|
+
"train_loss": "train_loss",
|
|
19
|
+
"eval/loss": "eval_loss",
|
|
20
|
+
"validation/loss": "eval_loss",
|
|
21
|
+
"eval/accuracy": "heldout_score",
|
|
22
|
+
"validation/accuracy": "heldout_score",
|
|
23
|
+
"eval/reward": "heldout_score",
|
|
24
|
+
"regression_safety": "regression_safety",
|
|
25
|
+
"safety/regression": "regression_safety",
|
|
26
|
+
"tokens/sec": "tokens_per_second",
|
|
27
|
+
"tokens_per_second": "tokens_per_second",
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def checkpoints_from_trackio_export(
|
|
32
|
+
path: str | Path,
|
|
33
|
+
*,
|
|
34
|
+
step_keys: Sequence[str] = ("step", "global_step", "_step"),
|
|
35
|
+
metric_aliases: Mapping[str, str] | None = None,
|
|
36
|
+
) -> list[TrainingCheckpoint]:
|
|
37
|
+
"""Load checkpoints from a Trackio metrics export."""
|
|
38
|
+
aliases = dict(TRACKIO_DEFAULT_ALIASES)
|
|
39
|
+
aliases.update(dict(metric_aliases or {}))
|
|
40
|
+
return checkpoints_from_export(path, step_keys=step_keys, metric_aliases=aliases)
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"""Weights & Biases history export adapter.
|
|
2
|
+
|
|
3
|
+
Supports exported history JSONL/JSON/CSV files. No W&B SDK is required.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from typing import Mapping, Sequence
|
|
10
|
+
|
|
11
|
+
from zeromodel.analysis.training import TrainingCheckpoint
|
|
12
|
+
|
|
13
|
+
from zeromodel.analysis.adapters.common import checkpoints_from_export
|
|
14
|
+
|
|
15
|
+
WANDB_DEFAULT_ALIASES = {
|
|
16
|
+
"train/loss": "train_loss",
|
|
17
|
+
"train_loss": "train_loss",
|
|
18
|
+
"eval/loss": "eval_loss",
|
|
19
|
+
"val/loss": "eval_loss",
|
|
20
|
+
"validation/loss": "eval_loss",
|
|
21
|
+
"eval/accuracy": "heldout_score",
|
|
22
|
+
"val/accuracy": "heldout_score",
|
|
23
|
+
"validation/accuracy": "heldout_score",
|
|
24
|
+
"eval/reward": "heldout_score",
|
|
25
|
+
"safety/regression": "regression_safety",
|
|
26
|
+
"regression/safety": "regression_safety",
|
|
27
|
+
"system/tokens_per_second": "tokens_per_second",
|
|
28
|
+
"tokens/sec": "tokens_per_second",
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def checkpoints_from_wandb_export(
|
|
33
|
+
path: str | Path,
|
|
34
|
+
*,
|
|
35
|
+
step_keys: Sequence[str] = ("_step", "step", "global_step"),
|
|
36
|
+
metric_aliases: Mapping[str, str] | None = None,
|
|
37
|
+
) -> list[TrainingCheckpoint]:
|
|
38
|
+
"""Load checkpoints from a W&B history export.
|
|
39
|
+
|
|
40
|
+
The adapter accepts flat history rows and nested ``metrics`` rows. Metric names
|
|
41
|
+
with slashes are normalized to underscores after aliasing.
|
|
42
|
+
"""
|
|
43
|
+
aliases = dict(WANDB_DEFAULT_ALIASES)
|
|
44
|
+
aliases.update(dict(metric_aliases or {}))
|
|
45
|
+
return checkpoints_from_export(path, step_keys=step_keys, metric_aliases=aliases)
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"""Differential analysis helpers for VPM artifacts and fields."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
import numpy as np
|
|
9
|
+
|
|
10
|
+
from zeromodel.analysis.compose import as_field, vpm_add, vpm_and, vpm_subtract, vpm_xor
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@dataclass(frozen=True)
|
|
14
|
+
class VPMComparison:
|
|
15
|
+
diff: np.ndarray
|
|
16
|
+
overlap: np.ndarray
|
|
17
|
+
contrast: np.ndarray
|
|
18
|
+
enriched: np.ndarray
|
|
19
|
+
gain: float
|
|
20
|
+
loss: float
|
|
21
|
+
improvement_ratio: float
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def compare_fields(
|
|
25
|
+
baseline: Any, target: Any, *, overlap_weight: float = 0.25
|
|
26
|
+
) -> VPMComparison:
|
|
27
|
+
"""Compare a baseline field with a target field.
|
|
28
|
+
|
|
29
|
+
``gain`` is positive target-minus-baseline mass; ``loss`` is negative mass;
|
|
30
|
+
``improvement_ratio`` is gain / (gain + loss).
|
|
31
|
+
"""
|
|
32
|
+
base = as_field(baseline)
|
|
33
|
+
tgt = as_field(target)
|
|
34
|
+
if base.shape != tgt.shape:
|
|
35
|
+
raise ValueError(
|
|
36
|
+
"VPM fields must have identical shapes; got %s and %s"
|
|
37
|
+
% (base.shape, tgt.shape)
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
signed = tgt - base
|
|
41
|
+
gain = float(np.sum(np.clip(signed, 0.0, None)))
|
|
42
|
+
loss = float(np.sum(np.clip(-signed, 0.0, None)))
|
|
43
|
+
total = gain + loss + 1e-12
|
|
44
|
+
overlap = vpm_and(base, tgt)
|
|
45
|
+
contrast = vpm_xor(base, tgt)
|
|
46
|
+
enriched = vpm_add(vpm_subtract(tgt, base), overlap * float(overlap_weight))
|
|
47
|
+
return VPMComparison(
|
|
48
|
+
diff=signed,
|
|
49
|
+
overlap=overlap,
|
|
50
|
+
contrast=contrast,
|
|
51
|
+
enriched=enriched,
|
|
52
|
+
gain=gain,
|
|
53
|
+
loss=loss,
|
|
54
|
+
improvement_ratio=float(gain / total),
|
|
55
|
+
)
|