Skip to content

Commit

Permalink
Merge pull request #124 from cliveseldon/r_wrappers
Browse files Browse the repository at this point in the history
R wrappers
  • Loading branch information
gsunner authored Mar 28, 2018
2 parents 5b26ede + c8111bf commit 481ca17
Show file tree
Hide file tree
Showing 28 changed files with 1,183 additions and 16 deletions.
7 changes: 7 additions & 0 deletions docs/wrappers/python.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@ If you are not familar with s2i you can read [general instructions on using s2i]
* Docker
* Git (if building from a remote git repo)

To check everything is working you can run

```bash
s2i usage seldonio/seldon-core-s2i-python3
```


# Step 2 - Create your source code

To use our s2i builder image to package your python model you will need:
Expand Down
163 changes: 163 additions & 0 deletions docs/wrappers/r.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
# Packaging an R model for Seldon Core using s2i


In this guide, we illustrate the steps needed to wrap your own R model in a docker image ready for deployment with Seldon Core using [source-to-image app s2i](https://github.com/openshift/source-to-image).

If you are not familar with s2i you can read [general instructions on using s2i](./s2i.md) and then follow the steps below.


# Step 1 - Install s2i

[Download and install s2i](https://github.com/openshift/source-to-image#installation)

* Prequisites for using s2i are:
* Docker
* Git (if building from a remote git repo)

To check everything is working you can run

```bash
s2i usage seldonio/seldon-core-s2i-r
```

# Step 2 - Create your source code

To use our s2i builder image to package your R model you will need:

* An R file which provides an S3 class for your model via an ```initialise_seldon``` function and that has appropriate generics for your component, e.g. predict for a model.
* An optional install.R to be run to install any libraries needed
* .s2i/environment - model definitions used by the s2i builder to correctly wrap your model

We will go into detail for each of these steps:

## R Runtime Model file
Your source code should contain an R file which defines an S3 class for your model. For example, looking at our skeleton R model file at ```wrappers/s2i/R/test/model-template-app/MyModel.R```:

```R
library(methods)

predict.mymodel <- function(mymodel,newdata=list()) {
write("MyModel predict called", stdout())
newdata
}


new_mymodel <- function() {
structure(list(), class = "mymodel")
}


initialise_seldon <- function(params) {
new_mymodel()
}
```

* A ```seldon_initialise``` function creates an S3 class for my model via a constructor ```new_mymodel```. This will be called on startup and you can use this to load any parameters your model needs.
* A generic ```predict``` function is created for my model class. This will be called with a ```newdata``` field with the ```data.frame``` to be predicted.

There are similar templates for ROUTERS and TRANSFORMERS.


## install.R
Populate an ```install.R``` with any software dependencies your code requires. For example:

```R
install.packages('rpart')
```

## .s2i/environment

Define the core parameters needed by our R builder image to wrap your model. An example is:

```bash
MODEL_NAME=MyModel
API_TYPE=REST
SERVICE_TYPE=MODEL
PERSISTENCE=0
```

These values can also be provided or overriden on the command line when building the image.

# Step 3 - Build your image
Use ```s2i build``` to create your Docker image from source code. You will need Docker installed on the machine and optionally git if your source code is in a public git repo.

Using s2i you can build directly from a git repo or from a local source folder. See the [s2i docs](https://github.com/openshift/source-to-image/blob/master/docs/cli.md#s2i-build) for further details. The general format is:

```bash
s2i build <git-repo> seldonio/seldon-core-s2i-r <my-image-name>
s2i build <src-folder> seldonio/seldon-core-s2i-r <my-image-name>
```

An example invocation using the test template model inside seldon-core:

```bash
s2i build https://github.com/seldonio/seldon-core.git --context-dir=wrappers/s2i/R/test/model-template-app seldonio/seldon-core-s2i-r seldon-core-template-model
```

The above s2i build invocation:

* uses the GitHub repo: https://github.com/seldonio/seldon-core.git and the directory ```wrappers/s2i/R/test/model-template-app``` inside that repo.
* uses the builder image ```seldonio/seldon-core-s2i-r```
* creates a docker image ```seldon-core-template-model```


For building from a local source folder, an example where we clone the seldon-core repo:

```bash
git clone https://github.com/seldonio/seldon-core.git
cd seldon-core
s2i build wrappers/s2i/R/test/model-template-app seldonio/seldon-core-s2i-r seldon-core-template-model
```

For more help see:

```
s2i usage seldonio/seldon-core-s2i-r
s2i build --help
```

# Reference

## Environment Variables
The required environment variables understood by the builder image are explained below. You can provide them in the ```.s2i/enviroment``` file or on the ```s2i build``` command line.


### MODEL_NAME
The name of the R file containing the model.

### API_TYPE

API type to create. Can be REST only at present.

### SERVICE_TYPE

The service type being created. Available options are:

* MODEL
* ROUTER
* TRANSFORMER

### PERSISTENCE

Can only by 0 at present. In future, will allow the state of the component to be saved periodically.


## Creating different service types

### MODEL

* [A minimal skeleton for model source code](https://github.com/cliveseldon/seldon-core/tree/s2i/wrappers/s2i/R/test/model-template-app)
* [Example models](https://github.com/SeldonIO/seldon-core/tree/master/examples/models)

### ROUTER

* [A minimal skeleton for router source code](https://github.com/cliveseldon/seldon-core/tree/s2i/wrappers/s2i/R/test/router-template-app)

### TRANSFORMER

* [A minimal skeleton for transformer source code](https://github.com/cliveseldon/seldon-core/tree/s2i/wrappers/s2i/R/test/transformer-template-app)





12 changes: 5 additions & 7 deletions docs/wrappers/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,12 @@ You can use either:
* [Source-to-image (s2i) tool](./python.md)
* [Seldon Docker wrapper application](./python-docker.md)

## H2O

* [H2O models](./h2o.md)
## R

## Future
* [R models can be wrapped using source-to-image](r.md)

Future languages:
## H2O

* [H2O models](./h2o.md)

* R based models
* Java based models
* Go based models
6 changes: 1 addition & 5 deletions docs/wrappers/s2i.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,4 @@ The general work flow is:
At present we have s2i builder images for

* [python (python2 or python3)](./python.md) : use this for Tensorflow, Keras, pyTorch or sklearn models.

We plan on also supporting other base languages such as:

* R
* Java
* [R](r.md)
4 changes: 4 additions & 0 deletions examples/models/r_iris/.s2i/environment
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
MODEL_NAME=iris.R
API_TYPE=REST
SERVICE_TYPE=MODEL
PERSISTENCE=0
83 changes: 83 additions & 0 deletions examples/models/r_iris/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# Deep MNIST
An R Iris model.

## Depenencies

R

## Train locally

```bash
Rscript train.R
```

## Wrap using [s2i](https://github.com/openshift/source-to-image#installation).

```bash
s2i build . seldonio/seldon-core-s2i-r r-iris:0.1
```

## Local Docker Smoke Test

Run under docker.

```bash
docker run --rm -p 5000:5000 r-iris:0.1
```

Ensure test grpc modules compiled.

```bash
pushd ../../../wrappers/testing ; make build_protos ; popd
```

Send a data request using the wrapper tester.

```bash
python ../../../wrappers/testing/tester.py contract.json 0.0.0.0 5000 -p
```

## Minikube test

```bash
minikube start --memory 4096
```

[Install seldon core](/readme.md#install)

Connect to Minikube Docker daemon

```bash
eval $(minikube docker-env)
```

Build image using minikube docker daemon.

```bash
s2i build . seldonio/seldon-core-s2i-r r-iris:0.1
```

Launch deployment

```bash
kubectl create -f r_iris_deployment.json
```

Port forward API server

```bash
kubectl port-forward $(kubectl get pods -n seldon -l app=seldon-apiserver-container-app -o jsonpath='{.items[0].metadata.name}') -n seldon 8080:8080
```

Ensure tester gRPC modules compiled.

```bash
pushd ../../../util/api_tester ; make build_protos ; popd
```

Send test request
```bash
python ../../../util/api_tester/api-tester.py contract.json 0.0.0.0 8080 --oauth-key oauth-key --oauth-secret oauth-secret -p
```


39 changes: 39 additions & 0 deletions examples/models/r_iris/contract.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{
"features":[
{
"name":"sepal_length",
"dtype":"FLOAT",
"ftype":"continuous",
"range":[4,8]
},
{
"name":"sepal_width",
"dtype":"FLOAT",
"ftype":"continuous",
"range":[2,5]
},
{
"name":"petal_length",
"dtype":"FLOAT",
"ftype":"continuous",
"range":[1,10]
},
{
"name":"petal_width",
"dtype":"FLOAT",
"ftype":"continuous",
"range":[0,3]
}
],
"targets":[
{
"name":"class",
"dtype":"FLOAT",
"ftype":"continuous",
"range":[0,1],
"repeat":3
}
]
}


1 change: 1 addition & 0 deletions examples/models/r_iris/install.R
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
install.packages('rpart')
14 changes: 14 additions & 0 deletions examples/models/r_iris/iris.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
library(methods)

predict.iris <- function(iris,newdata=list()) {
predict(iris$model, newdata = newdata)
}

new_iris <- function(filename) {
model <- readRDS(filename)
structure(list(model=model), class = "iris")
}

initialise_seldon <- function(params) {
new_iris("model.Rds")
}
Loading

0 comments on commit 481ca17

Please sign in to comment.