Skip to content
Permalink
Browse files

[DOCS] Add core concept section (#567)

* fix google cloud run docs image not readable

* Update quickstart.rst

* update deployment index

* doc: move core concepts to one file

* add batch serving section

* add note about batch serving

* Update quickstart.rst

* Introducing BentoService

* docs updates

* core concepts WIP

* Clean up @env decorator parameter and docs

* more docs udpate

* Update concepts.rst

* WIP

* updates

* Update bundler.py
  • Loading branch information
parano committed Mar 26, 2020
1 parent 707d30f commit aaca4db32bc78972a386a7a49998b3329e0c34e4
@@ -36,43 +36,50 @@ Installing BentoML with `pip`:
pip install bentoml
```

Creating a prediction service with BentoML:
A minimal prediction service in BentoML looks something like this:

```python
import bentoml
from bentoml import env, artifacts, api, BentoService
from bentoml.handlers import DataframeHandler
from bentoml.artifact import SklearnModelArtifact
@bentoml.env(pip_dependencies=["scikit-learn"]) # defining pip/conda dependencies to be packed
@bentoml.artifacts([SklearnModelArtifact('model')]) # defining required artifacts, typically trained models
class IrisClassifier(bentoml.BentoService):
@env(auto_pip_dependencies=True)
@artifacts([SklearnModelArtifact('model')])
class IrisClassifier(BentoService):
@bentoml.api(DataframeHandler) # defining prediction service endpoint and expected input format
@api(DataframeHandler)
def predict(self, df):
# Pre-processing logic and access to trained model artifacts in API function
return self.artifacts.model.predict(df)
```

Train a classifier model with default Iris dataset and pack the trained model
with the BentoService `IrisClassifier` defined above:
This code defines a prediction service that requires a scikit-learn model, and asks
BentoML to figure out the required PyPI pip packages automatically. It also defined
an API, which is the entry point for accessing this prediction service. And the API is
expecting a `pandas.DataFrame` object as its input data.

Now you are ready to train a model and serve the model with the `IrisClassifier` service
defined above:

```python
from sklearn import svm
from sklearn import datasets
if __name__ == "__main__":
clf = svm.SVC(gamma='scale')
# Load training data
iris = datasets.load_iris()
X, y = iris.data, iris.target
# Model Training
clf = svm.SVC(gamma='scale')
clf.fit(X, y)
# Create a iris classifier service
# Create a iris classifier service instance
iris_classifier_service = IrisClassifier()
# Pack it with the newly trained model artifact
# Pack the newly trained model artifact
iris_classifier_service.pack('model', clf)
# Save the prediction service to a BentoService bundle
# Save the prediction service to disk for model serving
saved_path = iris_classifier_service.save()
```
You've just created a BentoService SavedBundle, it's a versioned file archive that is
@@ -46,14 +46,15 @@
logger = logging.getLogger(__name__)


def save_to_dir(bento_service, path, version=None):
def save_to_dir(bento_service, path, version=None, silent=False):
"""Save given BentoService along with all its artifacts, source code and
dependencies to target file path, assuming path exist and empty. If target path
is not empty, this call may override existing files in the given path.
Args:
bento_service (bentoml.service.BentoService): a Bento Service instance
path (str): Destination of where the bento service will be saved
:param bento_service (bentoml.service.BentoService): a Bento Service instance
:param path (str): Destination of where the bento service will be saved
:param version (str): Override the service version with given version string
:param silent (boolean): whether to hide the log message showing target save path
"""
track_save(bento_service)

@@ -65,6 +66,8 @@ def save_to_dir(bento_service, path, version=None):
)

if version is not None:
# If parameter version provided, set bento_service version
# Otherwise it will bet set the first time the `version` property get accessed
bento_service.set_version(version)

if not os.path.exists(path):
@@ -159,9 +162,10 @@ def save_to_dir(bento_service, path, version=None):
if _is_bentoml_in_develop_mode():
add_local_bentoml_package_to_repo(path)

logger.info(
"BentoService bundle '%s:%s' created at: %s",
bento_service.name,
bento_service.version,
path,
)
if not silent:
logger.info(
"BentoService bundle '%s:%s' created at: %s",
bento_service.name,
bento_service.version,
path,
)
@@ -29,7 +29,7 @@
from bentoml.bundler.config import SavedBundleConfig
from bentoml.service_env import BentoServiceEnv
from bentoml.utils import isidentifier
from bentoml.utils.hybirdmethod import hybridmethod
from bentoml.utils.hybridmethod import hybridmethod
from bentoml.marshal.utils import DataLoader
from bentoml.utils.trace import trace
from bentoml.exceptions import NotFound, InvalidArgument
@@ -285,33 +285,37 @@ def decorator(bento_service_cls):


def env_decorator(
setup_sh=None,
pip_dependencies=None,
auto_pip_dependencies=False,
requirements_txt_file=None,
conda_channels=None,
conda_dependencies=None,
setup_sh=None,
):
"""Define environment and dependencies required for the BentoService being created
Args:
setup_sh (str): bash script for initializing docker environment before loading
the BentoService for inferencing
pip_dependencies (list(str)): List of python PyPI package dependencies
auto_pip_dependencies (bool): Flag to tell bentoml auto seek package
dependencies for project or not
conda_channels (list(str)): List of conda channels required for conda
dependencies
conda_dependencies (list(str)): List of conda dependencies required
pip_dependencies: list of pip_dependencies required, specified by package name
or with specified version `{package_name}=={package_version}`
auto_pip_dependencies: (Beta) whether to automatically find all the required
pip dependencies and pin their version
requirements_txt_file: pip dependencies in the form of a requirements.txt file,
this can be a relative path to the requirements.txt file or the content
of the file
conda_channels: extra conda channels to be used
conda_dependencies: list of conda dependencies required
setup_sh: user defined setup bash script, it is executed in docker build time
"""

def decorator(bento_service_cls):
bento_service_cls._env = BentoServiceEnv(
bento_service_name=bento_service_cls.name(),
setup_sh=setup_sh,
pip_dependencies=pip_dependencies,
auto_pip_dependencies=auto_pip_dependencies,
requirements_txt_file=requirements_txt_file,
conda_channels=conda_channels,
conda_dependencies=conda_dependencies,
setup_sh=setup_sh,
)
return bento_service_cls

@@ -382,6 +386,19 @@ def _validate_version_str(version_str):


def save(bento_service, base_path=None, version=None):
"""
Save and register the given BentoService via BentoML's built-in model management
system. BentoML by default keeps track of all the SavedBundle's files and metadata
in local file system under the $BENTOML_HOME(~/bentoml) directory. Users can also
configure BentoML to save their BentoService to a shared Database and cloud object
storage such as AWS S3.
:param bento_service: target BentoService instance to be saved
:param base_path: optional - override repository base path
:param version: optional - save with version override
:return: saved_path: file path to where the BentoService is saved
"""

from bentoml.yatai.client import YataiClient
from bentoml.yatai import get_yatai_service

@@ -395,10 +412,16 @@ def save(bento_service, base_path=None, version=None):


class BentoService(BentoServiceBase):
"""BentoService packs a list of artifacts and exposes service APIs
for BentoAPIServer and BentoCLI to execute. By subclassing BentoService,
users can customize the artifacts and environments required for
a ML service.
"""
BentoService is the base component for building prediction services using BentoML.
BentoService provide an abstraction for describing model artifacts and environment
dependencies required for a prediction service. And allows users to write custom
prediction API handling logic via BentoService API callback function.
Each BentoService can contain multiple models via the BentoML Artifact class, and
can define multiple APIs for accessing this service. Each API should specify a type
of Handler, which defines the expected input data format for this API.
>>> from bentoml import BentoService, env, api, artifacts, ver
>>> from bentoml.handlers import DataframeHandler
@@ -466,6 +489,9 @@ def _init_env(self):

@property
def artifacts(self):
"""
:return: List of model artifacts
"""
return self._packed_artifacts

@property
@@ -554,13 +580,42 @@ def version(self):
return self._bento_service_version

def save(self, base_path=None, version=None):
"""
Save and register this BentoService via BentoML's built-in model management
system. BentoML by default keeps track of all the SavedBundle's files and
metadata in local file system under the $BENTOML_HOME(~/bentoml) directory.
Users can also configure BentoML to save their BentoService to a shared Database
and cloud object storage such as AWS S3.
:param base_path: optional - override repository base path
:param version: optional - save with version override
:return: saved_path: file path to where the BentoService is saved
"""
return save(self, base_path, version)

def save_to_dir(self, path, version=None):
"""Save this BentoService along with all its artifacts, source code and
dependencies to target file path, assuming path exist and empty. If target path
is not empty, this call may override existing files in the given path.
:param path (str): Destination of where the bento service will be saved
:param version: optional - save with version override
"""
return save_to_dir(self, path, version)

@hybridmethod
def pack(self, name, *args, **kwargs):
"""
BentoService#pack method is used for packing trained model instances with a
BentoService instance and make it ready for BentoService#save.
pack(name, *args, **kwargs):
:param name: name of the declared model artifact
:param args: args passing to the target model artifact to be packed
:param kwargs: kwargs passing to the target model artifact to be packed
:return: this BentoService instance
"""
if name in self.artifacts:
logger.warning(
"BentoService '%s' #pack overriding existing artifact '%s'",
@@ -578,6 +633,20 @@ def pack(self, name, *args, **kwargs):

@pack.classmethod
def pack(cls, *args, **kwargs): # pylint: disable=no-self-argument
"""
**Deprecated**: Legacy `BentoService#pack` class method, which can be used to
initialize a BentoService instance along with trained model artifacts. This will
be deprecated soon:
:param args: args passing to the BentoService class
:param kwargs: kwargs passing to the BentoService class and (artifact_name,
args) pair for creating declared model artifacts
:return: a new BentoService instance
"""
logger.warning(
"BentoService#pack class method is deprecated, use instance method `pack` "
"instead. e.g.: svc = MyBentoService(); svc.pack('model', model_object)"
)
from bentoml.artifact import ArtifactCollection

if args and isinstance(args[0], ArtifactCollection):
@@ -92,27 +92,27 @@ class BentoServiceEnv(object):
Args:
bento_service_name: name of the BentoService name bundled with this Env
setup_sh: user defined setup bash script, it is executed in docker build time
pip_dependencies: list of pip_dependencies required, specified by package name
or with specified version `{package_name}=={package_version}`
auto_pip_dependencies: (Beta) whether to automatically find all the required
pip dependencies and pin their version
conda_channels: extra conda channels to be used
conda_dependencies: list of conda dependencies required
requirements_txt_file: pip dependencies in the form of a requirements.txt file,
this can be a relative path to the requirements.txt file or the content
of the file
conda_channels: extra conda channels to be used
conda_dependencies: list of conda dependencies required
setup_sh: user defined setup bash script, it is executed in docker build time
"""

def __init__(
self,
bento_service_name,
setup_sh=None,
pip_dependencies=None,
auto_pip_dependencies=False,
requirements_txt_file=None,
conda_channels=None,
conda_dependencies=None,
requirements_txt_file=None,
setup_sh=None,
):
self._python_version = PYTHON_VERSION

File renamed without changes.
@@ -57,7 +57,7 @@ def upload(self, bento_service, version=None):
URI to where the BentoService is being saved to
"""
with TempDirectory() as tmpdir:
save_to_dir(bento_service, tmpdir, version)
save_to_dir(bento_service, tmpdir, version, silent=True)
return self._upload_bento_service(tmpdir)

def _upload_bento_service(self, saved_bento_path):
@@ -1,8 +1,11 @@
BentoService API
================

.. _bentoml-bentoservice-label:

BentoService
++++++++++++

.. autoclass:: bentoml.BentoService

.. automethod:: bentoml.BentoService.name
@@ -13,11 +16,41 @@ BentoService

.. automethod:: bentoml.BentoService.get_service_apis

.. method:: bentoml.BentoService.artifacts

returns a dictionary of packed artifacts from the artifact name to the artifact
model instance in its native form

.. _bentoml-bentoservice-pack-label:
.. method:: pack(name, *args, *kwargs)

BentoService#pack method is used for packing trained model instances with a
BentoService instance and make it ready for BentoService#save.

:param name: name of the declared model artifact
:param args: args passing to the target model artifact to be packed
:param kwargs: kwargs passing to the target model artifact to be packed
:return: this BentoService instance

.. automethod:: bentoml.BentoService.pack

.. _bentoml-bentoservice-save-label:
.. automethod:: bentoml.BentoService.save


.. _bentoml-bentoservice-save-to-dir-label:
.. automethod:: bentoml.BentoService.save_to_dir


api
+++
.. autofunction:: bentoml.api

.. _bentoml-env-label:

env
+++
.. autofunction:: bentoml.env
@@ -38,6 +71,9 @@ save_to_dir
+++++++++++
.. autofunction:: bentoml.save_to_dir


.. _bentoml-load-label:

load
++++
.. autofunction:: bentoml.load

0 comments on commit aaca4db

Please sign in to comment.
You can’t perform that action at this time.