Skip to content

Commit

Permalink
Added support for ModelVersions and updating models
Browse files Browse the repository at this point in the history
  • Loading branch information
nbarraille committed Mar 19, 2019
1 parent 0f2d338 commit b9c9a5b
Show file tree
Hide file tree
Showing 12 changed files with 408 additions and 95 deletions.
5 changes: 5 additions & 0 deletions HISTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,14 @@

## dev

## 0.1.2 (2019-04-19)

### Improvements

- Allow to set host and api key through environment variables
- Add support for ModelVersions and updating models
- Prevent from deploying untrained models and custom estimators
- Nicer objects **repr**

## 0.1.1 (2019-04-14)

Expand Down
2 changes: 2 additions & 0 deletions Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,14 @@ setuptools = "*"
wheel = "*"
twine = "*"
sphinx = "*"
responses = "*"

[packages]
requests = "*"
sklearn = "*"
e1839a8 = {editable = true,path = "."}
blazee = {editable = true,path = "."}
python-dateutil = "*"

[requires]
python_version = "3.7"
31 changes: 27 additions & 4 deletions Pipfile.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion blazee/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
# Or predict a batch
>>> preds = model.batch_predict(X)
"""
__version__ = '0.1.1'
__version__ = '0.1.2'

from .client import Client as Blazee
from .model import BlazeeModel
Expand Down
68 changes: 12 additions & 56 deletions blazee/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,16 @@
This module provides a Client for interacting with the Blazee API.
"""
import io
import logging
import os
import pickle
import uuid
from datetime import datetime
from json import dumps as jsondumps

import requests
from requests.exceptions import HTTPError

from blazee.model import BlazeeModel
from blazee.model import BlazeeModel, _serialize_model
from blazee.utils import NumpyEncoder

DEFAULT_BLAZEE_HOST = 'https://api.blazee.io/v1'
Expand Down Expand Up @@ -61,7 +59,7 @@ def all_models(self):
return [BlazeeModel(self, m) for m in resp]

def get_model(self, model_id):
"""Returns the Blazee model with the give ID.
"""Returns the Blazee model with the given ID.
Returns
-------
Expand All @@ -80,7 +78,7 @@ def deploy_model(self, model, model_name=None):
"""Deploys a trained ML model on Blazee
At the moment only Scikit Learn models and pipelines are
supported.
Using another framework? Reach out at support@blazee.io
Looking for another framework? Reach out at support@blazee.io
Parameters
----------
Expand All @@ -95,61 +93,26 @@ def deploy_model(self, model, model_name=None):
The Blazee model that was deployed, ready to use for
predictions
"""
if self._is_sklearn(model):
return self.deploy_sklearn(model, model_name)
else:
raise TypeError(f'Model Type not supported: {type(model)}')

def deploy_sklearn(self, model, model_name=None):
"""Deploys a Scikit Learn model
See `deploy_model()`
"""
if not self._is_sklearn(model):
raise TypeError('Model is not a valid Scikit Learn estimator')
model_type, content = _serialize_model(model)

model_class = type(model).__name__
if not model_name:
model_name = f'{model_class} {datetime.now().isoformat()}'

# Serialize model
content = io.BytesIO()
pickle.dump(model, content)
model_name = f'{type(model).__name__} {datetime.now().isoformat()}'

return self._create_model('sklearn',
model_name=model_name,
model_content=content.getvalue())
model = self._create_model('sklearn',
model_name=model_name,
model_content=content)

def _is_sklearn(self, model):
try:
from sklearn.base import BaseEstimator
return isinstance(model, BaseEstimator)
except:
return False
version = model._upload_version(model_type, content)
return version.model

def _create_model(self, type, model_name, model_content):
response = self._api_call('/models',
method='POST',
json={
'name': model_name,
'type': type
'name': model_name
})
upload_data = response['upload_data']
logging.info(f'Uploading model to Blazee...')
upload_resp = requests.post(upload_data['url'],
data=upload_data['fields'],
files={'file': model_content})
upload_resp.raise_for_status()

logging.info(f"Successfully deployed model {response['id']}")

model = BlazeeModel(self, response)
logging.info(f"Deploying model... This will take a few moments")
try:
self._wait_for_depoyment(model)
except TimeoutError:
model.delete()
raise RuntimeError("Error deploying model")
return model
return BlazeeModel(self, response)

def _api_call(self, path, method='GET', json=None):
if json is None:
Expand Down Expand Up @@ -180,10 +143,3 @@ def _api_call(self, path, method='GET', json=None):
raise HTTPError(error_msg)
else:
return resp.json()

def _wait_for_depoyment(self, model, wait=5, max_tries=30):
for _ in range(max_tries):
m = self.get_model(model.id)
if m.uploaded:
return
raise TimeoutError('Deployment timeout')

0 comments on commit b9c9a5b

Please sign in to comment.