{ "cells": [ { "cell_type": "markdown", "id": "4f7eb540", "metadata": {}, "source": [ "# Multi-model SageMaker Pipeline with Hyperparamater Tuning and Experiments" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "\n", "This notebook's CI test result for us-west-2 is as follows. CI test results in other regions can be found at the end of the notebook. \n", "\n", "![This us-west-2 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/us-west-2/sagemaker-pipeline-multi-model|restate-project.ipynb)\n", "\n", "---" ] }, { "cell_type": "markdown", "id": "9fb71b60", "metadata": {}, "source": [ "Before proceeding, please see the context of this notebook in [README.md](README.md). This notebook has been tested in a SageMaker notebook that is using a kernel with at least Python 3.7 installed, e.g. conda_mxnet_latest_p37, conda_python3. Make sure you have created a SageMaker project outside of this notebook with the name `restate`. Recommendation is to create a SageMaker project using [SageMaker-provide MLOps template for model building, training, and deployment template](https://docs.aws.amazon.com/sagemaker/latest/dg/sagemaker-projects-templates-sm.html#sagemaker-projects-templates-code-commit). Note that this notebook will not create the SageMaker project for you. \n" ] }, { "cell_type": "markdown", "id": "56e11db5", "metadata": {}, "source": [ "## Pre-requisities" ] }, { "cell_type": "markdown", "id": "7ce1cbed", "metadata": {}, "source": [ "We create an S3 bucket and with encryption enabled for additional security. " ] }, { "cell_type": "code", "execution_count": null, "id": "ede47daf", "metadata": {}, "outputs": [], "source": [ "import boto3\n", "\n", "AWS_ACCOUNT = boto3.client(\"sts\").get_caller_identity()[\"Account\"]\n", "AWS_REGION = boto3.Session().region_name\n", "BUCKET_NAME = \"sagemaker-restate-{AWS_ACCOUNT}\".format(AWS_ACCOUNT=AWS_ACCOUNT)\n", "\n", "s3_client = boto3.client(\"s3\")\n", "location = {\"LocationConstraint\": AWS_REGION}\n", "s3_client.create_bucket(Bucket=BUCKET_NAME, CreateBucketConfiguration=location)\n", "s3_client.put_bucket_encryption(\n", " Bucket=BUCKET_NAME,\n", " ServerSideEncryptionConfiguration={\n", " \"Rules\": [\n", " {\n", " \"ApplyServerSideEncryptionByDefault\": {\"SSEAlgorithm\": \"AES256\"},\n", " },\n", " ]\n", " },\n", ")" ] }, { "cell_type": "markdown", "id": "eafed411", "metadata": {}, "source": [ "We create IAM role AWSGlueServiceRole-restate." ] }, { "cell_type": "code", "execution_count": null, "id": "662580dd", "metadata": {}, "outputs": [], "source": [ "import json\n", "\n", "iam_client = boto3.client(\"iam\")\n", "\n", "glue_assume_role_policy_document = json.dumps(\n", " {\n", " \"Version\": \"2012-10-17\",\n", " \"Statement\": [\n", " {\n", " \"Effect\": \"Allow\",\n", " \"Principal\": {\"Service\": \"glue.amazonaws.com\"},\n", " \"Action\": \"sts:AssumeRole\",\n", " }\n", " ],\n", " }\n", ")\n", "\n", "response = iam_client.create_role(\n", " RoleName=\"AWSGlueServiceRole-restate\", AssumeRolePolicyDocument=glue_assume_role_policy_document\n", ")\n", "\n", "iam_client.attach_role_policy(\n", " RoleName=response[\"Role\"][\"RoleName\"], PolicyArn=\"arn:aws:iam::aws:policy/AmazonS3FullAccess\"\n", ")\n", "\n", "iam_client.attach_role_policy(\n", " RoleName=response[\"Role\"][\"RoleName\"],\n", " PolicyArn=\"arn:aws:iam::aws:policy/service-role/AWSGlueServiceRole\",\n", ")" ] }, { "cell_type": "markdown", "id": "4e788adf", "metadata": {}, "source": [ "We create IAM role AmazonSageMakerServiceCatalogProductsUseRole-restate." ] }, { "cell_type": "code", "execution_count": null, "id": "c5f63cb8", "metadata": {}, "outputs": [], "source": [ "sagemaker_assume_role_policy_document = json.dumps(\n", " {\n", " \"Version\": \"2012-10-17\",\n", " \"Statement\": [\n", " {\n", " \"Effect\": \"Allow\",\n", " \"Principal\": {\"Service\": \"sagemaker.amazonaws.com\"},\n", " \"Action\": \"sts:AssumeRole\",\n", " }\n", " ],\n", " }\n", ")\n", "\n", "response = iam_client.create_role(\n", " RoleName=\"AmazonSageMakerServiceCatalogProductsUseRole-restate\",\n", " AssumeRolePolicyDocument=sagemaker_assume_role_policy_document,\n", ")\n", "\n", "iam_client.attach_role_policy(\n", " RoleName=response[\"Role\"][\"RoleName\"],\n", " PolicyArn=\"arn:aws:iam::aws:policy/AmazonAthenaFullAccess\",\n", ")\n", "\n", "iam_client.attach_role_policy(\n", " RoleName=response[\"Role\"][\"RoleName\"],\n", " PolicyArn=\"arn:aws:iam::aws:policy/AmazonSageMakerFullAccess\",\n", ")" ] }, { "cell_type": "markdown", "id": "fa76cff5", "metadata": {}, "source": [ "## Prepare Athena table" ] }, { "cell_type": "markdown", "id": "a6bbd97e", "metadata": {}, "source": [ "At this point, it is assumed that S3 bucket sagemaker-restate-`` and the necessary IAM roles are created. For the complete list of prerequisites, please see [README.md](README.md). \n", "\n", "We move the raw data to S3 bucket sagemaker-restate-``." ] }, { "cell_type": "code", "execution_count": null, "id": "7d2b8251", "metadata": {}, "outputs": [], "source": [ "%%sh\n", "\n", "AWS_ACCOUNT=$(aws sts get-caller-identity --query Account --output text)\n", "BUCKET_NAME=\"sagemaker-restate-${AWS_ACCOUNT}\"\n", "\n", "aws s3 cp s3://sagemaker-sample-files/datasets/tabular/california_housing/cal_housing.tgz .\n", "tar -zxf cal_housing.tgz -o\n", "aws s3 cp CaliforniaHousing/cal_housing.data s3://${BUCKET_NAME}/raw/california/\n", " \n", "\n", "\n" ] }, { "cell_type": "markdown", "id": "f5b4ff13", "metadata": {}, "source": [ "The step below creates a Glue database and table containing the raw data by running a Glue crawler. It is recommended to configure [Glue encryption](https://docs.aws.amazon.com/athena/latest/ug/querying.html#query-results-specify-location) for additional security. " ] }, { "cell_type": "code", "execution_count": null, "id": "8c5eddd6", "metadata": {}, "outputs": [], "source": [ "import boto3\n", "\n", "AWS_ACCOUNT = boto3.client(\"sts\").get_caller_identity()[\"Account\"]\n", "BUCKET_NAME = \"sagemaker-restate-{AWS_ACCOUNT}\".format(AWS_ACCOUNT=AWS_ACCOUNT)\n", "DATABASE_NAME = \"restate\"\n", "TABLE_NAME = \"california\"\n", "\n", "glue_client = boto3.client(\"glue\")\n", "\n", "try:\n", " response = glue_client.create_database(DatabaseInput={\"Name\": DATABASE_NAME})\n", " print(\"Successfully created database\")\n", "except Exception as e:\n", " print(\"Error in creating database: {ERROR}\".format(ERROR=e))" ] }, { "cell_type": "code", "execution_count": null, "id": "d69764d7", "metadata": {}, "outputs": [], "source": [ "# This assumes the Glue service role name is AWSGlueServiceRole-restate\n", "try:\n", " response = glue_client.create_crawler(\n", " Name=\"{DATABASE_NAME}-{TABLE_NAME}\".format(\n", " DATABASE_NAME=DATABASE_NAME, TABLE_NAME=TABLE_NAME\n", " ),\n", " Role=\"AWSGlueServiceRole-restate\",\n", " DatabaseName=DATABASE_NAME,\n", " Targets={\n", " \"S3Targets\": [\n", " {\n", " \"Path\": \"s3://{BUCKET_NAME}/raw/california/\".format(BUCKET_NAME=BUCKET_NAME),\n", " }\n", " ]\n", " },\n", " )\n", " print(\"Successfully created crawler\")\n", "except Exception as e:\n", " print(\"Error in creating crawler: {ERROR}\".format(ERROR=e))" ] }, { "cell_type": "code", "execution_count": null, "id": "211f8840", "metadata": {}, "outputs": [], "source": [ "try:\n", " response = glue_client.start_crawler(\n", " Name=\"{DATABASE_NAME}-{TABLE_NAME}\".format(\n", " DATABASE_NAME=DATABASE_NAME, TABLE_NAME=TABLE_NAME\n", " )\n", " )\n", " print(\"Successfully started crawler\")\n", "except Exception as e:\n", " print(\"Error in starting crawler: {ERROR}\".format(ERROR=e))" ] }, { "cell_type": "markdown", "id": "e7fa9be8", "metadata": {}, "source": [ "Once crawler is done crawling, table `california` in database `restate` should be visible in Glue catalog. We rename the Glue table columns for readability. " ] }, { "cell_type": "code", "execution_count": null, "id": "5b7f5a52", "metadata": {}, "outputs": [], "source": [ "import time\n", "\n", "while True:\n", " crawler = glue_client.get_crawler(\n", " Name=\"{DATABASE_NAME}-{TABLE_NAME}\".format(\n", " DATABASE_NAME=DATABASE_NAME, TABLE_NAME=TABLE_NAME\n", " )\n", " )\n", " if crawler[\"Crawler\"][\"State\"] == \"READY\":\n", " break\n", " print(\"Waiting for the crawler run to be completed..\")\n", " time.sleep(60)\n", "\n", "response = glue_client.get_table(DatabaseName=DATABASE_NAME, Name=TABLE_NAME)\n", "glue_table = response[\"Table\"]\n", "glue_table[\"StorageDescriptor\"][\"Columns\"][0][\"Name\"] = \"longitude\"\n", "glue_table[\"StorageDescriptor\"][\"Columns\"][1][\"Name\"] = \"latitude\"\n", "glue_table[\"StorageDescriptor\"][\"Columns\"][2][\"Name\"] = \"housingMedianAge\"\n", "glue_table[\"StorageDescriptor\"][\"Columns\"][3][\"Name\"] = \"totalRooms\"\n", "glue_table[\"StorageDescriptor\"][\"Columns\"][4][\"Name\"] = \"totalBedrooms\"\n", "glue_table[\"StorageDescriptor\"][\"Columns\"][5][\"Name\"] = \"population\"\n", "glue_table[\"StorageDescriptor\"][\"Columns\"][6][\"Name\"] = \"households\"\n", "glue_table[\"StorageDescriptor\"][\"Columns\"][7][\"Name\"] = \"medianIncome\"\n", "glue_table[\"StorageDescriptor\"][\"Columns\"][8][\"Name\"] = \"medianHouseValue\"\n", "glue_client.update_table(\n", " DatabaseName=DATABASE_NAME,\n", " TableInput={\"Name\": TABLE_NAME, \"StorageDescriptor\": glue_table[\"StorageDescriptor\"]},\n", ")" ] }, { "cell_type": "markdown", "id": "7ee75f05", "metadata": {}, "source": [ "Table `california` in database `restate` should be visible in Athena. We filter only the data where housingmedianage > 10. \n", "\n", "Make sure Athena [query result location](https://docs.aws.amazon.com/athena/latest/ug/querying.html#query-results-specify-location) and [encryption settings](https://docs.aws.amazon.com/athena/latest/ug/encrypting-query-results-stored-in-s3.html) are updated accordingly before proceeding to the next step. " ] }, { "cell_type": "code", "execution_count": null, "id": "e58cbfa1", "metadata": {}, "outputs": [], "source": [ "query = \"CREATE TABLE restate.california_10 AS SELECT * FROM restate.california where housingmedianage > 10;\"\n", "output = \"s3://{BUCKET_NAME}/athena\".format(BUCKET_NAME=BUCKET_NAME)\n", "\n", "athena_client = boto3.client(\"athena\")\n", "\n", "try:\n", " response = athena_client.start_query_execution(\n", " QueryString=query,\n", " QueryExecutionContext={\"Database\": DATABASE_NAME},\n", " ResultConfiguration={\n", " \"OutputLocation\": output,\n", " },\n", " )\n", "except Exception as e:\n", " print(\"Error running the query: {ERROR}\".format(ERROR=e))" ] }, { "cell_type": "markdown", "id": "d9eeccb3", "metadata": {}, "source": [ "## Prepare Decision Tree custom Docker image" ] }, { "cell_type": "markdown", "id": "bb6ca02b", "metadata": {}, "source": [ "We make a Docker image containing a custom algorithm using [Scikit-learn Decision Tree Regressor](https://scikit-learn.org/stable/modules/generated/sklearn.tree.DecisionTreeRegressor.html#sklearn.tree.DecisionTreeRegressor). Note that the Docker image has been modified to support hyperparameter tuning and validation data. \n", "\n" ] }, { "cell_type": "code", "execution_count": null, "id": "7c6490d2", "metadata": {}, "outputs": [], "source": [ "! sudo yum install docker -y" ] }, { "cell_type": "code", "execution_count": null, "id": "13da2f21", "metadata": {}, "outputs": [], "source": [ "%%sh\n", "\n", "# The name of our algorithm\n", "ALGORITHM_NAME=restate-decision-trees\n", "\n", "cd container\n", "\n", "chmod +x decision_trees/train\n", "chmod +x decision_trees/serve\n", "\n", "AWS_ACCOUNT=$(aws sts get-caller-identity --query Account --output text)\n", "AWS_REGION=$(aws configure get region)\n", "\n", "IMAGE_FULLNAME=\"${AWS_ACCOUNT}.dkr.ecr.${AWS_REGION}.amazonaws.com/${ALGORITHM_NAME}:latest\"\n", "\n", "# If the repository doesn't exist in ECR, create it.\n", "aws ecr describe-repositories --repository-names \"${ALGORITHM_NAME}\" > /dev/null 2>&1\n", "\n", "if [ $? -ne 0 ]\n", "then\n", " aws ecr create-repository --repository-name \"${ALGORITHM_NAME}\" > /dev/null\n", "fi\n", "\n", "# Get the login command from ECR and execute it directly\n", "aws ecr get-login-password --region ${AWS_REGION}|docker login --username AWS --password-stdin ${IMAGE_FULLNAME}\n", "\n", "# Build the docker image locally with the image name and then push it to ECR\n", "# with the full name.\n", "\n", "docker build -t ${ALGORITHM_NAME} .\n", "docker tag ${ALGORITHM_NAME} ${IMAGE_FULLNAME}\n", "docker push ${IMAGE_FULLNAME}\n" ] }, { "cell_type": "markdown", "id": "850ff88b", "metadata": {}, "source": [ "Once Docker image is pushed to ECR repository, we make the image accessible from SageMaker. " ] }, { "cell_type": "code", "execution_count": null, "id": "c015ffe0", "metadata": {}, "outputs": [], "source": [ "%%sh\n", "\n", "# The name of our algorithm\n", "SM_IMAGE_NAME=restate-dtree\n", "AWS_ACCOUNT=$(aws sts get-caller-identity --query Account --output text)\n", "\n", "# This assumes the role name is AmazonSageMakerServiceCatalogProductsUseRole-restate\n", "ROLE_ARN=\"arn:aws:iam::${AWS_ACCOUNT}:role/AmazonSageMakerServiceCatalogProductsUseRole-restate\"\n", "\n", "aws sagemaker create-image \\\n", " --image-name ${SM_IMAGE_NAME} \\\n", " --role-arn ${ROLE_ARN}\n" ] }, { "cell_type": "code", "execution_count": null, "id": "52276585", "metadata": {}, "outputs": [], "source": [ "%%sh\n", "AWS_ACCOUNT=$(aws sts get-caller-identity --query Account --output text)\n", "ALGORITHM_NAME=restate-decision-trees\n", "AWS_REGION=$(aws configure get region)\n", "SM_IMAGE_NAME=restate-dtree\n", "SM_BASE_IMAGE=\"${AWS_ACCOUNT}.dkr.ecr.${AWS_REGION}.amazonaws.com/${ALGORITHM_NAME}:latest\"\n", "\n", "aws sagemaker create-image-version \\\n", " --image-name ${SM_IMAGE_NAME} \\\n", " --base-image ${SM_BASE_IMAGE}" ] }, { "cell_type": "markdown", "id": "11a7aeab", "metadata": {}, "source": [ "## Start the SageMaker pipeline" ] }, { "cell_type": "markdown", "id": "1c96ea8d", "metadata": {}, "source": [ "Manually update `restate-athena-california.flow` with the `queryString` and `s3OutputLocation` of your choice. This has to be done outside of this Jupyter notebook. Once done, proceed to create your pipeline. " ] }, { "cell_type": "code", "execution_count": null, "id": "c27b9942", "metadata": {}, "outputs": [], "source": [ "! pip install sagemaker-pipeline/" ] }, { "cell_type": "markdown", "id": "77b43f2d", "metadata": {}, "source": [ "Verify that you can successfully run `get-pipeline-definition`." ] }, { "cell_type": "code", "execution_count": null, "id": "5a0dc2f1", "metadata": {}, "outputs": [], "source": [ "! get-pipeline-definition --help" ] }, { "cell_type": "markdown", "id": "627ed995", "metadata": {}, "source": [ "At this point, it is assumed that you have already created a SageMaker project with a name `restate` and a pipeline with a name `sagemaker-restate`." ] }, { "cell_type": "code", "execution_count": null, "id": "ee17359c", "metadata": {}, "outputs": [], "source": [ "%%sh\n", "\n", "# This assumes the SageMaker pipeline role name is AmazonSageMakerServiceCatalogProductsUseRole-restate\n", "\n", "AWS_ACCOUNT=$(aws sts get-caller-identity --query Account --output text)\n", "AWS_REGION=$(aws configure get region)\n", "SAGEMAKER_PROJECT_NAME=restate\n", "SAGEMAKER_PROJECT_ID=$(aws sagemaker describe-project --project-name ${SAGEMAKER_PROJECT_NAME} --query 'ProjectId' | tr -d '\"')\n", "echo ${SAGEMAKER_PROJECT_ID}\n", "SAGEMAKER_PROJECT_ARN=\"arn:aws:sagemaker:${AWS_REGION}:${AWS_ACCOUNT}:project/${SAGEMAKER_PROJECT_NAME}\"\n", "SAGEMAKER_PIPELINE_ROLE_ARN=\"arn:aws:iam::${AWS_ACCOUNT}:role/AmazonSageMakerServiceCatalogProductsUseRole-restate\"\n", "SAGEMAKER_PIPELINE_NAME=\"sagemaker-${SAGEMAKER_PROJECT_NAME}\"\n", "ARTIFACT_BUCKET=\"sagemaker-project-${SAGEMAKER_PROJECT_ID}\"\n", "SAGEMAKER_PROJECT_NAME_ID=\"${SAGEMAKER_PROJECT_NAME}-${SAGEMAKER_PROJECT_ID}\"\n", "\n", "run-pipeline --module-name pipelines.restate.pipeline \\\n", " --role-arn $SAGEMAKER_PIPELINE_ROLE_ARN \\\n", " --tags \"[{\\\"Key\\\":\\\"sagemaker:project-name\\\", \\\"Value\\\":\\\"${SAGEMAKER_PROJECT_NAME}\\\"}, {\\\"Key\\\":\\\"sagemaker:project-id\\\", \\\"Value\\\":\\\"${SAGEMAKER_PROJECT_ID}\\\"}]\" \\\n", " --kwargs \"{\\\"region\\\":\\\"${AWS_REGION}\\\",\\\"sagemaker_project_arn\\\":\\\"${SAGEMAKER_PROJECT_ARN}\\\",\\\"role\\\":\\\"${SAGEMAKER_PIPELINE_ROLE_ARN}\\\",\\\"default_bucket\\\":\\\"${ARTIFACT_BUCKET}\\\",\\\"pipeline_name\\\":\\\"${SAGEMAKER_PROJECT_NAME_ID}\\\",\\\"model_package_group_name\\\":\\\"${SAGEMAKER_PROJECT_NAME_ID}\\\",\\\"base_job_prefix\\\":\\\"${SAGEMAKER_PROJECT_NAME_ID}\\\"}\"\n" ] }, { "cell_type": "markdown", "id": "45e7ec6d", "metadata": {}, "source": [ "If you inspect the pipeline, you will see that the XGBoost model performs better than the decision tree model. Therefore, the XGBoost model is registered in the model registry." ] }, { "cell_type": "markdown", "id": "64a114d4", "metadata": {}, "source": [ "You can experiment on the data, e.g. use data for `housingmedianage > 50`, by changing the Athena query in `restate-athena-california.flow`. You can check if XGBoost would still be the winning model after these changes." ] }, { "cell_type": "markdown", "id": "3bb3d1e7", "metadata": {}, "source": [ "## Deploy the winning model" ] }, { "cell_type": "markdown", "id": "e231c14f", "metadata": {}, "source": [ "Make sure to update your desired `MODEL_VERSION`. We assume we approve the model version 1. " ] }, { "cell_type": "code", "execution_count": null, "id": "e3eede51", "metadata": {}, "outputs": [], "source": [ "from sagemaker import get_execution_role, session\n", "import boto3\n", "\n", "role = get_execution_role()\n", "sm_client = boto3.client(\"sagemaker\")\n", "\n", "MODEL_VERSION = \"1\"\n", "SAGEMAKER_PROJECT_NAME = \"restate\"\n", "SAGEMAKER_PROJECT_ID = sm_client.describe_project(ProjectName=SAGEMAKER_PROJECT_NAME)[\"ProjectId\"]\n", "AWS_REGION = boto3.Session().region_name\n", "MODEL_PACKAGE_ARN = \"arn:aws:sagemaker:{AWS_REGION}:{AWS_ACCOUNT}:model-package/{SAGEMAKER_PROJECT_NAME}-{SAGEMAKER_PROJECT_ID}/{MODEL_VERSION}\".format(\n", " AWS_REGION=AWS_REGION,\n", " AWS_ACCOUNT=AWS_ACCOUNT,\n", " SAGEMAKER_PROJECT_NAME=SAGEMAKER_PROJECT_NAME,\n", " SAGEMAKER_PROJECT_ID=SAGEMAKER_PROJECT_ID,\n", " MODEL_VERSION=MODEL_VERSION,\n", ")\n", "\n", "\n", "model_package_update_response = sm_client.update_model_package(\n", " ModelPackageArn=MODEL_PACKAGE_ARN, ModelApprovalStatus=\"Approved\"\n", ")" ] }, { "cell_type": "markdown", "id": "022ab8c5", "metadata": {}, "source": [ "At this point, you can deploy the approved model version by going through the steps below, or using [MLOps template for model deployment](https://docs.aws.amazon.com/sagemaker/latest/dg/sagemaker-projects-templates-sm.html#sagemaker-projects-templates-code-commit)." ] }, { "cell_type": "code", "execution_count": null, "id": "2f18b157", "metadata": {}, "outputs": [], "source": [ "from time import gmtime, strftime\n", "\n", "model_name = \"restate-modelregistry-model-\" + strftime(\"%Y-%m-%d-%H-%M-%S\", gmtime())\n", "print(\"Model name : {}\".format(model_name))\n", "container_list = [{\"ModelPackageName\": MODEL_PACKAGE_ARN}]\n", "\n", "create_model_response = sm_client.create_model(\n", " ModelName=model_name, ExecutionRoleArn=role, Containers=container_list\n", ")\n", "print(\"Model arn : {}\".format(create_model_response[\"ModelArn\"]))" ] }, { "cell_type": "code", "execution_count": null, "id": "fc00b181", "metadata": {}, "outputs": [], "source": [ "endpoint_config_name = \"restate-modelregistry-EndpointConfig-\" + strftime(\n", " \"%Y-%m-%d-%H-%M-%S\", gmtime()\n", ")\n", "print(endpoint_config_name)\n", "create_endpoint_config_response = sm_client.create_endpoint_config(\n", " EndpointConfigName=endpoint_config_name,\n", " ProductionVariants=[\n", " {\n", " \"InstanceType\": \"ml.m5.large\",\n", " \"InitialVariantWeight\": 1,\n", " \"InitialInstanceCount\": 1,\n", " \"ModelName\": model_name,\n", " \"VariantName\": \"AllTraffic\",\n", " }\n", " ],\n", ")" ] }, { "cell_type": "code", "execution_count": null, "id": "d66d73ce", "metadata": {}, "outputs": [], "source": [ "endpoint_name = \"restate-staging\"\n", "print(\"EndpointName={}\".format(endpoint_name))\n", "\n", "create_endpoint_response = sm_client.create_endpoint(\n", " EndpointName=endpoint_name, EndpointConfigName=endpoint_config_name\n", ")\n", "\n", "\n", "while True:\n", " endpoint = sm_client.describe_endpoint(EndpointName=endpoint_name)\n", " if endpoint[\"EndpointStatus\"] == \"InService\":\n", " break\n", " print(\"Waiting for the endpoint to be completed..\")\n", " time.sleep(60)\n", "\n", "print(\"Endpoint arn : {}\".format(create_endpoint_response[\"EndpointArn\"]))" ] }, { "cell_type": "markdown", "id": "021946b6", "metadata": {}, "source": [ "## Inference" ] }, { "cell_type": "markdown", "id": "0502e43c", "metadata": {}, "source": [ "Use the following data for inference:\n", "\n", "`-117.18,32.75,52.0,1504.0,208.0,518.0,196.0`\n", "\n", "This is a census block group with longitude -117.18, latitude 32.75, housing median age of 52.0, total rooms of 1504, total bedrooms of 208, population of 518, and households count of 196.\n", "\n", "Let's see its predicted value using our generated model." ] }, { "cell_type": "code", "execution_count": null, "id": "c73eda3a", "metadata": {}, "outputs": [], "source": [ "import json\n", "\n", "sm_runtime = boto3.client(\"runtime.sagemaker\")\n", "line = \"-117.18,32.75,52.0,1504.0,208.0,518.0,196.0\"\n", "response = sm_runtime.invoke_endpoint(EndpointName=endpoint_name, ContentType=\"text/csv\", Body=line)\n", "result = json.loads(response[\"Body\"].read().decode())\n", "print(result)" ] }, { "cell_type": "markdown", "id": "8a987778", "metadata": {}, "source": [ "Now you try:\n", "\n", "`-117.17,32.76,45.0,3149.0,639.0,1160.0,661.0`\n", "\n", "This is a census block group with longitude -117.17, latitude 32.76, housing median age of 45.0, total rooms of 3149, total bedrooms of 639, population of 1160, and households count of 661.\n" ] }, { "cell_type": "markdown", "id": "e0fd938d", "metadata": {}, "source": [ "## Cleanup" ] }, { "cell_type": "markdown", "id": "d4d881bb", "metadata": {}, "source": [ "Cleanup the Glue database, table, crawler, and S3 buckets used. " ] }, { "cell_type": "markdown", "id": "40ec7c56", "metadata": {}, "source": [ "Cleanup the ECR and SageMaker images created." ] }, { "cell_type": "markdown", "id": "3ad36ddb", "metadata": {}, "source": [ "Cleanup the SageMaker model and endpoint resources. " ] }, { "cell_type": "code", "execution_count": null, "id": "9a3706a6", "metadata": {}, "outputs": [], "source": [ "sm_client.delete_endpoint(EndpointName=endpoint_name)\n", "sm_client.delete_endpoint_config(EndpointConfigName=endpoint_config_name)\n", "sm_client.delete_model(ModelName=model_name)" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "## Notebook CI Test Results\n", "\n", "This notebook was tested in multiple regions. The test results are as follows, except for us-west-2 which is shown at the top of the notebook.\n", "\n", "![This us-east-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/us-east-1/sagemaker-pipeline-multi-model|restate-project.ipynb)\n", "\n", "![This us-east-2 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/us-east-2/sagemaker-pipeline-multi-model|restate-project.ipynb)\n", "\n", "![This us-west-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/us-west-1/sagemaker-pipeline-multi-model|restate-project.ipynb)\n", "\n", "![This ca-central-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/ca-central-1/sagemaker-pipeline-multi-model|restate-project.ipynb)\n", "\n", "![This sa-east-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/sa-east-1/sagemaker-pipeline-multi-model|restate-project.ipynb)\n", "\n", "![This eu-west-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/eu-west-1/sagemaker-pipeline-multi-model|restate-project.ipynb)\n", "\n", "![This eu-west-2 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/eu-west-2/sagemaker-pipeline-multi-model|restate-project.ipynb)\n", "\n", "![This eu-west-3 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/eu-west-3/sagemaker-pipeline-multi-model|restate-project.ipynb)\n", "\n", "![This eu-central-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/eu-central-1/sagemaker-pipeline-multi-model|restate-project.ipynb)\n", "\n", "![This eu-north-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/eu-north-1/sagemaker-pipeline-multi-model|restate-project.ipynb)\n", "\n", "![This ap-southeast-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/ap-southeast-1/sagemaker-pipeline-multi-model|restate-project.ipynb)\n", "\n", "![This ap-southeast-2 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/ap-southeast-2/sagemaker-pipeline-multi-model|restate-project.ipynb)\n", "\n", "![This ap-northeast-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/ap-northeast-1/sagemaker-pipeline-multi-model|restate-project.ipynb)\n", "\n", "![This ap-northeast-2 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/ap-northeast-2/sagemaker-pipeline-multi-model|restate-project.ipynb)\n", "\n", "![This ap-south-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/ap-south-1/sagemaker-pipeline-multi-model|restate-project.ipynb)\n" ] } ], "metadata": { "kernelspec": { "display_name": "conda_mxnet_latest_p37", "language": "python", "name": "conda_mxnet_latest_p37" }, "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": 5 }