@zhuoyuezs/ml-platform 0.2.7 → 0.2.9
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.
- package/CI-ARTIFACT.md +2 -2
- package/checksums.json +36 -36
- package/package.json +1 -1
- package/release.json +18 -18
- package/runtime/business-client/README.md +66 -3
- package/runtime/business-client/package-lock.json +2 -2
- package/runtime/business-client/package.json +1 -1
- package/runtime/business-client/src/catalog.js +25 -6
- package/runtime/business-client/src/cli.js +90 -6
- package/runtime/business-client/src/http.js +192 -32
- package/skills/feature-management/SKILL.md +17 -7
- package/skills/feature-management/references/commands.md +50 -7
- package/skills/feature-management/references/contracts.md +124 -6
- package/skills/feature-management/references/operator-authoring.md +116 -8
- package/skills/model-deployment-management/SKILL.md +3 -0
- package/skills/model-deployment-management/references/operations.md +14 -1
- package/skills/model-lifecycle-management/SKILL.md +16 -0
- package/skills/model-lifecycle-management/references/discovery.md +18 -3
- package/skills/model-lifecycle-management/references/evaluation.md +133 -0
- package/skills/model-lifecycle-management/references/packaging.md +46 -0
- package/skills/model-lifecycle-management/references/training-contracts.md +172 -1
- package/skills/model-lifecycle-management/references/training.md +26 -0
- package/skills/prediction-report-management/SKILL.md +42 -6
|
@@ -7,13 +7,25 @@ Read this file whenever a workflow creates or changes executable Operator code.
|
|
|
7
7
|
1. Package contract
|
|
8
8
|
2. Feature entrypoint contract
|
|
9
9
|
3. Causal calculation rules
|
|
10
|
-
4.
|
|
11
|
-
5.
|
|
12
|
-
6.
|
|
10
|
+
4. Online period aggregates
|
|
11
|
+
5. Required tests
|
|
12
|
+
6. Build and publication
|
|
13
|
+
7. Security boundary
|
|
13
14
|
|
|
14
15
|
## Package Contract
|
|
15
16
|
|
|
16
|
-
Build a standalone pure-Python wheel
|
|
17
|
+
Build a standalone pure-Python wheel (`py3-none-any`). The platform verifies
|
|
18
|
+
the wheel digest and only extracts it into an isolated import path; it does not
|
|
19
|
+
install `Requires-Dist` dependencies, run `pip`, or accept native code. At run
|
|
20
|
+
time an Operator can import only the Python standard library, its own wheel,
|
|
21
|
+
and packages already present in the image that executes it: dataset builds
|
|
22
|
+
(the `dataset-chronon` dependency group, which provides `pandas`, `numpy` via
|
|
23
|
+
`pandas`, `pyarrow` and `pydantic`) and API realtime reads (the `api`
|
|
24
|
+
dependency group). Do not import report-local, experiment-local, or
|
|
25
|
+
unregistered business packages, and do not depend on libraries such as `scipy`
|
|
26
|
+
or `scikit-learn` that those images do not provide; vendor small pure-Python
|
|
27
|
+
helpers into the wheel instead. `[project].dependencies` documents the expected
|
|
28
|
+
environment for local tests only; it does not make a dependency available.
|
|
17
29
|
|
|
18
30
|
Minimal `pyproject.toml`:
|
|
19
31
|
|
|
@@ -63,9 +75,19 @@ computation_hash
|
|
|
63
75
|
|
|
64
76
|
Each `metric_frames[parameter_key]` is a standard long frame with source timestamps and values. Resolve frames from `context.inputs`; do not reach into a database, API, filesystem secret, or environment credential.
|
|
65
77
|
|
|
66
|
-
Use `context.cutoff_times` for causal feature windows.
|
|
67
|
-
|
|
68
|
-
|
|
78
|
+
Use `context.cutoff_times` for causal feature windows. `context.target_times`
|
|
79
|
+
are the materialized rows' `event_time` values, which are the prediction
|
|
80
|
+
decision times, and `context.cutoff_times` equals them: a row's feature
|
|
81
|
+
cutoff is its own `event_time`. The DatasetManifest `prediction.horizon` moves
|
|
82
|
+
label availability to `label_time = event_time + horizon` (and the realtime
|
|
83
|
+
response `target_time = cutoff_time + horizon`); it does not move the Operator
|
|
84
|
+
context's feature reads earlier. Do not subtract `context.prediction_horizon`
|
|
85
|
+
from either index, and do not parse a duplicated Feature-level horizon. This
|
|
86
|
+
rule covers Operator inputs only: a DatasetManifest `endpoint_policy` evaluates
|
|
87
|
+
abnormal-window context overlap with its own `cutoff = t - h` formula, described
|
|
88
|
+
in [contracts.md](contracts.md). Resolved lineage records this as
|
|
89
|
+
`prediction_time_semantics: event_time_is_causal_cutoff` and
|
|
90
|
+
`label_time_derivation: prediction_time_plus_horizon`.
|
|
69
91
|
|
|
70
92
|
An Operator requires an explicit forecast contract whenever its formula or code
|
|
71
93
|
uses `context.cutoff_times`, or any `input_schema.history_requirements` entry uses
|
|
@@ -100,7 +122,11 @@ One Operator may return multiple physical columns. Each public Feature still bin
|
|
|
100
122
|
|
|
101
123
|
## Causal Calculation Rules
|
|
102
124
|
|
|
103
|
-
State every time rule in tests and descriptions
|
|
125
|
+
State every time rule in tests and descriptions. A formula that needs the
|
|
126
|
+
complete requested window rather than a bounded causal lookback (for example
|
|
127
|
+
full-window interpolation or smoothing) is not partition-invariant; document
|
|
128
|
+
that the Dataset must be built with `--partition-duration none
|
|
129
|
+
--max-parallelism 1` (see [commands.md](commands.md)).
|
|
104
130
|
|
|
105
131
|
- forecast horizon and cutoff derivation;
|
|
106
132
|
- whether an event exactly at cutoff is included (`<=`) or excluded (`<`);
|
|
@@ -113,6 +139,72 @@ State every time rule in tests and descriptions:
|
|
|
113
139
|
|
|
114
140
|
Never infer a rule from a Feature name alone. Require a business decision when a boundary is unspecified.
|
|
115
141
|
|
|
142
|
+
## Online Period Aggregates
|
|
143
|
+
|
|
144
|
+
Use this method when one Feature row summarizes a whole period (for example a
|
|
145
|
+
day, shift or batch window) and the Feature must also be served online through
|
|
146
|
+
`fetch-inference-data` or a model's `feature_lookup`. The realtime path gives
|
|
147
|
+
the Operator exactly one target row, `event_time = cutoff`, and only source
|
|
148
|
+
rows with `timestamp <= cutoff`, so the batch and online values agree only when
|
|
149
|
+
the formula is causal and bounded.
|
|
150
|
+
|
|
151
|
+
Row semantics:
|
|
152
|
+
|
|
153
|
+
- Anchor the row at the period end: the row at cutoff `T` summarizes the
|
|
154
|
+
period that ended at `T` (for a daily Feature, `T` is local midnight and the
|
|
155
|
+
period is the previous day). Never label a row with the period start and
|
|
156
|
+
aggregate data after it.
|
|
157
|
+
- Decide the period boundary from the source timestamp meaning, which must be
|
|
158
|
+
confirmed by the data owner (see [contracts.md](contracts.md), realtime
|
|
159
|
+
policy questions). If an hourly record is stamped at the hour start, the
|
|
160
|
+
record stamped `T` belongs to the next period, so use `[T - period, T)`. If it
|
|
161
|
+
is stamped at the hour end, the record stamped `T` closes the period, so use
|
|
162
|
+
`(T - period, T]`. Test the record exactly at `T` either way.
|
|
163
|
+
|
|
164
|
+
Contract declarations:
|
|
165
|
+
|
|
166
|
+
- `supports_online: true` on the Operator and `offline_online_supported: true`
|
|
167
|
+
on each Feature that will be served online.
|
|
168
|
+
- `input_schema.history_requirements` with `anchor: cutoff` and a lookback that
|
|
169
|
+
covers the aggregation period, any multi-period context (for example a
|
|
170
|
+
3-day rolling statistic), and alignment slack for source timestamps. For
|
|
171
|
+
example, a daily mean that also uses the two previous days needs at least
|
|
172
|
+
`3d` plus slack. This lookback is also the per-Parameter realtime read
|
|
173
|
+
window; the default realtime floor `min_lookback=1h` is far too short for a
|
|
174
|
+
period aggregate, and it is not a substitute for the declaration.
|
|
175
|
+
- `input_schema.prediction` with `required`, `minimum_horizon` and
|
|
176
|
+
`maximum_horizon` (a strict nowcast uses `true`, `0min`, `0min`).
|
|
177
|
+
- Do not use `anchor: target_time` with zero lookback for a period aggregate;
|
|
178
|
+
online that reads almost nothing.
|
|
179
|
+
|
|
180
|
+
Formula rules:
|
|
181
|
+
|
|
182
|
+
- Use only rows inside the declared lookback that are at or before the row's
|
|
183
|
+
cutoff. A row's value must not change when data after its cutoff is added,
|
|
184
|
+
or when history older than the lookback is added or removed.
|
|
185
|
+
- Freeze fitted constants in Feature `config`. Values fitted on training data,
|
|
186
|
+
such as fallback medians, clipping limits or normal ranges, must be computed
|
|
187
|
+
once offline, written into `config`, and versioned with the Feature. Do not
|
|
188
|
+
recompute them from the window at run time: the online window holds only
|
|
189
|
+
the lookback, so a recomputed value differs between batch and online and
|
|
190
|
+
between partitions. A retrain that refits these constants needs a new
|
|
191
|
+
Feature (and usually Operator) version.
|
|
192
|
+
- Fill gaps only forward in time, and bound each fill by a maximum age or a
|
|
193
|
+
frozen constant. Never backward-fill from an observation after the row's
|
|
194
|
+
cutoff. Avoid backward-filling the start of the window too: the result then
|
|
195
|
+
depends on where the window starts and breaks partition invariance.
|
|
196
|
+
- The Operator owns interior gap handling. The platform's realtime tolerances
|
|
197
|
+
(`allow_tail_edge_missing`, `allow_internal_gap_fill`) only judge how far the
|
|
198
|
+
newest source row lags the cutoff; they do not insert values. Keep one
|
|
199
|
+
missing-data rule, inside the Operator or a declared Parameter rule, so batch
|
|
200
|
+
builds and realtime reads compute the same value.
|
|
201
|
+
- Emit data-quality flags as their own output columns, each bound to its own
|
|
202
|
+
Feature: for example a valid-observation count, an "insufficient data" flag,
|
|
203
|
+
or a business state flag such as "plant stopped". A flag tells consumers
|
|
204
|
+
that a row was computed under a fallback rule; do not hide that by silently
|
|
205
|
+
filling the value. Include a flag in the model FeatureSet only if it is an
|
|
206
|
+
intended model input.
|
|
207
|
+
|
|
116
208
|
## Required Tests
|
|
117
209
|
|
|
118
210
|
Use deterministic fixtures and cover each applicable item with a separately
|
|
@@ -131,6 +223,22 @@ requested-output, event-time-order, or dtype/rounding cases below:
|
|
|
131
223
|
9. output dtype and rounding;
|
|
132
224
|
10. every dated business-rule branch.
|
|
133
225
|
|
|
226
|
+
For an online-capable Operator (`supports_online: true`), also add:
|
|
227
|
+
|
|
228
|
+
11. cutoff invariance: adding source rows after the cutoff leaves the row
|
|
229
|
+
unchanged;
|
|
230
|
+
12. lookback invariance: adding or removing history older than the declared
|
|
231
|
+
lookback leaves the row unchanged;
|
|
232
|
+
13. partition invariance: computing many cutoffs in one call equals computing
|
|
233
|
+
each cutoff alone with only its lookback window, which is what a realtime
|
|
234
|
+
read does;
|
|
235
|
+
14. fallback rows: a period with no or too few valid observations produces the
|
|
236
|
+
documented fallback value and quality flag, using the frozen constants.
|
|
237
|
+
|
|
238
|
+
After publication, compare `fetch-inference-data` at a few historical cutoffs
|
|
239
|
+
with the same rows of a batch DatasetArtifact. Any difference means the
|
|
240
|
+
Operator, its fill rule or its lookback is not causal; fix it before training.
|
|
241
|
+
|
|
134
242
|
Run package tests before building the wheel. Then inspect the wheel tag and ensure it is `py3-none-any`.
|
|
135
243
|
|
|
136
244
|
## Build And Publication
|
|
@@ -35,6 +35,9 @@ deployment does not reach `READY` or an operation is rejected.
|
|
|
35
35
|
the model capacity and sampling grid. In `feature_lookup` mode, never send
|
|
36
36
|
`future_covariates`; the platform retrieves the complete known-future Feature
|
|
37
37
|
window visible at the cutoff. Inline mode still supplies those rows in inputs.
|
|
38
|
+
- Clustering deployments take no `inference_policy`, `horizon`, or
|
|
39
|
+
`output_window`; an optional `include_inputs: true` echoes the model input
|
|
40
|
+
row. See the clustering request in [references/operations.md](references/operations.md).
|
|
38
41
|
- Run `validate-deployment` before `create-deployment`. Validation is read-only
|
|
39
42
|
and does not authorize creation.
|
|
40
43
|
- Obtain explicit authorization for the exact deployment and operation before
|
|
@@ -39,7 +39,11 @@ ml-platform --profile server list-deployments \
|
|
|
39
39
|
--model-artifact-id <artifact-id>
|
|
40
40
|
```
|
|
41
41
|
|
|
42
|
-
|
|
42
|
+
列表默认按 `deployment_id` 升序;需要按生命周期时间排序时使用
|
|
43
|
+
`--sort-by created_at|updated_at --sort-order asc|desc`。
|
|
44
|
+
|
|
45
|
+
Use `--service TEXT` for a case-insensitive service-name substring; surrounding
|
|
46
|
+
whitespace is ignored and an empty value does not filter. The filter may be combined with
|
|
43
47
|
`--environment`, `--state`, `--q`, `--limit`, and `--offset`. These results are
|
|
44
48
|
ITSMP platform deployments; external model-center delivery callbacks are a
|
|
45
49
|
separate status surface.
|
|
@@ -157,6 +161,15 @@ ml-platform --profile server predict-deployment <deployment-id> \
|
|
|
157
161
|
/absolute/path/request.json
|
|
158
162
|
```
|
|
159
163
|
|
|
164
|
+
For a clustering model (`task_type: clustering` in `GET /v1/model`), send no
|
|
165
|
+
`horizon` or `output_window`; they are rejected. The single result is
|
|
166
|
+
`prediction: {kind: "clustering", cluster_id, distance_to_center |
|
|
167
|
+
cluster_probability}` without `target_time`. Add `"include_inputs": true` to
|
|
168
|
+
receive `results[0].inputs`, the validated model input row in signature column
|
|
169
|
+
order (before the model's own transform); it defaults to `false`, is rejected
|
|
170
|
+
for forecasting models, and requires a package image that supports it. Missing
|
|
171
|
+
or non-finite retrieved inputs fail the request.
|
|
172
|
+
|
|
160
173
|
For a package with an explicit `availability_boundary`, inspect
|
|
161
174
|
`lineage.visibility` in the prediction response. It records the package's
|
|
162
175
|
boundary, `cutoff_time`, `attempt_started_at`, `knowledge_time`,
|
|
@@ -36,6 +36,22 @@ uses platform CLI contracts and works without an ITSMP TUI or a specific Agent
|
|
|
36
36
|
Runtime. An execution host may additionally persist plans, method hashes,
|
|
37
37
|
attempts and checkpoints; those records do not replace platform evidence.
|
|
38
38
|
|
|
39
|
+
For unsupervised clustering (`task.kind=clustering`, for example
|
|
40
|
+
`kmeans_clusterer` or `gaussian_mixture_clusterer`), read the clustering
|
|
41
|
+
section of [references/training-contracts.md](references/training-contracts.md)
|
|
42
|
+
for the Run, parameter and model-file contract, and the clustering section of
|
|
43
|
+
[references/packaging.md](references/packaging.md) for packaging and
|
|
44
|
+
single-row inference without a horizon. The cluster count and preprocessing
|
|
45
|
+
have silent defaults (8 clusters for KMeans, no scaling or PCA). Ask the user
|
|
46
|
+
for them, or select them with the documented method in that reference, before
|
|
47
|
+
submitting a clustering Run.
|
|
48
|
+
|
|
49
|
+
For clustering evaluation and registration, read the clustering section of
|
|
50
|
+
[references/evaluation.md](references/evaluation.md). Use a `task_type:
|
|
51
|
+
"clustering"` EvaluationConfig with `targets: ["cluster_id"]`, and label
|
|
52
|
+
`all`/`train` rowset results as in-sample. Register only with one PASS,
|
|
53
|
+
COMPLETE EvaluationResult for that artifact.
|
|
54
|
+
|
|
39
55
|
Read [references/zero-shot-inference.md](references/zero-shot-inference.md) when
|
|
40
56
|
the user wants synchronous zero-shot forecasting from JSON or CSV. This path
|
|
41
57
|
uses the platform-owned `chronos2_forecaster` model name, not a public project
|
|
@@ -65,6 +65,20 @@ Jobs in lists are immutable specs; use the exact get-job command for refreshed
|
|
|
65
65
|
status. Lists do not reconcile or schedule workloads. `get-training-run` returns
|
|
66
66
|
`training_run` plus `spec_hash`; artifact/package detail returns the object.
|
|
67
67
|
|
|
68
|
+
## Download artifact files
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
ml-platform --profile server download-model-artifact ARTIFACT_ID --out-dir /tmp/model-ARTIFACT_ID [--file runtime.json]
|
|
72
|
+
ml-platform --profile server download-evaluation-result-artifact RESULT_ID --out-dir /tmp/eval-RESULT_ID [--file predictions.parquet]
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Both commands download only files indexed by the registry record (all of them
|
|
76
|
+
unless `--file` is repeated), verify each sha256 against that record, and remove
|
|
77
|
+
the output directory on any mismatch. `--project` fails closed when the
|
|
78
|
+
resource belongs to another project. Report the returned `files[].sha256` as
|
|
79
|
+
content evidence; metadata reads alone do not prove file contents. Write
|
|
80
|
+
downloads outside the repository.
|
|
81
|
+
|
|
68
82
|
## Read-only preflight
|
|
69
83
|
|
|
70
84
|
```bash
|
|
@@ -97,10 +111,11 @@ Training Run `task`, `data`, `data.artifact`, `features.feature_set`, `splits`,
|
|
|
97
111
|
config references, members and execution, plus ModelPackage requests, are also
|
|
98
112
|
structured. Unknown keys return 422 with `detail[].loc` identifying the field.
|
|
99
113
|
Keep algorithm-specific `trainer.parameters` governed by the SystemModel
|
|
100
|
-
parameter schema. A typed
|
|
114
|
+
parameter schema. A typed contract such as Chronos-2 `lora_config` or the
|
|
115
|
+
KMeans/Gaussian Mixture clustering parameters (including `preprocessing`)
|
|
101
116
|
rejects unknown fields; a SystemModel that intentionally advertises
|
|
102
|
-
`additionalProperties` remains extensible.
|
|
103
|
-
|
|
117
|
+
`additionalProperties` remains extensible. Read `additionalProperties` from
|
|
118
|
+
the exact SystemModel instead of inferring one model's policy from another.
|
|
104
119
|
|
|
105
120
|
These HTTP checks preserve accepted values and do not rewrite historical stored
|
|
106
121
|
contracts or hashes. Legacy records remain readable. A previously ignored typo
|
|
@@ -100,6 +100,138 @@ not prove Worker dependency availability. Validate before submitting and confirm
|
|
|
100
100
|
the approved Worker supports the model plugin. Successful training in another
|
|
101
101
|
image does not establish evaluation support.
|
|
102
102
|
|
|
103
|
+
## Clustering evaluation
|
|
104
|
+
|
|
105
|
+
A clustering ModelArtifact (with `output_bindings`) is evaluated only by an
|
|
106
|
+
EvaluationConfig with `task_type: "clustering"`. Supervised configs reject
|
|
107
|
+
clustering artifacts, and clustering configs reject supervised artifacts.
|
|
108
|
+
There are no labels: the Worker loads the frozen model, predicts assignments
|
|
109
|
+
for the requested rowset, and computes metrics. It never refits the model or
|
|
110
|
+
its preprocessing and never relabels clusters.
|
|
111
|
+
|
|
112
|
+
Example release `evaluation-config.json`. The thresholds are placeholders and
|
|
113
|
+
must be business-approved before use:
|
|
114
|
+
|
|
115
|
+
```json
|
|
116
|
+
{
|
|
117
|
+
"name": "process_regimes_release",
|
|
118
|
+
"version": "v1",
|
|
119
|
+
"task_type": "clustering",
|
|
120
|
+
"mode": "release",
|
|
121
|
+
"metrics": [
|
|
122
|
+
{"name": "clustering.silhouette", "calculation_space": "transformed"},
|
|
123
|
+
{"name": "clustering.davies_bouldin", "calculation_space": "transformed"},
|
|
124
|
+
{"name": "clustering.cluster_count"},
|
|
125
|
+
{"name": "clustering.min_cluster_share"}
|
|
126
|
+
],
|
|
127
|
+
"validation": [
|
|
128
|
+
{"metric": "clustering.silhouette", "operator": ">=", "threshold": 0.25},
|
|
129
|
+
{"metric": "clustering.min_cluster_share", "operator": ">=", "threshold": 0.05}
|
|
130
|
+
],
|
|
131
|
+
"clustering": {"sample_limit": 5000, "sample_seed": 0}
|
|
132
|
+
}
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
The `clustering` object is optional and accepted only for `task_type:
|
|
136
|
+
"clustering"`:
|
|
137
|
+
|
|
138
|
+
- `sample_limit` (>= 2, default 5000) bounds the silhouette computation. Larger
|
|
139
|
+
rowsets are sampled deterministically with `sample_seed` (default 0). Other
|
|
140
|
+
metrics use every valid row.
|
|
141
|
+
- `reference_label_column` (optional) names an independent DataSchema column
|
|
142
|
+
with role `label` or `metadata`, never a model feature. It is required by the
|
|
143
|
+
external metrics `clustering.adjusted_rand_index` and
|
|
144
|
+
`clustering.normalized_mutual_info`, and is only a comparison reference,
|
|
145
|
+
never a training input.
|
|
146
|
+
- `distance_metric` currently accepts only `euclidean`.
|
|
147
|
+
|
|
148
|
+
Clustering configs reject `baseline`, comparison rules, sample weights and
|
|
149
|
+
package (code) metrics. Built-in `clustering.*` metrics and expression metrics
|
|
150
|
+
over them are supported:
|
|
151
|
+
|
|
152
|
+
| Metric | Inputs | Direction | Calculation spaces |
|
|
153
|
+
| --- | --- | --- | --- |
|
|
154
|
+
| `clustering.silhouette` | features, assignment | maximize | `business`, `transformed` |
|
|
155
|
+
| `clustering.davies_bouldin` | features, assignment | minimize | `business`, `transformed` |
|
|
156
|
+
| `clustering.calinski_harabasz` | features, assignment | maximize | `business`, `transformed` |
|
|
157
|
+
| `clustering.cluster_count` | assignment | neutral | `business` |
|
|
158
|
+
| `clustering.min_cluster_share` | assignment | maximize | `business` |
|
|
159
|
+
| `clustering.adjusted_rand_index` | assignment, reference label | maximize | `business` |
|
|
160
|
+
| `clustering.normalized_mutual_info` | assignment, reference label | maximize | `business` |
|
|
161
|
+
|
|
162
|
+
For feature-based metrics, `business` uses the raw FeatureSet values from the
|
|
163
|
+
DatasetArtifact. `transformed` uses the model's own train-fitted preprocessing
|
|
164
|
+
(the plugin's `transform`), which is the space the estimator clustered in and
|
|
165
|
+
is identical to `business` when the model has no preprocessing. Prefer
|
|
166
|
+
`transformed` for gates on models trained with a scaler or PCA, and record the
|
|
167
|
+
chosen space. `cluster_count` and `min_cluster_share` describe only the
|
|
168
|
+
non-empty clusters observed in the evaluated rowset. A trained cluster that
|
|
169
|
+
receives no rows there is not counted.
|
|
170
|
+
|
|
171
|
+
Example `evaluation-request.json`; `targets` is exactly the assignment output:
|
|
172
|
+
|
|
173
|
+
```json
|
|
174
|
+
{
|
|
175
|
+
"model_artifact_id": "replace_clustering_artifact_id",
|
|
176
|
+
"dataset": {
|
|
177
|
+
"project": "default",
|
|
178
|
+
"dataset_id": "replace_dataset_id",
|
|
179
|
+
"manifest_hash": "replace_with_exact_artifact_manifest_hash"
|
|
180
|
+
},
|
|
181
|
+
"rowset": "test",
|
|
182
|
+
"targets": ["cluster_id"],
|
|
183
|
+
"config": {"name": "process_regimes_release", "version": "v1"},
|
|
184
|
+
"execution": {"executor": "kubernetes", "resources": {"cpu": "2", "memory": "4Gi"}}
|
|
185
|
+
}
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
The rowset comes from the original TrainingRun's `data.splits`. Prefer a
|
|
189
|
+
holdout pool (`validation` or `test`). When the run declared no splits, the
|
|
190
|
+
only accepted rowset is `all`, which is the complete training population.
|
|
191
|
+
Evaluating `all` or `train` measures the population that fitted the model.
|
|
192
|
+
Label any such Result as in-sample in every report, and do not present it as
|
|
193
|
+
held-out evidence; the platform does not add that label for you.
|
|
194
|
+
|
|
195
|
+
Decision semantics follow the shared release policy. Exploratory mode is
|
|
196
|
+
always `INCONCLUSIVE`. In release mode:
|
|
197
|
+
|
|
198
|
+
- When a metric cannot be computed meaningfully (fewer than two non-empty
|
|
199
|
+
clusters, no more rows than clusters, zero dispersion, non-finite inputs),
|
|
200
|
+
the platform records reason `CLUSTERING_DEGENERATE` and writes no number.
|
|
201
|
+
- When a `transformed` metric is requested but the model runtime has no
|
|
202
|
+
`transform`, the platform records `CLUSTERING_TRANSFORM_UNAVAILABLE`.
|
|
203
|
+
- A required rule on such a missing metric is `INCONCLUSIVE`, and that
|
|
204
|
+
outranks a `FAIL` in another rule, so the decision is `INCONCLUSIVE`.
|
|
205
|
+
- Any configured metric that is missing makes `evidence_status` `INCOMPLETE`.
|
|
206
|
+
|
|
207
|
+
Fix the population or configuration rather than dropping the metric to get a
|
|
208
|
+
PASS.
|
|
209
|
+
|
|
210
|
+
Each Result stores `clustering_diagnostics.json` beside the standard artifacts.
|
|
211
|
+
It records the assignment and score outputs, feature order and hash, distance
|
|
212
|
+
metric, sampling parameters, whether the transformed space was available,
|
|
213
|
+
cluster sizes per slice, and the status of each metric (`computed`,
|
|
214
|
+
`degenerate` or `unavailable`, with sampled-row counts). The prediction
|
|
215
|
+
artifact carries the assignment and score per row key. List them with
|
|
216
|
+
`get-evaluation-result-artifacts <result-id>` and download sha256-verified
|
|
217
|
+
copies with `download-evaluation-result-artifact <result-id> --out-dir DIR
|
|
218
|
+
[--file NAME]`.
|
|
219
|
+
|
|
220
|
+
Registration requires all of the following:
|
|
221
|
+
|
|
222
|
+
- one Result for the same artifact with `decision=PASS`,
|
|
223
|
+
`evidence_status=COMPLETE` and compatibility `ok`;
|
|
224
|
+
- no required summary-level rule;
|
|
225
|
+
- a model runtime that reports `production_ready=true`.
|
|
226
|
+
|
|
227
|
+
```bash
|
|
228
|
+
ml-platform --profile server register-model-artifact <artifact-id> \
|
|
229
|
+
--evaluation-id <evaluation-result-id>
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
Training feedback (`cluster_count`, `min_cluster_share`,
|
|
233
|
+
`assignment_score_mean` in `metrics.json`) is not registration evidence.
|
|
234
|
+
|
|
103
235
|
## Diagnose before another build or training run
|
|
104
236
|
|
|
105
237
|
| Symptom | Actual check and next action |
|
|
@@ -199,6 +331,7 @@ An EvaluationRunRequest binds ModelArtifact(s), a frozen DatasetArtifact rowset,
|
|
|
199
331
|
ml-platform --profile server get-evaluation-result <result-id>
|
|
200
332
|
ml-platform --profile server get-evaluation-result-metrics <result-id>
|
|
201
333
|
ml-platform --profile server get-evaluation-result-artifacts <result-id>
|
|
334
|
+
ml-platform --profile server download-evaluation-result-artifact <result-id> --out-dir /tmp/eval-<result-id> --file predictions.parquet
|
|
202
335
|
ml-platform --profile server summarize-evaluation-run <run-id>
|
|
203
336
|
ml-platform --profile server get-evaluation-summary <summary-id>
|
|
204
337
|
```
|
|
@@ -159,3 +159,49 @@ ml-platform --profile server cancel-model-package <package-id> --package-version
|
|
|
159
159
|
```
|
|
160
160
|
|
|
161
161
|
Cancellation requires exact-package authorization. Do not rebuild an immutable failed version; correct inputs and create a new semantic package version. This Skill does not deploy images or write model-center delivery status.
|
|
162
|
+
|
|
163
|
+
## Clustering packages and requests
|
|
164
|
+
|
|
165
|
+
A clustering ModelArtifact has `output_bindings` and no `target_bindings`. Its
|
|
166
|
+
Serving contract reports `task_type=clustering`, `horizon_mode=null`, no
|
|
167
|
+
supported horizons, and `output_schema.kind=clustering` with the `cluster_id`
|
|
168
|
+
assignment and one score (`distance_to_center` or `cluster_probability`).
|
|
169
|
+
|
|
170
|
+
Package it with the ordinary request shape and `"input_modes": ["inline"]`.
|
|
171
|
+
Add `feature_lookup` only when the generic retrieval conditions above hold. A
|
|
172
|
+
clustering `feature_lookup_test` must omit `horizon` and `output_window`.
|
|
173
|
+
The platform-generated image smoke test sends exactly one inline row, in
|
|
174
|
+
ModelSignature column order, with no horizon. It requires one successful
|
|
175
|
+
result with `prediction.kind=clustering`, an integer `cluster_id` >= 0 and a
|
|
176
|
+
finite score.
|
|
177
|
+
|
|
178
|
+
Packaging includes every model file the artifact declares, including the v2
|
|
179
|
+
preprocessing sidecar. The Serving image must provide the scikit-learn version
|
|
180
|
+
recorded in a v2 model file, otherwise model loading fails and the package
|
|
181
|
+
cannot become `READY`. Use the clustering runtime binding from the same Runtime
|
|
182
|
+
Release rather than another image.
|
|
183
|
+
|
|
184
|
+
An inline request carries exactly one row, whose column names match the
|
|
185
|
+
ModelSignature order exactly. Its timestamp must not be later than
|
|
186
|
+
`cutoff_time`. Clustering requests reject `horizon` and `output_window`:
|
|
187
|
+
|
|
188
|
+
```json
|
|
189
|
+
{
|
|
190
|
+
"input_mode": "inline",
|
|
191
|
+
"cutoff_time": "2026-01-01T08:00:00+08:00",
|
|
192
|
+
"inputs": {
|
|
193
|
+
"timestamps": ["2026-01-01T08:00:00+08:00"],
|
|
194
|
+
"values": [{"pressure": 0.82, "temperature": 1180.0, "flow": 3.4}]
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
```bash
|
|
200
|
+
ml-platform predict-model /absolute/path/to/cluster-request.json \
|
|
201
|
+
--serving-url https://process-regimes.example
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
The single result returns `prediction.kind=clustering`, `cluster_id` and the
|
|
205
|
+
score field, and has no `horizon` or `target_time`. Report the `model_version`
|
|
206
|
+
(artifact ID) with each assignment, because cluster ids are not comparable
|
|
207
|
+
across artifacts.
|
|
@@ -112,6 +112,173 @@ capability requires it; do not attach it just because the task is a forecast.
|
|
|
112
112
|
For the platform's detailed diagnostic and label-statistics procedure, read
|
|
113
113
|
[`feature-management/references/supervised-datasets.md`](../../feature-management/references/supervised-datasets.md).
|
|
114
114
|
|
|
115
|
+
## Unsupervised clustering runs
|
|
116
|
+
|
|
117
|
+
Use this method for tabular clustering SystemModels such as
|
|
118
|
+
`kmeans_clusterer:v1` and `gaussian_mixture_clusterer:v1`. Confirm that the
|
|
119
|
+
inspected SystemModel advertises `tasks=["clustering"]`; do not reuse a
|
|
120
|
+
supervised Trainer for clustering.
|
|
121
|
+
|
|
122
|
+
```json
|
|
123
|
+
{
|
|
124
|
+
"schema_version": "ml_data_platform.training_run/v4",
|
|
125
|
+
"run_id": "process_regimes_kmeans_01",
|
|
126
|
+
"experiment": "process_regimes",
|
|
127
|
+
"task": {"kind": "clustering", "objective": "clustering"},
|
|
128
|
+
"data": {
|
|
129
|
+
"artifact": {
|
|
130
|
+
"project": "default", "dataset_id": "process_features",
|
|
131
|
+
"manifest_hash": "REPLACE_WITH_RETURNED_MANIFEST_HASH"
|
|
132
|
+
},
|
|
133
|
+
"features": {"feature_set": {
|
|
134
|
+
"project": "default", "name": "process_cluster_inputs", "version": "v1"
|
|
135
|
+
}},
|
|
136
|
+
"labels": [],
|
|
137
|
+
"splits": {
|
|
138
|
+
"assignment_column": "rowset_split", "train": ["training"],
|
|
139
|
+
"validation": ["validation"], "test": ["test"]
|
|
140
|
+
}
|
|
141
|
+
},
|
|
142
|
+
"input_adapter": {"kind": "tabular"},
|
|
143
|
+
"label_transform": {"name": "identity", "version": "v1"},
|
|
144
|
+
"trainer": {
|
|
145
|
+
"project": "default", "name": "kmeans_clusterer", "version": "v1",
|
|
146
|
+
"parameters": {
|
|
147
|
+
"n_clusters": 4, "n_init": 20, "random_state": 42,
|
|
148
|
+
"preprocessing": {"scaler": "robust", "pca_variance": 0.95}
|
|
149
|
+
}
|
|
150
|
+
},
|
|
151
|
+
"reproducibility": {"seed": 42, "deterministic": true}
|
|
152
|
+
}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
Validation enforces these rules:
|
|
156
|
+
|
|
157
|
+
- `task.objective` is `clustering`, `data.labels` is empty, `input_adapter.kind`
|
|
158
|
+
is `tabular`, and `label_transform` is `identity:v1`. Do not declare
|
|
159
|
+
`data.temporal`, `forecast_target_adapter` or label materializations for the
|
|
160
|
+
model; clustering has no supervised target.
|
|
161
|
+
- The model FeatureSet is non-empty. Every column is a numeric
|
|
162
|
+
`role=feature` column available `at_prediction` or `static`, and every
|
|
163
|
+
artifact row's value is finite and non-null. Correct data gaps in the
|
|
164
|
+
DatasetArtifact; the trainer does not impute.
|
|
165
|
+
- `data.splits` is optional. Without it, every artifact row is a training row.
|
|
166
|
+
With it, the cluster count must be between 2 and the train-pool row count.
|
|
167
|
+
Validation and test pools may be empty. Splits matter for preprocessing,
|
|
168
|
+
because transforms are fitted on train rows only.
|
|
169
|
+
- `trainer.parameters` is strict. Unknown keys, booleans in integer fields,
|
|
170
|
+
integral floats such as `4.0`, and out-of-range values are rejected before
|
|
171
|
+
scheduling. Read the authoritative schema with
|
|
172
|
+
`get-system-model kmeans_clusterer v1` or
|
|
173
|
+
`get-system-model gaussian_mixture_clusterer v1`.
|
|
174
|
+
|
|
175
|
+
| SystemModel | Cluster count (default) | Other estimator fields (defaults) |
|
|
176
|
+
| --- | --- | --- |
|
|
177
|
+
| `kmeans_clusterer:v1` | `n_clusters` >= 2 (8) | `init` `k-means++`/`random`; `n_init` >= 1 or `auto` (`auto`); `max_iter` >= 1 (300); `tol` >= 0 (1e-4) |
|
|
178
|
+
| `gaussian_mixture_clusterer:v1` | `n_components` >= 2 (2) | `covariance_type` `full`/`tied`/`diag`/`spherical` (`full`); `init_params` `kmeans`/`k-means++`/`random`/`random_from_data` (`kmeans`); `n_init` >= 1 (1); `max_iter` >= 1 (100); `tol` >= 0 (1e-3); `reg_covar` >= 0 (1e-6) |
|
|
179
|
+
|
|
180
|
+
Both models also accept `random_state` (0..2^32-1; when it is unset, the
|
|
181
|
+
Worker uses the run's `reproducibility.seed`, which it injects as `seed` at
|
|
182
|
+
run time and which overrides any `seed` in the parameters) and an optional
|
|
183
|
+
`preprocessing` object with exactly two fields:
|
|
184
|
+
|
|
185
|
+
- `scaler`: `"robust"` or `null`. A robust scaler centers each column on its
|
|
186
|
+
train-pool median and divides by its interquartile range.
|
|
187
|
+
- `pca_variance`: a float strictly between 0 and 1, or `null`. PCA keeps the
|
|
188
|
+
fewest components that explain that fraction of train-pool variance and runs
|
|
189
|
+
after the scaler.
|
|
190
|
+
|
|
191
|
+
The trainer fits both transforms on train rows only and freezes them in the
|
|
192
|
+
artifact. Validation, test, evaluation and Serving rows are transformed and
|
|
193
|
+
assigned without refitting. Clustering distances and scores are computed in
|
|
194
|
+
this transformed space.
|
|
195
|
+
|
|
196
|
+
Apart from that runtime `seed`, clustering parameters are not filled from
|
|
197
|
+
top-level `reproducibility`.
|
|
198
|
+
`effective_trainer_parameters` contains exactly the submitted keys, and omitted
|
|
199
|
+
fields use the schema defaults inside the Worker. Set the cluster count,
|
|
200
|
+
`random_state` and `n_init` explicitly when the run must be reproducible and
|
|
201
|
+
reviewable. Changing any of them requires a new `run_id`.
|
|
202
|
+
|
|
203
|
+
### Choosing the cluster count and preprocessing
|
|
204
|
+
|
|
205
|
+
The defaults are silent. If the Run omits the cluster count, KMeans trains 8
|
|
206
|
+
clusters and Gaussian Mixture 2; if it omits `preprocessing`, no scaling or PCA
|
|
207
|
+
is applied. Validation does not warn, and `effective_trainer_parameters` echoes
|
|
208
|
+
only the submitted keys, so the default does not show up in the evidence you
|
|
209
|
+
review. Never submit a clustering Run that relies on either default.
|
|
210
|
+
|
|
211
|
+
Cluster count. Ask the user whether the business has a fixed number of regimes
|
|
212
|
+
or categories. If it does, use that number and record who confirmed it. If it
|
|
213
|
+
does not, select K with a documented method before treating any Run as final:
|
|
214
|
+
|
|
215
|
+
1. Agree a candidate range with the user (for example 2–10), bounded by how
|
|
216
|
+
many clusters the business can name and act on and by the train-pool size.
|
|
217
|
+
2. Fix everything except K: the same DatasetArtifact, model FeatureSet,
|
|
218
|
+
`preprocessing`, `n_init` and `random_state`. Each K is a separate
|
|
219
|
+
TrainingRun with its own `run_id`. Get authorization for the whole scan,
|
|
220
|
+
and follow [model-comparison.md](model-comparison.md) for recording
|
|
221
|
+
candidates, failures and stopping.
|
|
222
|
+
3. Evaluate every candidate with one shared clustering EvaluationConfig
|
|
223
|
+
([evaluation.md](evaluation.md)): `clustering.silhouette` (higher is
|
|
224
|
+
better), `clustering.davies_bouldin` (lower is better),
|
|
225
|
+
`clustering.calinski_harabasz` and `clustering.min_cluster_share`. Compare
|
|
226
|
+
transformed-space metrics only between runs with identical preprocessing;
|
|
227
|
+
use `calculation_space: "business"` when the comparison spans different
|
|
228
|
+
preprocessing.
|
|
229
|
+
4. Check stability: retrain the leading candidates with two or three other
|
|
230
|
+
`random_state` values (or on subsamples) and compare the assignments, for
|
|
231
|
+
example with adjusted Rand index. Compute this in the workspace and label it
|
|
232
|
+
exploratory; it is not a governed EvaluationResult. A K whose clusters
|
|
233
|
+
change between seeds is not a stable business vocabulary.
|
|
234
|
+
5. Show the user the leading candidates with cluster sizes and per-cluster
|
|
235
|
+
feature profiles in business units, and let the business judge whether the
|
|
236
|
+
clusters can be named and acted on. Metrics rarely give one clear winner,
|
|
237
|
+
so the final K is a business decision backed by the evidence above. Record
|
|
238
|
+
the range, metrics, stability result and decision.
|
|
239
|
+
|
|
240
|
+
Preprocessing. Ask, or justify from the data, instead of accepting the
|
|
241
|
+
default:
|
|
242
|
+
|
|
243
|
+
- `scaler`: KMeans and Gaussian Mixture are distance-based, so a column with a
|
|
244
|
+
large numeric range dominates. Use `"robust"` when columns have different
|
|
245
|
+
units or scales, or contain outliers. Use `null` only when every column
|
|
246
|
+
shares one unit and absolute differences are meaningful to the business
|
|
247
|
+
(for example, a set of temperatures where a 10-degree gap means the same
|
|
248
|
+
thing in every column), and record that reason.
|
|
249
|
+
- `pca_variance`: use it when many input columns are strongly correlated and
|
|
250
|
+
would otherwise count the same signal several times. A higher fraction
|
|
251
|
+
(0.95–0.99) keeps more detail; a lower one removes more noise. PCA makes
|
|
252
|
+
clusters harder to explain in business terms, so leave it `null` unless the
|
|
253
|
+
correlation is shown and the user accepts the trade-off.
|
|
254
|
+
|
|
255
|
+
Write the chosen K and `preprocessing` explicitly in `trainer.parameters`, even
|
|
256
|
+
when they equal the defaults.
|
|
257
|
+
|
|
258
|
+
A successful clustering Job writes training feedback (`cluster_count`,
|
|
259
|
+
`min_cluster_share`, `assignment_score_mean`) on the training `evaluation.split`,
|
|
260
|
+
which defaults to `auto`. This is diagnostic evidence only. The ModelSignature
|
|
261
|
+
outputs are `cluster_id` (int64) plus `distance_to_center` for KMeans or
|
|
262
|
+
`cluster_probability` for Gaussian Mixture. Cluster ids are meaningful only
|
|
263
|
+
within one immutable ModelArtifact.
|
|
264
|
+
|
|
265
|
+
The model file (`model.kmeans.json` or `model.gmm.json`) records its format:
|
|
266
|
+
|
|
267
|
+
- `<kind>_clustering/v1`: no preprocessing; estimator sidecar only.
|
|
268
|
+
- `<kind>_clustering/v2`: preprocessing is present. The file additionally
|
|
269
|
+
lists `transform_file` in `model_files`, records the training-time
|
|
270
|
+
`scikit_learn_version`, the preprocessing config, and the fitted summary:
|
|
271
|
+
scaler type, PCA component count, retained explained-variance ratio and
|
|
272
|
+
input feature order.
|
|
273
|
+
|
|
274
|
+
Loading refuses an unknown format, a missing estimator or transform sidecar,
|
|
275
|
+
or a v2 file whose recorded scikit-learn version differs from the runtime.
|
|
276
|
+
A v1 file records no scikit-learn version. Its safety relies on the training,
|
|
277
|
+
evaluation and Serving images of one Runtime Release sharing the same locked
|
|
278
|
+
scikit-learn stack, so keep v1 artifacts on images from that release line. Resolve a
|
|
279
|
+
version mismatch by using the Runtime Release binding whose image matches the
|
|
280
|
+
training runtime, or by retraining. Never edit artifact files.
|
|
281
|
+
|
|
115
282
|
## Chronos-2 LoRA parameters
|
|
116
283
|
|
|
117
284
|
Chronos-2 fine-tuning settings belong under `trainer.parameters`; they are
|
|
@@ -227,7 +394,11 @@ weather observations.
|
|
|
227
394
|
|
|
228
395
|
Inspect `data_schema.json`, `resolved_manifest.json` and the feature Parquet via
|
|
229
396
|
`download-dataset-artifact DATASET_ID MANIFEST_HASH --project PROJECT --out-dir DIR`
|
|
230
|
-
(repeat `--file` for selective downloads).
|
|
397
|
+
(repeat `--file` for selective downloads). `MANIFEST_HASH` is the artifact
|
|
398
|
+
manifest hash from `list-dataset-artifacts` or `artifact.manifest_hash` of a
|
|
399
|
+
succeeded `build-registered-dataset --wait`, not the registered manifest hash.
|
|
400
|
+
After training, `download-model-artifact ARTIFACT_ID --out-dir DIR [--file NAME]`
|
|
401
|
+
returns sha256-verified ModelArtifact files such as `runtime.json` and the model file. In TrainingRun v4, the FeatureSet
|
|
231
402
|
reference defines the ordered model inputs. It may be a registered exact-version
|
|
232
403
|
subset of the DatasetArtifact's materialized FeatureSet, in its own order. The
|
|
233
404
|
platform freezes both identities and the projected dependency contract in the
|