{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Automate Retraining of Models using SageMaker Pipelines\n", "\n", "# Learning Objectives\n", "1. Construct a [SageMaker Pipeline](https://aws.amazon.com/sagemaker/pipelines/) that consists of a data preprocessing step and a model training step.\n", "2. Execute a SageMaker Pipeline manually\n", "3. (optional) Build infrastructure, using [CloudFormation](https://aws.amazon.com/cloudformation/) and [AWS Lambda](https://aws.amazon.com/lambda/) to allow the Pipeline steps be executed in an event-driven manner when new data is dropped in S3.\n", "\n", "\n", "## Introduction\n", "This workshop shows how you can build and deploy SageMaker Pipelines for multistep processes. In this example, we will build a pipeline that:\n", "\n", " 1. Deduplicates the underlying data\n", " \n", " 2. Trains a built-in SageMaker algorithm (XGBoost) \n", "\n", "A common workflow is that models need to be retrained when new data arrives. This notebook also shows how you can set up a Lambda function that will retrigger the retraining pipeline when new data comes in.\n", "\n", "Please use the `Python 3 (Data Science)` kernel for this workshop." ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "import boto3\n", "import json\n", "import logging\n", "import os\n", "import pandas\n", "import sagemaker\n", "from sagemaker.workflow.parameters import ParameterString\n", "from sagemaker.workflow.steps import ProcessingStep, TrainingStep\n", "from sagemaker.sklearn.processing import SKLearnProcessor\n", "from sagemaker.workflow.pipeline import Pipeline\n", "from sagemaker.inputs import TrainingInput\n", "from sagemaker.processing import ProcessingInput, ProcessingOutput\n", "from sagemaker.estimator import Estimator\n", "from time import gmtime, strftime\n", "\n", "# set logs if not done already\n", "logger = logging.getLogger(\"log\")\n", "if not logger.handlers:\n", " logger.setLevel(logging.INFO)\n", " logger.addHandler(logging.StreamHandler())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "First, get permissions and other information. We will also create a pipeline name" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "session = sagemaker.Session()\n", "default_bucket = session.default_bucket()\n", "role = sagemaker.get_execution_role()\n", "region = boto3.Session().region_name\n", "s3_client = boto3.client(\"s3\", region_name=region)\n", "\n", "current_timestamp = strftime(\"%m-%d-%H-%M\", gmtime())\n", "pipeline_name = f\"my-pipeline-{current_timestamp}\"\n", "prefix = f\"pipeline-lab{current_timestamp}\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Transfer Data into Your Account" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "copy_source = {\n", " \"Bucket\": \"aws-hcls-ml\",\n", " \"Key\": \"workshop/immersion_day_workshop_data_DO_NOT_DELETE/data/ObesityDataSet_with_duplicates.csv\",\n", "}\n", "s3_client.copy(\n", " copy_source, default_bucket, f\"{prefix}/ObesityDataSet_with_duplicates.csv\"\n", ")\n", "\n", "copy_source = {\n", " \"Bucket\": \"aws-hcls-ml\",\n", " \"Key\": \"workshop/immersion_day_workshop_data_DO_NOT_DELETE/kick_off_sagemaker_pipelines_lambda/other_material/lambda.zip\",\n", "}\n", "s3_client.copy(copy_source, default_bucket, f\"{prefix}/lambda.zip\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Define the Pipeline\n", "\n", "First we will create a preprocessing step. The preprocessing step simply removes duplicated rows from the dataset. The `preprocessing.py` script will be written locally, and then built as a SageMaker Pipelines step." ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "input_data = ParameterString(\n", " name=\"InputData\",\n", " default_value=f\"s3://{default_bucket}/{prefix}/ObesityDataSet_with_duplicates.csv\",\n", ")" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Writing preprocessing.py\n" ] } ], "source": [ "%%writefile preprocessing.py\n", "import pandas\n", "import os\n", "base_dir = \"/opt/ml/processing/input\"\n", "the_files = os.listdir(base_dir)\n", "the_file=[i for i in the_files if \".csv\" in i][0] #get the first csv\n", "print(the_file)\n", "df_1=pandas.read_csv(f'{base_dir}/{the_file}',engine='python')\n", "df_2=df_1.drop_duplicates()\n", "df_2.to_csv(f'/opt/ml/processing/output/deduped_{the_file}.csv') \n" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [], "source": [ "# Specify the container and framework options\n", "\n", "sklearn_processor = SKLearnProcessor(\n", " framework_version=\"0.23-1\",\n", " instance_type=\"ml.t3.medium\",\n", " instance_count=1,\n", " base_job_name=\"sklearn-abalone-process\",\n", " role=role,\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now will will turn the preprocessing step as a SageMaker Processing Step with SageMaker Pipelines." ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [], "source": [ "step_process = ProcessingStep(\n", " name=\"deduplication-process\",\n", " processor=sklearn_processor,\n", " inputs=[\n", " ProcessingInput(source=input_data, destination=\"/opt/ml/processing/input\"),\n", " ],\n", " outputs=[\n", " ProcessingOutput(output_name=\"deduplicated\", source=\"/opt/ml/processing/output\")\n", " ],\n", " code=\"preprocessing.py\",\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Define the Model\n", "Now we will create a SageMaker model. We will use the SageMaker built-in XGBoost Algorithm." ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [], "source": [ "# Define the model training parameters\n", "model_path = f\"s3://{default_bucket}/{prefix}/myPipelineTrain\"\n", "\n", "image_uri = sagemaker.image_uris.retrieve(\n", " framework=\"xgboost\",\n", " region=region,\n", " version=\"1.0-1\",\n", " py_version=\"py3\",\n", " instance_type=\"ml.m5.large\",\n", ")\n", "xgb_train = Estimator(\n", " image_uri=image_uri,\n", " instance_type=\"ml.m5.large\",\n", " instance_count=1,\n", " output_path=model_path,\n", " role=role,\n", ")\n", "xgb_train.set_hyperparameters(\n", " objective=\"reg:linear\",\n", " num_round=50,\n", " max_depth=5,\n", " eta=0.2,\n", " gamma=4,\n", " min_child_weight=6,\n", " subsample=0.7,\n", " silent=0,\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Turn the model training into a SageMaker Pipeline Training Step." ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [], "source": [ "# Define the training steps\n", "\n", "step_train = TrainingStep(\n", " name=\"model-training\",\n", " estimator=xgb_train,\n", " inputs={\n", " \"train\": TrainingInput(\n", " s3_data=step_process.properties.ProcessingOutputConfig.Outputs[\n", " \"deduplicated\"\n", " ].S3Output.S3Uri,\n", " content_type=\"text/csv\",\n", " ),\n", " \"validation\": TrainingInput(\n", " s3_data=step_process.properties.ProcessingOutputConfig.Outputs[\n", " \"deduplicated\"\n", " ].S3Output.S3Uri,\n", " content_type=\"text/csv\",\n", " ),\n", " },\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Create the Pipeline" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'PipelineArn': 'arn:aws:sagemaker:us-east-1:111918798052:pipeline/obesitymodelretrainingpipeline',\n", " 'ResponseMetadata': {'RequestId': '3d83e959-f472-41e1-bca3-e518d87770d1',\n", " 'HTTPStatusCode': 200,\n", " 'HTTPHeaders': {'x-amzn-requestid': '3d83e959-f472-41e1-bca3-e518d87770d1',\n", " 'content-type': 'application/x-amz-json-1.1',\n", " 'content-length': '98',\n", " 'date': 'Mon, 30 Jan 2023 15:09:38 GMT'},\n", " 'RetryAttempts': 0}}" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Create a two-step data processing and model training pipeline\n", "\n", "pipeline_name = \"ObesityModelRetrainingPipeLine\"\n", "pipeline = Pipeline(\n", " name=pipeline_name,\n", " parameters=[\n", " input_data,\n", " ],\n", " steps=[step_process, step_train],\n", ")\n", "pipeline.upsert(role_arn=role)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Run the Pipeline On Separate Files" ] }, { "cell_type": "markdown", "metadata": { "tags": [] }, "source": [ "### Execution 1" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [], "source": [ "\n", "s3uri=f\"s3://{default_bucket}/{prefix}/ObesityDataSet_with_duplicates.csv\"\n", "client = boto3.client(\"sagemaker\")\n", "PipelineParameters = [\n", " {\"Name\": \"InputData\", \"Value\": f\"{s3uri}\"},\n", "]\n", "response = client.start_pipeline_execution(\n", " PipelineName=pipeline_name, PipelineParameters=PipelineParameters\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Execution 2" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [], "source": [ "copy_source = {\n", " \"Bucket\": \"aws-hcls-ml\",\n", " \"Key\": \"workshop/immersion_day_workshop_data_DO_NOT_DELETE/data/ObesityDataSet_with_duplicates.csv\",\n", "}\n", "s3_client.copy(\n", " copy_source, default_bucket, f\"{prefix}/Second_File_ObesityDataSet_with_duplicates.csv\"\n", ")\n" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [], "source": [ "second_s3uri=s3uri=f\"s3://{default_bucket}/{prefix}/Second_File_ObesityDataSet_with_duplicates.csv\"\n", "PipelineParameters = [\n", " {\"Name\": \"InputData\", \"Value\": f\"{second_s3uri}\"},\n", "]\n", "response = client.start_pipeline_execution(\n", " PipelineName=pipeline_name, PipelineParameters=PipelineParameters\n", ")" ] }, { "attachments": { "image.png": { "image/png": "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" } }, "cell_type": "markdown", "metadata": {}, "source": [ "## (Optional) Deploy a CloudFormation Template to retrain the Pipeline\n", "\n", "Now we will deploy a cloudformation template that will allow for automated calling of the Pipeline when new files are dropped in an S3 bucket.\n", "\n", "The architecture looks like this:\n", "\n", "![image.png](attachment:image.png)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "NOTE: In order to run the following steps you must first associate the following IAM policies to your SageMaker execution role:\n", "- cloudformation:CreateStack\n", "- cloudformation:DeleteStack\n", "- cloudformation:DescribeStacks\n", "- iam:CreateRole\n", "- iam:DeleteRole\n", "- iam:DeleteRolePolicy\n", "- iam:GetRole\n", "- iam:GetRolePolicy\n", "- iam:PassRole\n", "- iam:PutRolePolicy\n", "- lambda:AddPermission\n", "- lambda:CreateFunction\n", "- lambda:GetFunction\n", "- lambda:DeleteFuncton" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Create a new CloudFormation stack to trigger retraining with new data\n", "\n", "stack_name = \"sagemaker-automated-retraining\"\n", "\n", "with open(\"cfn_sagemaker_pipelines.yaml\") as f:\n", " template_str = f.read()\n", "cfn = boto3.client(\"cloudformation\")\n", "cfn.create_stack(\n", " StackName=stack_name,\n", " TemplateBody=template_str,\n", " Capabilities=[\"CAPABILITY_IAM\"],\n", " Parameters=[\n", " {\"ParameterKey\": \"StaticCodeBucket\", \"ParameterValue\": default_bucket},\n", " {\"ParameterKey\": \"StaticCodeKey\", \"ParameterValue\": f\"{prefix}/lambda.zip\"},\n", " ],\n", ")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Wait until stack creation is complete\n", "waiter = cfn.get_waiter(\"stack_create_complete\")\n", "waiter.wait(StackName=stack_name)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Identify the S3 bucket for triggering the training pipeline\n", "input_bucket_name = cfn.describe_stacks(StackName=stack_name)[\"Stacks\"][0][\"Outputs\"][0][\"OutputValue\"]" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Copy the training data to the input bucket to start a new pipeline execution\n", "copy_source = {\n", " \"Bucket\": default_bucket,\n", " \"Key\": f\"{prefix}/ObesityDataSet_with_duplicates.csv\",\n", "}\n", "s3_client.copy(copy_source, input_bucket_name, \"ObesityDataSet_with_duplicates.csv\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### (Optional)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "1. Inspect that the `InputBucket` has new data\n", "2. Examine the `SageMaker Pipelines` execution from the SageMaker Studio console" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#!aws s3 rm --recursive s3://{input_bucket_name}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Closing" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In this notebook we demonstrated how to create a SageMaker pipeline for data processing and model training and triggered it using an S3 event." ] } ], "metadata": { "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 }