dispcraft.model_registry¶
model_registry ¶
MLflow model-registry helpers for persisting residual-correction models.
This project's original convention (see CLAUDE.md, dispcraft/ml.py) was
to not checkpoint residual-correction models -- retrain from data on every
use instead, since Stage 4/5's own experimentation never needed a persisted
artifact. Distributing the recommended production models (the "best model
per mode" in docs/User_Guide.md) changes that: end users of the library
should not have to retrain an MLP just to get a prediction.
Registers/loads dispcraft.ml.LitResidualRegressor instances via MLflow's
model registry API, pointed by default at GitLab's MLflow-compatible model
registry for this project (DEFAULT_TRACKING_URI below; override by setting
MLFLOW_TRACKING_URI yourself before importing this module). Both reading
and writing need MLFLOW_TRACKING_TOKEN set to a GitLab access token --
dispers/dispcraft is a private project, so even read-only calls
(load_model, latest_version) get a bare 401 without one. Registering a
new version additionally needs that token to carry the api scope and
Developer role; a lower-privileged (e.g. read_api, Reporter role) token is
enough for load_model alone -- see docs/User_Guide.md.
Four GitLab-specific quirks found while validating this module against the
real endpoint (none of this is exercised by tests/, which stay offline --
scripts/register_models.py is what actually exercises it, against real
data):
MlflowClient().search_model_versions("")(empty filter string) raisesINVALID_PARAMETER_VALUE--latest_versionbelow always passes a realname='...'filter to avoid it.- Unlike a local
sqlite:///tracking store, GitLab's registry has no auto-created "Default" experiment (experiment_id=0) --start_run()with no experiment set raisesRESOURCE_DOES_NOT_EXIST.register_modelalways callsmlflow.set_experiment(...)first, which creates the experiment on first use. - MLflow 3's default
mlflow.pytorch.log_model(...)/mlflow.register_model(...)path creates a "Logged Model" tracking entity as a side effect (CreateLoggedModel/SearchLoggedModels) that GitLab's implementation doesn't support (bare404, wrapped asINTERNAL_ERROR) -- this silently aborts after printing "Successfully registered model", leaving a registered model with zero versions attached. Worked around by not using the pytorch "flavor" packaging at all:register_modelsaves a plaintorch.save({"state_dict": ..., "hparams": ...})checkpoint as a single artifact and callsMlflowClient.create_model_versiondirectly against it, andload_modelreconstructsLitResidualRegressorfrom that checkpoint rather than viamlflow.pytorch.load_model(whose "models:/" URI resolution also hit a separate path-nesting mismatch against this registry -- downloads succeeded butModel.load()'s expectedMLmodelfile wasn't at the root of the download). Simpler and more robust than chasing either bug: skip the flavor system, since all we need is a state_dict + hyperparams. MlflowClient.search_model_versions(...)404s outright against this registry (unlikesearch_registered_models, which works) --latest_versionusesget_registered_model(name).latest_versionsinstead, which returns the correct per-name version list.MlflowClient.search_registered_models()itself always sends afilterquery parameter, even "" when called with no arguments -- which hits the sameINVALID_PARAMETER_VALUEas quirk 1, this time with no way to avoid it from the client (there's no name to filter by when you want all models). A bareGET .../registered-models/searchwith nofilterparameter at all works fine and returns everything --list_modelsmakes that call directly withrequestsrather than going through the MLflow client.ModelVersion.source(a field vanilla MLflow uses for an artifact path) is repurposed by GitLab's implementation to hold that version's own web UI URL instead (.../-/ml/models/<model_id>/versions/<version>) --model_web_urlbelow reads it straight off the sameget_registered_model(name).latest_versionscalllatest_versionalready makes, no extra API call needed. (A GraphQL-based lookup of GitLab's numericMl::ModelID was tried first and worked, but this is simpler -- one call, one API, already-importedMlflowClient-- andclient.get_model_version(name, version)404s on this registry the same waysearch_model_versionsdoes (quirk 4), so a specific older version's URL is derived by substituting the trailing/versions/<n>segment of the latest one rather than a second lookup.)
latest_version ¶
latest_version(name)
Highest version number currently registered under name.
Uses get_registered_model(name).latest_versions, not
search_model_versions -- the latter is a fourth GitLab quirk found
while validating this module: SearchModelVersions 404s outright on
this registry (unlike search_registered_models, which works), while
GetRegisteredModel's latest_versions field returns the real,
per-name version list correctly.
Source code in dispcraft/model_registry.py
153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 | |
list_models ¶
list_models()
Names of every model currently registered (sorted).
Bypasses MlflowClient.search_registered_models() -- see quirk 5 in the
module docstring -- with a direct, unfiltered REST call instead.
Source code in dispcraft/model_registry.py
139 140 141 142 143 144 145 146 147 148 149 150 | |
load_model ¶
load_model(name, version=None)
Load a registered LitResidualRegressor by name.
| Parameters: |
|
|---|
| Returns: |
|
|---|
Source code in dispcraft/model_registry.py
170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 | |
model_web_url ¶
model_web_url(name, version=None)
(model_url, version_url) -- GitLab UI links for a registered model,
for documentation/models/*.toml where a human wants to click through
and inspect a model, as opposed to load_model (name/version alone is
enough to fetch weights programmatically).
Reads the URL straight off ModelVersion.source (see quirk 6 in the
module docstring) -- no extra API call beyond what latest_version
already makes.
| Parameters: |
|
|---|
| Returns: |
|
|---|
Source code in dispcraft/model_registry.py
201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 | |
register_model ¶
register_model(lit_model, name, params=None, extra=None, run_name=None, experiment_name=DEFAULT_EXPERIMENT)
Register a trained LitResidualRegressor as a new version of the
model registry entry name (creating both the experiment and the
registered model on first use).
| Parameters: |
|
|---|
| Returns: |
|
|---|
Source code in dispcraft/model_registry.py
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 | |