Skip to content

Commit 708cb53

Browse files
committed
updated docs, notebooks and readme
1 parent c0f1c9e commit 708cb53

10 files changed

Lines changed: 536 additions & 14 deletions

File tree

docs/source/client_api_content.rst

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -461,6 +461,61 @@ Organize resources with channels
461461
462462
See also the tutorial notebooks: `upload_data.ipynb <https://github.com/SonanceAI/datamint-python-api/blob/main/notebooks/upload_data.ipynb>`_
463463

464+
Working with Models
465+
--------------------
466+
467+
``api.models`` is a thin facade over Datamint's MLflow-backed model registry:
468+
it wraps MLflow's ``RegisteredModel``/``ModelVersion`` objects in
469+
:py:class:`~datamint.api.endpoints.model_types.Model` /
470+
:py:class:`~datamint.api.endpoints.model_types.ModelVersion`, so you can
471+
register, list, and inspect models without knowing MLflow's object model.
472+
473+
Register and list models
474+
+++++++++++++++++++++++++
475+
476+
.. code-block:: python
477+
478+
# Create a model (or fetch it if it already exists, the default behavior)
479+
model = api.models.create("my-model", description="Segmentation model")
480+
481+
# Look up a model by name; returns None if it doesn't exist
482+
model = api.models.get_by_name("my-model")
483+
484+
# List every registered model
485+
all_models = api.models.get_list()
486+
487+
# Only models with a deployed image
488+
deployed_models = api.models.get_list(only_deployed=True)
489+
490+
Models are also created automatically when you pass ``--ai-model`` to
491+
:doc:`command_line_tools` (``datamint-upload``) with a name that doesn't
492+
exist yet.
493+
494+
Inspect versions and metrics
495+
++++++++++++++++++++++++++++
496+
497+
Each :py:class:`~datamint.api.endpoints.model_types.Model` can list its
498+
:py:class:`~datamint.api.endpoints.model_types.ModelVersion` objects, and each
499+
version exposes what it was trained for and how it performed:
500+
501+
.. code-block:: python
502+
503+
model = api.models.get_by_name("my-model")
504+
505+
versions = model.get_versions()
506+
latest = model.get_latest_version() # highest version number
507+
champion = model.get_latest_version(alias="champion")
508+
509+
print(latest.get_task_type()) # e.g. "segmentation"
510+
print(latest.get_supported_modes()) # e.g. ["auto", "interactive"]
511+
print(latest.get_metrics()) # e.g. {"val/dice": 0.87}
512+
513+
``get_metrics()`` returns ``{}`` for versions with no training run behind
514+
them (for example, a model registered externally rather than trained through
515+
a Datamint :mod:`~datamint.lightning.trainers`), rather than raising.
516+
``Model.get_supported_modes()``/``get_metrics()`` are shortcuts that delegate
517+
to the latest version when you don't need a specific one.
518+
464519
Deploy a registered model
465520
+++++++++++++++++++++++++
466521

@@ -479,6 +534,9 @@ Use ``api.deploy.start()`` to deploy a model:
479534
deploy_job = deploy_job.wait()
480535
print("Deployment complete:", deploy_job.status)
481536
537+
# Check whether a model has a deployed image
538+
model.is_deployed()
539+
482540
Working with Users
483541
------------------
484542

docs/source/datamint.api.endpoints.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,11 @@ Models API
5959
:undoc-members:
6060
:show-inheritance:
6161

62+
.. automodule:: datamint.api.endpoints.model_types
63+
:members:
64+
:undoc-members:
65+
:show-inheritance:
66+
6267
Deploy Model API
6368
----------------
6469

Lines changed: 259 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,259 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "markdown",
5+
"id": "556c43fc",
6+
"metadata": {},
7+
"source": [
8+
"# Model Registry Tutorial",
9+
"",
10+
"`api.models` is a facade over Datamint's MLflow-backed model registry. It wraps MLflow's",
11+
"`RegisteredModel` / `ModelVersion` objects in plain Python objects (`Model`, `ModelVersion`),",
12+
"so you can register, list, and inspect models without learning MLflow's object model.",
13+
"",
14+
"This notebook covers:",
15+
"",
16+
"- Registering a model with `api.models.create()`",
17+
"- Listing and finding models with `api.models.get_list()` / `get_by_name()`",
18+
"- Filtering to deployed models with `only_deployed=True`",
19+
"- Inspecting a model's versions with `model.get_versions()` / `get_latest_version()`",
20+
"- Reading what a version was trained for: `get_task_type()`, `get_supported_modes()`, `get_annotation_specs()`",
21+
"- Reading training metrics with `get_metrics()`",
22+
"- Checking deployment status with `is_deployed()`"
23+
]
24+
},
25+
{
26+
"cell_type": "markdown",
27+
"id": "ff7cc0e3",
28+
"metadata": {},
29+
"source": [
30+
"## Setup",
31+
"",
32+
"Update `datamint` first if needed, then configure your API key."
33+
]
34+
},
35+
{
36+
"cell_type": "code",
37+
"execution_count": null,
38+
"id": "3d323bd4",
39+
"metadata": {},
40+
"outputs": [],
41+
"source": [
42+
"%pip install -U datamint --quiet"
43+
]
44+
},
45+
{
46+
"cell_type": "code",
47+
"execution_count": null,
48+
"id": "ef4c457d",
49+
"metadata": {},
50+
"outputs": [],
51+
"source": [
52+
"from datamint import Api\n",
53+
"\n",
54+
"api = Api()"
55+
]
56+
},
57+
{
58+
"cell_type": "markdown",
59+
"id": "547f3483",
60+
"metadata": {},
61+
"source": [
62+
"## Register A Model",
63+
"",
64+
"Registering ahead of training gives you a stable name to reference later. `create()` returns the",
65+
"existing model instead of raising when one with this name is already registered",
66+
"(`exists_ok=True` by default)."
67+
]
68+
},
69+
{
70+
"cell_type": "code",
71+
"execution_count": null,
72+
"id": "05e434aa",
73+
"metadata": {},
74+
"outputs": [],
75+
"source": [
76+
"MODEL_NAME = \"tutorial_model_registry_demo\"\n",
77+
"\n",
78+
"model = api.models.create(MODEL_NAME, description=\"Model created for the model registry tutorial\")\n",
79+
"model.name, model.description"
80+
]
81+
},
82+
{
83+
"cell_type": "markdown",
84+
"id": "7cc966eb",
85+
"metadata": {},
86+
"source": [
87+
"## List And Find Models",
88+
"",
89+
"`get_list()` returns every registered model; `get_by_name()` returns a single one, or `None` if it",
90+
"doesn't exist."
91+
]
92+
},
93+
{
94+
"cell_type": "code",
95+
"execution_count": null,
96+
"id": "2571c3f9",
97+
"metadata": {},
98+
"outputs": [],
99+
"source": [
100+
"all_models = api.models.get_list()\n",
101+
"print(f\"Registered models: {[m.name for m in all_models]}\")\n",
102+
"\n",
103+
"found = api.models.get_by_name(MODEL_NAME)\n",
104+
"missing = api.models.get_by_name(\"does-not-exist\")\n",
105+
"found.name, missing"
106+
]
107+
},
108+
{
109+
"cell_type": "markdown",
110+
"id": "c30b3598",
111+
"metadata": {},
112+
"source": [
113+
"## Filter To Deployed Models",
114+
"",
115+
"Pass `only_deployed=True` to skip models that don't have a deployed image yet. See",
116+
"`05_deployment/01_deploy_registered_model.ipynb` for how to deploy one."
117+
]
118+
},
119+
{
120+
"cell_type": "code",
121+
"execution_count": null,
122+
"id": "1c605a73",
123+
"metadata": {},
124+
"outputs": [],
125+
"source": [
126+
"deployed_models = api.models.get_list(only_deployed=True)\n",
127+
"print(f\"Deployed models: {[m.name for m in deployed_models]}\")\n",
128+
"\n",
129+
"model.is_deployed()"
130+
]
131+
},
132+
{
133+
"cell_type": "markdown",
134+
"id": "fab1e7a0",
135+
"metadata": {},
136+
"source": [
137+
"## Inspect Versions Of A Trained Model",
138+
"",
139+
"The rest of this notebook needs a model with at least one version behind it, typically one",
140+
"registered by a Datamint trainer (see `06_end_to_end`) or by",
141+
"`04_experiment_tracking/01_mlflow_manual_logging.ipynb`. Replace `MODEL_NAME` below with one",
142+
"you've already trained."
143+
]
144+
},
145+
{
146+
"cell_type": "code",
147+
"execution_count": null,
148+
"id": "2b0203fc",
149+
"metadata": {},
150+
"outputs": [],
151+
"source": [
152+
"MODEL_NAME = \"FracAtlas_adapted\" # replace with a model you've already registered/trained\n",
153+
"\n",
154+
"model = api.models.get_by_name(MODEL_NAME)\n",
155+
"if model is None:\n",
156+
" raise ValueError(f\"Model '{MODEL_NAME}' was not found. Train one first, e.g. via the 06_end_to_end notebooks.\")\n",
157+
"\n",
158+
"versions = model.get_versions()\n",
159+
"print(f\"{MODEL_NAME} has {len(versions)} version(s)\")\n",
160+
"\n",
161+
"latest = model.get_latest_version()\n",
162+
"latest.version, latest.run_id"
163+
]
164+
},
165+
{
166+
"cell_type": "markdown",
167+
"id": "d3045992",
168+
"metadata": {},
169+
"source": [
170+
"## What A Version Was Trained For",
171+
"",
172+
"If the version was logged with the `datamint` MLflow flavor (true for anything trained through a",
173+
"Datamint trainer), you can read the task type, supported prediction modes, and annotation specs",
174+
"straight from the model artifact, without inspecting the training run."
175+
]
176+
},
177+
{
178+
"cell_type": "code",
179+
"execution_count": null,
180+
"id": "3ef28bd9",
181+
"metadata": {},
182+
"outputs": [],
183+
"source": [
184+
"print(\"Task type:\", latest.get_task_type())\n",
185+
"print(\"Supported modes:\", latest.get_supported_modes())\n",
186+
"print(\"Annotation specs:\", latest.get_annotation_specs())\n",
187+
"\n",
188+
"# Model.get_supported_modes() is a shortcut that delegates to the latest version\n",
189+
"model.get_supported_modes() == latest.get_supported_modes()"
190+
]
191+
},
192+
{
193+
"cell_type": "markdown",
194+
"id": "cdfdcb81",
195+
"metadata": {},
196+
"source": [
197+
"## Training Metrics",
198+
"",
199+
"`get_metrics()` reads the metrics logged for this version's training run. It returns `{}` instead",
200+
"of raising when there's no training run behind the version, for example a model registered from",
201+
"outside Datamint."
202+
]
203+
},
204+
{
205+
"cell_type": "code",
206+
"execution_count": null,
207+
"id": "f984040b",
208+
"metadata": {},
209+
"outputs": [],
210+
"source": [
211+
"latest.get_metrics()"
212+
]
213+
},
214+
{
215+
"cell_type": "code",
216+
"execution_count": null,
217+
"id": "ee63e20b",
218+
"metadata": {},
219+
"outputs": [],
220+
"source": [
221+
"model.get_metrics() # shortcut, uses the latest version"
222+
]
223+
},
224+
{
225+
"cell_type": "markdown",
226+
"id": "5edb693f",
227+
"metadata": {},
228+
"source": [
229+
"## Next Steps",
230+
"",
231+
"Once you have a model version you're happy with, alias it and deploy it, see",
232+
"`05_deployment/01_deploy_registered_model.ipynb`. Registered models are also created",
233+
"automatically when you pass `--ai-model <name>` to `datamint-upload` with a name that doesn't",
234+
"exist yet."
235+
]
236+
}
237+
],
238+
"metadata": {
239+
"kernelspec": {
240+
"display_name": ".venv",
241+
"language": "python",
242+
"name": "python3"
243+
},
244+
"language_info": {
245+
"codemirror_mode": {
246+
"name": "ipython",
247+
"version": 3
248+
},
249+
"file_extension": ".py",
250+
"mimetype": "text/x-python",
251+
"name": "python",
252+
"nbconvert_exporter": "python",
253+
"pygments_lexer": "ipython3",
254+
"version": "3.12.13"
255+
}
256+
},
257+
"nbformat": 4,
258+
"nbformat_minor": 5
259+
}
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
# 04 — Experiment Tracking
22

3-
Logging experiments with MLflow through the Datamint backend.
3+
Logging experiments and managing the model registry with MLflow through the Datamint backend.
44

55
| Notebook | Level | Description |
66
|---|---|---|
77
| [01_mlflow_manual_logging](01_mlflow_manual_logging.ipynb) | ![Intermediate](https://img.shields.io/badge/level-intermediate-yellow) | Log metrics, parameters, and model artifacts manually using `mlflow.set_tracking_uri("datamint://...")` |
8+
| [02_model_registry](02_model_registry.ipynb) | ![Intermediate](https://img.shields.io/badge/level-intermediate-yellow) | Register, list, and inspect models and versions with `api.models` |

0 commit comments

Comments
 (0)