Skip to content

Commit

Permalink
Sklearn fixes (kubeflow#91)
Browse files Browse the repository at this point in the history
* sklearn tests and refactor

* adding successful test executions

* fixing based on review comments

* adding static type checking as part of maketest
  • Loading branch information
animeshsingh authored and k8s-ci-robot committed May 14, 2019
1 parent 59795cd commit 6e26436
Show file tree
Hide file tree
Showing 9 changed files with 118 additions and 8 deletions.
10 changes: 10 additions & 0 deletions python/sklearnserver/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@

dev_install:
pip install -e .
pip install -e .[test]

test: type_check
pytest -W ignore

type_check:
mypy --ignore-missing-imports sklearnserver
68 changes: 68 additions & 0 deletions python/sklearnserver/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,71 @@ __main__.py: error: the following arguments are required: --model_dir
```

You can now point to your `joblib` model file and use the server to load the model and test for prediction. Models can be on local filesystem, S3 compatible object storage or Google Cloud Storage. Please follow [this sample](https://github.com/kubeflow/kfserving/tree/master/docs/samples/sklearn) to test your server by generating your own model.

## Development

Install the development dependencies with:

```bash
pip install -e .[test]
```

The following indicates a successful install.

```
Obtaining file:///Users/animeshsingh/DevAdv/kfserving/python/sklearnserver
Requirement already satisfied: kfserver==0.1.0 in /Users/animeshsingh/DevAdv/kfserving/python/kfserving (from sklearnserver==0.1.0) (0.1.0)
Requirement already satisfied: scikit-learn==0.20.3 in /Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages (from sklearnserver==0.1.0) (0.20.3)
Requirement already satisfied: argparse>=1.4.0 in /Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages (from sklearnserver==0.1.0) (1.4.0)
Requirement already satisfied: numpy>=1.8.2 in /Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages (from sklearnserver==0.1.0) (1.16.3)
Requirement already satisfied: joblib>=0.13.0 in /Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages (from sklearnserver==0.1.0) (0.13.2)
Requirement already satisfied: pytest in /Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages (from sklearnserver==0.1.0) (4.5.0)
Requirement already satisfied: pytest-tornasync in /Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages(from sklearnserver==0.1.0) (0.6.0.post1)
Requirement already satisfied: mypy in /Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages (from sklearnserver==0.1.0) (0.701)
Requirement already satisfied: tornado>=1.4.1 in /Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages (from kfserver==0.1.0->sklearnserver==0.1.0) (6.0.2)
Requirement already satisfied: scipy>=0.13.3 in /Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages (from scikit-learn==0.20.3->sklearnserver==0.1.0) (1.2.1)
Requirement already satisfied: attrs>=17.4.0 in /Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages (from pytest->sklearnserver==0.1.0) (19.1.0)
Requirement already satisfied: setuptools in /Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages (frompytest->sklearnserver==0.1.0) (40.8.0)
Requirement already satisfied: wcwidth in /Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages (from pytest->sklearnserver==0.1.0) (0.1.7)
Requirement already satisfied: atomicwrites>=1.0 in /Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages (from pytest->sklearnserver==0.1.0) (1.3.0)
Requirement already satisfied: pluggy!=0.10,<1.0,>=0.9 in /Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages (from pytest->sklearnserver==0.1.0) (0.11.0)
Requirement already satisfied: more-itertools>=4.0.0; python_version > "2.7" in /Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages (from pytest->sklearnserver==0.1.0) (7.0.0)
Requirement already satisfied: six>=1.10.0 in /Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages (from pytest->sklearnserver==0.1.0) (1.12.0)
Requirement already satisfied: py>=1.5.0 in /Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages (from pytest->sklearnserver==0.1.0) (1.8.0)
Requirement already satisfied: typed-ast<1.4.0,>=1.3.1 in /Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages (from mypy->sklearnserver==0.1.0) (1.3.5)
Requirement already satisfied: mypy-extensions<0.5.0,>=0.4.0 in /Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages (from mypy->sklearnserver==0.1.0) (0.4.1)
Installing collected packages: sklearnserver
Found existing installation: sklearnserver 0.1.0
Uninstalling sklearnserver-0.1.0:
Successfully uninstalled sklearnserver-0.1.0
Running setup.py develop for sklearnserver
Successfully installed sklearnserver
```

To run tests, please change the test file to point to your model.joblib file. Then run the following command:

```bash
make test
```

The following shows the type of output you should see:

```
pytest -W ignore
====================================================== test session starts ======================================================
platform darwin -- Python 3.7.3, pytest-4.5.0, py-1.8.0, pluggy-0.11.0
rootdir: /Users/animeshsingh/DevAdv/kfserving/python/sklearnserver
plugins: tornasync-0.6.0.post1
collected 1 item
sklearnserver/test_model.py . [100%]
=================================================== 1 passed in 0.43 seconds ====================================================
```

To run static type checks:

```bash
mypy --ignore-missing-imports sklearnserver
```
An empty result will indicate success.
7 changes: 7 additions & 0 deletions python/sklearnserver/setup.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
from setuptools import setup, find_packages

tests_require = [
'pytest',
'pytest-tornasync',
'mypy'
]
setup(
name='sklearnserver',
version='0.1.0',
Expand All @@ -17,4 +22,6 @@
"numpy >= 1.8.2",
"joblib >= 0.13.0"
],
tests_require=tests_require,
extras_require={'test': tests_require}
)
Binary file added python/sklearnserver/sklearnserver/__init__.pyc
Binary file not shown.
13 changes: 9 additions & 4 deletions python/sklearnserver/sklearnserver/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,26 @@
import joblib
import numpy as np
import os
from typing import List, Any

JOBLIB_FILE = "model.joblib"

class SKLearnModel(kfserving.KFModel):
def __init__(self, name, model_dir):
def __init__(self, name: str, model_dir: str):
super().__init__(name)
self.name = name
self.model_dir = model_dir
self.ready = False

def load(self):
model_file = kfserving.Storage.download(self.model_dir)
model_file = os.path.join(
kfserving.Storage.download(self.model_dir),JOBLIB_FILE)
self._joblib = joblib.load(model_file)
self.ready = True

def predict(self, inputs):
def predict(self, body: List) -> List:
try:
inputs = np.array(inputs)
inputs = np.array(body)
except Exception as e:
raise Exception(
"Failed to initialize NumPy array from inputs: %s, %s" % (e, inputs))
Expand Down
21 changes: 21 additions & 0 deletions python/sklearnserver/sklearnserver/test_model.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from sklearn import svm
from sklearn import datasets
from sklearnserver import SKLearnModel
import joblib
import os

model_dir = "/path/to/kfserving/docs/samples/sklearn"
JOBLIB_FILE = "model.joblib"

def test_model():
iris = datasets.load_iris()
X, y = iris.data, iris.target
sklearn_model = svm.SVC(gamma='scale')
sklearn_model.fit(X, y)
model_file = os.path.join((model_dir),JOBLIB_FILE)
joblib.dump(value=sklearn_model, filename=model_file)
server = SKLearnModel("sklearnmodel", model_dir)
server.load()
request = X[0:1].tolist()
response = server.predict(request)
assert response == [0]
2 changes: 1 addition & 1 deletion python/xgbserver/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ dev_install:
pip install -e .
pip install -e .[test]

test:
test: type_check
pytest -W ignore

type_check:
Expand Down
4 changes: 2 additions & 2 deletions python/xgbserver/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,10 @@ Successfully installed xgbserver
```


to run tests:
To run tests:

```bash
make tests
make test
```

The following shows the type of output you should see:
Expand Down
1 change: 0 additions & 1 deletion python/xgbserver/xgbserver/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@

BOOSTER_FILE = "model.bst"


class XGBoostModel(kfserving.KFModel):
def __init__(self, name: str, model_dir: str, booster: XGBModel = None):
super().__init__(name)
Expand Down

0 comments on commit 6e26436

Please sign in to comment.