{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# SageMaker Serial Inference Pipeline(SIP) with Scikit-learn and Linear Learner\n", "Typically a Machine Learning (ML) process consists of few steps: data gathering with various ETL jobs, pre-processing the data, featurizing the dataset by incorporating standard techniques or prior knowledge, and finally training an ML model using an algorithm. \n", "In many cases, when the trained model is used for processing real time or batch prediction requests, the model receives data in a format which needs to pre-processed (e.g. featurized) before it can be passed to the algorithm. In the following notebook, we will demonstrate how to deploy a Pipeline (Data preprocessing and Linear Learner) as an Inference Pipeline behind a single Endpoint for real time inference. The Pipeline is made up a Scikit-learn Preprocessor and a learner model pretrained on the Abalone dataset to guess the age of Abalone with physical features. \n", "The dataset is available from [UCI Machine Learning](https://archive.ics.uci.edu/ml/datasets/abalone).\n", "\n", "### Table of contents\n", "* [Inference Pipeline with Scikit preprocessor and Linear Learner](#inference_pipeline)\n", " * [Set up the inference pipeline](#pipeline_setup)\n", " * [Make a request to our pipeline endpoint](#pipeline_inference_request)\n", " * [Delete Endpoint](#delete_endpoint)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's first create our Sagemaker session and role, and create a S3 prefix to use for the notebook example." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Serial Inference Pipeline with Scikit preprocessor and Linear Learner \n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Step 1: Set up the inference pipeline \n", "Setting up a Machine Learning pipeline can be done with the Pipeline Model. This sets up a list of models in a single endpoint; in this example, we configure our pipeline model with the fitted Scikit-learn inference model and the fitted Linear Learner model. Deploying the model follows the same ```deploy``` pattern in the SDK." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "upload: scikit-learn/model.tar.gz to s3://sagemaker-us-east-1-171503325295/Scikit-LinearLearner-pipeline-abalone-example/scikit-learn/model.tar.gz\n", "upload: linear-learner/model.tar.gz to s3://sagemaker-us-east-1-171503325295/Scikit-LinearLearner-pipeline-abalone-example/linear-learner/model.tar.gz\n" ] } ], "source": [ "import sagemaker, boto3, json\n", "from sagemaker import get_execution_role\n", "sagemaker_session = sagemaker.Session()\n", "aws_role = get_execution_role()\n", "aws_region = boto3.Session().region_name\n", "sess = sagemaker.Session()\n", "bucket = sagemaker_session.default_bucket()\n", "prefix = \"Scikit-LinearLearner-pipeline-abalone-example\"\n", "\n", "!aws s3 cp scikit-learn/model.tar.gz s3://{bucket}/{prefix}/scikit-learn/model.tar.gz\n", "!aws s3 cp linear-learner/model.tar.gz s3://{bucket}/{prefix}/linear-learner/model.tar.gz\n", "\n", "import sagemaker \n", "image_uri = sagemaker.image_uris.retrieve(\"linear-learner\", \"us-east-1\")\n", " \n", "from sagemaker.sklearn.model import SKLearnModel\n", "from sagemaker.model import Model\n", "scikit_learn_inference_model = SKLearnModel(\n", " model_data=f\"s3://{bucket}/{prefix}/scikit-learn/model.tar.gz\",\n", " entry_point=\"scikit-learn/sklearn_abalone_featurizer.py\",\n", " framework_version=\"1.0-1\",\n", " role=aws_role,\n", " sagemaker_session=sess\n", " )\n", "\n", "linear_learner_model = Model(\n", " model_data=f\"s3://{bucket}/{prefix}/linear-learner/model.tar.gz\",\n", " image_uri=image_uri,\n", " role=aws_role,\n", " sagemaker_session=sess\n", ")" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "-----------------!" ] } ], "source": [ "from sagemaker.sklearn.model import SKLearnModel\n", "from sagemaker.pipeline import PipelineModel\n", "import boto3\n", "from time import gmtime, strftime\n", "\n", "timestamp_prefix = strftime(\"%Y-%m-%d-%H-%M-%S\", gmtime())\n", "\n", "model_name = \"inference-pipeline-\" + timestamp_prefix\n", "endpoint_name = \"inference-pipeline-inference-pipeline\" + timestamp_prefix\n", "sm_model = PipelineModel(\n", " name=model_name, role=aws_role, models=[scikit_learn_inference_model, linear_learner_model]\n", ")\n", "\n", "sm_model.deploy(initial_instance_count=1, instance_type=\"ml.c4.xlarge\", endpoint_name=endpoint_name)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Step 2: Make a request to our pipeline endpoint \n", "\n", "Here we just grab the first line from the test data (you'll notice that the inference python script is very particular about the ordering of the inference request data). The ```ContentType``` field configures the first container, while the ```Accept``` field configures the last container. You can also specify each container's ```Accept``` and ```ContentType``` values using environment variables.\n", "\n", "We make our request with the payload in ```'text/csv'``` format, since that is what our script currently supports. If other formats need to be supported, this would have to be added to the ```output_fn()``` method in our entry point. Note that we set the ```Accept``` to ```application/json```, since Linear Learner does not support ```text/csv``` ```Accept```. The prediction output in this case is trying to guess the number of rings the abalone specimen would have given its other physical features; the actual number of rings is 10." ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "b'{\"predictions\": [{\"score\": 9.528051376342773}]}'\n" ] } ], "source": [ "from sagemaker.predictor import Predictor\n", "from sagemaker.serializers import CSVSerializer\n", "\n", "payload = \"M, 0.44, 0.365, 0.125, 0.516, 0.2155, 0.114, 0.155\"\n", "actual_rings = 10\n", "predictor = Predictor(\n", " endpoint_name=endpoint_name, sagemaker_session=sagemaker_session, serializer=CSVSerializer()\n", ")\n", "\n", "print(predictor.predict(payload))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Step 3: Delete Endpoint \n", "Once we are finished with the endpoint, we clean up the resources!" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "# sm_client = sagemaker_session.boto_session.client(\"sagemaker\")\n", "# predictor.delete_model()\n", "# sm_client.delete_endpoint(EndpointName=endpoint_name)" ] } ], "metadata": { "celltoolbar": "Tags", "instance_type": "ml.t3.medium", "kernelspec": { "display_name": "Python 3 (Data Science)", "language": "python", "name": "python3__SAGEMAKER_INTERNAL__arn:aws:sagemaker:us-east-1:081325390199:image/datascience-1.0" }, "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.7.10" } }, "nbformat": 4, "nbformat_minor": 4 }