From 5a69ccfbce0522416f95d4e7a9043d04691d5f61 Mon Sep 17 00:00:00 2001
From: Roman <58133204+rktraz@users.noreply.github.com>
Date: Fri, 11 Nov 2022 00:49:25 +0100
Subject: [PATCH 1/3] added snippets for Connection, Model Registry
---
docs/index.md | 114 ++++++++++++++++++++++++++++
python/hsml/connection.py | 11 +++
python/hsml/model.py | 55 +++++++++++++-
python/hsml/model_registry.py | 30 ++++++++
python/hsml/model_schema.py | 14 ++++
python/hsml/python/signature.py | 11 +++
python/hsml/schema.py | 14 ++++
python/hsml/sklearn/signature.py | 11 +++
python/hsml/tensorflow/signature.py | 10 +++
python/hsml/torch/signature.py | 10 +++
10 files changed, 278 insertions(+), 2 deletions(-)
create mode 100644 docs/index.md
diff --git a/docs/index.md b/docs/index.md
new file mode 100644
index 00000000..2504b8d8
--- /dev/null
+++ b/docs/index.md
@@ -0,0 +1,114 @@
+# Hopsworks Model Management
+
+
+
+
+
+
+
+
+
+
+
+HSML is the library to interact with the Hopsworks Model Registry and Model Serving. The library makes it easy to export, manage and deploy models.
+
+The library automatically configures itself based on the environment it is run.
+However, to connect from an external Python environment additional connection information, such as host and port, is required. For more information about the setup from external environments, see the setup section.
+
+## Getting Started On Hopsworks
+
+Instantiate a connection and get the project model registry and serving handles
+```python
+import hsml
+
+# Create a connection
+connection = hsml.connection()
+
+# Get the model registry handle for the project's model registry
+mr = connection.get_model_registry()
+
+# Get the model serving handle for the current model registry
+ms = connection.get_model_serving()
+```
+
+Create a new model
+```python
+model = mr.tensorflow.create_model(name="mnist",
+ version=1,
+ metrics={"accuracy": 0.94},
+ description="mnist model description")
+model.save("/tmp/model_directory") # or /tmp/model_file
+```
+
+Download a model
+```python
+model = mr.get_model("mnist", version=1)
+
+model_path = model.download()
+```
+
+Delete a model
+```python
+model.delete()
+```
+
+Get best performing model
+```python
+best_model = mr.get_best_model('mnist', 'accuracy', 'max')
+
+```
+
+Deploy a model
+```python
+deployment = model.deploy()
+```
+
+Start a deployment
+```python
+deployment.start()
+```
+
+Make predictions with a deployed model
+```python
+data = { "instances": model.input_example }
+
+predictions = deployment.predict(data)
+```
+
+You can find more examples on how to use the library in [examples.hopsworks.ai](https://examples.hopsworks.ai).
+
+## Documentation
+
+Documentation is available at [Hopsworks Model Management Documentation](https://docs.hopsworks.ai/).
+
+## Issues
+
+For general questions about the usage of Hopsworks Machine Learning please open a topic on [Hopsworks Community](https://community.hopsworks.ai/).
+
+Please report any issue using [Github issue tracking](https://github.com/logicalclocks/machine-learning-api/issues).
+
+
+## Contributing
+
+If you would like to contribute to this library, please see the [Contribution Guidelines](CONTRIBUTING.md).
diff --git a/python/hsml/connection.py b/python/hsml/connection.py
index a25fe83b..023eb845 100644
--- a/python/hsml/connection.py
+++ b/python/hsml/connection.py
@@ -119,6 +119,12 @@ def get_model_registry(self, project: str = None):
"""Get a reference to a model registry to perform operations on, defaulting to the project's default model registry.
Shared model registries can be retrieved by passing the `project` argument.
+ !!! example
+ ```python
+ mr = conn.get_model_registry() # Get the project's default model registry
+ ```
+
+
# Arguments
project: The name of the project that owns the shared model registry,
the model registry must be shared with the project the connection was established for, defaults to `None`.
@@ -131,6 +137,11 @@ def get_model_registry(self, project: str = None):
def get_model_serving(self):
"""Get a reference to model serving to perform operations on. Model serving operates on top of a model registry, defaulting to the project's default model registry.
+ !!! example
+ ```python
+ ms = conn.get_model_serving()
+ ```
+
# Returns
`ModelServing`. A model serving handle object to perform operations on.
"""
diff --git a/python/hsml/model.py b/python/hsml/model.py
index f9b4ba55..75d1e5ab 100644
--- a/python/hsml/model.py
+++ b/python/hsml/model.py
@@ -84,18 +84,41 @@ def __init__(
self._model_engine = model_engine.ModelEngine()
def save(self, model_path, await_registration=480):
- """Persist this model including model files and metadata to the model registry."""
+ """Persist this model including model files and metadata to the model registry.
+
+ !!! example
+ ```python
+ model.save('model.pkl')
+ ```
+
+ """
return self._model_engine.save(
self, model_path, await_registration=await_registration
)
def download(self):
- """Download the model files to a local folder."""
+ """Download the model files to a local folder.
+
+ !!! example
+ ```python
+ model_dir = model.download()
+ ```
+
+ """
return self._model_engine.download(self)
def delete(self):
"""Delete the model
+ !!! example
+ ```python
+ # get model object
+ model = mr.get_model("citibike_mlp_model", version=1)
+
+ # delete this model version
+ model.delete()
+ ```
+
!!! danger "Potentially dangerous operation"
This operation drops all metadata associated with **this version** of the
model **and** deletes the model files.
@@ -370,6 +393,11 @@ def set_tag(self, name: str, value: Union[str, dict]):
A tag consists of a pair. Tag names are unique identifiers across the whole cluster.
The value of a tag can be any valid json - primitives, arrays or json objects.
+ !!! example
+ ```python
+ model.set_tag(name="tag_name", value=42)
+ ```
+
# Arguments
name: Name of the tag to be added.
value: Value of the tag to be added.
@@ -382,6 +410,11 @@ def set_tag(self, name: str, value: Union[str, dict]):
def delete_tag(self, name: str):
"""Delete a tag attached to a model.
+ !!! example
+ ```python
+ model.delete_tag("tag_name")
+ ```
+
# Arguments
name: Name of the tag to be removed.
# Raises
@@ -392,6 +425,11 @@ def delete_tag(self, name: str):
def get_tag(self, name: str):
"""Get the tags of a model.
+ !!! example
+ ```python
+ tag_value = model.get_tag("tag_name")
+ ```
+
# Arguments
name: Name of the tag to get.
# Returns
@@ -404,6 +442,11 @@ def get_tag(self, name: str):
def get_tags(self):
"""Retrieves all tags attached to a model.
+ !!! example
+ ```python
+ tags = model.get_tags()
+ ```
+
# Returns
`Dict[str, obj]` of tags.
# Raises
@@ -415,6 +458,14 @@ def __repr__(self):
return f"Model(name: {self._name!r}, version: {self._version!r})"
def get_url(self):
+ """Returns URL of the specific model.
+
+ !!! example
+ ```python
+ model_url = model.get_url()
+ ```
+
+ """
path = (
"/p/"
+ str(client.get_instance()._project_id)
diff --git a/python/hsml/model_registry.py b/python/hsml/model_registry.py
index bea6a5a7..53814262 100644
--- a/python/hsml/model_registry.py
+++ b/python/hsml/model_registry.py
@@ -63,6 +63,20 @@ def get_model(self, name: str, version: int = None):
Getting a model from the Model Registry means getting its metadata handle
so you can subsequently download the model directory.
+ !!! example
+ ```python
+ import hsml
+
+ # connect with Hopsworks
+ conn = hsml.connection()
+
+ # get Hopsworks Model Registry
+ mr = conn.get_model_registry(project="my_project")
+
+ # get model object
+ model = mr.get_model("citibike_mlp_model", version=1)
+ ```
+
# Arguments
name: Name of the model to get.
version: Version of the model to retrieve, defaults to `None` and will
@@ -94,6 +108,11 @@ def get_models(self, name: str):
Getting all models from the Model Registry for a given name returns a list of model entities, one for each version registered under
the specified model name.
+ !!! example
+ ```python
+ models = mr.get_models("churnmodel")
+ ```
+
# Arguments
name: Name of the model to get.
# Returns
@@ -114,6 +133,17 @@ def get_best_model(self, name: str, metric: str, direction: str):
name corresponding to one of the keys in the training_metrics dict of the model and a direction. For example to
get the model version with the highest accuracy, specify metric='accuracy' and direction='max'.
+ !!! example
+ ```python
+ EVALUATION_METRIC = "r2_score"
+ SORT_METRICS_BY = "max" # your sorting criteria
+
+ # get best model based on custom metrics
+ best_model = mr.get_best_model("citibike_mlp_model",
+ EVALUATION_METRIC,
+ SORT_METRICS_BY)
+
+ ```
# Arguments
name: Name of the model to get.
metric: Name of the key in the training metrics field to compare.
diff --git a/python/hsml/model_schema.py b/python/hsml/model_schema.py
index 13be1dd8..d68091df 100644
--- a/python/hsml/model_schema.py
+++ b/python/hsml/model_schema.py
@@ -23,6 +23,14 @@
class ModelSchema:
"""Create a schema for a model.
+ !!! example
+ ```python
+ from hsml.schema import Schema
+ from hsml.model_schema import ModelSchema
+
+ model_schema = ModelSchema(input_schema=Schema(X_train), output_schema=Schema(y_train))
+ ```
+
# Arguments
input_schema: Schema to describe the inputs.
output_schema: Schema to describe the outputs.
@@ -50,6 +58,12 @@ def json(self):
def to_dict(self):
"""
Get dict representation of the ModelSchema.
+
+ !!! example
+ ```python
+ model_schema.to_dict()
+ ```
+
"""
return json.loads(self.json())
diff --git a/python/hsml/python/signature.py b/python/hsml/python/signature.py
index f572096a..500035d4 100644
--- a/python/hsml/python/signature.py
+++ b/python/hsml/python/signature.py
@@ -35,6 +35,17 @@ def create_model(
):
"""Create a generic Python model metadata object.
+ !!! example
+ ```python
+ model = mr.python.create_model(
+ name="knn_iris_model",
+ metrics=metrics,
+ model_schema=model_schema,
+ input_example=X_train.sample(),
+ description="Iris Flower Predictor"
+ )
+ ```
+
!!! note "Lazy"
This method is lazy and does not persist any metadata or uploads model artifacts in the
model registry on its own. To save the model object and the model artifacts, call the `save()` method with a
diff --git a/python/hsml/schema.py b/python/hsml/schema.py
index bad972a3..6d1e4d85 100644
--- a/python/hsml/schema.py
+++ b/python/hsml/schema.py
@@ -25,6 +25,14 @@
class Schema:
"""Create a schema for a model input or output.
+ !!! example
+ ```python
+ from hsml.schema import Schema
+
+ input_schema = Schema(X_train)
+ output_schema = Schema(y_train)
+ ```
+
# Arguments
object: The object to construct the schema from.
@@ -74,6 +82,12 @@ def json(self):
def to_dict(self):
"""
Get dict representation of the Schema.
+
+ !!! example
+ ```python
+ input_schema.to_dict()
+ ```
+
"""
return json.loads(self.json())
diff --git a/python/hsml/sklearn/signature.py b/python/hsml/sklearn/signature.py
index 27adb6f5..ef3b7ae4 100644
--- a/python/hsml/sklearn/signature.py
+++ b/python/hsml/sklearn/signature.py
@@ -35,6 +35,17 @@ def create_model(
):
"""Create an SkLearn model metadata object.
+ !!! example
+ ```python
+ model = mr.sklearn.create_model(
+ name="nyc_taxi_fares_model",
+ metrics=metrics,
+ description="LogisticRegression.",
+ input_example=X_test.sample(),
+ model_schema=model_schema
+ )
+ ```
+
!!! note "Lazy"
This method is lazy and does not persist any metadata or uploads model artifacts in the
model registry on its own. To save the model object and the model artifacts, call the `save()` method with a
diff --git a/python/hsml/tensorflow/signature.py b/python/hsml/tensorflow/signature.py
index f1d1635f..66e154c9 100644
--- a/python/hsml/tensorflow/signature.py
+++ b/python/hsml/tensorflow/signature.py
@@ -35,6 +35,16 @@ def create_model(
):
"""Create a TensorFlow model metadata object.
+ !!! example
+ ```python
+ model = mr.tensorflow.create_model(
+ name="bitcoin_price_model",
+ metrics=metrics,
+ description="bitcoin daily price detection model.",
+ input_example=[1613512800000]
+ )
+ ```
+
!!! note "Lazy"
This method is lazy and does not persist any metadata or uploads model artifacts in the
model registry on its own. To save the model object and the model artifacts, call the `save()` method with a
diff --git a/python/hsml/torch/signature.py b/python/hsml/torch/signature.py
index 32f359be..ee0ea4d8 100644
--- a/python/hsml/torch/signature.py
+++ b/python/hsml/torch/signature.py
@@ -35,6 +35,16 @@ def create_model(
):
"""Create a Torch model metadata object.
+ !!! example
+ ```python
+ model = mr.torch.create_model(
+ name="electricity_price_prediction_model",
+ metrics=metrics,
+ description="Daily electricity price prediction model.",
+ input_example=n_step_window.example[0].numpy()
+ )
+ ```
+
!!! note "Lazy"
This method is lazy and does not persist any metadata or uploads model artifacts in the
model registry on its own. To save the model object and the model artifacts, call the `save()` method with a
From d4da5357bef3459eb4ed15fbc5f0c4b872923c3d Mon Sep 17 00:00:00 2001
From: Roman <58133204+rktraz@users.noreply.github.com>
Date: Wed, 16 Nov 2022 18:05:23 +0100
Subject: [PATCH 2/3] made fixes, suggested by Jim
---
docs/index.md | 16 ++++++++++++----
1 file changed, 12 insertions(+), 4 deletions(-)
diff --git a/docs/index.md b/docs/index.md
index 2504b8d8..5d8f7f06 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -33,8 +33,7 @@
HSML is the library to interact with the Hopsworks Model Registry and Model Serving. The library makes it easy to export, manage and deploy models.
-The library automatically configures itself based on the environment it is run.
-However, to connect from an external Python environment additional connection information, such as host and port, is required. For more information about the setup from external environments, see the setup section.
+However, to connect from an external Python environment additional connection information, such as the Hopsworks hostname (or IP address) and port (if it is not port 443), is required. For more information about the setup from external environments, see the setup section.
## Getting Started On Hopsworks
@@ -43,7 +42,7 @@ Instantiate a connection and get the project model registry and serving handles
import hsml
# Create a connection
-connection = hsml.connection()
+connection = hsml.connection(host="my.cluster.com", project="fraud")
# Get the model registry handle for the project's model registry
mr = connection.get_model_registry()
@@ -54,11 +53,17 @@ ms = connection.get_model_serving()
Create a new model
```python
+import tensorflow as tf
+
+
model = mr.tensorflow.create_model(name="mnist",
version=1,
metrics={"accuracy": 0.94},
description="mnist model description")
-model.save("/tmp/model_directory") # or /tmp/model_file
+
+export_path = "/tmp/model_directory" # or "/tmp/model_file"
+tf.saved_model.save(model, export_path)
+model.save(export_path)
```
Download a model
@@ -87,6 +92,9 @@ deployment = model.deploy()
Start a deployment
```python
deployment.start()
+
+# Get the logs from a running deployment
+deployment.logs()
```
Make predictions with a deployed model
From 60f3aab12d821bcb43f3e21749edc2852aa9bdc8 Mon Sep 17 00:00:00 2001
From: rktraz
Date: Wed, 21 Dec 2022 19:37:05 +0100
Subject: [PATCH 3/3] resolved comments for PR
---
docs/index.md | 25 +++++++++++++++----------
python/hsml/connection.py | 4 ++--
python/hsml/model.py | 7 +++----
python/hsml/model_registry.py | 4 ++--
python/hsml/model_schema.py | 6 ------
python/hsml/python/signature.py | 8 ++++----
python/hsml/schema.py | 6 ------
python/hsml/sklearn/signature.py | 10 +++++-----
python/hsml/tensorflow/signature.py | 9 +++++----
python/hsml/torch/signature.py | 9 +++++----
10 files changed, 41 insertions(+), 47 deletions(-)
diff --git a/docs/index.md b/docs/index.md
index 5d8f7f06..aa9d37c7 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -33,6 +33,7 @@
HSML is the library to interact with the Hopsworks Model Registry and Model Serving. The library makes it easy to export, manage and deploy models.
+The library automatically configures itself based on the environment in which it runs.
However, to connect from an external Python environment additional connection information, such as the Hopsworks hostname (or IP address) and port (if it is not port 443), is required. For more information about the setup from external environments, see the setup section.
## Getting Started On Hopsworks
@@ -42,7 +43,8 @@ Instantiate a connection and get the project model registry and serving handles
import hsml
# Create a connection
-connection = hsml.connection(host="my.cluster.com", project="fraud")
+connection = hsml.connection()
+# or connection = hsml.connection(host="my.hopsworks.cluster", project="my_project")
# Get the model registry handle for the project's model registry
mr = connection.get_model_registry()
@@ -56,19 +58,22 @@ Create a new model
import tensorflow as tf
-model = mr.tensorflow.create_model(name="mnist",
- version=1,
- metrics={"accuracy": 0.94},
- description="mnist model description")
-
-export_path = "/tmp/model_directory" # or "/tmp/model_file"
+export_path = "/tmp/model_directory"
tf.saved_model.save(model, export_path)
-model.save(export_path)
+model = mr.tensorflow.create_model(
+ name="my_model",
+ metrics=metrics_dict,
+ model_schema=model_schema,
+ input_example=input_example,
+ description="Iris Flower Classifier"
+ )
+
+model.save(export_path) # "/tmp/model_directory" or "/tmp/model_file"
```
Download a model
```python
-model = mr.get_model("mnist", version=1)
+model = mr.get_model("my_model", version=1)
model_path = model.download()
```
@@ -80,7 +85,7 @@ model.delete()
Get best performing model
```python
-best_model = mr.get_best_model('mnist', 'accuracy', 'max')
+best_model = mr.get_best_model('my_model', 'accuracy', 'max')
```
diff --git a/python/hsml/connection.py b/python/hsml/connection.py
index 023eb845..a1c3a24a 100644
--- a/python/hsml/connection.py
+++ b/python/hsml/connection.py
@@ -61,8 +61,8 @@ class Connection:
api_key_file='modelregistry.key', # The file containing the API key generated above
hostname_verification=True) # Disable for self-signed certificates
)
- mr = conn.get_model_registry() # Get the project's default model registry
- ms = conn.get_model_serving() # Uses the previous model registry
+ mr = conn.get_model_registry()
+ ms = conn.get_model_serving()
```
Clients in external clusters need to connect to the Hopsworks Model Registry and Model Serving using an
diff --git a/python/hsml/model.py b/python/hsml/model.py
index 75d1e5ab..d7b77ea0 100644
--- a/python/hsml/model.py
+++ b/python/hsml/model.py
@@ -112,10 +112,9 @@ def delete(self):
!!! example
```python
- # get model object
- model = mr.get_model("citibike_mlp_model", version=1)
-
- # delete this model version
+ # get model object of a specific version
+ model = mr.get_model("my_model", version=1)
+ # delete the model version
model.delete()
```
diff --git a/python/hsml/model_registry.py b/python/hsml/model_registry.py
index 53814262..41e5cbca 100644
--- a/python/hsml/model_registry.py
+++ b/python/hsml/model_registry.py
@@ -74,7 +74,7 @@ def get_model(self, name: str, version: int = None):
mr = conn.get_model_registry(project="my_project")
# get model object
- model = mr.get_model("citibike_mlp_model", version=1)
+ model = mr.get_model("my_model", version=1)
```
# Arguments
@@ -110,7 +110,7 @@ def get_models(self, name: str):
!!! example
```python
- models = mr.get_models("churnmodel")
+ models = mr.get_models("my_model")
```
# Arguments
diff --git a/python/hsml/model_schema.py b/python/hsml/model_schema.py
index d68091df..018ca6d4 100644
--- a/python/hsml/model_schema.py
+++ b/python/hsml/model_schema.py
@@ -58,12 +58,6 @@ def json(self):
def to_dict(self):
"""
Get dict representation of the ModelSchema.
-
- !!! example
- ```python
- model_schema.to_dict()
- ```
-
"""
return json.loads(self.json())
diff --git a/python/hsml/python/signature.py b/python/hsml/python/signature.py
index 500035d4..95e1bb7b 100644
--- a/python/hsml/python/signature.py
+++ b/python/hsml/python/signature.py
@@ -38,11 +38,11 @@ def create_model(
!!! example
```python
model = mr.python.create_model(
- name="knn_iris_model",
- metrics=metrics,
+ name="my_model",
+ metrics=metrics_dict,
model_schema=model_schema,
- input_example=X_train.sample(),
- description="Iris Flower Predictor"
+ input_example=input_example,
+ description="Iris Flower Classifier"
)
```
diff --git a/python/hsml/schema.py b/python/hsml/schema.py
index 6d1e4d85..2e767403 100644
--- a/python/hsml/schema.py
+++ b/python/hsml/schema.py
@@ -82,12 +82,6 @@ def json(self):
def to_dict(self):
"""
Get dict representation of the Schema.
-
- !!! example
- ```python
- input_schema.to_dict()
- ```
-
"""
return json.loads(self.json())
diff --git a/python/hsml/sklearn/signature.py b/python/hsml/sklearn/signature.py
index ef3b7ae4..ecc93817 100644
--- a/python/hsml/sklearn/signature.py
+++ b/python/hsml/sklearn/signature.py
@@ -38,11 +38,11 @@ def create_model(
!!! example
```python
model = mr.sklearn.create_model(
- name="nyc_taxi_fares_model",
- metrics=metrics,
- description="LogisticRegression.",
- input_example=X_test.sample(),
- model_schema=model_schema
+ name="my_model",
+ metrics=metrics_dict,
+ model_schema=model_schema,
+ input_example=input_example,
+ description="Iris Flower Classifier"
)
```
diff --git a/python/hsml/tensorflow/signature.py b/python/hsml/tensorflow/signature.py
index 66e154c9..dd68af19 100644
--- a/python/hsml/tensorflow/signature.py
+++ b/python/hsml/tensorflow/signature.py
@@ -38,10 +38,11 @@ def create_model(
!!! example
```python
model = mr.tensorflow.create_model(
- name="bitcoin_price_model",
- metrics=metrics,
- description="bitcoin daily price detection model.",
- input_example=[1613512800000]
+ name="my_model",
+ metrics=metrics_dict,
+ model_schema=model_schema,
+ input_example=input_example,
+ description="Iris Flower Classifier"
)
```
diff --git a/python/hsml/torch/signature.py b/python/hsml/torch/signature.py
index ee0ea4d8..c77f01b8 100644
--- a/python/hsml/torch/signature.py
+++ b/python/hsml/torch/signature.py
@@ -38,10 +38,11 @@ def create_model(
!!! example
```python
model = mr.torch.create_model(
- name="electricity_price_prediction_model",
- metrics=metrics,
- description="Daily electricity price prediction model.",
- input_example=n_step_window.example[0].numpy()
+ name="my_model",
+ metrics=metrics_dict,
+ model_schema=model_schema,
+ input_example=input_example,
+ description="Iris Flower Classifier"
)
```