{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "## Deploying Voting ensemble Sklearn models on SageMaker" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "rm: cannot remove ‘src’: No such file or directory\r\n" ] } ], "source": [ "!rm modelscript_ensemble_sklearn.py\n", "!rm *.joblib\n", "!rm src" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0.7617053998632947\n" ] } ], "source": [ "# Voting Ensemble for Classification\n", "import pandas\n", "from sklearn import model_selection\n", "from sklearn.linear_model import LogisticRegression\n", "from sklearn.tree import DecisionTreeClassifier\n", "from sklearn.svm import SVC\n", "from sklearn.ensemble import VotingClassifier\n", "\n", "# Get Data\n", "url = \"https://raw.githubusercontent.com/jbrownlee/Datasets/master/pima-indians-diabetes.data.csv\"\n", "names = ['preg', 'plas', 'pres', 'skin', 'test', 'mass', 'pedi', 'age', 'class']\n", "dataframe = pandas.read_csv(url, names=names)\n", "array = dataframe.values\n", "X = array[:,0:8]\n", "Y = array[:,8]\n", "\n", "# Fit\n", "kfold = model_selection.KFold(n_splits=10)\n", "# create the sub models\n", "estimators = []\n", "model1 = LogisticRegression(solver='newton-cg')\n", "estimators.append(('logistic', model1))\n", "model2 = DecisionTreeClassifier()\n", "estimators.append(('cart', model2))\n", "model3 = SVC()\n", "estimators.append(('svm', model3))\n", "# create the ensemble model\n", "ensemble = VotingClassifier(estimators)\n", "\n", "ensemble.fit(X,Y)\n", "results = model_selection.cross_val_score(ensemble, X, Y, cv=kfold)\n", "print(results.mean())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Save model files" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\u001b[33mWARNING: You are using pip version 20.3.3; however, version 21.0.1 is available.\r\n", "You should consider upgrading via the '/home/ec2-user/anaconda3/envs/python3/bin/python -m pip install --upgrade pip' command.\u001b[0m\r\n" ] } ], "source": [ "!pip install joblib -q\n", "from joblib import dump" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "logistic\n", "cart\n", "svm\n" ] }, { "data": { "text/plain": [ "['ensemble.joblib']" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "for estimator in ensemble.estimators:\n", " print(estimator[0])\n", " dump(estimator[1],estimator[0]+'.joblib')\n", "\n", "dump(ensemble,'ensemble.joblib')" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "cart.joblib ensemble.joblib logistic.joblib svm.joblib\r\n" ] } ], "source": [ "!ls *.joblib" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([1.])" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "ensemble.predict(X[0].reshape(1,8))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Step 1 : Write a model transform script\n", "\n", "#### Make sure you have a ...\n", "\n", "- \"load_model\" function\n", " - input args are model path\n", " - returns loaded model object\n", " - model name is the same as what you saved the model file as (see above step)\n", "<br><br>\n", "- \"predict\" function\n", " - input args are the loaded model object and a payload\n", " - returns the result of model.predict\n", " - make sure you format it as a single (or multiple) string return inside a list for real time (for mini batch)\n", " - from a client, a list or string or np.array that is sent for prediction is interpreted as bytes. Do what you have to for converting back to list or string or np.array\n", " - return the error for debugging\n" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Writing modelscript_ensemble_sklearn.py\n" ] } ], "source": [ "%%writefile modelscript_ensemble_sklearn.py\n", "import sklearn\n", "from joblib import load\n", "import numpy as np\n", "import os\n", "\n", "#Return loaded model\n", "def load_model(modelpath):\n", " print(modelpath)\n", " \n", " # Either load individually\n", " print(\"loading individuals\")\n", " logistic = load(os.path.join(modelpath,'logistic.joblib'))\n", " cart = load(os.path.join(modelpath,'cart.joblib'))\n", " svm = load(os.path.join(modelpath,'svm.joblib'))\n", " \n", " # Or load the entire ensemble\n", " print(\"loading ensemble\")\n", " ensemble = load(os.path.join(modelpath,'ensemble.joblib'))\n", " print(\"loaded\")\n", " return ensemble\n", "\n", "# return prediction based on loaded model (from the step above) and an input payload\n", "def predict(model, payload):\n", " try:\n", " # locally, payload may come in as an np.ndarray\n", " if type(payload)==np.ndarray:\n", " out = [str(model.predict(payload.reshape((1,8))))]\n", " # in remote / container based deployment, payload comes in as a stream of bytes\n", " else:\n", "\n", " out = [str(model.predict(np.frombuffer(payload).reshape((1,8))))]\n", " except Exception as e:\n", " out = [type(payload),str(e)] #useful for debugging!\n", " \n", " return out" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Does this work locally? (not \"_in a container locally_\", but _actually_ in local)" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ ".\n", "loading individuals\n", "loading ensemble\n", "loaded\n" ] } ], "source": [ "from modelscript_ensemble_sklearn import *\n", "model = load_model('.')" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['[1.]']" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "predict(model,X[0])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### ok great! Now let's install ezsmdeploy\n", "In some cases, installs fail due to an existing package installed called greenlet.\n", "This is not a direct dependency of ezsmdeploy but interferes with the installation. \n", "To fix this, either install in a virtualenv as seen above, or do:\n", "pip install ezsmdeploy[locust] --ignore-installed greenlet" ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\u001b[33mWARNING: Skipping ezsmdeploy as it is not installed.\u001b[0m\n", "Collecting ezsmdeploy==1.0.8\n", " Downloading ezsmdeploy-1.0.8-py3-none-any.whl (23 kB)\n", "Requirement already satisfied: boto3>=1.14.12 in /home/ec2-user/anaconda3/envs/python3/lib/python3.6/site-packages (from ezsmdeploy==1.0.8) (1.16.63)\n", "Requirement already satisfied: shortuuid==1.0.1 in /home/ec2-user/anaconda3/envs/python3/lib/python3.6/site-packages (from ezsmdeploy==1.0.8) (1.0.1)\n", "Requirement already satisfied: sagemaker-studio-image-build==0.5.0 in /home/ec2-user/anaconda3/envs/python3/lib/python3.6/site-packages (from ezsmdeploy==1.0.8) (0.5.0)\n", "Requirement already satisfied: yaspin==0.16.0 in /home/ec2-user/anaconda3/envs/python3/lib/python3.6/site-packages (from ezsmdeploy==1.0.8) (0.16.0)\n", "Requirement already satisfied: sagemaker==2.16.1 in /home/ec2-user/anaconda3/envs/python3/lib/python3.6/site-packages (from ezsmdeploy==1.0.8) (2.16.1)\n", "Requirement already satisfied: smdebug-rulesconfig==0.1.5 in /home/ec2-user/anaconda3/envs/python3/lib/python3.6/site-packages (from sagemaker==2.16.1->ezsmdeploy==1.0.8) (0.1.5)\n", "Requirement already satisfied: numpy>=1.9.0 in /home/ec2-user/anaconda3/envs/python3/lib/python3.6/site-packages (from sagemaker==2.16.1->ezsmdeploy==1.0.8) (1.19.5)\n", "Requirement already satisfied: protobuf>=3.1 in /home/ec2-user/anaconda3/envs/python3/lib/python3.6/site-packages (from sagemaker==2.16.1->ezsmdeploy==1.0.8) (3.14.0)\n", "Requirement already satisfied: packaging>=20.0 in /home/ec2-user/anaconda3/envs/python3/lib/python3.6/site-packages (from sagemaker==2.16.1->ezsmdeploy==1.0.8) (20.8)\n", "Requirement already satisfied: importlib-metadata>=1.4.0 in /home/ec2-user/anaconda3/envs/python3/lib/python3.6/site-packages (from sagemaker==2.16.1->ezsmdeploy==1.0.8) (3.4.0)\n", "Requirement already satisfied: google-pasta in /home/ec2-user/anaconda3/envs/python3/lib/python3.6/site-packages (from sagemaker==2.16.1->ezsmdeploy==1.0.8) (0.2.0)\n", "Requirement already satisfied: protobuf3-to-dict>=0.1.5 in /home/ec2-user/anaconda3/envs/python3/lib/python3.6/site-packages (from sagemaker==2.16.1->ezsmdeploy==1.0.8) (0.1.5)\n", "Requirement already satisfied: botocore<1.20.0,>=1.19.63 in /home/ec2-user/anaconda3/envs/python3/lib/python3.6/site-packages (from boto3>=1.14.12->ezsmdeploy==1.0.8) (1.19.63)\n", "Requirement already satisfied: s3transfer<0.4.0,>=0.3.0 in /home/ec2-user/anaconda3/envs/python3/lib/python3.6/site-packages (from boto3>=1.14.12->ezsmdeploy==1.0.8) (0.3.4)\n", "Requirement already satisfied: jmespath<1.0.0,>=0.7.1 in /home/ec2-user/anaconda3/envs/python3/lib/python3.6/site-packages (from boto3>=1.14.12->ezsmdeploy==1.0.8) (0.10.0)\n", "Requirement already satisfied: urllib3<1.27,>=1.25.4 in /home/ec2-user/anaconda3/envs/python3/lib/python3.6/site-packages (from botocore<1.20.0,>=1.19.63->boto3>=1.14.12->ezsmdeploy==1.0.8) (1.26.2)\n", "Requirement already satisfied: python-dateutil<3.0.0,>=2.1 in /home/ec2-user/anaconda3/envs/python3/lib/python3.6/site-packages (from botocore<1.20.0,>=1.19.63->boto3>=1.14.12->ezsmdeploy==1.0.8) (2.8.1)\n", "Requirement already satisfied: typing-extensions>=3.6.4 in /home/ec2-user/anaconda3/envs/python3/lib/python3.6/site-packages (from importlib-metadata>=1.4.0->sagemaker==2.16.1->ezsmdeploy==1.0.8) (3.7.4.3)\n", "Requirement already satisfied: zipp>=0.5 in /home/ec2-user/anaconda3/envs/python3/lib/python3.6/site-packages (from importlib-metadata>=1.4.0->sagemaker==2.16.1->ezsmdeploy==1.0.8) (3.4.0)\n", "Requirement already satisfied: pyparsing>=2.0.2 in /home/ec2-user/anaconda3/envs/python3/lib/python3.6/site-packages (from packaging>=20.0->sagemaker==2.16.1->ezsmdeploy==1.0.8) (2.4.7)\n", "Requirement already satisfied: six>=1.9 in /home/ec2-user/anaconda3/envs/python3/lib/python3.6/site-packages (from protobuf>=3.1->sagemaker==2.16.1->ezsmdeploy==1.0.8) (1.15.0)\n", "Installing collected packages: ezsmdeploy\n", "Successfully installed ezsmdeploy-1.0.8\n", "\u001b[33mWARNING: You are using pip version 20.3.3; however, version 21.0.1 is available.\n", "You should consider upgrading via the '/home/ec2-user/anaconda3/envs/python3/bin/python -m pip install --upgrade pip' command.\u001b[0m\n" ] } ], "source": [ "!pip uninstall -y ezsmdeploy\n", "!pip install ezsmdeploy==1.0.8" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [], "source": [ "import ezsmdeploy" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### If you have been running other inference containers in local mode, stop existing containers to avoid conflict" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [], "source": [ "!docker container stop $(docker container ls -aq) >/dev/null" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Deploy locally" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### tar all models" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [], "source": [ "!rm model.tar.gz\n", "!find ./ -name \"*.joblib\" | tar -czf model.tar.gz -T -" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\u001b[K0:00:00.082217 | compressed model(s)\n", "\u001b[K0:00:00.205353 | uploaded model tarball(s) ; check returned modelpath\n", "\u001b[K0:00:00.206102 | added requirements file\n", "\u001b[K0:00:00.207730 | added source file\n", "\u001b[K0:00:00.208891 | added Dockerfile\n", "\u001b[K0:00:00.210776 | added model_handler and docker utils\n", "\u001b[K0:00:00.210855 | building docker container\n", "\u001b[K0:00:43.321145 | built docker container\n", "\u001b[K2m∙∙∙\u001b[0m \u001b[K" ] }, { "name": "stderr", "output_type": "stream", "text": [ "update_endpoint is a no-op in sagemaker>=2.\n", "See: https://sagemaker.readthedocs.io/en/stable/v2.html for details.\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\u001b[K0:00:43.453548 | created model(s). Now deploying on local\n", "\u001b[32m∙∙∙\u001b[0m \u001b[KAttaching to tmpctykbmbm_algo-1-tj704_1\n", "\u001b[36malgo-1-tj704_1 |\u001b[0m Starting the inference server with 64 workers.\n", "\u001b[32m∙â—∙\u001b[0m \u001b[K\u001b[36malgo-1-tj704_1 |\u001b[0m [2021-02-12 01:06:49 +0000] [9] [INFO] Starting gunicorn 20.0.4\n", "\u001b[36malgo-1-tj704_1 |\u001b[0m [2021-02-12 01:06:49 +0000] [9] [INFO] Listening at: unix:/tmp/gunicorn.sock (9)\n", "\u001b[36malgo-1-tj704_1 |\u001b[0m [2021-02-12 01:06:49 +0000] [9] [INFO] Using worker: gevent\n", "\u001b[36malgo-1-tj704_1 |\u001b[0m [2021-02-12 01:06:49 +0000] [13] [INFO] Booting worker with pid: 13\n", "\u001b[36malgo-1-tj704_1 |\u001b[0m [2021-02-12 01:06:49 +0000] [14] [INFO] Booting worker with pid: 14\n", "\u001b[36malgo-1-tj704_1 |\u001b[0m [2021-02-12 01:06:49 +0000] [15] [INFO] Booting worker with pid: 15\n", "\u001b[36malgo-1-tj704_1 |\u001b[0m [2021-02-12 01:06:49 +0000] [16] [INFO] Booting worker with pid: 16\n", "\u001b[32m∙∙â—\u001b[0m \u001b[K\u001b[36malgo-1-tj704_1 |\u001b[0m [2021-02-12 01:06:49 +0000] [18] [INFO] Booting worker with pid: 18\n", "\u001b[36malgo-1-tj704_1 |\u001b[0m [2021-02-12 01:06:49 +0000] [24] [INFO] Booting worker with pid: 24\n", "\u001b[32m∙∙∙\u001b[0m \u001b[K\u001b[36malgo-1-tj704_1 |\u001b[0m [2021-02-12 01:06:49 +0000] [85] [INFO] Booting worker with pid: 85\n", "\u001b[36malgo-1-tj704_1 |\u001b[0m [2021-02-12 01:06:49 +0000] [212] [INFO] Booting worker with pid: 212\n", "\u001b[36malgo-1-tj704_1 |\u001b[0m [2021-02-12 01:06:49 +0000] [214] [INFO] Booting worker with pid: 214\n", "\u001b[36malgo-1-tj704_1 |\u001b[0m [2021-02-12 01:06:49 +0000] [215] [INFO] Booting worker with pid: 215\n", "\u001b[32m∙∙∙\u001b[0m \u001b[K\u001b[36malgo-1-tj704_1 |\u001b[0m [2021-02-12 01:06:49 +0000] [344] [INFO] Booting worker with pid: 344\n", "\u001b[36malgo-1-tj704_1 |\u001b[0m [2021-02-12 01:06:49 +0000] [345] [INFO] Booting worker with pid: 345\n", "\u001b[32mâ—∙∙\u001b[0m \u001b[K\u001b[36malgo-1-tj704_1 |\u001b[0m [2021-02-12 01:06:49 +0000] [409] [INFO] Booting worker with pid: 409\n", "\u001b[32m∙â—∙\u001b[0m \u001b[K\u001b[36malgo-1-tj704_1 |\u001b[0m [2021-02-12 01:06:49 +0000] [476] [INFO] Booting worker with pid: 476\n", "\u001b[36malgo-1-tj704_1 |\u001b[0m [2021-02-12 01:06:49 +0000] [666] [INFO] Booting worker with pid: 666\n", "\u001b[36malgo-1-tj704_1 |\u001b[0m [2021-02-12 01:06:49 +0000] [730] [INFO] Booting worker with pid: 730\n", "\u001b[32m∙∙â—\u001b[0m \u001b[K\u001b[36malgo-1-tj704_1 |\u001b[0m [2021-02-12 01:06:49 +0000] [795] [INFO] Booting worker with pid: 795\n", "\u001b[36malgo-1-tj704_1 |\u001b[0m [2021-02-12 01:06:49 +0000] [796] [INFO] Booting worker with pid: 796\n", "\u001b[32m∙∙∙\u001b[0m \u001b[K\u001b[36malgo-1-tj704_1 |\u001b[0m [2021-02-12 01:06:50 +0000] [923] [INFO] Booting worker with pid: 923\n", "\u001b[36malgo-1-tj704_1 |\u001b[0m [2021-02-12 01:06:50 +0000] [1115] [INFO] Booting worker with pid: 1115\n", "\u001b[32m∙∙∙\u001b[0m \u001b[K\u001b[36malgo-1-tj704_1 |\u001b[0m [2021-02-12 01:06:50 +0000] [1180] [INFO] Booting worker with pid: 1180\n", "\u001b[32mâ—∙∙\u001b[0m \u001b[K\u001b[36malgo-1-tj704_1 |\u001b[0m [2021-02-12 01:06:50 +0000] [1244] [INFO] Booting worker with pid: 1244\n", "\u001b[36malgo-1-tj704_1 |\u001b[0m [2021-02-12 01:06:50 +0000] [1309] [INFO] Booting worker with pid: 1309\n", "\u001b[36malgo-1-tj704_1 |\u001b[0m [2021-02-12 01:06:50 +0000] [1373] [INFO] Booting worker with pid: 1373\n", "\u001b[32m∙â—∙\u001b[0m \u001b[K\u001b[36malgo-1-tj704_1 |\u001b[0m [2021-02-12 01:06:50 +0000] [1438] [INFO] Booting worker with pid: 1438\n", "\u001b[36malgo-1-tj704_1 |\u001b[0m [2021-02-12 01:06:50 +0000] [1565] [INFO] Booting worker with pid: 1565\n", "\u001b[36malgo-1-tj704_1 |\u001b[0m [2021-02-12 01:06:50 +0000] [1567] [INFO] Booting worker with pid: 1567\n", "\u001b[32m∙∙â—\u001b[0m \u001b[K\u001b[36malgo-1-tj704_1 |\u001b[0m [2021-02-12 01:06:50 +0000] [1631] [INFO] Booting worker with pid: 1631\n", "\u001b[36malgo-1-tj704_1 |\u001b[0m [2021-02-12 01:06:50 +0000] [1695] [INFO] Booting worker with pid: 1695\n", "\u001b[36malgo-1-tj704_1 |\u001b[0m [2021-02-12 01:06:50 +0000] [1696] [INFO] Booting worker with pid: 1696\n", "\u001b[32m∙∙∙\u001b[0m \u001b[K\u001b[36malgo-1-tj704_1 |\u001b[0m [2021-02-12 01:06:50 +0000] [1762] [INFO] Booting worker with pid: 1762\n", "\u001b[36malgo-1-tj704_1 |\u001b[0m [2021-02-12 01:06:50 +0000] [1905] [INFO] Booting worker with pid: 1905\n", "\u001b[36malgo-1-tj704_1 |\u001b[0m [2021-02-12 01:06:50 +0000] [2018] [INFO] Booting worker with pid: 2018\n", "\u001b[32m∙∙∙\u001b[0m \u001b[K\u001b[36malgo-1-tj704_1 |\u001b[0m [2021-02-12 01:06:50 +0000] [2020] [INFO] Booting worker with pid: 2020\n", "\u001b[36malgo-1-tj704_1 |\u001b[0m [2021-02-12 01:06:50 +0000] [2021] [INFO] Booting worker with pid: 2021\n", "\u001b[36malgo-1-tj704_1 |\u001b[0m [2021-02-12 01:06:50 +0000] [2086] [INFO] Booting worker with pid: 2086\n", "\u001b[36malgo-1-tj704_1 |\u001b[0m [2021-02-12 01:06:50 +0000] [2151] [INFO] Booting worker with pid: 2151\n", "\u001b[32mâ—∙∙\u001b[0m \u001b[K\u001b[36malgo-1-tj704_1 |\u001b[0m [2021-02-12 01:06:50 +0000] [2152] [INFO] Booting worker with pid: 2152\n", "\u001b[36malgo-1-tj704_1 |\u001b[0m [2021-02-12 01:06:50 +0000] [2153] [INFO] Booting worker with pid: 2153\n", "\u001b[32m∙â—∙\u001b[0m \u001b[K\u001b[36malgo-1-tj704_1 |\u001b[0m [2021-02-12 01:06:51 +0000] [2475] [INFO] Booting worker with pid: 2475\n", "\u001b[36malgo-1-tj704_1 |\u001b[0m [2021-02-12 01:06:51 +0000] [2474] [INFO] Booting worker with pid: 2474\n", "\u001b[36malgo-1-tj704_1 |\u001b[0m [2021-02-12 01:06:51 +0000] [2524] [INFO] Booting worker with pid: 2524\n", "\u001b[32m∙∙â—\u001b[0m \u001b[K\u001b[36malgo-1-tj704_1 |\u001b[0m [2021-02-12 01:06:51 +0000] [2540] [INFO] Booting worker with pid: 2540\n", "\u001b[36malgo-1-tj704_1 |\u001b[0m [2021-02-12 01:06:51 +0000] [2686] [INFO] Booting worker with pid: 2686\n", "\u001b[36malgo-1-tj704_1 |\u001b[0m [2021-02-12 01:06:51 +0000] [2796] [INFO] Booting worker with pid: 2796\n", "\u001b[36malgo-1-tj704_1 |\u001b[0m [2021-02-12 01:06:51 +0000] [2797] [INFO] Booting worker with pid: 2797\n", "\u001b[32m∙∙∙\u001b[0m \u001b[K\u001b[36malgo-1-tj704_1 |\u001b[0m [2021-02-12 01:06:51 +0000] [2927] [INFO] Booting worker with pid: 2927\n", "\u001b[36malgo-1-tj704_1 |\u001b[0m [2021-02-12 01:06:51 +0000] [2903] [INFO] Booting worker with pid: 2903\n", "\u001b[36malgo-1-tj704_1 |\u001b[0m [2021-02-12 01:06:51 +0000] [2929] [INFO] Booting worker with pid: 2929\n", "\u001b[32m∙∙∙\u001b[0m \u001b[K\u001b[36malgo-1-tj704_1 |\u001b[0m [2021-02-12 01:06:51 +0000] [3418] [INFO] Booting worker with pid: 3418\n", "\u001b[36malgo-1-tj704_1 |\u001b[0m [2021-02-12 01:06:51 +0000] [3309] [INFO] Booting worker with pid: 3309\n", "\u001b[36malgo-1-tj704_1 |\u001b[0m [2021-02-12 01:06:51 +0000] [3478] [INFO] Booting worker with pid: 3478\n", "\u001b[32mâ—∙∙\u001b[0m \u001b[K\u001b[36malgo-1-tj704_1 |\u001b[0m [2021-02-12 01:06:51 +0000] [3502] [INFO] Booting worker with pid: 3502\n", "\u001b[36malgo-1-tj704_1 |\u001b[0m [2021-02-12 01:06:51 +0000] [3501] [INFO] Booting worker with pid: 3501\n", "\u001b[36malgo-1-tj704_1 |\u001b[0m [2021-02-12 01:06:51 +0000] [3503] [INFO] Booting worker with pid: 3503\n", "\u001b[36malgo-1-tj704_1 |\u001b[0m [2021-02-12 01:06:51 +0000] [3506] [INFO] Booting worker with pid: 3506\n", "\u001b[32m∙â—∙\u001b[0m \u001b[K\u001b[36malgo-1-tj704_1 |\u001b[0m [2021-02-12 01:06:51 +0000] [3634] [INFO] Booting worker with pid: 3634\n", "\u001b[36malgo-1-tj704_1 |\u001b[0m [2021-02-12 01:06:51 +0000] [3699] [INFO] Booting worker with pid: 3699\n", "\u001b[36malgo-1-tj704_1 |\u001b[0m [2021-02-12 01:06:51 +0000] [3726] [INFO] Booting worker with pid: 3726\n", "\u001b[36malgo-1-tj704_1 |\u001b[0m [2021-02-12 01:06:51 +0000] [3744] [INFO] Booting worker with pid: 3744\n", "\u001b[32m∙∙â—\u001b[0m \u001b[K\u001b[36malgo-1-tj704_1 |\u001b[0m [2021-02-12 01:06:51 +0000] [3844] [INFO] Booting worker with pid: 3844\n", "\u001b[36malgo-1-tj704_1 |\u001b[0m [2021-02-12 01:06:51 +0000] [3845] [INFO] Booting worker with pid: 3845\n", "\u001b[36malgo-1-tj704_1 |\u001b[0m [2021-02-12 01:06:51 +0000] [4139] [INFO] Booting worker with pid: 4139\n", "\u001b[32m∙∙∙\u001b[0m \u001b[K\u001b[36malgo-1-tj704_1 |\u001b[0m [2021-02-12 01:06:51 +0000] [4301] [INFO] Booting worker with pid: 4301\n", "\u001b[32m∙â—∙\u001b[0m \u001b[K\u001b[36malgo-1-tj704_1 |\u001b[0m /opt/ml/model\n", "\u001b[36malgo-1-tj704_1 |\u001b[0m loading individuals\n", "\u001b[32m∙∙â—\u001b[0m \u001b[K\u001b[36malgo-1-tj704_1 |\u001b[0m loading ensemble\n", "\u001b[32m∙∙∙\u001b[0m \u001b[K\u001b[36malgo-1-tj704_1 |\u001b[0m loaded\n", "!\u001b[36malgo-1-tj704_1 |\u001b[0m 172.18.0.1 - - [12/Feb/2021:01:06:52 +0000] \"GET /ping HTTP/1.1\" 200 1 \"-\" \"python-urllib3/1.26.2\"\n", "\u001b[K0:00:49.014930 | deployed model\n", "\u001b[K\u001b[32m0:00:49.015318 | Done! ✔\u001b[0m \n" ] } ], "source": [ "ez = ezsmdeploy.Deploy(model = 'model.tar.gz', # if you intend to add models later, pass model as list, otherwise str\n", " script = 'modelscript_ensemble_sklearn.py',\n", " requirements = ['scikit-learn=='+sklearn.__version__,'numpy','joblib'], #or pass in the path to requirements.txt\n", " instance_type = 'local',\n", " wait = True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Test containerized version locally" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\u001b[36malgo-1-tj704_1 |\u001b[0m received input data\r\n", "\u001b[36malgo-1-tj704_1 |\u001b[0m b'\\x00\\x00\\x00\\x00\\x00\\x00\\x18@\\x00\\x00\\x00\\x00\\x00\\x80b@\\x00\\x00\\x00\\x00\\x00\\x00R@\\x00\\x00\\x00\\x00\\x00\\x80A@\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\xcd\\xcc\\xcc\\xcc\\xcc\\xcc@@\\xaa\\xf1\\xd2Mb\\x10\\xe4?\\x00\\x00\\x00\\x00\\x00\\x00I@'\r\n", "\u001b[36malgo-1-tj704_1 |\u001b[0m /opt/ml/model\r\n", "\u001b[36malgo-1-tj704_1 |\u001b[0m loading individuals\r\n", "\u001b[36malgo-1-tj704_1 |\u001b[0m loading ensemble\r\n", "\u001b[36malgo-1-tj704_1 |\u001b[0m loaded\r\n", "\u001b[36malgo-1-tj704_1 |\u001b[0m predictions from model\r\n", "\u001b[36malgo-1-tj704_1 |\u001b[0m ['[1.]']\r\n" ] }, { "data": { "text/plain": [ "'[1.]'" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" }, { "name": "stdout", "output_type": "stream", "text": [ "\u001b[36malgo-1-tj704_1 |\u001b[0m 172.18.0.1 - - [12/Feb/2021:01:07:29 +0000] \"POST /invocations HTTP/1.1\" 200 4 \"-\" \"python-urllib3/1.26.2\"\r\n" ] } ], "source": [ "out = ez.predictor.predict(X[0].reshape((1,8)).tobytes()).decode()\n", "out" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\u001b[36malgo-1-tj704_1 |\u001b[0m [2021-02-12 01:07:29 +0000] [9] [INFO] Handling signal: term\n", "\u001b[36malgo-1-tj704_1 |\u001b[0m [2021-02-12 01:07:30 +0000] [212] [INFO] Worker exiting (pid: 212)\n", "\u001b[36mtmpctykbmbm_algo-1-tj704_1 exited with code 0\n", "\u001b[0mAborting on container exit...\n" ] } ], "source": [ "!docker container stop $(docker container ls -aq) >/dev/null" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Deploy on SageMaker" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\u001b[K0:00:00.081814 | compressed model(s)\n", "\u001b[K0:00:00.277634 | uploaded model tarball(s) ; check returned modelpath\n", "\u001b[K0:00:00.278338 | added requirements file\n", "\u001b[K0:00:00.279678 | added source file\n", "\u001b[K0:00:00.280726 | added Dockerfile\n", "\u001b[K0:00:00.282357 | added model_handler and docker utils\n", "\u001b[K0:00:00.282483 | building docker container\n", "\u001b[K0:00:43.422978 | built docker container\n", "\u001b[K2mâ—∙∙\u001b[0m \u001b[K" ] }, { "name": "stderr", "output_type": "stream", "text": [ "update_endpoint is a no-op in sagemaker>=2.\n", "See: https://sagemaker.readthedocs.io/en/stable/v2.html for details.\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\u001b[K0:00:43.630886 | created model(s). Now deploying on ml.m5.xlarge\n", "\u001b[K0:07:15.817639 | deployed model\n", "\u001b[K0:07:15.818150 | estimated cost is $0.3 per hour\n", "\u001b[K\u001b[32m0:07:15.818299 | Done! ✔\u001b[0m \n" ] } ], "source": [ "ezonsm = ezsmdeploy.Deploy(model = 'model.tar.gz', \n", " script = 'modelscript_ensemble_sklearn.py',\n", " requirements = ['scikit-learn=='+sklearn.__version__,'numpy','joblib'], #or pass in the path to requirements.txt\n", " prefix = 'testingprefix',\n", " wait = True)" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [], "source": [ "# !./src/build-docker.sh test" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'[1.]'" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "out = ezonsm.predictor.predict(X[0].reshape((1,8)).tobytes()).decode()\n", "out" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [], "source": [ "ezonsm.predictor.delete_endpoint()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "conda_python3", "language": "python", "name": "conda_python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.6.10" } }, "nbformat": 4, "nbformat_minor": 4 }