<jupyter_start><jupyter_text>Amazon SageMaker scikit-learn Bring Your Own Model_**Hosting a pre-trained scikit-learn Model in Amazon SageMaker scikit-learn Container**_------ BackgroundAmazon SageMaker includes functionality to support a hosted notebook environment, distributed, serverless training, and real-time hosting. We think it works best when all three of these services are used together, but they can also be used independently.  Some use cases may only require hosting.  Maybe the model was trained prior to Amazon SageMaker existing, in a different service.This notebook shows how to use a pre-trained scikit-learn model with the Amazon SageMaker scikit-learn container to quickly create a hosted endpoint for that model.We use the California Housing dataset, present in Scikit-Learn: https://scikit-learn.org/stable/modules/generated/sklearn.datasets.fetch_california_housing.html. The California Housing dataset was originally published in:> Pace, <NAME>, and <NAME>. "Sparse spatial auto-regressions." Statistics & Probability Letters 33.3 (1997): 291-297.--- SetupLet's start by specifying:* AWS region.* The IAM role arn used to give learning and hosting access to your data.* The S3 bucket that you want to use for training and model data.<jupyter_code>import os
import boto3
import re
import json
import pandas as pd
import numpy as np
import sagemaker
from sagemaker import get_execution_role
from sagemaker.sklearn.model import SKLearnModel
from sklearn.datasets import fetch_california_housing
from sklearn.model_selection import train_test_split


region = boto3.Session().region_name

role = get_execution_role()

bucket = sagemaker.Session().default_bucket()
prefix = "sagemaker/DEMO-sklearn-byo-model"

print(f"bucket: {bucket}")<jupyter_output><empty_output><jupyter_text>Prepare data for model inferenceWe load the California housing dataset from sklearn, and will use it to invoke SageMaker Endpoint<jupyter_code>data = fetch_california_housing()
X_train, X_test, y_train, y_test = train_test_split(
    data.data, data.target, test_size=0.25, random_state=42
)

# we don't train a model, so we will need only the testing data
testX = pd.DataFrame(X_test, columns=data.feature_names)
testX.head(10)<jupyter_output><empty_output><jupyter_text>Download a pre-trained model fileDownload a pretrained Scikit-Learn Random Forest model.We used the California Housing dataset, present in Scikit-Learn: https://scikit-learn.org/stable/datasets/real_world.htmlcalifornia-housing-dataset to train the model.For more details on how to train the model with Amazon SageMaker, please refer to the [Develop, Train, Optimize and Deploy Scikit-Learn Random Forest notebook](https://github.com/aws/amazon-sagemaker-examples/blob/master/sagemaker-python-sdk/scikit_learn_randomforest/Sklearn_on_SageMaker_end2end.ipynb)<jupyter_code>!aws s3 cp s3://aws-ml-blog/artifacts/scikit_learn_bring_your_own_model/model.joblib .<jupyter_output><empty_output><jupyter_text>Compressed the model file to a GZIP tar archive Note that the model file name must satisfy the regular expression pattern: `^[a-zA-Z0-9](-*[a-zA-Z0-9])*;`. The model file needs to be tar-zipped.<jupyter_code>model_file_name = "model.joblib"
!tar czvf model.tar.gz $model_file_name<jupyter_output><empty_output><jupyter_text>Upload the pre-trained model `model.tar.gz` file to S3<jupyter_code>fObj = open("model.tar.gz", "rb")
key = os.path.join(prefix, "model.tar.gz")
boto3.Session().resource("s3").Bucket(bucket).Object(key).upload_fileobj(fObj)<jupyter_output><empty_output><jupyter_text>Set up hosting for the modelThis involves creating a SageMaker model from the model file previously uploaded to S3.<jupyter_code>model_data = "s3://{}/{}".format(bucket, key)
print(f"model data: {model_data}")<jupyter_output><empty_output><jupyter_text>Write the Inference ScriptWhen using endpoints with the Amazon SageMaker managed `Scikit Learn` container, we need to provide an entry point script for inference that will **at least** load the saved model.After the SageMaker model server has loaded your model by calling `model_fn`, SageMaker will serve your model. Model serving is the process of responding to inference requests, received by SageMaker `InvokeEndpoint` API calls.We will implement also the `predict_fn()` function that takes the deserialized request object and performs inference against the loaded model.We will now create this script and call it `inference.py` and store it at the root of a directory called `code`.**Note:** You would modify the script below to implement your own inferencing logic.Additional information on model loading and model serving for scikit-learn on SageMaker can be found in the [SageMaker Scikit-learn Model Server documentation](https://sagemaker.readthedocs.io/en/stable/frameworks/sklearn/using_sklearn.htmldeploy-a-scikit-learn-model)There are also several functions for hosting which we won't define, - `input_fn()` - Takes request data and deserializes the data into an object for prediction. - `output_fn()` - Takes the result of prediction and serializes this according to the response content type.These will take on their default values as described [SageMaker Scikit-learn Serve a Model documentation](https://sagemaker.readthedocs.io/en/stable/frameworks/sklearn/using_sklearn.htmlserve-a-model)<jupyter_code>!pygmentize ./code/inference.py<jupyter_output><empty_output><jupyter_text>Installing additional Python dependenciesIt also may be necessary to supply a `requirements.txt` file to ensure any necessary dependencies are installed in the container along with the script. For this script, in addition to the Python standard libraries, we showcase how to install the `boto3` `requests`, and `nltk` libraries.<jupyter_code>!pygmentize ./code/requirements.txt<jupyter_output><empty_output><jupyter_text>Deploy with Python SDKHere we showcase the process of creating a model from s3 artifacts, that could be used to deploy a model that was trained in a different session or even out of SageMaker.<jupyter_code>model = SKLearnModel(
    role=role,
    model_data=model_data,
    framework_version="1.0-1",
    py_version="py3",
    source_dir="code",
    entry_point="inference.py",
)<jupyter_output><empty_output><jupyter_text>Create endpointLastly, you create the endpoint that serves up the model, through specifying the name and configuration defined above. The end result is an endpoint that can be validated and incorporated into production applications. This takes 5-10 minutes to complete.<jupyter_code>%%time

predictor = model.deploy(instance_type="ml.t2.medium", initial_instance_count=1)<jupyter_output><empty_output><jupyter_text>Validate the model for useNow you can obtain the endpoint from the client library using the result from previous operations and generate classifications from the model using that endpoint.  Invoke with the Python SDK Let's generate the prediction for a single data point. We'll pick one from the test data generated earlier.<jupyter_code># the SKLearnPredictor does the serialization from pandas for us
predictions = predictor.predict(testX[data.feature_names])
print(predictions)<jupyter_output><empty_output><jupyter_text>Alternative: invoke with `boto3`This is useful when invoking the model from external clients, e.g. Lambda Functions, or other micro-services.<jupyter_code>runtime = boto3.client("sagemaker-runtime")<jupyter_output><empty_output><jupyter_text>Option 1: `csv` serialization<jupyter_code># csv serialization
response = runtime.invoke_endpoint(
    EndpointName=predictor.endpoint,
    Body=testX[data.feature_names].to_csv(header=False, index=False).encode("utf-8"),
    ContentType="text/csv",
)

print(response["Body"].read())<jupyter_output><empty_output><jupyter_text>Option 2: `npy` serialization<jupyter_code># npy serialization
from io import BytesIO


# Serialise numpy ndarray as bytes
buffer = BytesIO()
# Assuming testX is a data frame
np.save(buffer, testX[data.feature_names].values)

response = runtime.invoke_endpoint(
    EndpointName=predictor.endpoint, Body=buffer.getvalue(), ContentType="application/x-npy"
)

print(response["Body"].read())<jupyter_output><empty_output><jupyter_text>(Optional) Delete the EndpointIf you're ready to be done with this notebook, please run the delete_endpoint line in the cell below.  This will remove the hosted endpoint you created and avoid any charges from a stray instance being left on.<jupyter_code>predictor.delete_endpoint()<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.08156070043483371, 'fraction_numerical': 0.005993653778352333, 'mean_word_length': 6.267292912040991, 'pattern_counts': {'":': 0, '<': 63, '<?xml version=': 0, '>': 64, 'https://': 5, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 3, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '15', 'dir': 'jupyter-structured-clean-dedup', 'id': '114698', 'license': 'Apache-2.0', 'n_tokens_mistral': 2541, 'n_tokens_neox': 2434, 'n_words': 853, 'path': 'advanced_functionality/scikit_learn_bring_your_own_model/scikit_learn_bring_your_own_model.ipynb', 'repo_name': 'Neo9061/amazon-sagemaker-examples', 'size': '8518'}