BentoML Example

XGBoost League of legend Win prediction

This is a BentoML Demo Project demonstrating how to train a League of Legend win prdiction model, and use BentoML to package and serve the model for building applictions.

BentoML is an open source platform for machine learning model serving and deployment.

Example notebook built based on https://slundberg.github.io/shap/notebooks/League%20of%20Legends%20Win%20Prediction%20with%20XGBoost.html

Impression

In [1]:
%reload_ext autoreload
%autoreload 2
%matplotlib inline

import warnings
warnings.filterwarnings("ignore")
In [1]:
!pip install bentoml
!pip install numpy xgboost sklearn matplotlib kaggle
Requirement already satisfied: bentoml in /Users/chaoyuyang/workspace/BentoML (0.3.1)
Requirement already satisfied: ruamel.yaml>=0.15.0 in /Users/chaoyuyang/anaconda3/envs/bentoml-dev/lib/python3.7/site-packages (from bentoml) (0.15.99)
Requirement already satisfied: numpy in /Users/chaoyuyang/anaconda3/envs/bentoml-dev/lib/python3.7/site-packages (from bentoml) (1.16.4)
Requirement already satisfied: flask in /Users/chaoyuyang/anaconda3/envs/bentoml-dev/lib/python3.7/site-packages (from bentoml) (1.1.1)
Requirement already satisfied: gunicorn in /Users/chaoyuyang/anaconda3/envs/bentoml-dev/lib/python3.7/site-packages (from bentoml) (19.9.0)
Requirement already satisfied: six in /Users/chaoyuyang/anaconda3/envs/bentoml-dev/lib/python3.7/site-packages (from bentoml) (1.12.0)
Requirement already satisfied: click in /Users/chaoyuyang/anaconda3/envs/bentoml-dev/lib/python3.7/site-packages (from bentoml) (7.0)
Requirement already satisfied: pandas in /Users/chaoyuyang/anaconda3/envs/bentoml-dev/lib/python3.7/site-packages (from bentoml) (0.24.2)
Requirement already satisfied: dill in /Users/chaoyuyang/anaconda3/envs/bentoml-dev/lib/python3.7/site-packages (from bentoml) (0.3.0)
Requirement already satisfied: prometheus_client in /Users/chaoyuyang/anaconda3/envs/bentoml-dev/lib/python3.7/site-packages (from bentoml) (0.7.1)
Requirement already satisfied: python-json-logger in /Users/chaoyuyang/anaconda3/envs/bentoml-dev/lib/python3.7/site-packages (from bentoml) (0.1.11)
Requirement already satisfied: boto3 in /Users/chaoyuyang/anaconda3/envs/bentoml-dev/lib/python3.7/site-packages (from bentoml) (1.9.188)
Requirement already satisfied: pathlib2 in /Users/chaoyuyang/anaconda3/envs/bentoml-dev/lib/python3.7/site-packages (from bentoml) (2.3.4)
Requirement already satisfied: requests in /Users/chaoyuyang/anaconda3/envs/bentoml-dev/lib/python3.7/site-packages (from bentoml) (2.22.0)
Requirement already satisfied: packaging in /Users/chaoyuyang/anaconda3/envs/bentoml-dev/lib/python3.7/site-packages (from bentoml) (19.0)
Requirement already satisfied: docker in /Users/chaoyuyang/anaconda3/envs/bentoml-dev/lib/python3.7/site-packages (from bentoml) (4.0.2)
Requirement already satisfied: configparser in /Users/chaoyuyang/anaconda3/envs/bentoml-dev/lib/python3.7/site-packages (from bentoml) (3.7.4)
Requirement already satisfied: sqlalchemy in /Users/chaoyuyang/anaconda3/envs/bentoml-dev/lib/python3.7/site-packages (from bentoml) (1.3.4)
Requirement already satisfied: protobuf>=3.6.0 in /Users/chaoyuyang/anaconda3/envs/bentoml-dev/lib/python3.7/site-packages (from bentoml) (3.7.0)
Requirement already satisfied: Werkzeug>=0.15 in /Users/chaoyuyang/anaconda3/envs/bentoml-dev/lib/python3.7/site-packages (from flask->bentoml) (0.15.4)
Requirement already satisfied: itsdangerous>=0.24 in /Users/chaoyuyang/anaconda3/envs/bentoml-dev/lib/python3.7/site-packages (from flask->bentoml) (1.1.0)
Requirement already satisfied: Jinja2>=2.10.1 in /Users/chaoyuyang/anaconda3/envs/bentoml-dev/lib/python3.7/site-packages (from flask->bentoml) (2.10.1)
Requirement already satisfied: python-dateutil>=2.5.0 in /Users/chaoyuyang/anaconda3/envs/bentoml-dev/lib/python3.7/site-packages (from pandas->bentoml) (2.8.0)
Requirement already satisfied: pytz>=2011k in /Users/chaoyuyang/anaconda3/envs/bentoml-dev/lib/python3.7/site-packages (from pandas->bentoml) (2019.1)
Requirement already satisfied: botocore<1.13.0,>=1.12.188 in /Users/chaoyuyang/anaconda3/envs/bentoml-dev/lib/python3.7/site-packages (from boto3->bentoml) (1.12.188)
Requirement already satisfied: s3transfer<0.3.0,>=0.2.0 in /Users/chaoyuyang/anaconda3/envs/bentoml-dev/lib/python3.7/site-packages (from boto3->bentoml) (0.2.1)
Requirement already satisfied: jmespath<1.0.0,>=0.7.1 in /Users/chaoyuyang/.local/lib/python3.7/site-packages (from boto3->bentoml) (0.9.3)
Requirement already satisfied: urllib3!=1.25.0,!=1.25.1,<1.26,>=1.21.1 in /Users/chaoyuyang/anaconda3/envs/bentoml-dev/lib/python3.7/site-packages (from requests->bentoml) (1.25.3)
Requirement already satisfied: chardet<3.1.0,>=3.0.2 in /Users/chaoyuyang/anaconda3/envs/bentoml-dev/lib/python3.7/site-packages (from requests->bentoml) (3.0.4)
Requirement already satisfied: idna<2.9,>=2.5 in /Users/chaoyuyang/anaconda3/envs/bentoml-dev/lib/python3.7/site-packages (from requests->bentoml) (2.8)
Requirement already satisfied: certifi>=2017.4.17 in /Users/chaoyuyang/anaconda3/envs/bentoml-dev/lib/python3.7/site-packages (from requests->bentoml) (2019.6.16)
Requirement already satisfied: pyparsing>=2.0.2 in /Users/chaoyuyang/anaconda3/envs/bentoml-dev/lib/python3.7/site-packages (from packaging->bentoml) (2.4.0)
Requirement already satisfied: websocket-client>=0.32.0 in /Users/chaoyuyang/anaconda3/envs/bentoml-dev/lib/python3.7/site-packages (from docker->bentoml) (0.56.0)
Requirement already satisfied: setuptools in /Users/chaoyuyang/.local/lib/python3.7/site-packages (from protobuf>=3.6.0->bentoml) (40.6.3)
Requirement already satisfied: MarkupSafe>=0.23 in /Users/chaoyuyang/anaconda3/envs/bentoml-dev/lib/python3.7/site-packages (from Jinja2>=2.10.1->flask->bentoml) (1.1.1)
Requirement already satisfied: docutils>=0.10 in /Users/chaoyuyang/.local/lib/python3.7/site-packages (from botocore<1.13.0,>=1.12.188->boto3->bentoml) (0.14)
Requirement already satisfied: numpy in /Users/chaoyuyang/anaconda3/envs/bentoml-dev/lib/python3.7/site-packages (1.16.4)
Requirement already satisfied: xgboost in /Users/chaoyuyang/anaconda3/envs/bentoml-dev/lib/python3.7/site-packages (0.90)
Requirement already satisfied: sklearn in /Users/chaoyuyang/anaconda3/envs/bentoml-dev/lib/python3.7/site-packages (0.0)
Requirement already satisfied: matplotlib in /Users/chaoyuyang/anaconda3/envs/bentoml-dev/lib/python3.7/site-packages (3.1.1)
Requirement already satisfied: scipy in /Users/chaoyuyang/anaconda3/envs/bentoml-dev/lib/python3.7/site-packages (from xgboost) (1.3.0)
Requirement already satisfied: scikit-learn in /Users/chaoyuyang/anaconda3/envs/bentoml-dev/lib/python3.7/site-packages (from sklearn) (0.21.2)
Requirement already satisfied: python-dateutil>=2.1 in /Users/chaoyuyang/anaconda3/envs/bentoml-dev/lib/python3.7/site-packages (from matplotlib) (2.8.0)
Requirement already satisfied: kiwisolver>=1.0.1 in /Users/chaoyuyang/anaconda3/envs/bentoml-dev/lib/python3.7/site-packages (from matplotlib) (1.0.1)
Requirement already satisfied: pyparsing!=2.0.4,!=2.1.2,!=2.1.6,>=2.0.1 in /Users/chaoyuyang/anaconda3/envs/bentoml-dev/lib/python3.7/site-packages (from matplotlib) (2.4.0)
Requirement already satisfied: cycler>=0.10 in /Users/chaoyuyang/anaconda3/envs/bentoml-dev/lib/python3.7/site-packages (from matplotlib) (0.10.0)
Requirement already satisfied: joblib>=0.11 in /Users/chaoyuyang/anaconda3/envs/bentoml-dev/lib/python3.7/site-packages (from scikit-learn->sklearn) (0.13.2)
Requirement already satisfied: six>=1.5 in /Users/chaoyuyang/anaconda3/envs/bentoml-dev/lib/python3.7/site-packages (from python-dateutil>=2.1->matplotlib) (1.12.0)
Requirement already satisfied: setuptools in /Users/chaoyuyang/.local/lib/python3.7/site-packages (from kiwisolver>=1.0.1->matplotlib) (40.6.3)
In [2]:
import pandas as pd
import numpy as np
import xgboost as xgb
import matplotlib.pyplot as pl
from sklearn.model_selection import train_test_split

Download Data

This notebook uses data from kaggle paololol/league-of-legends-ranked-matches

You can set your Kaggle credential below and download the dataset automatically. The kaggle key can be created by going to the 'Account' tab of your user profile (https://www.kaggle.com//account) and select 'Create API Token'. This will trigger the download of kaggle.json, a file containing your API credentials, and fill it in the cell below.

Alternativelly, you can download it manually from here and place unzip'd data in this folder.

In [4]:
%%bash
export KAGGLE_USERNAME=
export KAGGLE_KEY=

if [ ! -f ./league-of-legends-ranked-matches.zip ]; then
    kaggle datasets download paololol/league-of-legends-ranked-matches
    unzip -n league-of-legends-ranked-matches.zip
fi
Process is interrupted.

Load data

In [5]:
# read in the data
matches = pd.read_csv("matches.csv")
participants = pd.read_csv("participants.csv")
stats1 = pd.read_csv("stats1.csv", low_memory=False)
stats2 = pd.read_csv("stats2.csv", low_memory=False)
stats = pd.concat([stats1,stats2])

# merge into a single DataFrame
a = pd.merge(participants, matches, left_on="matchid", right_on="id")
allstats_orig = pd.merge(a, stats, left_on="matchid", right_on="id")
allstats = allstats_orig.copy()

# drop games that lasted less than 10 minutes
allstats = allstats.loc[allstats["duration"] >= 10*60,:]

# Convert string-based categories to numeric values
cat_cols = ["role", "position", "version", "platformid"]
for c in cat_cols:
    allstats[c] = allstats[c].astype('category')
    allstats[c] = allstats[c].cat.codes
allstats["wardsbought"] = allstats["wardsbought"].astype(np.int32)

X = allstats.drop(["win"], axis=1)
y = allstats["win"]

# convert all features we want to consider as rates
rate_features = [
    "kills", "deaths", "assists", "killingsprees", "doublekills",
    "triplekills", "quadrakills", "pentakills", "legendarykills",
    "totdmgdealt", "magicdmgdealt", "physicaldmgdealt", "truedmgdealt",
    "totdmgtochamp", "magicdmgtochamp", "physdmgtochamp", "truedmgtochamp",
    "totheal", "totunitshealed", "dmgtoobj", "timecc", "totdmgtaken",
    "magicdmgtaken" , "physdmgtaken", "truedmgtaken", "goldearned", "goldspent",
    "totminionskilled", "neutralminionskilled", "ownjunglekills",
    "enemyjunglekills", "totcctimedealt", "pinksbought", "wardsbought",
    "wardsplaced", "wardskilled"
]
for feature_name in rate_features:
    X[feature_name] /= X["duration"] / 60 # per minute rate

# convert to fraction of game
X["longesttimespentliving"] /= X["duration"]

# define friendly names for the features
full_names = {
    "kills": "Kills per min.",
    "deaths": "Deaths per min.",
    "assists": "Assists per min.",
    "killingsprees": "Killing sprees per min.",
    "longesttimespentliving": "Longest time living as % of game",
    "doublekills": "Double kills per min.",
    "triplekills": "Triple kills per min.",
    "quadrakills": "Quadra kills per min.",
    "pentakills": "Penta kills per min.",
    "legendarykills": "Legendary kills per min.",
    "totdmgdealt": "Total damage dealt per min.",
    "magicdmgdealt": "Magic damage dealt per min.",
    "physicaldmgdealt": "Physical damage dealt per min.",
    "truedmgdealt": "True damage dealt per min.",
    "totdmgtochamp": "Total damage to champions per min.",
    "magicdmgtochamp": "Magic damage to champions per min.",
    "physdmgtochamp": "Physical damage to champions per min.",
    "truedmgtochamp": "True damage to champions per min.",
    "totheal": "Total healing per min.",
    "totunitshealed": "Total units healed per min.",
    "dmgtoobj": "Damage to objects per min.",
    "timecc": "Time spent with crown control per min.",
    "totdmgtaken": "Total damage taken per min.",
    "magicdmgtaken": "Magic damage taken per min.",
    "physdmgtaken": "Physical damage taken per min.",
    "truedmgtaken": "True damage taken per min.",
    "goldearned": "Gold earned per min.",
    "goldspent": "Gold spent per min.",
    "totminionskilled": "Total minions killed per min.",
    "neutralminionskilled": "Neutral minions killed per min.",
    "ownjunglekills": "Own jungle kills per min.",
    "enemyjunglekills": "Enemy jungle kills per min.",
    "totcctimedealt": "Total crown control time dealt per min.",
    "pinksbought": "Pink wards bought per min.",
    "wardsbought": "Wards bought per min.",
    "wardsplaced": "Wards placed per min.",
    "turretkills": "# of turret kills",
    "inhibkills": "# of inhibitor kills",
    "dmgtoturrets": "Damage to turrets"
}
feature_names = [full_names.get(n, n) for n in X.columns]
X.columns = feature_names

# create train/validation split
Xt, Xv, yt, yv = train_test_split(X,y, test_size=0.2, random_state=10)
dt = xgb.DMatrix(Xt, label=yt.values)
dv = xgb.DMatrix(Xv, label=yv.values)

Train the XGBoost model

In [7]:
params = {
    "eta": 0.5,
    "max_depth": 4,
    "objective": "binary:logistic",
    "silent": 1,
    "base_score": np.mean(yt),
    "eval_metric": "logloss"
}
model = xgb.train(params, dt, 100, [(dt, "train"),(dv, "valid")], early_stopping_rounds=5, verbose_eval=10)
[0]	train-logloss:0.543193	valid-logloss:0.541947
Multiple eval metrics have been passed: 'valid-logloss' will be used for early stopping.

Will train until valid-logloss hasn't improved in 5 rounds.
[10]	train-logloss:0.340893	valid-logloss:0.340785
[20]	train-logloss:0.298629	valid-logloss:0.298923
[30]	train-logloss:0.275069	valid-logloss:0.27588
[40]	train-logloss:0.262759	valid-logloss:0.264077
[50]	train-logloss:0.251781	valid-logloss:0.253591
[60]	train-logloss:0.243637	valid-logloss:0.245847
[70]	train-logloss:0.236876	valid-logloss:0.239301
[80]	train-logloss:0.230745	valid-logloss:0.233482
[90]	train-logloss:0.225845	valid-logloss:0.228773
[99]	train-logloss:0.221568	valid-logloss:0.224798
In [8]:
Xt[:3]
Out[8]:
id_x matchid player championid ss1 ss2 role position id_y gameid ... Neutral minions killed per min. Own jungle kills per min. Enemy jungle kills per min. Total crown control time dealt per min. champlvl Pink wards bought per min. Wards bought per min. Wards placed per min. wardskilled firstblood
1215555 1501034 150933 10 59 4 11 2 2 150933 3162804935 ... 0.023086 0.023086 0.000000 7.572143 18 0.069257 0.0 0.831089 0.253944 0
1427835 1713614 172357 6 35 11 14 3 1 172357 3186087472 ... 0.028262 0.028262 0.000000 10.937353 16 0.000000 0.0 0.197833 0.000000 0
1204118 1489597 149786 3 34 4 14 4 2 149786 3193266242 ... 0.882817 0.693642 0.189175 11.192853 18 0.063058 0.0 0.567525 0.189175 0

3 rows × 71 columns

In [9]:
model.predict(xgb.DMatrix(Xt[:3]))
Out[9]:
array([0.35312295, 0.06715316, 0.04429299], dtype=float32)

Create ML service with BentoML

In [10]:
%%writefile lol_win_predictions.py

from bentoml import api, env, BentoService, artifacts
from bentoml.artifact import XgboostModelArtifact
from bentoml.handlers import DataframeHandler

import xgboost as xgb

@env(pip_dependencies=['xgboost'])
@artifacts([XgboostModelArtifact('model')])
class LeagueWinPrediction(BentoService):
    
    @api(DataframeHandler)
    def predict(self, df):
        dmatrix = xgb.DMatrix(df)
        return self.artifacts.model.predict(dmatrix)
Overwriting lol_win_predictions.py
In [12]:
# 1) import the custom BentoService defined above
from lol_win_predictions import LeagueWinPrediction

# 2) `pack` it with required artifacts
bento_svc = LeagueWinPrediction()
bento_svc.pack('model', model)

# 3) save your BentoSerivce
saved_path = bento_svc.save()
[2020-02-13 15:19:56,905] WARNING - BentoML local changes detected - Local BentoML repository including all code changes will be bundled together with the BentoService bundle. When used with docker, the base docker image will be default to same version as last PyPI release at version: 0.6.2. You can also force bentoml to use a specific version for deploying your BentoService bundle, by setting the config 'core/bentoml_deploy_version' to a pinned version or your custom BentoML on github, e.g.:'bentoml_deploy_version = git+https://github.com/{username}/[email protected]{branch}'
[2020-02-13 15:20:20,365] WARNING - BentoML local changes detected - Local BentoML repository including all code changes will be bundled together with the BentoService bundle. When used with docker, the base docker image will be default to same version as last PyPI release at version: 0.6.2. You can also force bentoml to use a specific version for deploying your BentoService bundle, by setting the config 'core/bentoml_deploy_version' to a pinned version or your custom BentoML on github, e.g.:'bentoml_deploy_version = git+https://github.com/{username}/[email protected]{branch}'
running sdist
running egg_info
writing BentoML.egg-info/PKG-INFO
writing dependency_links to BentoML.egg-info/dependency_links.txt
writing entry points to BentoML.egg-info/entry_points.txt
writing requirements to BentoML.egg-info/requires.txt
writing top-level names to BentoML.egg-info/top_level.txt
reading manifest file 'BentoML.egg-info/SOURCES.txt'
reading manifest template 'MANIFEST.in'
no previously-included directories found matching 'examples'
no previously-included directories found matching 'tests'
no previously-included directories found matching 'docs'
no previously-included directories found matching 'scripts'
warning: no previously-included files matching '*~' found anywhere in distribution
warning: no previously-included files matching '*.pyo' found anywhere in distribution
warning: no previously-included files matching '.git' found anywhere in distribution
warning: no previously-included files matching '.ipynb_checkpoints' found anywhere in distribution
warning: no previously-included files matching '__pycache__' found anywhere in distribution
writing manifest file 'BentoML.egg-info/SOURCES.txt'
running check
warning: check: missing meta-data: if 'author' supplied, 'author_email' must be supplied too

creating BentoML-0.6.2+8.gd95a887
creating BentoML-0.6.2+8.gd95a887/BentoML.egg-info
creating BentoML-0.6.2+8.gd95a887/bentoml
creating BentoML-0.6.2+8.gd95a887/bentoml/artifact
creating BentoML-0.6.2+8.gd95a887/bentoml/bundler
creating BentoML-0.6.2+8.gd95a887/bentoml/cli
creating BentoML-0.6.2+8.gd95a887/bentoml/clipper
creating BentoML-0.6.2+8.gd95a887/bentoml/configuration
creating BentoML-0.6.2+8.gd95a887/bentoml/deployment
creating BentoML-0.6.2+8.gd95a887/bentoml/deployment/aws_lambda
creating BentoML-0.6.2+8.gd95a887/bentoml/deployment/sagemaker
creating BentoML-0.6.2+8.gd95a887/bentoml/handlers
creating BentoML-0.6.2+8.gd95a887/bentoml/marshal
creating BentoML-0.6.2+8.gd95a887/bentoml/migrations
creating BentoML-0.6.2+8.gd95a887/bentoml/migrations/versions
creating BentoML-0.6.2+8.gd95a887/bentoml/proto
creating BentoML-0.6.2+8.gd95a887/bentoml/repository
creating BentoML-0.6.2+8.gd95a887/bentoml/server
creating BentoML-0.6.2+8.gd95a887/bentoml/server/static
creating BentoML-0.6.2+8.gd95a887/bentoml/utils
creating BentoML-0.6.2+8.gd95a887/bentoml/utils/validator
creating BentoML-0.6.2+8.gd95a887/bentoml/yatai
creating BentoML-0.6.2+8.gd95a887/bentoml/yatai/client
copying files to BentoML-0.6.2+8.gd95a887...
copying LICENSE -> BentoML-0.6.2+8.gd95a887
copying MANIFEST.in -> BentoML-0.6.2+8.gd95a887
copying README.md -> BentoML-0.6.2+8.gd95a887
copying pyproject.toml -> BentoML-0.6.2+8.gd95a887
copying setup.cfg -> BentoML-0.6.2+8.gd95a887
copying setup.py -> BentoML-0.6.2+8.gd95a887
copying versioneer.py -> BentoML-0.6.2+8.gd95a887
copying BentoML.egg-info/PKG-INFO -> BentoML-0.6.2+8.gd95a887/BentoML.egg-info
copying BentoML.egg-info/SOURCES.txt -> BentoML-0.6.2+8.gd95a887/BentoML.egg-info
copying BentoML.egg-info/dependency_links.txt -> BentoML-0.6.2+8.gd95a887/BentoML.egg-info
copying BentoML.egg-info/entry_points.txt -> BentoML-0.6.2+8.gd95a887/BentoML.egg-info
copying BentoML.egg-info/requires.txt -> BentoML-0.6.2+8.gd95a887/BentoML.egg-info
copying BentoML.egg-info/top_level.txt -> BentoML-0.6.2+8.gd95a887/BentoML.egg-info
copying bentoml/__init__.py -> BentoML-0.6.2+8.gd95a887/bentoml
copying bentoml/_version.py -> BentoML-0.6.2+8.gd95a887/bentoml
copying bentoml/alembic.ini -> BentoML-0.6.2+8.gd95a887/bentoml
copying bentoml/db.py -> BentoML-0.6.2+8.gd95a887/bentoml
copying bentoml/exceptions.py -> BentoML-0.6.2+8.gd95a887/bentoml
copying bentoml/service.py -> BentoML-0.6.2+8.gd95a887/bentoml
copying bentoml/service_env.py -> BentoML-0.6.2+8.gd95a887/bentoml
copying bentoml/artifact/__init__.py -> BentoML-0.6.2+8.gd95a887/bentoml/artifact
copying bentoml/artifact/artifact.py -> BentoML-0.6.2+8.gd95a887/bentoml/artifact
copying bentoml/artifact/fastai_model_artifact.py -> BentoML-0.6.2+8.gd95a887/bentoml/artifact
copying bentoml/artifact/h2o_model_artifact.py -> BentoML-0.6.2+8.gd95a887/bentoml/artifact
copying bentoml/artifact/keras_model_artifact.py -> BentoML-0.6.2+8.gd95a887/bentoml/artifact
copying bentoml/artifact/lightgbm_model_artifact.py -> BentoML-0.6.2+8.gd95a887/bentoml/artifact
copying bentoml/artifact/pickle_artifact.py -> BentoML-0.6.2+8.gd95a887/bentoml/artifact
copying bentoml/artifact/pytorch_model_artifact.py -> BentoML-0.6.2+8.gd95a887/bentoml/artifact
copying bentoml/artifact/sklearn_model_artifact.py -> BentoML-0.6.2+8.gd95a887/bentoml/artifact
copying bentoml/artifact/text_file_artifact.py -> BentoML-0.6.2+8.gd95a887/bentoml/artifact
copying bentoml/artifact/tf_savedmodel_artifact.py -> BentoML-0.6.2+8.gd95a887/bentoml/artifact
copying bentoml/artifact/xgboost_model_artifact.py -> BentoML-0.6.2+8.gd95a887/bentoml/artifact
copying bentoml/bundler/__init__.py -> BentoML-0.6.2+8.gd95a887/bentoml/bundler
copying bentoml/bundler/bundler.py -> BentoML-0.6.2+8.gd95a887/bentoml/bundler
copying bentoml/bundler/config.py -> BentoML-0.6.2+8.gd95a887/bentoml/bundler
copying bentoml/bundler/loader.py -> BentoML-0.6.2+8.gd95a887/bentoml/bundler
copying bentoml/bundler/py_module_utils.py -> BentoML-0.6.2+8.gd95a887/bentoml/bundler
copying bentoml/bundler/templates.py -> BentoML-0.6.2+8.gd95a887/bentoml/bundler
copying bentoml/bundler/utils.py -> BentoML-0.6.2+8.gd95a887/bentoml/bundler
copying bentoml/cli/__init__.py -> BentoML-0.6.2+8.gd95a887/bentoml/cli
copying bentoml/cli/aws_lambda.py -> BentoML-0.6.2+8.gd95a887/bentoml/cli
copying bentoml/cli/aws_sagemaker.py -> BentoML-0.6.2+8.gd95a887/bentoml/cli
copying bentoml/cli/bento.py -> BentoML-0.6.2+8.gd95a887/bentoml/cli
copying bentoml/cli/click_utils.py -> BentoML-0.6.2+8.gd95a887/bentoml/cli
copying bentoml/cli/config.py -> BentoML-0.6.2+8.gd95a887/bentoml/cli
copying bentoml/cli/deployment.py -> BentoML-0.6.2+8.gd95a887/bentoml/cli
copying bentoml/cli/utils.py -> BentoML-0.6.2+8.gd95a887/bentoml/cli
copying bentoml/clipper/__init__.py -> BentoML-0.6.2+8.gd95a887/bentoml/clipper
copying bentoml/configuration/__init__.py -> BentoML-0.6.2+8.gd95a887/bentoml/configuration
copying bentoml/configuration/configparser.py -> BentoML-0.6.2+8.gd95a887/bentoml/configuration
copying bentoml/configuration/default_bentoml.cfg -> BentoML-0.6.2+8.gd95a887/bentoml/configuration
copying bentoml/deployment/__init__.py -> BentoML-0.6.2+8.gd95a887/bentoml/deployment
copying bentoml/deployment/operator.py -> BentoML-0.6.2+8.gd95a887/bentoml/deployment
copying bentoml/deployment/store.py -> BentoML-0.6.2+8.gd95a887/bentoml/deployment
copying bentoml/deployment/utils.py -> BentoML-0.6.2+8.gd95a887/bentoml/deployment
copying bentoml/deployment/aws_lambda/__init__.py -> BentoML-0.6.2+8.gd95a887/bentoml/deployment/aws_lambda
copying bentoml/deployment/aws_lambda/download_extra_resources.py -> BentoML-0.6.2+8.gd95a887/bentoml/deployment/aws_lambda
copying bentoml/deployment/aws_lambda/lambda_app.py -> BentoML-0.6.2+8.gd95a887/bentoml/deployment/aws_lambda
copying bentoml/deployment/aws_lambda/utils.py -> BentoML-0.6.2+8.gd95a887/bentoml/deployment/aws_lambda
copying bentoml/deployment/sagemaker/__init__.py -> BentoML-0.6.2+8.gd95a887/bentoml/deployment/sagemaker
copying bentoml/deployment/sagemaker/sagemaker_nginx.conf -> BentoML-0.6.2+8.gd95a887/bentoml/deployment/sagemaker
copying bentoml/deployment/sagemaker/sagemaker_serve.py -> BentoML-0.6.2+8.gd95a887/bentoml/deployment/sagemaker
copying bentoml/deployment/sagemaker/sagemaker_wsgi.py -> BentoML-0.6.2+8.gd95a887/bentoml/deployment/sagemaker
copying bentoml/handlers/__init__.py -> BentoML-0.6.2+8.gd95a887/bentoml/handlers
copying bentoml/handlers/base_handlers.py -> BentoML-0.6.2+8.gd95a887/bentoml/handlers
copying bentoml/handlers/clipper_handler.py -> BentoML-0.6.2+8.gd95a887/bentoml/handlers
copying bentoml/handlers/dataframe_handler.py -> BentoML-0.6.2+8.gd95a887/bentoml/handlers
copying bentoml/handlers/fastai_image_handler.py -> BentoML-0.6.2+8.gd95a887/bentoml/handlers
copying bentoml/handlers/image_handler.py -> BentoML-0.6.2+8.gd95a887/bentoml/handlers
copying bentoml/handlers/json_handler.py -> BentoML-0.6.2+8.gd95a887/bentoml/handlers
copying bentoml/handlers/pytorch_tensor_handler.py -> BentoML-0.6.2+8.gd95a887/bentoml/handlers
copying bentoml/handlers/tensorflow_tensor_handler.py -> BentoML-0.6.2+8.gd95a887/bentoml/handlers
copying bentoml/handlers/utils.py -> BentoML-0.6.2+8.gd95a887/bentoml/handlers
copying bentoml/marshal/__init__.py -> BentoML-0.6.2+8.gd95a887/bentoml/marshal
copying bentoml/marshal/marshal.py -> BentoML-0.6.2+8.gd95a887/bentoml/marshal
copying bentoml/marshal/utils.py -> BentoML-0.6.2+8.gd95a887/bentoml/marshal
copying bentoml/migrations/README -> BentoML-0.6.2+8.gd95a887/bentoml/migrations
copying bentoml/migrations/env.py -> BentoML-0.6.2+8.gd95a887/bentoml/migrations
copying bentoml/migrations/script.py.mako -> BentoML-0.6.2+8.gd95a887/bentoml/migrations
copying bentoml/migrations/versions/a6b00ae45279_add_last_updated_at_for_deployments.py -> BentoML-0.6.2+8.gd95a887/bentoml/migrations/versions
copying bentoml/proto/__init__.py -> BentoML-0.6.2+8.gd95a887/bentoml/proto
copying bentoml/proto/deployment_pb2.py -> BentoML-0.6.2+8.gd95a887/bentoml/proto
copying bentoml/proto/repository_pb2.py -> BentoML-0.6.2+8.gd95a887/bentoml/proto
copying bentoml/proto/status_pb2.py -> BentoML-0.6.2+8.gd95a887/bentoml/proto
copying bentoml/proto/yatai_service_pb2.py -> BentoML-0.6.2+8.gd95a887/bentoml/proto
copying bentoml/proto/yatai_service_pb2_grpc.py -> BentoML-0.6.2+8.gd95a887/bentoml/proto
copying bentoml/repository/__init__.py -> BentoML-0.6.2+8.gd95a887/bentoml/repository
copying bentoml/repository/metadata_store.py -> BentoML-0.6.2+8.gd95a887/bentoml/repository
copying bentoml/server/__init__.py -> BentoML-0.6.2+8.gd95a887/bentoml/server
copying bentoml/server/bento_api_server.py -> BentoML-0.6.2+8.gd95a887/bentoml/server
copying bentoml/server/bento_sagemaker_server.py -> BentoML-0.6.2+8.gd95a887/bentoml/server
copying bentoml/server/gunicorn_config.py -> BentoML-0.6.2+8.gd95a887/bentoml/server
copying bentoml/server/gunicorn_server.py -> BentoML-0.6.2+8.gd95a887/bentoml/server
copying bentoml/server/marshal_server.py -> BentoML-0.6.2+8.gd95a887/bentoml/server
copying bentoml/server/middlewares.py -> BentoML-0.6.2+8.gd95a887/bentoml/server
copying bentoml/server/utils.py -> BentoML-0.6.2+8.gd95a887/bentoml/server
copying bentoml/server/static/swagger-ui-bundle.js -> BentoML-0.6.2+8.gd95a887/bentoml/server/static
copying bentoml/server/static/swagger-ui.css -> BentoML-0.6.2+8.gd95a887/bentoml/server/static
copying bentoml/utils/__init__.py -> BentoML-0.6.2+8.gd95a887/bentoml/utils
copying bentoml/utils/cloudpickle.py -> BentoML-0.6.2+8.gd95a887/bentoml/utils
copying bentoml/utils/hybirdmethod.py -> BentoML-0.6.2+8.gd95a887/bentoml/utils
copying bentoml/utils/log.py -> BentoML-0.6.2+8.gd95a887/bentoml/utils
copying bentoml/utils/s3.py -> BentoML-0.6.2+8.gd95a887/bentoml/utils
copying bentoml/utils/tempdir.py -> BentoML-0.6.2+8.gd95a887/bentoml/utils
copying bentoml/utils/usage_stats.py -> BentoML-0.6.2+8.gd95a887/bentoml/utils
copying bentoml/utils/validator/__init__.py -> BentoML-0.6.2+8.gd95a887/bentoml/utils/validator
copying bentoml/yatai/__init__.py -> BentoML-0.6.2+8.gd95a887/bentoml/yatai
copying bentoml/yatai/deployment_utils.py -> BentoML-0.6.2+8.gd95a887/bentoml/yatai
copying bentoml/yatai/status.py -> BentoML-0.6.2+8.gd95a887/bentoml/yatai
copying bentoml/yatai/yatai_service_impl.py -> BentoML-0.6.2+8.gd95a887/bentoml/yatai
copying bentoml/yatai/client/__init__.py -> BentoML-0.6.2+8.gd95a887/bentoml/yatai/client
copying bentoml/yatai/client/bento_repository_api.py -> BentoML-0.6.2+8.gd95a887/bentoml/yatai/client
copying bentoml/yatai/client/deployment_api.py -> BentoML-0.6.2+8.gd95a887/bentoml/yatai/client
Writing BentoML-0.6.2+8.gd95a887/setup.cfg
UPDATING BentoML-0.6.2+8.gd95a887/bentoml/_version.py
set BentoML-0.6.2+8.gd95a887/bentoml/_version.py to '0.6.2+8.gd95a887'
Creating tar archive
removing 'BentoML-0.6.2+8.gd95a887' (and everything under it)
[2020-02-13 15:20:21,674] INFO - BentoService bundle 'LeagueWinPrediction:20200213151956_D4CD71' created at: /private/var/folders/kn/xnc9k74x03567n1mx2tfqnpr0000gn/T/bentoml-temp-lgy8tfbv
[2020-02-13 15:20:21,676] WARNING - BentoML local changes detected - Local BentoML repository including all code changes will be bundled together with the BentoService bundle. When used with docker, the base docker image will be default to same version as last PyPI release at version: 0.6.2. You can also force bentoml to use a specific version for deploying your BentoService bundle, by setting the config 'core/bentoml_deploy_version' to a pinned version or your custom BentoML on github, e.g.:'bentoml_deploy_version = git+https://github.com/{username}/[email protected]{branch}'
[2020-02-13 15:20:21,689] WARNING - Saved BentoService bundle version mismatch: loading BentoServie bundle create with BentoML version 0.6.2,  but loading from BentoML version 0.6.2+8.gd95a887
[2020-02-13 15:20:21,745] INFO - BentoService bundle 'LeagueWinPrediction:20200213151956_D4CD71' created at: /Users/bozhaoyu/bentoml/repository/LeagueWinPrediction/20200213151956_D4CD71
In [13]:
from bentoml import load

svc = load(saved_path)

print(svc.predict(Xt[:3]))
[2020-02-13 15:20:30,224] WARNING - BentoML local changes detected - Local BentoML repository including all code changes will be bundled together with the BentoService bundle. When used with docker, the base docker image will be default to same version as last PyPI release at version: 0.6.2. You can also force bentoml to use a specific version for deploying your BentoService bundle, by setting the config 'core/bentoml_deploy_version' to a pinned version or your custom BentoML on github, e.g.:'bentoml_deploy_version = git+https://github.com/{username}/[email protected]{branch}'
[2020-02-13 15:20:30,235] WARNING - Saved BentoService bundle version mismatch: loading BentoServie bundle create with BentoML version 0.6.2,  but loading from BentoML version 0.6.2+8.gd95a887
[2020-02-13 15:20:30,237] WARNING - Module `lol_win_predictions` already loaded, using existing imported module.
[2020-02-13 15:20:30,240] WARNING - BentoML local changes detected - Local BentoML repository including all code changes will be bundled together with the BentoService bundle. When used with docker, the base docker image will be default to same version as last PyPI release at version: 0.6.2. You can also force bentoml to use a specific version for deploying your BentoService bundle, by setting the config 'core/bentoml_deploy_version' to a pinned version or your custom BentoML on github, e.g.:'bentoml_deploy_version = git+https://github.com/{username}/[email protected]{branch}'
[0.35312295 0.06715316 0.04429299]
In [14]:
!bentoml get LeagueWinPrediction
BENTO_SERVICE                              AGE            APIS                       ARTIFACTS
LeagueWinPrediction:20200213151956_D4CD71  45.98 seconds  predict<DataframeHandler>  model<XgboostModelArtifact>
In [15]:
!bentoml get LeagueWinPrediction:20200213151956_D4CD71
{
  "name": "LeagueWinPrediction",
  "version": "20200213151956_D4CD71",
  "uri": {
    "type": "LOCAL",
    "uri": "/Users/bozhaoyu/bentoml/repository/LeagueWinPrediction/20200213151956_D4CD71"
  },
  "bentoServiceMetadata": {
    "name": "LeagueWinPrediction",
    "version": "20200213151956_D4CD71",
    "createdAt": "2020-02-13T23:20:20.366628Z",
    "env": {
      "condaEnv": "name: bentoml-LeagueWinPrediction\nchannels:\n- defaults\ndependencies:\n- python=3.7.3\n- pip\n",
      "pipDependencies": "bentoml==0.6.2\nxgboost",
      "pythonVersion": "3.7.3"
    },
    "artifacts": [
      {
        "name": "model",
        "artifactType": "XgboostModelArtifact"
      }
    ],
    "apis": [
      {
        "name": "predict",
        "handlerType": "DataframeHandler",
        "docs": "BentoService API",
        "handlerConfig": {
          "orient": "records",
          "typ": "frame",
          "input_dtypes": null,
          "output_orient": "records"
        }
      }
    ]
  }
}
In [28]:
Xt[:3].to_csv('test.csv')
In [16]:
!bentoml run LeagueWinPrediction:20200213151956_D4CD71 predict --input test.csv
[2020-02-13 15:21:35,595] WARNING - BentoML local changes detected - Local BentoML repository including all code changes will be bundled together with the BentoService bundle. When used with docker, the base docker image will be default to same version as last PyPI release at version: 0.6.2. You can also force bentoml to use a specific version for deploying your BentoService bundle, by setting the config 'core/bentoml_deploy_version' to a pinned version or your custom BentoML on github, e.g.:'bentoml_deploy_version = git+https://github.com/{username}/[email protected]{branch}'
[2020-02-13 15:21:35,607] WARNING - Saved BentoService bundle version mismatch: loading BentoServie bundle create with BentoML version 0.6.2,  but loading from BentoML version 0.6.2+8.gd95a887
[2020-02-13 15:21:36,171] WARNING - BentoML local changes detected - Local BentoML repository including all code changes will be bundled together with the BentoService bundle. When used with docker, the base docker image will be default to same version as last PyPI release at version: 0.6.2. You can also force bentoml to use a specific version for deploying your BentoService bundle, by setting the config 'core/bentoml_deploy_version' to a pinned version or your custom BentoML on github, e.g.:'bentoml_deploy_version = git+https://github.com/{username}/[email protected]{branch}'
[2020-02-13 15:21:36,172] WARNING - BentoML local changes detected - Local BentoML repository including all code changes will be bundled together with the BentoService bundle. When used with docker, the base docker image will be default to same version as last PyPI release at version: 0.6.2. You can also force bentoml to use a specific version for deploying your BentoService bundle, by setting the config 'core/bentoml_deploy_version' to a pinned version or your custom BentoML on github, e.g.:'bentoml_deploy_version = git+https://github.com/{username}/[email protected]{branch}'
[0.9998702  0.42565873 0.7701393 ]
In [17]:
!bentoml serve LeagueWinPrediction:20200213151956_D4CD71
[2020-02-13 15:22:10,016] WARNING - BentoML local changes detected - Local BentoML repository including all code changes will be bundled together with the BentoService bundle. When used with docker, the base docker image will be default to same version as last PyPI release at version: 0.6.2. You can also force bentoml to use a specific version for deploying your BentoService bundle, by setting the config 'core/bentoml_deploy_version' to a pinned version or your custom BentoML on github, e.g.:'bentoml_deploy_version = git+https://github.com/{username}/[email protected]{branch}'
[2020-02-13 15:22:10,034] WARNING - Saved BentoService bundle version mismatch: loading BentoServie bundle create with BentoML version 0.6.2,  but loading from BentoML version 0.6.2+8.gd95a887
[2020-02-13 15:22:10,431] WARNING - BentoML local changes detected - Local BentoML repository including all code changes will be bundled together with the BentoService bundle. When used with docker, the base docker image will be default to same version as last PyPI release at version: 0.6.2. You can also force bentoml to use a specific version for deploying your BentoService bundle, by setting the config 'core/bentoml_deploy_version' to a pinned version or your custom BentoML on github, e.g.:'bentoml_deploy_version = git+https://github.com/{username}/[email protected]{branch}'
[2020-02-13 15:22:10,434] WARNING - BentoML local changes detected - Local BentoML repository including all code changes will be bundled together with the BentoService bundle. When used with docker, the base docker image will be default to same version as last PyPI release at version: 0.6.2. You can also force bentoml to use a specific version for deploying your BentoService bundle, by setting the config 'core/bentoml_deploy_version' to a pinned version or your custom BentoML on github, e.g.:'bentoml_deploy_version = git+https://github.com/{username}/[email protected]{branch}'
 * Serving Flask app "LeagueWinPrediction" (lazy loading)
 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: off
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
^C
In [ ]:
 
In [ ]:
 

Using BentoML archive as CLI tool

In [27]:
!pip install {saved_path}
Processing /tmp/bent_archive/LeagueWinPrediction/2019_08_02_bc041570
Building wheels for collected packages: LeagueWinPrediction
  Building wheel for LeagueWinPrediction (setup.py) ... done
  Stored in directory: /private/var/folders/ns/vc9qhmqx5dx_9fws7d869lqh0000gn/T/pip-ephem-wheel-cache-biki_9_b/wheels/3e/ff/49/21f15e9b7e99a81b164fb2cadf8de9c6c1d135e5a858f467f7
Successfully built LeagueWinPrediction
Installing collected packages: LeagueWinPrediction
Successfully installed LeagueWinPrediction-2019-08-02-bc041570
In [29]:
!LeagueWinPrediction predict --input=test.csv
[0.99658453 0.01096581 0.06465738]

Use archive as REST API server

notes: This doesn't work with Google Colab right now, because we can't access the local port from it.

In [ ]:
!bentoml serve {saved_path}

Make requeset to the REST server

After navigate to the location of this notebook, copy and paste the following code to your terminal and run it to make request

curl -i \
--request POST \
--header "Content-Type: text/csv" \
-d @test.csv \
localhost:5000/predict
In [ ]:
 
In [ ]:
 
In [18]:
!bentoml lambda deploy xgboost-lol -b LeagueWinPrediction:20200213151956_D4CD71 
Deploying Lambda deployment -[2020-02-13 15:22:50,246] INFO - Building lambda project
|[2020-02-13 15:28:44,204] INFO - Packaging AWS Lambda project at /private/var/folders/kn/xnc9k74x03567n1mx2tfqnpr0000gn/T/bentoml-temp-a9v3r7jc ...
|[2020-02-13 15:29:08,363] INFO - Deploying lambda project
|[2020-02-13 15:30:00,729] INFO - ApplyDeployment (xgboost-lol, namespace bobo) succeeded
Successfully created AWS Lambda deployment xgboost-lol
{
  "namespace": "bobo",
  "name": "xgboost-lol",
  "spec": {
    "bentoName": "LeagueWinPrediction",
    "bentoVersion": "20200213151956_D4CD71",
    "operator": "AWS_LAMBDA",
    "awsLambdaOperatorConfig": {
      "region": "us-west-2",
      "memorySize": 1024,
      "timeout": 3
    }
  },
  "state": {
    "state": "RUNNING",
    "infoJson": {
      "endpoints": [
        "https://esuj190n16.execute-api.us-west-2.amazonaws.com/Prod/predict"
      ],
      "s3_bucket": "btml-bobo-xgboost-lol-cc0cda"
    },
    "timestamp": "2020-02-13T23:30:00.931414Z"
  },
  "createdAt": "2020-02-13T23:22:45.342091Z",
  "lastUpdatedAt": "2020-02-13T23:22:45.342120Z"
}
In [21]:
!bentoml lambda list
NAME                     NAMESPACE    PLATFORM    BENTO_SERVICE                              STATUS    AGE
xgboost-lol              bobo         aws-lambda  LeagueWinPrediction:20200213151956_D4CD71  running   7 minutes and 59.44 seconds
tests-lambda-e2e-f7948d  bobo         aws-lambda  IrisClassifier:20200210154953_02AAA1       running   2 days and 23 hours
In [20]:
!bentoml lambda get xgboost-lol
{
  "namespace": "bobo",
  "name": "xgboost-lol",
  "spec": {
    "bentoName": "LeagueWinPrediction",
    "bentoVersion": "20200213151956_D4CD71",
    "operator": "AWS_LAMBDA",
    "awsLambdaOperatorConfig": {
      "region": "us-west-2",
      "memorySize": 1024,
      "timeout": 3
    }
  },
  "state": {
    "state": "RUNNING",
    "infoJson": {
      "endpoints": [
        "https://esuj190n16.execute-api.us-west-2.amazonaws.com/Prod/predict"
      ],
      "s3_bucket": "btml-bobo-xgboost-lol-cc0cda"
    },
    "timestamp": "2020-02-13T23:30:16.620816Z"
  },
  "createdAt": "2020-02-13T23:22:45.342091Z",
  "lastUpdatedAt": "2020-02-13T23:22:45.342120Z"
}
In [ ]:
!curl -i \
--request POST \
--header "Content-Type: text/csv" \
-d @test.csv \
https://esuj190n16.execute-api.us-west-2.amazonaws.com/Prod/predict
In [25]:
!bentoml lambda delete xgboost-lol
Successfully deleted AWS Lambda deployment "xgboost-lol"
In [ ]: