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.
@@ -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
+ )