omega|ml plugins come in two forms:
- Mixins - extend the functionality of an existing component, e.g.
om.datasets
,om.models
orom.runtime
- Backends - add new capabilities to store and process a certain type of model (framework) or data object
If you want to add support for a new machine learning framework that omega|ml does not support yet, implement a backend. If you want to add pre- and post-processing to some method already provided by omega|ml, implement a mixin.
Model backends have two main responsibilities:
- store and retrieve machine learning models - these are the
put
andget
methods - run model actions, e.g. fit, score, predict etc. - these are the
fit
,score
,predict
methods
To implement a backend, write a class as follows:
class MyBackend(BaseModelBackend):
KIND = 'mybackend.type'
@classmethod
def supports(cls, obj, name, **kwargs):
valid = ... # some condition that returns True if the backend supports obj
return ok
def put(self, model, name, **kwargs):
gridfile = save(model) # your function/code to serialize the model at a persistent location
meta = self.model_store._make_metadata(
name=name,
prefix=self.model_store.prefix,
bucket=self.model_store.bucket,
kind=MyBackend.KIND,
attributes=attributes,
gridfile=gridfile).save()
return meta
def get(self, name, **kwargs):
model = load(...) # your load function/code to deserialize the model
return model
def fit(self, modelname, Xname, Yname, **kwargs):
X = om.data_store.get(Xname)
Y = om.data_store.get(Yname)
model = om.model_store.get(model)
model = om.model_store.fit(X, Y)
meta = om.model_store.put(model, modelname)
return meta
Notes:
- the
supports
method is a@classmethod
for efficiency - omega|ml will only instantiate the class if there is some work to perform. - model backends do not need to know where and how the data is stored, but they need to know how to get data from omega|ml. For this, the model backend provides the
.data_store
which is the same asom.datasets
- it is the backend's own responsibility to ensure the data retrieved matches the type and structure the model requires. The good news is that by omega|ml's name-based object resolution any data type and source can be supported
- at runtime, the backend will be instantiated in both the client (e.g. in Jupyter Notebook) as well as omega|ml's runtime environment in the cloud. Therefore the backend will have to be deployed to both your users and your cloud instance of omega|ml.
It is important to test your backend before you can run it. Here's how, in a nutshell
import omegaml as om
backend = MyBackend(data_store=om.datasets, model_store=om.models)
backend.put(model, 'name')
model_ = backend.get('name')
assert type(model_) == type(model)
model.fit(...)
model.predict(...)
To deploy your model onto an omega|ml cluster and make it ready for use by your users and applications, you need to package it. Packaging follows the same process as for any Python package, namely by writing a pip-installable module. There is a nice tutorial at https://packaging.python.org/tutorials/packaging-projects/
The gist of it is this:
- create a pip-installable package that contains your backend code
- install the backend so that all omega|ml components have access to it
- register the backend to omega|ml
Here's the gory details:
-
create a Python module
$ mkdir mybackend $ touch mybackend/__init__.py # add your backend's code in mybackend.__init__.py class MyBackend: ....
-
write a
setup.py
from setuptools import setup setup(name='funniest', version='0.1', description='mybackend for omega/Uml', url='http://github.com/foobar/mybackend', author='Flying Circus', author_email='flyingcircus@example.com', license='MIT', packages=['mybackend'], zip_safe=False)
-
check everything into github, so it is accessible for installation from the cloud (if you run omega|ml locally you can skip this step)
-
Write the omega|ml configuration file,
config.yml
OMEGA_USER_EXTENSIONS: OMEGA_STORE_BACKENDS: mybackend.type: mybackend.MyBackend
-
Map your config.yml into docker-compose
# find all the volumes: statements in docker-compose.yml, amend like this services: ... volumes: - pythonlib:/app/pylib - /host/path/to/config.yml:/app/config.yml volumes: pythonlib:
-
Install your package created above
# install in pylib $ mkdir /path/to/pylib $ pip install --target /path/to/pylib
-
Restart omega|ml
$ docker-compose restart
-
Test that it works
# open your jupyter notebook and work with your plugin # say your plugin can work with some new model types # -- save the model model = SomeNewModel() meta = om.models.put(model, 'name') assert meta is not None # -- load the model model_ = om.models.get('name') assert type(model_) == type(model) # -- run fit using the runtime meta_ = om.runtime.model('name').fit(X, y).get() assert 'Metadata' in meta_
Written with StackEdit.