Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added snippets for Connection, Model Registry #160

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 114 additions & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
# Hopsworks Model Management

<p align="center">
<a href="https://community.hopsworks.ai"><img
src="https://img.shields.io/discourse/users?label=Hopsworks%20Community&server=https%3A%2F%2Fcommunity.hopsworks.ai"
alt="Hopsworks Community"
/></a>
<a href="https://docs.hopsworks.ai"><img
src="https://img.shields.io/badge/docs-HSML-orange"
alt="Hopsworks Model Management Documentation"
/></a>
<a href="https://pypi.org/project/hsml/"><img
src="https://img.shields.io/pypi/v/hsml?color=blue"
alt="PyPiStatus"
/></a>
<a href="https://archiva.hops.works/#artifact/com.logicalclocks/hsml"><img
src="https://img.shields.io/badge/java-HSML-green"
alt="Scala/Java Artifacts"
/></a>
<a href="https://pepy.tech/project/hsml/month"><img
src="https://pepy.tech/badge/hsml/month"
alt="Downloads"
/></a>
<a href="https://github.com/psf/black"><img
src="https://img.shields.io/badge/code%20style-black-000000.svg"
alt="CodeStyle"
/></a>
<a><img
src="https://img.shields.io/pypi/l/hsml?color=green"
alt="License"
/></a>
</p>

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.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This sentence doesn't mean anything.
configures itself how?
Technically, it should be
"The library automatically configures itself based on the environment it is run in."
Do you mean?
The library automatically configures itself based on the environment it is run in, either Python or Spark.
If you mean - it configures itself based on whether it is run inside Hopsworks or outside Hopsworks - in this case, just remove the sentence. Users will expect it should work inside/outside Hopsworks. We shouldn't need to tell them.

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.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you connect to Hopsworks from an external Python environment to your own managed Hopsworks cluster, you need to provide additional connection information - the Hopsworks hostname (or IP address) and port (if it is not port 443).


## 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()

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

put the hostname and project in the example here:

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()

# 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

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a line of code before this where you export the tensorflow model to the local directory:
"/tmp/model_directory"

Otherwise this code snippet doesn't actually upload a tensorflow model

```

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()
```

javierdlrm marked this conversation as resolved.
Show resolved Hide resolved
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).
11 changes: 11 additions & 0 deletions python/hsml/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
mr = conn.get_model_registry() # Get the project's default model registry
mr = conn.get_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`.
Expand All @@ -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.
"""
Expand Down
55 changes: 53 additions & 2 deletions python/hsml/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
model.save('model.pkl')
model.save('model.pkl') # save a single model file, or
model.save('path/to/model_directory') # save a model with multiple files

```

"""
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()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# get model object
model = mr.get_model("citibike_mlp_model", version=1)
# delete this model version
model.delete()
# get model object of a specific version
model = mr.get_model("mnist", version=1)
# delete the 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.
Expand Down Expand Up @@ -370,6 +393,11 @@ def set_tag(self, name: str, value: Union[str, dict]):
A tag consists of a <name,value> 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.
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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)
Expand Down
30 changes: 30 additions & 0 deletions python/hsml/model_registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
models = mr.get_models("churnmodel")
models = mr.get_models("mnist")

```

# Arguments
name: Name of the model to get.
# Returns
Expand All @@ -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",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
best_model = mr.get_best_model("citibike_mlp_model",
best_model = mr.get_best_model("mnist",

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.
Expand Down
14 changes: 14 additions & 0 deletions python/hsml/model_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -50,6 +58,12 @@ def json(self):
def to_dict(self):
"""
Get dict representation of the ModelSchema.

!!! example
```python
model_schema.to_dict()
```

"""
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"""
Get dict representation of the ModelSchema.
!!! example
```python
model_schema.to_dict()
```
"""
""" Get dict representation of the ModelSchema. """

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method is thought to be used internally only. No need for example here.

return json.loads(self.json())

Expand Down
11 changes: 11 additions & 0 deletions python/hsml/python/signature.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
model = mr.python.create_model(
name="knn_iris_model",
metrics=metrics,
model_schema=model_schema,
input_example=X_train.sample(),
description="Iris Flower Predictor"
)
model = mr.python.create_model(
name="iris_flower_classifier",
metrics=metrics,
model_schema=model_schema,
input_example=input_example,
description="Iris Flower Classifier"
)

```

!!! 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
Expand Down
14 changes: 14 additions & 0 deletions python/hsml/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down Expand Up @@ -74,6 +82,12 @@ def json(self):
def to_dict(self):
"""
Get dict representation of the Schema.

!!! example
```python
input_schema.to_dict()
```

"""
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"""
Get dict representation of the Schema.
!!! example
```python
input_schema.to_dict()
```
"""
""" Get dict representation of the Schema. """

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to add example for internal method.

return json.loads(self.json())

Expand Down
11 changes: 11 additions & 0 deletions python/hsml/sklearn/signature.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
model = mr.sklearn.create_model(
name="nyc_taxi_fares_model",
metrics=metrics,
description="LogisticRegression.",
input_example=X_test.sample(),
model_schema=model_schema
)
model = mr.sklearn.create_model(
name="iris_flower_classifier",
metrics=metrics,
model_schema=model_schema,
input_example=input_example,
description="Iris Flower Classifier"
)

```

!!! 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
Expand Down
Loading