From 61fc76f5a493021ad7ca07444822207868dbdf0e Mon Sep 17 00:00:00 2001 From: "Ehsan M. Kermani" <6980212+ehsanmok@users.noreply.github.com> Date: Wed, 26 May 2021 17:31:03 -0700 Subject: [PATCH] Add SageMaker Studio support (#32) * Init studio support Fix build Fix assert syntax error Update README Init IAM prune Reformat Tighten permissions and bind with unique prefix Update build Update README Add pyproject.toml Cleanup Pin black version in build and cleanup Improve onboarding and various cleanups Update README for SageMaker Studio Update project prefix description Find the custom resource stack deletion Remove unnecessary return None Fix datacapture uri and remove canary Remove canary.js Update canary deployment descriptions * Address comments Update docs Remove synthetics windonw from dashboard Tag pipeline with sagemaker project id and format Fix retrain rule Include necessary permissions to run worflow.ipynb Update README Setup pre-commit to lint and add default kernel Fix trailing newline Update README with one-click button Cleanup Update project tree structure in README Remove dev artifacts from build Update README --- .gitignore | 4 + .pre-commit-config.yaml | 16 + LICENSE | 1 - README.md | 94 +- api/app.py | 4 +- api/pre_traffic_hook.py | 13 +- assets/deploy-model-dev.yml | 8 +- assets/deploy-model-prd.yml | 32 +- assets/suggest-baseline.yml | 12 +- assets/training-job.yml | 10 +- .../sagemaker_add_transform_header.py | 1 - .../sagemaker_create_experiment.py | 5 +- custom_resource/sagemaker_query_drift.py | 4 +- custom_resource/sagemaker_suggest_baseline.py | 49 +- custom_resource/sagemaker_training_job.py | 6 +- docs/cloudwatch-dashboard.png | Bin 32368 -> 31516 bytes docs/sagemaker-notebook.png | Bin 38548 -> 0 bytes docs/studio-cft.png | Bin 0 -> 74648 bytes docs/studio-execution-role.png | Bin 0 -> 156976 bytes docs/studio-sagemaker-project-template.png | Bin 0 -> 239466 bytes model/buildspec.yml | 24 +- model/dashboard.json | 2 +- model/requirements.txt | 2 +- model/{run.py => run_pipeline.py} | 66 +- notebook/canary.js | 37 - notebook/dashboard.json | 17 - notebook/mlops.ipynb | 1906 +---------------- notebook/workflow.ipynb | 1187 +--------- pipeline.yml | 384 ++-- pyproject.toml | 3 + scripts/build.sh | 52 + scripts/lint.sh | 11 + scripts/set_kernelspec.py | 24 + studio.yml | 208 ++ 34 files changed, 665 insertions(+), 3517 deletions(-) create mode 100644 .gitignore create mode 100644 .pre-commit-config.yaml delete mode 100644 docs/sagemaker-notebook.png create mode 100644 docs/studio-cft.png create mode 100644 docs/studio-execution-role.png create mode 100644 docs/studio-sagemaker-project-template.png rename model/{run.py => run_pipeline.py} (89%) delete mode 100644 notebook/canary.js create mode 100644 pyproject.toml create mode 100755 scripts/build.sh create mode 100755 scripts/lint.sh create mode 100644 scripts/set_kernelspec.py create mode 100644 studio.yml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f4da28d --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.vscode +build +__pycache__ +*.ipynb_checkpoints diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..3c2c231 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,16 @@ +default_language_version: + python: python3.7 + +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v2.3.0 + hooks: + - id: trailing-whitespace + - repo: local + hooks: + - id: lint + name: lint + always_run: true + entry: scripts/lint.sh + language: system + types: [python] diff --git a/LICENSE b/LICENSE index 1bb4f21..6aa0c45 100644 --- a/LICENSE +++ b/LICENSE @@ -12,4 +12,3 @@ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - diff --git a/README.md b/README.md index 6be3441..d6b3a35 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,4 @@ # Amazon SageMaker Safe Deployment Pipeline - ## Introduction This is a sample solution to build a safe deployment pipeline for Amazon SageMaker. This example could be useful for any organization looking to operationalize machine learning with native AWS development tools such as AWS CodePipeline, AWS CodeBuild and AWS CodeDeploy. @@ -32,48 +31,52 @@ In the following diagram, you can view the continuous delivery stages of AWS Cod The following is the list of steps required to get up and running with this sample. -### Prepare an AWS Account +### Requirements + +* Create your AWS account at [http://aws.amazon.com](http://aws.amazon.com) by following the instructions on the site. +* A Studio user account, see [onboard to Amazon SageMaker Studio](https://docs.aws.amazon.com/sagemaker/latest/dg/gs-studio-onboard.html) +### Enable Amazon SageMaker Studio Project -Create your AWS account at [http://aws.amazon.com](http://aws.amazon.com) by following the instructions on the site. +1. From AWS console navigate to Amazon SageMaker Studio and click on your studio user name (do **not** Open Studio now) and copy the name of execution role as shown below (similar to `AmazonSageMaker-ExecutionRole-20210112T085906`) -### *Optionally* fork this GitHub Repository and create an Access Token - -1. [Fork](https://github.com/aws-samples/sagemaker-safe-deployment-pipeline/fork) a copy of this repository into your own GitHub account by clicking the **Fork** in the upper right-hand corner. -2. Follow the steps in the [GitHub documentation](https://help.github.com/en/github/authenticating-to-github/creating-a-personal-access-token-for-the-command-line) to create a new (OAuth 2) token with the following scopes (permissions): `admin:repo_hook` and `repo`. If you already have a token with these permissions, you can use that. You can find a list of all your personal access tokens in [https://github.com/settings/tokens](https://github.com/settings/tokens). -3. Copy the access token to your clipboard. For security reasons, after you navigate off the page, you will not be able to see the token again. If you have lost your token, you can [regenerate](https://docs.aws.amazon.com/codepipeline/latest/userguide/GitHub-authentication.html#GitHub-rotate-personal-token-CLI) your token. +

+ role +

-### Launch the AWS CloudFormation Stack +2. Click on the launch button below to setup the stack -Click on the **Launch Stack** button below to launch the CloudFormation Stack to set up the SageMaker safe deployment pipeline. +

+ +

-[![Launch CFN stack](https://s3.amazonaws.com/cloudformation-examples/cloudformation-launch-stack.png)](https://us-east-1.console.aws.amazon.com/cloudformation/home?region=us-east-1#/stacks/quickcreate?templateUrl=https%3A%2F%2Famazon-sagemaker-safe-deployment-pipeline.s3.amazonaws.com%2Fsfn%2Fpipeline.yml&stackName=nyctaxi¶m_GitHubBranch=master¶m_GitHubRepo=amazon-sagemaker-safe-deployment-pipeline¶m_GitHubUser=aws-samples¶m_ModelName=nyctaxi¶m_NotebookInstanceType=ml.t3.medium) +and paste the role name copied in step 1 as the value of the parameter `SageMakerStudioRoleName` as shown below and click **Create Stack** -Provide a stack name eg **sagemaker-safe-deployment-pipeline** and specify the parameters. +

+ role +

+ +*Alternatively*, one can use the provided `scripts/build.sh` (which required [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html) installed with appropriate IAM permissions) as follows +``` +# bash scripts/build.sh S3_BUCKET_NAME STACK_NAME REGION STUDIO_ROLE_NAME +# REGION should match your default AWS CLI region +# STUDIO_ROLE_NAME is copied from step 1. Example: +bash scripts/build.sh example-studio example-pipeline us-east-1 AmazonSageMaker-ExecutionRole-20210112T085906 +``` -Parameters | Description ------------ | ----------- -Model Name | A unique name for this model (must be less than 15 characters long). -S3 Bucket for Dataset | The bucket containing the dataset (defaults to [nyc-tlc](https://registry.opendata.aws/nyc-tlc-trip-records-pds/)) -Notebook Instance Type | The [Amazon SageMaker instance type](https://aws.amazon.com/sagemaker/pricing/instance-types/). Default is ml.t3.medium. -GitHub Repository | The name (not URL) of the GitHub repository to pull from. -GitHub Branch | The name (not URL) of the GitHub repository’s branch to use. -GitHub Username | GitHub Username for this repository. Update this if you have forked the repository. -GitHub Access Token | The optional Secret OAuthToken with access to your GitHub repository. -Email Address | The optional Email address to notify on successful or failed deployments. +3. From the AWS console navigate to `cloudformation` and once the stack `STACK_NAME` is ready +4. Go to your SageMaker Studio and **Open Studio** (and possibly refresh your browser if you're already in Studio) and from the your left hand side panel, click on the inverted triangle. As with the screenshot below, under `Projects -> Create project -> Organization templates`, you should be able to see the added **SageMaker Safe Deployment Pipeline**. Click on the template name and **Select project template** -![code-pipeline](docs/stack-parameters.png) +

+ role +

-You can launch the same stack using the AWS CLI. Here's an example: +5. Choose a name for the project and can leave the rest of the fields with their default values (can use your own email for SNS notifications) and click on **Create project** +6. Once the project is created, it gives you the option to clone it locally from AWS CodeCommit by a single click. Click clone and it goes directly to the project +7. Navigate to the code base and go to `notebook/mlops.ipynb` +8. Choose a kernel from the prompt such as `Python 3 (Data Science)` +9. Assign your project name to the placeholder `PROJECT_NAME` in the first code cell of the `mlops.ipynb` notebook +10. Now you are ready to go through the rest of the cells in `notebook/mlops.ipynb` -` - aws cloudformation create-stack --stack-name sagemaker-safe-deployment \ - --template-body file://pipeline.yml \ - --capabilities CAPABILITY_IAM \ - --parameters \ - ParameterKey=ModelName,ParameterValue=mymodelname \ - ParameterKey=GitHubUser,ParameterValue=youremailaddress@example.com \ - ParameterKey=GitHubToken,ParameterValue=YOURGITHUBTOKEN12345ab1234234 -` ### Start, Test and Approve the Deployment @@ -81,15 +84,11 @@ Once the deployment is complete, there will be a new AWS CodePipeline created, w ![code-pipeline](docs/data-source-before.png) -Launch the newly created SageMaker Notebook in your [AWS console](https://aws.amazon.com/getting-started/hands-on/build-train-deploy-machine-learning-model-sagemaker/), navigate to the `notebook` directory and opening the notebook by clicking on the `mlops.ipynb` link. - -![code-pipeline](docs/sagemaker-notebook.png) - Once the notebook is running, you will be guided through a series of steps starting with downloading the [New York City Taxi](https://registry.opendata.aws/nyc-tlc-trip-records-pds/) dataset, uploading this to an Amazon SageMaker S3 bucket along with the data source meta data to trigger a new build in the AWS CodePipeline. ![code-pipeline](docs/datasource-after.png) -Once your pipeline is kicked off it will run model training and deploy a development SageMaker Endpoint. +Once your pipeline is kicked off it will run model training and deploy a development SageMaker Endpoint. There is a manual approval step which you can action directly within the SageMaker Notebook to promote this to production, send some traffic to the live endpoint and create a REST API. @@ -138,15 +137,20 @@ This project is written in Python, and design to be customized for your own mode │   ├── buildspec.yml │   ├── dashboard.json │   ├── requirements.txt -│   └── run.py +│   └── run_pipeline.py ├── notebook -│   ├── canary.js │   ├── dashboard.json +| ├── workflow.ipynb │   └── mlops.ipynb -└── pipeline.yml +├── scripts +| ├── build.sh +| ├── lint.sh +| └── set_kernelspec.py +├── pipeline.yml +└── studio.yml ``` -Edit the `get_training_params` method in the `model/run.py` script that is run as part of the AWS CodeBuild step to add your own estimator or model definition. +Edit the `get_training_params` method in the `model/run_pipeline.py` script that is run as part of the AWS CodeBuild step to add your own estimator or model definition. Extend the AWS Lambda hooks in `api/pre_traffic_hook.py` and `api/post_traffic_hook.py` to add your own validation or inference against the deployed Amazon SageMaker endpoints. You can also edit the `api/app.py` lambda to add any enrichment or transformation to the request/response payload. @@ -158,8 +162,7 @@ This section outlines cost considerations for running the SageMaker Safe Deploym - **CodeCommit** – $1/month if you didn't opt to use your own GitHub repository. - **CodeDeploy** – No cost with AWS Lambda. - **CodePipeline** – CodePipeline costs $1 per active pipeline* per month. Pipelines are free for the first 30 days after creation. More can be found at [AWS CodePipeline Pricing](https://aws.amazon.com/codepipeline/pricing/). -- **CloudWatch** - This template includes a [Canary](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch_Synthetics_Canaries.html), 1 dashboard and 4 alarms (2 for deployment, 1 for model drift and 1 for canary) which costs less than $10 per month. - - Canaries cost $0.0012 per run, or $5/month if they run every 10 minutes. +- **CloudWatch** - This template includes 1 dashboard and 3 alarms (2 for deployment and 1 for model drift) which costs less than $10 per month. - Dashboards cost $3/month. - Alarm metrics cost $0.10 per alarm. - **CloudTrail** - Low cost, $0.10 per 100,000 data events to enable [S3 CloudWatch Event](https://docs.aws.amazon.com/codepipeline/latest/userguide/create-cloudtrail-S3-source-console.html). For more information, see [AWS CloudTrail Pricing](https://aws.amazon.com/cloudtrail/pricing/) @@ -170,7 +173,7 @@ This section outlines cost considerations for running the SageMaker Safe Deploym - The `ml.t3.medium` instance *notebook* costs $0.0582 an hour. - The `ml.m4.xlarge` instance for the *training* job costs $0.28 an hour. - The `ml.m5.xlarge` instance for the *monitoring* baseline costs $0.269 an hour. - - The `ml.t2.medium` instance for the dev *hosting* endpoint costs $0.065 an hour. + - The `ml.t2.medium` instance for the dev *hosting* endpoint costs $0.065 an hour. - The two `ml.m5.large` instances for production *hosting* endpoint costs 2 x $0.134 per hour. - The `ml.m5.xlarge` instance for the hourly scheduled *monitoring* job costs $0.269 an hour. - **S3** – Prices will vary depending on the size of the model/artifacts stored. The first 50 TB each month will cost only $0.023 per GB stored. For more information, see [Amazon S3 Pricing](https://aws.amazon.com/s3/pricing/). @@ -193,4 +196,3 @@ See [CONTRIBUTING](CONTRIBUTING.md#security-issue-notifications) for more inform ## License This library is licensed under the MIT-0 License. See the LICENSE file. - diff --git a/api/app.py b/api/app.py index 86b6c34..c499b17 100644 --- a/api/app.py +++ b/api/app.py @@ -50,8 +50,6 @@ def lambda_handler(event, context): "body": predictions, } except ClientError as e: - logger.error( - "Unexpected sagemaker error: {}".format(e.response["Error"]["Message"]) - ) + logger.error("Unexpected sagemaker error: {}".format(e.response["Error"]["Message"])) logger.error(e) return {"statusCode": 500, "message": "Unexpected sagemaker error"} diff --git a/api/pre_traffic_hook.py b/api/pre_traffic_hook.py index e6fded5..03780fa 100644 --- a/api/pre_traffic_hook.py +++ b/api/pre_traffic_hook.py @@ -29,16 +29,9 @@ def lambda_handler(event, context): else: # Validate that endpoint config has data capture enabled endpoint_config_name = response["EndpointConfigName"] - response = sm.describe_endpoint_config( - EndpointConfigName=endpoint_config_name - ) - if ( - "DataCaptureConfig" in response - and response["DataCaptureConfig"]["EnableCapture"] - ): - logger.info( - "data capture enabled for endpoint config %s", endpoint_config_name - ) + response = sm.describe_endpoint_config(EndpointConfigName=endpoint_config_name) + if "DataCaptureConfig" in response and response["DataCaptureConfig"]["EnableCapture"]: + logger.info("data capture enabled for endpoint config %s", endpoint_config_name) else: error_message = "SageMaker data capture not enabled for endpoint config" # TODO: Invoke endpoint if don't have canary / live traffic diff --git a/assets/deploy-model-dev.yml b/assets/deploy-model-dev.yml index e73eafd..3b86b03 100644 --- a/assets/deploy-model-dev.yml +++ b/assets/deploy-model-dev.yml @@ -23,10 +23,10 @@ Resources: Model: Type: "AWS::SageMaker::Model" Properties: - ModelName: !Sub mlops-${ModelName}-dev-${TrainJobId} + ModelName: !Sub ${ModelName}-dev-${TrainJobId} PrimaryContainer: Image: !Ref ImageRepoUri - ModelDataUrl: !Sub s3://sagemaker-${AWS::Region}-${AWS::AccountId}/${ModelName}/mlops-${ModelName}-${TrainJobId}/output/model.tar.gz + ModelDataUrl: !Sub s3://sagemaker-${AWS::Region}-${AWS::AccountId}/${ModelName}/${ModelName}-${TrainJobId}/output/model.tar.gz ExecutionRoleArn: !Ref DeployRoleArn EndpointConfig: @@ -38,11 +38,11 @@ Resources: InstanceType: ml.t2.medium ModelName: !GetAtt Model.ModelName VariantName: !Sub ${ModelVariant}-${ModelName} - EndpointConfigName: !Sub mlops-${ModelName}-dec-${TrainJobId} + EndpointConfigName: !Sub ${ModelName}-dec-${TrainJobId} KmsKeyId: !Ref KmsKeyId Endpoint: Type: "AWS::SageMaker::Endpoint" Properties: - EndpointName: !Sub mlops-${ModelName}-dev-${TrainJobId} + EndpointName: !Sub ${ModelName}-dev-${TrainJobId} EndpointConfigName: !GetAtt EndpointConfig.EndpointConfigName diff --git a/assets/deploy-model-prd.yml b/assets/deploy-model-prd.yml index 73f7303..42aee98 100644 --- a/assets/deploy-model-prd.yml +++ b/assets/deploy-model-prd.yml @@ -81,10 +81,10 @@ Resources: Model: Type: "AWS::SageMaker::Model" Properties: - ModelName: !Sub mlops-${ModelName}-prd-${TrainJobId} + ModelName: !Sub ${ModelName}-prd-${TrainJobId} PrimaryContainer: Image: !Ref ImageRepoUri - ModelDataUrl: !Sub s3://sagemaker-${AWS::Region}-${AWS::AccountId}/${ModelName}/mlops-${ModelName}-${TrainJobId}/output/model.tar.gz + ModelDataUrl: !Sub s3://sagemaker-${AWS::Region}-${AWS::AccountId}/${ModelName}/${ModelName}-${TrainJobId}/output/model.tar.gz ExecutionRoleArn: !Ref DeployRoleArn EndpointConfig: @@ -109,19 +109,19 @@ Resources: EnableCapture: True InitialSamplingPercentage: 100 KmsKeyId: !Ref KmsKeyId - EndpointConfigName: !Sub mlops-${ModelName}-pec-${TrainJobId} + EndpointConfigName: !Sub ${ModelName}-pec-${TrainJobId} KmsKeyId: !Ref KmsKeyId Endpoint: Type: "AWS::SageMaker::Endpoint" Properties: - EndpointName: !Sub mlops-${ModelName}-prd-${TrainJobId} + EndpointName: !Sub ${ModelName}-prd-${TrainJobId} EndpointConfigName: !GetAtt EndpointConfig.EndpointConfigName ApiFunction: Type: AWS::Serverless::Function Properties: - FunctionName: !Sub mlops-${ModelName}-api + FunctionName: !Sub ${ModelName}-api CodeUri: ../api Handler: app.lambda_handler Runtime: python3.7 @@ -177,7 +177,7 @@ Resources: Effect: Allow Action: - sagemaker:InvokeEndpoint - Resource: "arn:aws:sagemaker:*:*:endpoint/mlops-*" + Resource: "arn:aws:sagemaker:*:*:endpoint/*" - Sid: AlowSNS Effect: Allow Action: @@ -205,7 +205,7 @@ Resources: - sagemaker:DescribeEndpointConfig - sagemaker:InvokeEndpoint Resource: - - "arn:aws:sagemaker:*:*:*/mlops-*" + - "arn:aws:sagemaker:*:*:*/*" - Sid: AllowCodeDeploy Effect: Allow Action: @@ -261,9 +261,9 @@ Resources: MonitoringJobDefinition: BaselineConfig: ConstraintsResource: - S3Uri: !Sub s3://sagemaker-${AWS::Region}-${AWS::AccountId}/${ModelName}/monitoring/baseline/mlops-${ModelName}-pbl-${TrainJobId}/constraints.json + S3Uri: !Sub s3://sagemaker-${AWS::Region}-${AWS::AccountId}/${ModelName}/monitoring/baseline/${ModelName}-pbl-${TrainJobId}/constraints.json StatisticsResource: - S3Uri: !Sub s3://sagemaker-${AWS::Region}-${AWS::AccountId}/${ModelName}/monitoring/baseline/mlops-${ModelName}-pbl-${TrainJobId}/statistics.json + S3Uri: !Sub s3://sagemaker-${AWS::Region}-${AWS::AccountId}/${ModelName}/monitoring/baseline/${ModelName}-pbl-${TrainJobId}/statistics.json MonitoringAppSpecification: ImageUri: !FindInMap [ModelAnalyzerMap, !Ref "AWS::Region", "ImageUri"] @@ -287,19 +287,19 @@ Resources: MaxRuntimeInSeconds: 1800 ScheduleConfig: ScheduleExpression: "cron(0 * ? * * *)" - MonitoringScheduleName: !Sub mlops-${ModelName}-pms + MonitoringScheduleName: !Sub ${ModelName}-pms SagemakerScheduleAlarm: Type: "AWS::CloudWatch::Alarm" Properties: - AlarmName: !Sub mlops-${ModelName}-metric-gt-threshold + AlarmName: !Sub ${ModelName}-metric-gt-threshold AlarmDescription: Schedule Metric > Threshold ComparisonOperator: GreaterThanThreshold Dimensions: - Name: Endpoint Value: !GetAtt Endpoint.EndpointName - Name: MonitoringSchedule - Value: !Sub mlops-${ModelName}-pms + Value: !Sub ${ModelName}-pms EvaluationPeriods: 1 DatapointsToAlarm: 1 MetricName: !Ref ScheduleMetricName @@ -311,7 +311,7 @@ Resources: AliasErrorMetricGreaterThanZeroAlarm: Type: "AWS::CloudWatch::Alarm" Properties: - AlarmName: !Sub mlops-${ModelName}-alias-gt-zero + AlarmName: !Sub ${ModelName}-alias-gt-zero AlarmDescription: Lambda Function Error > 0 ComparisonOperator: GreaterThanThreshold Dimensions: @@ -329,7 +329,7 @@ Resources: LatestVersionErrorMetricGreaterThanZeroAlarm: Type: "AWS::CloudWatch::Alarm" Properties: - AlarmName: !Sub mlops-${ModelName}-version-gt-zero + AlarmName: !Sub ${ModelName}-version-gt-zero AlarmDescription: Lambda Function Error > 0 ComparisonOperator: GreaterThanThreshold Dimensions: @@ -351,7 +351,7 @@ Resources: Properties: MaxCapacity: 10 MinCapacity: 2 - ResourceId: !Sub endpoint/mlops-${ModelName}-prd-${TrainJobId}/variant/${ModelVariant}-${ModelName} + ResourceId: !Sub endpoint/${ModelName}-prd-${TrainJobId}/variant/${ModelVariant}-${ModelName} RoleARN: !Sub arn:aws:iam::${AWS::AccountId}:role/MLOps ScalableDimension: sagemaker:variant:DesiredInstanceCount ServiceNamespace: sagemaker @@ -362,7 +362,7 @@ Resources: Properties: PolicyName: SageMakerVariantInvocationsPerInstance PolicyType: TargetTrackingScaling - ResourceId: !Sub endpoint/mlops-${ModelName}-prd-${TrainJobId}/variant/${ModelVariant}-${ModelName} + ResourceId: !Sub endpoint/${ModelName}-prd-${TrainJobId}/variant/${ModelVariant}-${ModelName} ScalableDimension: sagemaker:variant:DesiredInstanceCount ServiceNamespace: sagemaker TargetTrackingScalingPolicyConfiguration: diff --git a/assets/suggest-baseline.yml b/assets/suggest-baseline.yml index 20fc986..e70787c 100644 --- a/assets/suggest-baseline.yml +++ b/assets/suggest-baseline.yml @@ -1,5 +1,11 @@ Description: Suggest baseline for training job Parameters: + ProjectPrefix: + Type: String + Description: | + Makes resource privileges for services using this template scoped-limited. + Changing the default must be done with care + Default: PROJECT_PREFIX ModelName: Type: String Description: Name of the model @@ -20,10 +26,10 @@ Resources: SagemakerSuggestBaseline: Type: Custom::SuggestBaseline Properties: - ServiceToken: !Sub arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:sagemaker-cfn-suggest-baseline - ProcessingJobName: !Sub mlops-${ModelName}-pbl-${TrainJobId} + ServiceToken: !Sub arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:${ProjectPrefix}-sagemaker-cfn-suggest-baseline + ProcessingJobName: !Sub ${ProjectPrefix}-${ModelName}-pbl-${TrainJobId} BaselineInputUri: !Ref BaselineInputUri - BaselineResultsUri: !Sub s3://sagemaker-${AWS::Region}-${AWS::AccountId}/${ModelName}/monitoring/baseline/mlops-${ModelName}-pbl-${TrainJobId} + BaselineResultsUri: !Sub s3://sagemaker-${AWS::Region}-${AWS::AccountId}/${ModelName}/monitoring/baseline/${ProjectPrefix}-${ModelName}-pbl-${TrainJobId} KmsKeyId: !Ref KmsKeyId PassRoleArn: !Ref MLOpsRoleArn ExperimentName: !Ref ModelName diff --git a/assets/training-job.yml b/assets/training-job.yml index b782a1f..e207d0f 100644 --- a/assets/training-job.yml +++ b/assets/training-job.yml @@ -1,5 +1,11 @@ Description: Wait for a training job Parameters: + ProjectPrefix: + Type: String + Description: | + Makes resource privileges for services using this template scoped-limited. + Changing the default must be done with care + Default: PROJECT_PREFIX ModelName: Type: String Description: Name of the model @@ -17,8 +23,8 @@ Resources: SagemakerTrainingJob: Type: Custom::TrainingJob Properties: - ServiceToken: !Sub "arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:sagemaker-cfn-training-job" - TrainingJobName: !Sub mlops-${ModelName}-${TrainJobId} + ServiceToken: !Sub "arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:${ProjectPrefix}-sagemaker-cfn-training-job" + TrainingJobName: !Sub ${ProjectPrefix}-${ModelName}-${TrainJobId} TrainingJobRequest: !Ref TrainJobRequest ExperimentName: !Ref ModelName TrialName: !Ref TrainJobId diff --git a/custom_resource/sagemaker_add_transform_header.py b/custom_resource/sagemaker_add_transform_header.py index 8cd58df..d1e22d9 100644 --- a/custom_resource/sagemaker_add_transform_header.py +++ b/custom_resource/sagemaker_add_transform_header.py @@ -37,4 +37,3 @@ def lambda_handler(event, context): return new_obj.put( Body=body.encode("utf-8"), ContentType="text/csv", Metadata={"header": "true"} ) - diff --git a/custom_resource/sagemaker_create_experiment.py b/custom_resource/sagemaker_create_experiment.py index af6c2ab..3d9e3d9 100644 --- a/custom_resource/sagemaker_create_experiment.py +++ b/custom_resource/sagemaker_create_experiment.py @@ -46,5 +46,8 @@ def lambda_handler(event, context): raise error return { "statusCode": 200, - "results": {"ExperimentCreated": experiment_created, "TrialCreated": trial_created,}, + "results": { + "ExperimentCreated": experiment_created, + "TrialCreated": trial_created, + }, } diff --git a/custom_resource/sagemaker_query_drift.py b/custom_resource/sagemaker_query_drift.py index 6e33af4..ec6884d 100644 --- a/custom_resource/sagemaker_query_drift.py +++ b/custom_resource/sagemaker_query_drift.py @@ -23,7 +23,8 @@ def get_processing_job(processing_job_name): def get_s3_results_json(result_bucket, result_path, filename): s3_object = s3_client.get_object( - Bucket=result_bucket, Key=os.path.join(result_path.lstrip("/"), filename), + Bucket=result_bucket, + Key=os.path.join(result_path.lstrip("/"), filename), ) return json.loads(s3_object["Body"].read()) @@ -81,4 +82,3 @@ def lambda_handler(event, context): message = "Failed to read processing status!" print(e) return {"statusCode": 500, "error": message} - diff --git a/custom_resource/sagemaker_suggest_baseline.py b/custom_resource/sagemaker_suggest_baseline.py index e2d0efe..40fc9a3 100644 --- a/custom_resource/sagemaker_suggest_baseline.py +++ b/custom_resource/sagemaker_suggest_baseline.py @@ -53,7 +53,7 @@ def poll_create(event, context): @helper.poll_delete def poll_delete(event, context): """ - Return true if the resource has been stopped. + Return true if the resource has been stopped. """ processing_job_name = get_processing_job_name(event) logger.info("Polling for stopped processing job: %s", processing_job_name) @@ -64,9 +64,7 @@ def poll_delete(event, context): def get_model_monitor_container_uri(region): - container_uri_format = ( - "{0}.dkr.ecr.{1}.amazonaws.com/sagemaker-model-monitor-analyzer" - ) + container_uri_format = "{0}.dkr.ecr.{1}.amazonaws.com/sagemaker-model-monitor-analyzer" regions_to_accounts = { "eu-north-1": "895015795356", @@ -113,9 +111,7 @@ def is_processing_job_ready(processing_job_name): ) else: raise Exception( - "Processing Job ({}) has unexpected status: {}".format( - processing_job_name, status - ) + "Processing Job ({}) has unexpected status: {}".format(processing_job_name, status) ) return is_ready @@ -140,9 +136,7 @@ def create_processing_job(event): def stop_processing_job(processing_job_name): try: - processing_job = sm.describe_processing_job( - ProcessingJobName=processing_job_name - ) + processing_job = sm.describe_processing_job(ProcessingJobName=processing_job_name) status = processing_job["ProcessingJobStatus"] if status == "InProgress": logger.info("Stopping InProgress processing job: %s", processing_job_name) @@ -165,8 +159,7 @@ def stop_processing_job(processing_job_name): class DatasetFormat(object): - """Represents a Dataset Format that is used when calling a DefaultModelMonitor. - """ + """Represents a Dataset Format that is used when calling a DefaultModelMonitor.""" @staticmethod def csv(header=True, output_columns_position="START"): @@ -203,9 +196,7 @@ def sagemaker_capture_json(): dict: JSON string containing DatasetFormat to be used by DefaultModelMonitor. """ return { - "sagemaker_capture_json": { - "captureIndexNames": ["endpointInput", "endpointOutput"] - } + "sagemaker_capture_json": {"captureIndexNames": ["endpointInput", "endpointOutput"]} } @@ -256,22 +247,16 @@ def get_processing_request(event, dataset_format=DatasetFormat.csv()): } }, "StoppingCondition": { - "MaxRuntimeInSeconds": int( - props.get("MaxRuntimeInSeconds", 1800) - ) # 30 minutes + "MaxRuntimeInSeconds": int(props.get("MaxRuntimeInSeconds", 1800)) # 30 minutes }, "AppSpecification": { - "ImageUri": props.get( - "ImageURI", get_model_monitor_container_uri(helper._region) - ), + "ImageUri": props.get("ImageURI", get_model_monitor_container_uri(helper._region)), }, "Environment": { "dataset_format": json.dumps(dataset_format), "dataset_source": "/opt/ml/processing/input/baseline_dataset_input", "output_path": "/opt/ml/processing/output", - "publish_cloudwatch_metrics": props.get( - "PublishCloudwatchMetrics", "Disabled" - ), + "publish_cloudwatch_metrics": props.get("PublishCloudwatchMetrics", "Disabled"), }, "RoleArn": props["PassRoleArn"], } @@ -279,9 +264,7 @@ def get_processing_request(event, dataset_format=DatasetFormat.csv()): # Add the KmsKeyId to monitoring outputs and cluster volume if provided if props.get("KmsKeyId") is not None: request["ProcessingOutputConfig"]["KmsKeyId"] = props["KmsKeyId"] - request["ProcessingResources"]["ClusterConfig"]["VolumeKmsKeyId"] = props[ - "KmsKeyId" - ] + request["ProcessingResources"]["ClusterConfig"]["VolumeKmsKeyId"] = props["KmsKeyId"] # Add experiment tracking request["ExperimentConfig"] = { @@ -295,9 +278,7 @@ def get_processing_request(event, dataset_format=DatasetFormat.csv()): if props.get("RecordPreprocessorSourceUri"): env = request["Environment"] fn = get_file_name(props["RecordPreprocessorSourceUri"]) - env["record_preprocessor_script"] = ( - "/opt/ml/processing/code/postprocessing/" + fn - ) + env["record_preprocessor_script"] = "/opt/ml/processing/code/postprocessing/" + fn request["ProcessingInputs"].append( { "InputName": "pre_processor_script", @@ -315,9 +296,7 @@ def get_processing_request(event, dataset_format=DatasetFormat.csv()): if props.get("PostAnalyticsProcessorSourceUri"): env = request["Environment"] fn = get_file_name(props["PostAnalyticsProcessorSourceUri"]) - env["post_analytics_processor_script"] = ( - "/opt/ml/processing/code/postprocessing/" + fn - ) + env["post_analytics_processor_script"] = "/opt/ml/processing/code/postprocessing/" + fn request["ProcessingInputs"].append( { "InputName": "post_processor_script", @@ -339,9 +318,7 @@ def get_processing_request(event, dataset_format=DatasetFormat.csv()): # Add baseline constraints logger.debug("Update with constraints: %s", data["BaselineConstraintsUri"]) env = request["Environment"] - env[ - "baseline_constraints" - ] = "/opt/ml/processing/baseline/constraints/constraints.json" + env["baseline_constraints"] = "/opt/ml/processing/baseline/constraints/constraints.json" request["ProcessingInputs"].append( { "InputName": "constraints", diff --git a/custom_resource/sagemaker_training_job.py b/custom_resource/sagemaker_training_job.py index 9fd8c04..bd4b0ed 100644 --- a/custom_resource/sagemaker_training_job.py +++ b/custom_resource/sagemaker_training_job.py @@ -53,7 +53,7 @@ def poll_create(event, context): @helper.poll_delete def poll_delete(event, context): """ - Return true if the resource has been stopped. + Return true if the resource has been stopped. """ training_job_name = get_training_job_name(event) logger.info("Polling for stopped training job: %s", training_job_name) @@ -87,9 +87,7 @@ def is_training_job_ready(training_job_name): ) else: raise Exception( - "Training job ({}) has unexpected status: {}".format( - training_job_name, status - ) + "Training job ({}) has unexpected status: {}".format(training_job_name, status) ) return is_ready diff --git a/docs/cloudwatch-dashboard.png b/docs/cloudwatch-dashboard.png index 84ebe7ae8f22d4417881bc0ae5a99d013aea96b6..ef17cb3e2b6dfa93de7557c327f1a13fbd571e3f 100644 GIT binary patch literal 31516 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 literal 32368 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
  • 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 diff --git a/docs/sagemaker-notebook.png b/docs/sagemaker-notebook.png deleted file mode 100644 index dd79e0d3e23b538fc7e5aac69e8400a6865af7c9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 38548 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 diff --git a/docs/studio-cft.png b/docs/studio-cft.png new file mode 100644 index 0000000000000000000000000000000000000000..fa4511d9277613e454aa627d3dd4d51710da4752 GIT binary patch literal 74648 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

    o#UW*ZGT5f%RaLq=ZwVott^5OlaVwGkb5?iW~D z$7A9khduzYK?*2E;`*RKp#UOE|GzTNg+!N@9ZH1V^8qjO*0m{%DTC1M^w@+&pjhzrS`z=dRa`6Zk`N7pyBZUF!2M&%&R1uAem zx0I8*j=4Dpenzbwq=y)JRFq&8*A*^qhw!SYjUbcV53;fzo{6q+nO}#2k(Yl@@-`zvw07&0N4><~WuBMF&n+y2i&x z!Ul}TaX)ft2@Zw=7j1otINJy#M+;(?6b-%0AJ!YhH{SsPig8|-<*ukT9()DA2c7Bj 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 literal 0 HcmV?d00001 diff --git a/docs/studio-execution-role.png b/docs/studio-execution-role.png new file mode 100644 index 0000000000000000000000000000000000000000..81026e0c2b6ce43c95fb8250a5aa30041d2308a2 GIT binary patch literal 156976 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 z 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

    2T({iVl=f^e;zaQ}iB3VgYi7=5nV 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 A82|tP literal 0 HcmV?d00001 diff --git a/docs/studio-sagemaker-project-template.png b/docs/studio-sagemaker-project-template.png new file mode 100644 index 0000000000000000000000000000000000000000..191ffddab7be971ec88182cea16b01bea1d0a160 GIT binary patch literal 239466 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 api/commit.txt - echo $CODEBUILD_BUILD_ID >> api/commit.txt # Add build ID when commit doesn't change diff --git a/model/dashboard.json b/model/dashboard.json index b897a48..3c379b1 100644 --- a/model/dashboard.json +++ b/model/dashboard.json @@ -214,4 +214,4 @@ } } ] -} \ No newline at end of file +} diff --git a/model/requirements.txt b/model/requirements.txt index 09dc519..5252677 100644 --- a/model/requirements.txt +++ b/model/requirements.txt @@ -1,2 +1,2 @@ sagemaker>=2.1.0<3 -stepfunctions==2.0.0 \ No newline at end of file +stepfunctions==2.0.0 diff --git a/model/run.py b/model/run_pipeline.py similarity index 89% rename from model/run.py rename to model/run_pipeline.py index 6d59679..8185f07 100644 --- a/model/run.py +++ b/model/run_pipeline.py @@ -22,7 +22,10 @@ def create_experiment_step(create_experiment_function_name): "Create Experiment", parameters={ "FunctionName": create_experiment_function_name, - "Payload": {"ExperimentName.$": "$.ExperimentName", "TrialName.$": "$.TrialName",}, + "Payload": { + "ExperimentName.$": "$.ExperimentName", + "TrialName.$": "$.TrialName", + }, }, result_path="$.CreateTrialResults", ) @@ -236,7 +239,7 @@ def create_graph(create_experiment_step, baseline_step, training_step): return steps.states.Chain([create_experiment_step, sagemaker_jobs]) -def get_dev_config(model_name, job_id, role, image_uri, kms_key_id): +def get_dev_config(model_name, job_id, role, image_uri, kms_key_id, sagemaker_project_id): return { "Parameters": { "ImageRepoUri": image_uri, @@ -246,21 +249,27 @@ def get_dev_config(model_name, job_id, role, image_uri, kms_key_id): "ModelVariant": "dev", "KmsKeyId": kms_key_id, }, - "Tags": {"mlops:model-name": model_name, "mlops:stage": "dev"}, + "Tags": { + "mlops:model-name": model_name, + "mlops:stage": "dev", + "SageMakerProjectId": sagemaker_project_id, + }, } -def get_prd_config(model_name, job_id, role, image_uri, kms_key_id, notification_arn): - dev_config = get_dev_config(model_name, job_id, role, image_uri, kms_key_id) +def get_prd_config( + model_name, job_id, role, image_uri, kms_key_id, notification_arn, sagemaker_project_id +): + dev_config = get_dev_config( + model_name, job_id, role, image_uri, kms_key_id, sagemaker_project_id + ) prod_params = { "ModelVariant": "prd", "ScheduleMetricName": "feature_baseline_drift_total_amount", "ScheduleMetricThreshold": str("0.20"), "NotificationArn": notification_arn, } - prod_tags = { - "mlops:stage": "prd", - } + prod_tags = {"mlops:stage": "prd", "SageMakerProjectId": sagemaker_project_id} return { "Parameters": dict(dev_config["Parameters"], **prod_params), "Tags": dict(dev_config["Tags"], **prod_tags), @@ -305,6 +314,8 @@ def main( kms_key_id, workflow_role_arn, notification_arn, + sagemaker_project_id, + tags, ): # Define the function names create_experiment_function_name = "mlops-create-experiment" @@ -341,7 +352,7 @@ def main( # Set the output Data output_data = { "ModelOutputUri": "s3://{}/{}".format(sagemaker_bucket, model_name), - "BaselineOutputUri": f"s3://{sagemaker_bucket}/{model_name}/monitoring/baseline/mlops-{model_name}-pbl-{job_id}", + "BaselineOutputUri": f"s3://{sagemaker_bucket}/{model_name}/monitoring/baseline/{model_name}-pbl-{job_id}", } print("model output uri: {}".format(output_data["ModelOutputUri"])) @@ -384,7 +395,7 @@ def main( # Create the workflow as the model name workflow = Workflow(model_name, workflow_definition, workflow_role_arn) - print("Creating workflow: {}".format(model_name)) + print("Creating workflow: {0}-{1}".format(model_name, sagemaker_project_id)) # Create output directory if not os.path.exists(output_dir): @@ -401,30 +412,52 @@ def main( # Write the workflow inputs to file with open(os.path.join(output_dir, "workflow-input.json"), "w") as f: workflow_inputs = { - "ExperimentName": "mlops-{}".format(model_name), - "TrialName": "mlops-{}-{}".format(model_name, job_id), + "ExperimentName": "{}".format(model_name), + "TrialName": "{}-{}".format(model_name, job_id), "GitBranch": git_branch, "GitCommitHash": git_commit_id, "DataVersionId": data_verison_id, - "BaselineJobName": "mlops-{}-pbl-{}".format(model_name, job_id), + "BaselineJobName": "{}-pbl-{}".format(model_name, job_id), "BaselineOutputUri": output_data["BaselineOutputUri"], - "TrainingJobName": "mlops-{}-{}".format(model_name, job_id), + "TrainingJobName": "{}-{}".format(model_name, job_id), } json.dump(workflow_inputs, f) # Write the dev & prod params for CFN with open(os.path.join(output_dir, "deploy-model-dev.json"), "w") as f: - config = get_dev_config(model_name, job_id, deploy_role, image_uri, kms_key_id) + config = get_dev_config( + model_name, job_id, deploy_role, image_uri, kms_key_id, sagemaker_project_id + ) json.dump(config, f) with open(os.path.join(output_dir, "deploy-model-prd.json"), "w") as f: config = get_prd_config( - model_name, job_id, deploy_role, image_uri, kms_key_id, notification_arn + model_name, + job_id, + deploy_role, + image_uri, + kms_key_id, + notification_arn, + sagemaker_project_id, ) json.dump(config, f) if __name__ == "__main__": parser = argparse.ArgumentParser(description="Load parameters") + parser.add_argument( + "-role-arn", + "--role-arn", + dest="sagemaker_role", + type=str, + help="The role arn for the pipeline service execution role.", + ) + parser.add_argument( + "-tags", + "--tags", + dest="tags", + default=None, + help="""List of dict strings of '[{"Key": "string", "Value": "string"}, ..]'""", + ) parser.add_argument("--codebuild-id", required=True) parser.add_argument("--data-dir", required=True) parser.add_argument("--output-dir", required=True) @@ -438,6 +471,7 @@ def main( parser.add_argument("--git-branch", required=True) parser.add_argument("--workflow-role-arn", required=True) parser.add_argument("--notification-arn", required=True) + parser.add_argument("--sagemaker-project-id", required=True) args = vars(parser.parse_args()) print("args: {}".format(args)) main(**args) diff --git a/notebook/canary.js b/notebook/canary.js deleted file mode 100644 index 96afdb7..0000000 --- a/notebook/canary.js +++ /dev/null @@ -1,37 +0,0 @@ - -var synthetics = require('Synthetics'); -const log = require('SyntheticsLogger'); -const https = require('https'); - -const apiCanaryBlueprint = async function (hostname, path, postData) { - const verifyRequest = async function (requestOption) { - return new Promise((resolve, reject) => { - log.info("Making request with options: " + JSON.stringify(requestOption)); - const req = https.request(requestOption); - req.on('response', (res) => { - log.info('Status Code:',res.statusCode); - log.info('Response Headers:',JSON.stringify(res.headers)); - if (res.statusCode !== 200) { - reject("Failed: " + requestOption.path); - } - res.on('data', (d) => { - log.info("Response: " + d); - }); - res.on('end', resolve); - }); - req.on('error', reject); - req.write(postData); - req.end(); - }); - } - - const headers = {"Content-Type":"text/csv"} - headers['User-Agent'] = [synthetics.getCanaryUserAgentString(), headers['User-Agent']].join(' '); - const requestOptions = {"hostname":hostname,"method":"POST","path":path,"port":443} - requestOptions['headers'] = headers; - await verifyRequest(requestOptions); -}; - -exports.handler = async () => { - return await apiCanaryBlueprint("${hostname}", "${path}", "${data}"); -}; diff --git a/notebook/dashboard.json b/notebook/dashboard.json index 4cd0d29..96e2ef8 100644 --- a/notebook/dashboard.json +++ b/notebook/dashboard.json @@ -343,23 +343,6 @@ "view": "timeSeries", "stacked": false } - }, - { - "type": "metric", - "x": 16, - "y": 20, - "width": 8, - "height": 7, - "properties": { - "title": "CloudWatch Synthetics Alarm", - "annotations": { - "alarms": [ - "arn:aws:cloudwatch:${region}:${account_id}:alarm:mlops-${model_name}-synth-lt-threshold" - ] - }, - "view": "timeSeries", - "stacked": false - } } ] } diff --git a/notebook/mlops.ipynb b/notebook/mlops.ipynb index 6bd4be8..472eade 100644 --- a/notebook/mlops.ipynb +++ b/notebook/mlops.ipynb @@ -1,1905 +1 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Safe MLOps Deployment Pipeline\n", - "\n", - "\n", - "## Overview\n", - "\n", - "In this notebook you will step through an MLOps pipeline to build, train, deploy and monitor an XGBoost regression model for predicting the expected taxi fare using the New York City Taxi [dataset](https://registry.opendata.aws/nyc-tlc-trip-records-pds/)⇗. This safe pipeline features a [canary deployment](https://docs.aws.amazon.com/wellarchitected/latest/machine-learning-lens/canary-deployment.html)⇗ strategy with rollback on error. You will learn how to trigger and monitor the pipeline, inspect the training workflow, use model monitor to set up alerts, and create a canary deployment.\n", - "\n", - "

    \n", - "\n", - "### Contents\n", - "\n", - "This notebook has the following key sections:\n", - "\n", - "1. [Data Prep](#Data-Prep)\n", - "2. [Build](#Build)\n", - "3. [Train Model](#Train-Model)\n", - "4. [Deploy Dev](#Deploy-Dev)\n", - "5. [Deploy Prod](#Deploy-Prod)\n", - "6. [Monitor](#Monitor)\n", - "6. [Cleanup](#Cleanup)\n", - "\n", - "### Architecture\n", - "\n", - "The architecture diagram below shows the entire MLOps pipeline at a high level.\n", - "\n", - "Use the CloudFormation template provided in this repository (`pipeline.yml`) to build the demo in your own AWS account. If you are currently viewing this notebook from SageMaker in your AWS account, then you have already completed this step. CloudFormation deploys several resources:\n", - " \n", - "1. A customer-managed encryption key in in Amazon KMS for encrypting data and artifacts.\n", - "1. A secret in Amazon Secrets Manager to securely store your GitHub Access Token.\n", - "1. Several AWS IAM roles so CloudFormation, SageMaker, and other AWS services can perform actions in your AWS account, following the principle of [least privilege](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#grant-least-privilege)⇗.\n", - "1. A messaging service in Amazon SNS to notify you when CodeDeploy has successfully deployed the API, and to receive alerts for retraining and drift detection (signing up for these notifications is optional).\n", - "1. Two Amazon CloudWatch event rules: one which schedules the pipeline to run every month, and one which triggers the pipeline to run when SageMaker Model Monitor detects certain metrics.\n", - "1. An Amazon SageMaker Jupyter notebook with this workshop content pre-loaded.\n", - "1. An Amazon S3 bucket for storing model artifacts.\n", - "1. An AWS CodePipeline instance with several pre-defined stages. \n", - "\n", - "Take a moment to look at all of these resources now deployed in your account. \n", - "\n", - "![MLOps pipeline architecture](../docs/mlops-architecture.png)\n", - "\n", - "In this notebook, you will work through the CodePipeline instance created by the CloudFormation template. It has several stages:\n", - "\n", - "1. **Source** - The pipeline is already configured with two sources. If you upload a new dataset to a specific location in the S3 data bucket, this will trigger the pipeline to run. The Git source can be GitHub, or CodeCommit if you don’t supply your access token. If you commit new code to your repository, this will trigger the pipeline to run. \n", - "1. **Build** - In this stage, CodeBuild configured by the build specification `model/buildspec.yml` will execute `model/run.py` to generate AWS CloudFormation templates for creating the AWS Step Function (including AWS Lambda custom resources), and deployment templates used in the following stages based on the data sets and hyperparameters specified for this pipeline run. You will take a closer look at these files later in this notebook. \n", - "1. **Train** The Step Functions workflow created in the Build stage is run in this stage. The workflow creates a baseline for the model monitor using a SageMaker processing job, and trains an XGBoost model on the taxi ride dataset using a SageMaker training job.\n", - "1. **Deploy Dev** In this stage, a CloudFormation template created in the build stage (from `assets/deploy-model-dev.yml`) deploys a dev endpoint. This will allow you to run tests on the model and decide if the model is of sufficient quality to deploy into production.\n", - "1. **Deploy Production** The final stage of the pipeline is the only stage which does not run automatically as soon as the previous stage is complete. It waits for a user to manually approve the model which was previously deployed to dev. As soon as the model is approved, a CloudFormation template (packaged from `assets/deploy-model-prod.yml` to include the Lambda functions saved and uploaded as ZIP files in S3) deploys the production endpoint. It configures autoscaling and enables data capture. It creates a model monitoring schedule and sets CloudWatch alarms for certain metrics. It also sets up an AWS CodeDeploy instance which deploys a set of AWS Lambda functions and an Amazon API Gateway to sit in front of the SageMaker endpoint. This stage can make use of canary deployment to safely switch from an old model to a new model. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Import the latest sagemaker and boto3 SDKs.\n", - "import sys\n", - "!{sys.executable} -m pip install --upgrade pip\n", - "!{sys.executable} -m pip install -qU awscli boto3 \"sagemaker>=2.1.0<3\" tqdm\n", - "!{sys.executable} -m pip install -qU \"stepfunctions==2.0.0\"\n", - "!{sys.executable} -m pip show sagemaker stepfunctions" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Restart your SageMaker kernel then continue with this notebook." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Data Prep\n", - " \n", - "In this section of the notebook, you will download the publicly available New York Taxi dataset in preparation for uploading it to S3.\n", - "\n", - "### Download Dataset\n", - "\n", - "First, download a sample of the New York City Taxi [dataset](https://registry.opendata.aws/nyc-tlc-trip-records-pds/)⇗ to this notebook instance. This dataset contains information on trips taken by taxis and for-hire vehicles in New York City, including pick-up and drop-off times and locations, fares, distance traveled, and more. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "!aws s3 cp 's3://nyc-tlc/trip data/green_tripdata_2018-02.csv' 'nyc-tlc.csv'" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now load the dataset into a pandas data frame, taking care to parse the dates correctly." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import pandas as pd\n", - "\n", - "parse_dates= ['lpep_dropoff_datetime', 'lpep_pickup_datetime']\n", - "trip_df = pd.read_csv('nyc-tlc.csv', parse_dates=parse_dates)\n", - "\n", - "trip_df.head()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Data manipulation\n", - "\n", - "Instead of the raw date and time features for pick-up and drop-off, let's use these features to calculate the total time of the trip in minutes, which will be easier to work with for our model." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "trip_df['duration_minutes'] = (trip_df['lpep_dropoff_datetime'] - trip_df['lpep_pickup_datetime']).dt.seconds/60" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The dataset contains a lot of columns we don't need, so let's select a sample of columns for our machine learning model. Keep only `total_amount` (fare), `duration_minutes`, `passenger_count`, and `trip_distance`." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "cols = ['total_amount', 'duration_minutes', 'passenger_count', 'trip_distance']\n", - "data_df = trip_df[cols]\n", - "print(data_df.shape)\n", - "data_df.head()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Generate some quick statistics for the dataset to understand the quality." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "data_df.describe()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The table above shows some clear outliers, e.g. -400 or 2626 as fare, or 0 passengers. There are many intelligent methods for identifying and removing outliers, but data cleaning is not the focus of this notebook, so just remove the outliers by setting some min and max values which seem more reasonable. Removing the outliers results in a final dataset of 754,671 rows." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "data_df = data_df[(data_df.total_amount > 0) & (data_df.total_amount < 200) & \n", - " (data_df.duration_minutes > 0) & (data_df.duration_minutes < 120) & \n", - " (data_df.trip_distance > 0) & (data_df.trip_distance < 121) & \n", - " (data_df.passenger_count > 0)].dropna()\n", - "print(data_df.shape)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Data visualization\n", - "\n", - "Since this notebook will build a regression model for the taxi data, it's a good idea to check if there is any correlation between the variables in our data. Use scatter plots on a sample of the data to compare trip distance with duration in minutes, and total amount (fare) with duration in minutes." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import seaborn as sns \n", - "\n", - "sample_df = data_df.sample(1000)\n", - "sns.scatterplot(data=sample_df, x='duration_minutes', y='trip_distance')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "sns.scatterplot(data=sample_df, x='duration_minutes', y='total_amount')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "These scatter plots look fine and show at least some correlation between our variables. \n", - "\n", - "### Data splitting and saving\n", - "\n", - "We are now ready to split the dataset into train, validation, and test sets. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from sklearn.model_selection import train_test_split\n", - "train_df, val_df = train_test_split(data_df, test_size=0.20, random_state=42)\n", - "val_df, test_df = train_test_split(val_df, test_size=0.05, random_state=42)\n", - "\n", - "# Reset the index for our test dataframe\n", - "test_df.reset_index(inplace=True, drop=True)\n", - "\n", - "print('Size of\\n train: {},\\n val: {},\\n test: {} '.format(train_df.shape[0], val_df.shape[0], test_df.shape[0]))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Save the train, validation, and test files as CSV locally on this notebook instance. Notice that you save the train file twice - once as the training data file and once as the baseline data file. The baseline data file will be used by [SageMaker Model Monitor](https://docs.aws.amazon.com/sagemaker/latest/dg/model-monitor.html)⇗ to detect data drift. Data drift occurs when the statistical nature of the data that your model receives while in production drifts away from the nature of the baseline data it was trained on, which means the model begins to lose accuracy in its predictions." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "train_cols = ['total_amount', 'duration_minutes','passenger_count','trip_distance']\n", - "train_df.to_csv('train.csv', index=False, header=False)\n", - "val_df.to_csv('validation.csv', index=False, header=False)\n", - "test_df.to_csv('test.csv', index=False, header=False)\n", - "\n", - "# Save test and baseline with headers\n", - "train_df.to_csv('baseline.csv', index=False, header=True)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now upload these CSV files to your default SageMaker S3 bucket. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import sagemaker\n", - "\n", - "# Get the session and default bucket\n", - "session = sagemaker.session.Session()\n", - "bucket = session.default_bucket()\n", - "\n", - "# Specify data prefix and version\n", - "prefix = 'nyc-tlc/v1'\n", - "\n", - "s3_train_uri = session.upload_data('train.csv', bucket, prefix + '/data/training')\n", - "s3_val_uri = session.upload_data('validation.csv', bucket, prefix + '/data/validation')\n", - "s3_test_uri = session.upload_data('test.csv', bucket, prefix + '/data/test')\n", - "s3_baseline_uri = session.upload_data('baseline.csv', bucket, prefix + '/data/baseline')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "You will use the datasets which you have prepared and saved in this section to trigger the pipeline to train and deploy a model in the next section." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Build\n", - "\n", - "If you navigate to the CodePipeline instance created for this workshop, you will notice that the Source stage is initially in a `Failed` state. This happens because the dataset, which is one of the sources that can trigger the pipeline, has not yet been uploaded to the S3 location expected by the pipeline.\n", - "\n", - "![Failed code pipeline](../docs/pipeline_failed.png)\n", - "\n", - "### Trigger Build\n", - "\n", - "In this section, you will start a model build and deployment pipeline by packaging up the datasets you prepared in the previous section and uploading these to the S3 source location which triggers the CodePipeline instance created for this workshop. \n", - "\n", - "First, import some libraries and load some environment variables which you will need. These environment variables have been set through a [lifecycle configuration](https://docs.aws.amazon.com/sagemaker/latest/dg/notebook-lifecycle-config.html)⇗ script attached to this notebook." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import boto3\n", - "from botocore.exceptions import ClientError\n", - "import os\n", - "import time\n", - "\n", - "region = boto3.Session().region_name\n", - "artifact_bucket = os.environ['ARTIFACT_BUCKET']\n", - "pipeline_name = os.environ['PIPELINE_NAME']\n", - "model_name = os.environ['MODEL_NAME']\n", - "workflow_pipeline_arn = os.environ['WORKFLOW_PIPELINE_ARN']\n", - "\n", - "print('region: {}'.format(region))\n", - "print('artifact bucket: {}'.format(artifact_bucket))\n", - "print('pipeline: {}'.format(pipeline_name))\n", - "print('model name: {}'.format(model_name))\n", - "print('workflow: {}'.format(workflow_pipeline_arn))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "From the AWS CodePipeline [documentation](https://docs.aws.amazon.com/codepipeline/latest/userguide/tutorials-simple-s3.html)⇗:\n", - "\n", - "> When Amazon S3 is the source provider for your pipeline, you may zip your source file or files into a single .zip and upload the .zip to your source bucket. You may also upload a single unzipped file; however, downstream actions that expect a .zip file will fail.\n", - "\n", - "To train a model, you need multiple datasets (train, validation, and test) along with a file specifying the hyperparameters. In this example, you will create one JSON file which contains the S3 dataset locations and one JSON file which contains the hyperparameter values. Then you compress both files into a zip package to be used as input for the pipeline run. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from io import BytesIO\n", - "import zipfile\n", - "import json\n", - "\n", - "input_data = {\n", - " 'TrainingUri': s3_train_uri,\n", - " 'ValidationUri': s3_val_uri,\n", - " 'TestUri': s3_test_uri,\n", - " 'BaselineUri': s3_baseline_uri\n", - "}\n", - "\n", - "hyperparameters = {\n", - " 'num_round': 50\n", - "}\n", - "\n", - "zip_buffer = BytesIO()\n", - "with zipfile.ZipFile(zip_buffer, 'a') as zf:\n", - " zf.writestr('inputData.json', json.dumps(input_data))\n", - " zf.writestr('hyperparameters.json', json.dumps(hyperparameters))\n", - "zip_buffer.seek(0)\n", - "\n", - "data_source_key = '{}/data-source.zip'.format(pipeline_name)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now upload the zip package to your artifact S3 bucket - this action will trigger the pipeline to train and deploy a model." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "s3 = boto3.client('s3')\n", - "s3.put_object(Bucket=artifact_bucket, Key=data_source_key, Body=bytearray(zip_buffer.read()))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Click the link below to open the AWS console at the Code Pipeline if you don't have it open in another tab.\n", - "\n", - "
    \n", - " Tip: You may need to wait a minute to see the DataSource stage turn green. The page will refresh automatically.\n", - "
    \n", - "\n", - "![Source Green](../docs/datasource-after.png)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from IPython.core.display import HTML\n", - "\n", - "HTML('Code Pipeline'.format(region, pipeline_name))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Inspect Build Logs\n", - "\n", - "Once the build stage is running, you will see the AWS CodeBuild job turn blue with a status of **In progress**.\n", - "\n", - "![Failed code pipeline](../docs/codebuild-inprogress.png)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "You can click on the **Details** link displayed in the CodePipeline UI or click the link below to jump directly to the CodeBuild logs.\n", - "\n", - "
    \n", - " Tip: You may need to wait a few seconds for the pipeline to transition into the active (blue) state and for the build to start.\n", - "
    " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "codepipeline = boto3.client('codepipeline')\n", - "\n", - "def get_pipeline_stage(pipeline_name, stage_name):\n", - " response = codepipeline.get_pipeline_state(name=pipeline_name)\n", - " for stage in response['stageStates']:\n", - " if stage['stageName'] == stage_name:\n", - " return stage\n", - "\n", - "# Get last execution id\n", - "build_stage = get_pipeline_stage(pipeline_name, 'Build') \n", - "if not 'latestExecution' in build_stage:\n", - " raise(Exception('Please wait. Build not started'))\n", - "\n", - "build_url = build_stage['actionStates'][0]['latestExecution']['externalExecutionUrl']\n", - "\n", - "# Out a link to the code build logs\n", - "HTML('Code Build Logs'.format(build_url))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The AWS CodeBuild process is responsible for creating a number of AWS CloudFormation templates which we will explore in more detail in the next section. Two of these templates are used to set up the **Train** step by creating the AWS Step Functions worklow and the custom AWS Lambda functions used within this workflow." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Train Model\n", - "\n", - "### Inspect Training Job\n", - "\n", - "Wait until the pipeline has started running the Train step (see screenshot) before continuing with the next cells in this notebook. \n", - "\n", - "![Training in progress](../docs/train-in-progress.png)\n", - "\n", - "When the pipeline has started running the train step, you can click on the **Details** link displayed in the CodePipeline UI (see screenshot above) to view the Step Functions workflow which is running the training job. \n", - "\n", - "Alternatively, you can click on the Workflow link from the cell output below once it's available." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from stepfunctions.workflow import Workflow\n", - "while True:\n", - " try:\n", - " workflow = Workflow.attach(workflow_pipeline_arn)\n", - " break\n", - " except ClientError as e:\n", - " print(e.response[\"Error\"][\"Message\"])\n", - " time.sleep(10)\n", - "\n", - "workflow" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Or simply run the cell below to display the Step Functions workflow, and re-run it after a few minutes to see the progress." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "executions = workflow.list_executions()\n", - "if not executions:\n", - " raise(Exception('Please wait. Training not started'))\n", - " \n", - "executions[0].render_progress()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Review Build Script\n", - "\n", - "While you wait for the training job to complete, let's take a look at the `run.py` code which was used by the AWS CodeBuild process.\n", - "\n", - "This script takes all of the input parameters, including the dataset locations and hyperparameters which you saved to JSON files earlier in this notebook, and uses them to generate the templates which the pipeline needs to run the training job. It *does not* create the actual Step Functions instance - it only generates the templates which define the Step Functions workflow, as well as the CloudFormation input templates which CodePipeline uses to instantiate the Step Functions instance.\n", - "\n", - "Step-by-step, the script does the following:\n", - "\n", - "1. It collects all the input parameters it needs to generate the templates. This includes information about the environment container needed to run the training job, the input and output data locations, IAM roles needed by various components, encryption keys, and more. It then sets up some basic parameters like the AWS region and the function names.\n", - "1. If the input parameters specify an environment container stored in ECR, it fetches that container. Otherwise, it fetches the URI of the AWS managed environment container needed for the training job.\n", - "1. It reads the input data JSON file which you generated earlier in this notebook (and which was included in the zip source for the pipeline), thereby fetching the locations of the train, validation, and baseline data files. Then it formats more parameters which will be needed later in the script, including version IDs and output data locations.\n", - "1. It reads the hyperparameter JSON file which you generated earlier in this notebook.\n", - "1. It defines the Step Functions workflow, starting with the input schema, followed by each step of the workflow (i.e. Create Experiment, Baseline Job, Training Job), and finally combines those steps into a workflow graph. \n", - "1. The workflow graph is saved to file, along with a file containing all of the input parameters saved according to the schema defined in the workflow.\n", - "1. It saves parameters to file which will be used by CloudFormation to instantiate the Step Functions workflow." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "!pygmentize ../model/run.py" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Customize Workflow (Optional)\n", - "\n", - "If you are interested in customising the workflow used in the Build Script, store the `input_data` to be used within the local [workflow.ipynb](workflow.ipynb) notebook. The workflow notebook can be used to experiment with the Step Functions workflow and training job definitions for your model." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "scrolled": true - }, - "outputs": [], - "source": [ - "%store input_data" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Training Analytics\n", - "\n", - "Once the training and baseline jobs are complete (meaning they are displayed in a green color in the Step Functions workflow, this takes around 5 minutes), you can inspect the experiment metrics. The code below will display all experiments in a table. Note that the baseline processing job won't have RMSE metrics - it calculates metrics based on the training data, but does not train a machine learning model. \n", - "\n", - "You will [explore the baseline](#Explore-Baseline) results later in this notebook. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from sagemaker import analytics\n", - "experiment_name = 'mlops-{}'.format(model_name)\n", - "model_analytics = analytics.ExperimentAnalytics(experiment_name=experiment_name)\n", - "analytics_df = model_analytics.dataframe()\n", - "\n", - "if (analytics_df.shape[0] == 0):\n", - " raise(Exception('Please wait. No training or baseline jobs'))\n", - "\n", - "pd.set_option('display.max_colwidth', 100) # Increase column width to show full copmontent name\n", - "cols = ['TrialComponentName', 'DisplayName', 'SageMaker.InstanceType', \n", - " 'train:rmse - Last', 'validation:rmse - Last'] # return the last rmse for training and validation\n", - "analytics_df[analytics_df.columns & cols].head(2)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Deploy Dev\n", - "\n", - "### Test Dev Deployment\n", - "\n", - "When the pipeline has finished training a model, it automatically moves to the next step, where the model is deployed as a SageMaker Endpoint. This endpoint is part of your dev deployment, therefore, in this section, you will run some tests on the endpoint to decide if you want to deploy this model into production.\n", - "\n", - "First, run the cell below to fetch the name of the SageMaker Endpoint." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "codepipeline = boto3.client('codepipeline')\n", - "\n", - "deploy_dev = get_pipeline_stage(pipeline_name, 'DeployDev')\n", - "if not 'latestExecution' in deploy_dev:\n", - " raise(Exception('Please wait. Deploy dev not started'))\n", - " \n", - "execution_id = deploy_dev['latestExecution']['pipelineExecutionId']\n", - "dev_endpoint_name = 'mlops-{}-dev-{}'.format(model_name, execution_id)\n", - "\n", - "print('endpoint name: {}'.format(dev_endpoint_name))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "If you moved through the previous section very quickly, you will need to wait until the dev endpoint has been successfully deployed and the pipeline is waiting for approval to deploy to production (see screenshot). It can take up to 10 minutes for SageMaker to create an endpoint.\n", - "\n", - "![Deploying dev endpoint in code pipeline](../docs/dev-deploy-ready.png)\n", - "\n", - "Alternatively, run the code below to check the status of your endpoint. Wait until the status of the endpoint is 'InService'." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "sm = boto3.client('sagemaker')\n", - "\n", - "while True:\n", - " try:\n", - " response = sm.describe_endpoint(EndpointName=dev_endpoint_name)\n", - " print(\"Endpoint status: {}\".format(response['EndpointStatus']))\n", - " if response['EndpointStatus'] == 'InService':\n", - " break\n", - " except ClientError as e:\n", - " print(e.response[\"Error\"][\"Message\"])\n", - " time.sleep(10)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now that your endpoint is ready, let's write some code to run the test data (which you split off from the dataset and saved to file at the start of this notebook) through the endpoint for inference. The code below supports both v1 and v2 of the SageMaker SDK, but we recommend using v2 of the SDK in all of your future projects." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import numpy as np\n", - "from tqdm import tqdm\n", - "\n", - "try:\n", - " # Support SageMaker v2 SDK: https://sagemaker.readthedocs.io/en/stable/v2.html\n", - " from sagemaker.predictor import Predictor\n", - " from sagemaker.serializers import CSVSerializer\n", - " def get_predictor(endpoint_name):\n", - " xgb_predictor = Predictor(endpoint_name)\n", - " xgb_predictor.serializer = CSVSerializer()\n", - " return xgb_predictor\n", - "except:\n", - " # Fallback to SageMaker v1.70 SDK\n", - " from sagemaker.predictor import RealTimePredictor, csv_serializer\n", - " def get_predictor(endpoint_name):\n", - " xgb_predictor = RealTimePredictor(endpoint_name)\n", - " xgb_predictor.content_type = 'text/csv'\n", - " xgb_predictor.serializer = csv_serializer\n", - " return xgb_predictor\n", - "\n", - "def predict(predictor, data, rows=500):\n", - " split_array = np.array_split(data, round(data.shape[0] / float(rows)))\n", - " predictions = ''\n", - " for array in tqdm(split_array):\n", - " predictions = ','.join([predictions, predictor.predict(array).decode('utf-8')])\n", - " return np.fromstring(predictions[1:], sep=',')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now use the `predict` function, which was defined in the code above, to run the test data through the endpoint and generate the predictions." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "dev_predictor = get_predictor(dev_endpoint_name)\n", - "predictions = predict(dev_predictor, test_df[test_df.columns[1:]].values)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Next, load the predictions into a data frame, and join it with your test data. Then, calculate absolute error as the difference between the actual taxi fare and the predicted taxi fare. Display the results in a table, sorted by the highest absolute error values." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "pred_df = pd.DataFrame({'total_amount_predictions': predictions })\n", - "pred_df = test_df.join(pred_df) # Join on all\n", - "pred_df['error'] = abs(pred_df['total_amount']-pred_df['total_amount_predictions'])\n", - "\n", - "pred_df.sort_values('error', ascending=False).head()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "From this table, we note that some short trip distances have large errors because the low predicted fare does not match the high actual fare. This could be the result of a generous tip which we haven't included in this dataset.\n", - "\n", - "You can also analyze the results by plotting the absolute error to visualize outliers. In this graph, we see that most of the outliers are cases where the model predicted a much lower fare than the actual fare. There are only a few outliers where the model predicted a higher fare than the actual fare." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "sns.scatterplot(data=pred_df, x='total_amount_predictions', y='total_amount', hue='error')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "If you want one overall measure of quality for the model, you can calculate the root mean square error (RMSE) for the predicted fares compared to the actual fares. Compare this to the [results calculated on the validation set](#validation-results) at the end of the 'Inspect Training Job' section." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from math import sqrt\n", - "from sklearn.metrics import mean_squared_error\n", - "\n", - "def rmse(pred_df):\n", - " return sqrt(mean_squared_error(pred_df['total_amount'], pred_df['total_amount_predictions']))\n", - "\n", - "print('RMSE: {}'.format(rmse(pred_df)))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Deploy Prod\n", - "\n", - "### Approve Deployment to Production\n", - "\n", - "If you are happy with the results of the model, you can go ahead and approve the model to be deployed into production. You can do so by clicking the **Review** button in the CodePipeline UI, leaving a comment to explain why you approve this model, and clicking on **Approve**. \n", - "\n", - "Alternatively, you can create a Jupyter widget which (when enabled) allows you to comment and approve the model directly from this notebook. Run the cell below to see this in action." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import ipywidgets as widgets\n", - "\n", - "def on_click(obj):\n", - " result = { 'summary': approval_text.value, 'status': obj.description }\n", - " response = codepipeline.put_approval_result(\n", - " pipelineName=pipeline_name,\n", - " stageName='DeployDev',\n", - " actionName='ApproveDeploy',\n", - " result=result,\n", - " token=approval_action['token']\n", - " )\n", - " button_box.close()\n", - " print(result)\n", - " \n", - "# Create the widget if we are ready for approval\n", - "deploy_dev = get_pipeline_stage(pipeline_name, 'DeployDev')\n", - "if not 'latestExecution' in deploy_dev['actionStates'][-1]:\n", - " raise(Exception('Please wait. Deploy dev not complete'))\n", - "\n", - "approval_action = deploy_dev['actionStates'][-1]['latestExecution']\n", - "if approval_action['status'] == 'Succeeded':\n", - " print('Dev approved: {}'.format(approval_action['summary']))\n", - "elif 'token' in approval_action:\n", - " approval_text = widgets.Text(placeholder='Optional approval message') \n", - " approve_btn = widgets.Button(description=\"Approved\", button_style='success', icon='check')\n", - " reject_btn = widgets.Button(description=\"Rejected\", button_style='danger', icon='close')\n", - " approve_btn.on_click(on_click)\n", - " reject_btn.on_click(on_click)\n", - " button_box = widgets.HBox([approval_text, approve_btn, reject_btn])\n", - " display(button_box)\n", - "else:\n", - " raise(Exception('Please wait. No dev approval'))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Test Production Deployment\n", - "\n", - "Within about a minute after approving the model deployment, you should see the pipeline start on the final step: deploying your model into production. In this section, you will check the deployment status and test the production endpoint after it has been deployed.\n", - "\n", - "![Deploy production endpoint in code pipeline](../docs/deploy-production.png)\n", - "\n", - "This step of the pipeline uses CloudFormation to deploy a number of resources on your behalf. In particular, it creates:\n", - "\n", - "1. A production-ready SageMaker Endpoint for your model, with [data capture](https://docs.aws.amazon.com/sagemaker/latest/dg/model-monitor-data-capture.html)⇗ (used by SageMaker Model Monitor) and [autoscaling](https://docs.aws.amazon.com/sagemaker/latest/dg/endpoint-auto-scaling.html)⇗ enabled.\n", - "1. A [model monitoring schedule](https://docs.aws.amazon.com/sagemaker/latest/dg/model-monitor-scheduling.html)⇗ which outputs the results to CloudWatch metrics, along with a [CloudWatch Alarm](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/AlarmThatSendsEmail.html)⇗ which will notify you when a violation occurs. \n", - "1. A CodeDeploy instance which creates a simple app by deploying API Gateway, three Lambda functions, and an alarm to notify of the success or failure of this deployment. The code for the Lambda functions can be found in `api/app.py`, `api/pre_traffic_hook.py`, and `api/post_traffic_hook.py`. These functions update the endpoint to enable data capture, format and submit incoming traffic to the SageMaker endpoint, and capture the data logs.\n", - "\n", - "![Components of production deployment](../docs/cloud-formation.png)\n", - "\n", - "Let's check how the deployment is progressing. Use the code below to fetch the execution ID of the depoyment step. Then generate a table which lists the resources created by the CloudFormation stack and their creation status. You can re-run the cell after a few minutes to see how the steps are progressing." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "deploy_prd = get_pipeline_stage(pipeline_name, 'DeployPrd')\n", - "if not 'latestExecution' in deploy_prd or not 'latestExecution' in deploy_prd['actionStates'][0]:\n", - " raise(Exception('Please wait. Deploy prd not started'))\n", - " \n", - "execution_id = deploy_prd['latestExecution']['pipelineExecutionId']" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from datetime import datetime, timedelta\n", - "from dateutil.tz import tzlocal\n", - "\n", - "def get_event_dataframe(events):\n", - " stack_cols = ['LogicalResourceId', 'ResourceStatus', 'ResourceStatusReason', 'Timestamp']\n", - " stack_event_df = pd.DataFrame(events)[stack_cols].fillna('')\n", - " stack_event_df['TimeAgo'] = (datetime.now(tzlocal())-stack_event_df['Timestamp'])\n", - " return stack_event_df.drop('Timestamp', axis=1)\n", - "\n", - "cfn = boto3.client('cloudformation')\n", - "\n", - "stack_name = stack_name='{}-deploy-prd'.format(pipeline_name)\n", - "print('stack name: {}'.format(stack_name))\n", - "\n", - "# Get latest stack events\n", - "while True:\n", - " try:\n", - " response = cfn.describe_stack_events(StackName=stack_name)\n", - " break\n", - " except ClientError as e:\n", - " print(e.response[\"Error\"][\"Message\"])\n", - " time.sleep(10)\n", - " \n", - "get_event_dataframe(response['StackEvents']).head()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The resource of most interest to us is the endpoint. This takes on average 10 minutes to deploy. In the meantime, you can take a look at the Python code used for the application. \n", - "\n", - "The `app.py` is the main entry point invoking the Amazon SageMaker endpoint. It returns results along with a custom header for the endpoint we invoked." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "!pygmentize ../api/app.py" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The `pre_traffic_hook.py` lambda is invoked prior to deployment and confirms the endpoint has data capture enabled." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "!pygmentize ../api/pre_traffic_hook.py" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The `post_traffic_hook.py` lambda is invoked to perform any final checks, in this case to verify that we have received log data from data capature." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "!pygmentize ../api/post_traffic_hook.py" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Use the code below to fetch the name of the endpoint, then run a loop to wait for the endpoint to be fully deployed. You need the status to be 'InService'." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "prd_endpoint_name='mlops-{}-prd-{}'.format(model_name, execution_id)\n", - "print('prod endpoint: {}'.format(prd_endpoint_name))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "sm = boto3.client('sagemaker')\n", - "\n", - "while True:\n", - " try:\n", - " response = sm.describe_endpoint(EndpointName=prd_endpoint_name)\n", - " print(\"Endpoint status: {}\".format(response['EndpointStatus']))\n", - " # Wait until the endpoint is in service with data capture enabled\n", - " if response['EndpointStatus'] == 'InService' \\\n", - " and 'DataCaptureConfig' in response \\\n", - " and response['DataCaptureConfig']['EnableCapture']:\n", - " break\n", - " except ClientError as e:\n", - " print(e.response[\"Error\"][\"Message\"])\n", - " time.sleep(10)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "When the endpoint status is 'InService', you can continue. Earlier in this notebook, you created some code to send data to the dev endpoint. Reuse this code now to send a sample of the test data to the production endpoint. Since data capture is enabled on this endpoint, you want to send single records at a time, so the model monitor can map these records to the baseline. \n", - "\n", - "You will [inspect the model monitor](#Inspect-Model-Monitor) later in this notebook. For now, just check if you can send data to the endpoint and receive predictions in return." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "prd_predictor = get_predictor(prd_endpoint_name)\n", - "sample_values = test_df[test_df.columns[1:]].sample(100).values\n", - "predictions = predict(prd_predictor, sample_values, rows=1)\n", - "predictions" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Test REST API\n", - "\n", - "Although you already tested the SageMaker endpoint in the previous section, it is also a good idea to test the application created with API Gateway. \n", - "\n", - "![Traffic shift between endpoints](../docs/lambda-deploy-create.png)\n", - "\n", - "Follow the link below to open the Lambda Deployment where you can see the in-progress and completed deployments. You can also click to expand the **SAM template** to see the packaged CloudFormation template used in the deployment." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "scrolled": true - }, - "outputs": [], - "source": [ - "HTML('Lambda Deployment'.format(region, model_name))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Run the code below to confirm that the endpoint is in service. It will complete once the REST API is available." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def get_stack_status(stack_name):\n", - " response = cfn.describe_stacks(StackName=stack_name)\n", - " if response['Stacks']:\n", - " stack = response['Stacks'][0]\n", - " outputs = None\n", - " if 'Outputs' in stack:\n", - " outputs = dict([(o['OutputKey'], o['OutputValue']) for o in stack['Outputs']])\n", - " return stack['StackStatus'], outputs \n", - "\n", - "outputs = None\n", - "while True:\n", - " try:\n", - " status, outputs = get_stack_status(stack_name)\n", - " response = sm.describe_endpoint(EndpointName=prd_endpoint_name)\n", - " print(\"Endpoint status: {}\".format(response['EndpointStatus']))\n", - " if outputs:\n", - " break\n", - " elif status.endswith('FAILED'):\n", - " raise(Exception('Stack status: {}'.format(status)))\n", - " except ClientError as e:\n", - " print(e.response[\"Error\"][\"Message\"])\n", - " time.sleep(10)\n", - "\n", - "if outputs:\n", - " print('deployment application: {}'.format(outputs['DeploymentApplication']))\n", - " print('rest api: {}'.format(outputs['RestApi']))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "If you are performing an update on your production deployment as a result of running [Trigger Retraining](#Trigger-Retraining) you will then be able to expand the Lambda Deployment tab to reveal the resources. Click on the **ApiFunctionAliaslive** link to see the Lambda Deployment in progress. \n", - "\n", - "![Traffic shift between endpoints](../docs/lambda-deploy-update.png)\n", - "\n", - "This page will be updated to list the deployment events. It also has a link to the Deployment Application which you can access in the output of the next cell." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "HTML('CodeDeploy application'.format(region, outputs['DeploymentApplication']))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "CodeDeploy will perform a canary deployment and send 10% of the traffic to the new endpoint over a 5-minute period.\n", - "\n", - "![Traffic shift between endpoints](../docs/code-deploy.gif)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We can invoke the REST API and inspect the headers being returned to see which endpoint we are hitting. You will occasionally see the cell below show a different endpoint that settles to the new version once the stack is complete. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "scrolled": false - }, - "outputs": [], - "source": [ - "%%time\n", - "\n", - "from urllib import request\n", - "\n", - "headers = {\"Content-type\": \"text/csv\"}\n", - "payload = test_df[test_df.columns[1:]].head(1).to_csv(header=False, index=False).encode('utf-8')\n", - "rest_api = outputs['RestApi']\n", - "\n", - "while True:\n", - " try:\n", - " resp = request.urlopen(request.Request(rest_api, data=payload, headers=headers))\n", - " print(\"Response code: %d: endpoint: %s\" % (resp.getcode(), resp.getheader('x-sagemaker-endpoint')))\n", - " status, outputs = get_stack_status(stack_name) \n", - " if status.endswith('COMPLETE'):\n", - " print('Deployment complete\\n')\n", - " break\n", - " elif status.endswith('FAILED'):\n", - " raise(Exception('Stack status: {}'.format(status)))\n", - " except ClientError as e:\n", - " print(e.response[\"Error\"][\"Message\"])\n", - " time.sleep(10)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Monitor\n", - "\n", - "### Inspect Model Monitor\n", - "\n", - "When you prepared the datasets for model training at the start of this notebook, you saved a baseline dataset (a copy of the train dataset). Then, when you approved the model for deployment into production, the pipeline set up an SageMaker Endpoint with data capture enabled and a model monitoring schedule. In this section, you will take a closer look at the model monitor results.\n", - "\n", - "To start off, fetch the latest production deployment execution ID." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "deploy_prd = get_pipeline_stage(pipeline_name, 'DeployPrd')\n", - "if not 'latestExecution' in deploy_prd:\n", - " raise(Exception('Please wait. Deploy prod not complete'))\n", - " \n", - "execution_id = deploy_prd['latestExecution']['pipelineExecutionId']" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Under the hood, SageMaker model monitor runs in SageMaker processing jobs. Use the execution ID to fetch the names of the processing job and the schedule." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "processing_job_name='mlops-{}-pbl-{}'.format(model_name, execution_id)\n", - "schedule_name='mlops-{}-pms'.format(model_name)\n", - "\n", - "print('processing job name: {}'.format(processing_job_name))\n", - "print('schedule name: {}'.format(schedule_name))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Explore Baseline\n", - "\n", - "Now fetch the baseline results from the processing job. This cell will throw an exception if the processing job is not complete - if that happens, just wait several minutes and try again. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "scrolled": true - }, - "outputs": [], - "source": [ - "import sagemaker\n", - "from sagemaker.model_monitor import BaseliningJob, MonitoringExecution\n", - "from sagemaker.s3 import S3Downloader\n", - "\n", - "sagemaker_session = sagemaker.Session()\n", - "baseline_job = BaseliningJob.from_processing_name(sagemaker_session, processing_job_name)\n", - "status = baseline_job.describe()['ProcessingJobStatus']\n", - "if status != 'Completed':\n", - " raise(Exception('Please wait. Processing job not complete, status: {}'.format(status)))\n", - " \n", - "baseline_results_uri = baseline_job.outputs[0].destination" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "SageMaker model monitor generates two types of files. Take a look at the statistics file first. It calculates various statistics for each feature of the dataset, including the mean, standard deviation, minimum value, maximum value, and more. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "scrolled": true - }, - "outputs": [], - "source": [ - "import pandas as pd\n", - "import json\n", - "\n", - "baseline_statistics = baseline_job.baseline_statistics().body_dict\n", - "schema_df = pd.json_normalize(baseline_statistics[\"features\"])\n", - "schema_df[[\"name\", \"numerical_statistics.mean\", \"numerical_statistics.std_dev\",\n", - " \"numerical_statistics.min\", \"numerical_statistics.max\"]].head()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now look at the suggested [constraints files](https://docs.aws.amazon.com/sagemaker/latest/dg/model-monitor-byoc-constraints.html)⇗. As the name implies, these are constraints which SageMaker model monitor recommends. If the live data which is sent to your production SageMaker Endpoint violates these constraints, this indicates data drift, and model monitor can raise an alert to trigger retraining. Of course, you can set different constraints based on the statistics which you viewed previously." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "baseline_constraints = baseline_job.suggested_constraints().body_dict\n", - "constraints_df = pd.json_normalize(baseline_constraints[\"features\"])\n", - "constraints_df.head()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### View data capture\n", - "\n", - "When the \"Deploy Production\" stage of the MLOps pipeline deploys a SageMaker endpoint, it also enables data capture. This means the incoming requests to the endpoint, as well as the results from the ML model, are stored in an S3 location. Model monitor can analyze this data and compare it to the baseline to ensure that no constraints are violated. \n", - "\n", - "Use the code below to check how many files have been created by the data capture, and view the latest file in detail. Note, data capture relies on data being sent to the production endpoint. If you don't see any files yet, wait several minutes and try again." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "bucket = sagemaker_session.default_bucket()\n", - "data_capture_logs_uri = 's3://{}/{}/datacapture/{}'.format(bucket, model_name, prd_endpoint_name)\n", - "\n", - "capture_files = S3Downloader.list(data_capture_logs_uri)\n", - "print('Found {} files'.format(len(capture_files)))\n", - "\n", - "if capture_files:\n", - " # Get the first line of the most recent file \n", - " event = json.loads(S3Downloader.read_file(capture_files[-1]).split('\\n')[0])\n", - " print('\\nLast file:\\n{}'.format(json.dumps(event, indent=2)))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### View monitoring schedule\n", - "\n", - "There are some useful functions for plotting and rendering distribution statistics or constraint violations provided in a `utils` file in the [SageMaker Examples GitHub](https://github.com/aws/amazon-sagemaker-examples/tree/master/sagemaker_model_monitor/visualization)⇗. Grab a copy of this code to use in this notebook. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "!wget -O utils.py --quiet https://raw.githubusercontent.com/awslabs/amazon-sagemaker-examples/master/sagemaker_model_monitor/visualization/utils.py\n", - "import utils as mu" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The [minimum scheduled run time](https://docs.aws.amazon.com/sagemaker/latest/dg/model-monitor-scheduling.html)⇗ for model monitor is one hour, which means you will need to wait at least an hour to see any results. Use the code below to check the schedule status and list the next run. If you are completing this notebook as part of a workshop, your host will have activities which you can complete while you wait. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "sm = boto3.client('sagemaker')\n", - "\n", - "response = sm.describe_monitoring_schedule(MonitoringScheduleName=schedule_name)\n", - "print('Schedule Status: {}'.format(response['MonitoringScheduleStatus']))\n", - "\n", - "now = datetime.now(tzlocal())\n", - "next_hour = (now+timedelta(hours=1)).replace(minute=0)\n", - "scheduled_diff = (next_hour-now).seconds//60\n", - "print('Next schedule in {} minutes'.format(scheduled_diff))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "While you wait, you can take a look at the CloudFormation template which is used as a base for the CloudFormation template built by CodeDeploy to deploy the production application. \n", - "\n", - "Alterntively, you can jump ahead to [Trigger Retraining](#Trigger-Retraining) which will kick off another run of the code pipeline whilst you wait." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "!cat ../assets/deploy-model-prd.yml" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "A couple of minutes after the model monitoring schedule has run, you can use the code below to fetch the latest schedule status. A completed schedule run may have found violations. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "processing_job_arn = None\n", - "\n", - "while processing_job_arn == None:\n", - " try:\n", - " response = sm.list_monitoring_executions(MonitoringScheduleName=schedule_name)\n", - " except ClientError as e:\n", - " print(e.response[\"Error\"][\"Message\"])\n", - " for mon in response['MonitoringExecutionSummaries']:\n", - " status = mon['MonitoringExecutionStatus']\n", - " now = datetime.now(tzlocal())\n", - " created_diff = (now-mon['CreationTime']).seconds//60\n", - " print('Schedule status: {}, Created: {} minutes ago'.format(status, created_diff))\n", - " if status in ['Completed', 'CompletedWithViolations']:\n", - " processing_job_arn = mon['ProcessingJobArn']\n", - " break\n", - " if status == 'InProgress':\n", - " break\n", - " else:\n", - " raise(Exception('Please wait. No Schedules executing'))\n", - " time.sleep(10)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### View monitoring results\n", - "\n", - "Once the model monitoring schedule has had a chance to run at least once, you can take a look at the results. First, load the monitoring execution results from the latest scheduled run." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "if processing_job_arn:\n", - " execution = MonitoringExecution.from_processing_arn(sagemaker_session=sagemaker.Session(),\n", - " processing_job_arn=processing_job_arn)\n", - " exec_inputs = {inp['InputName']: inp for inp in execution.describe()['ProcessingInputs']}\n", - " exec_results_uri = execution.output.destination\n", - "\n", - " print('Monitoring Execution results: {}'.format(exec_results_uri))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Take a look at the files which have been saved in the S3 output location. If violations were found, you should see a constraint violations file in addition to the statistics and constraints file which you viewed before." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "!aws s3 ls $exec_results_uri/" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now, fetch the monitoring statistics and violations. Then use the utils code to visualize the results in a table. It will highlight any baseline drift found by the model monitor. Drift can happen for categorical features (for inferred string styles) or for numerical features (e.g. total fare amount)." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Get the baseline and monitoring statistics & violations\n", - "baseline_statistics = baseline_job.baseline_statistics().body_dict\n", - "execution_statistics = execution.statistics().body_dict\n", - "violations = execution.constraint_violations().body_dict['violations']" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "mu.show_violation_df(baseline_statistics=baseline_statistics, \n", - " latest_statistics=execution_statistics, \n", - " violations=violations)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Trigger Retraining\n", - "\n", - "The CodePipeline instance is configured with [CloudWatch Events](https://docs.aws.amazon.com/codepipeline/latest/userguide/create-cloudtrail-S3-source.html)⇗ to start the pipeline for retraining when the drift detection triggers specific metric alarms.\n", - "\n", - "You can simulate drift by putting a metric value above the threshold of `0.2` directly into CloudWatch. This will trigger the alarm, and start the code pipeline.\n", - "\n", - "
    \n", - " Tip: This alarm is configured only for the latest production endpoint, so re-training will only occur if you are putting metrics against the latest endpoint.\n", - "
    \n", - "\n", - "![Metric graph in CloudWatch](../docs/cloudwatch-alarm.png)\n", - "\n", - "Run the code below to trigger the metric alarm. The cell output will be a link to CloudWatch, where you can see the alarm (similar to the screenshot above), and a link to CodePipeline which you will see run again. Note that it can take a couple of minutes for everything to trigger." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from datetime import datetime\n", - "import random\n", - "\n", - "cloudwatch = boto3.client('cloudwatch')\n", - "\n", - "# Define the metric name and threshold\n", - "metric_name = 'feature_baseline_drift_total_amount'\n", - "metric_threshold = 0.2\n", - "\n", - "# Put a new metric to trigger an alaram\n", - "def put_drift_metric(value):\n", - " print('Putting metric: {}'.format(value))\n", - " response = cloudwatch.put_metric_data(\n", - " Namespace='aws/sagemaker/Endpoints/data-metrics',\n", - " MetricData=[\n", - " {\n", - " 'MetricName': metric_name,\n", - " 'Dimensions': [\n", - " {\n", - " 'Name': 'MonitoringSchedule',\n", - " 'Value': schedule_name\n", - " },\n", - " {\n", - " 'Name': 'Endpoint',\n", - " 'Value': prd_endpoint_name\n", - " },\n", - " ],\n", - " 'Timestamp': datetime.now(),\n", - " 'Value': value,\n", - " 'Unit': 'None'\n", - " },\n", - " ]\n", - " )\n", - " \n", - "def get_drift_stats():\n", - " response = cloudwatch.get_metric_statistics(\n", - " Namespace='aws/sagemaker/Endpoints/data-metrics',\n", - " MetricName=metric_name,\n", - " Dimensions=[\n", - " {\n", - " 'Name': 'MonitoringSchedule',\n", - " 'Value': schedule_name\n", - " },\n", - " {\n", - " 'Name': 'Endpoint',\n", - " 'Value': prd_endpoint_name\n", - " },\n", - " ],\n", - " StartTime=datetime.now() - timedelta(minutes=2),\n", - " EndTime=datetime.now(),\n", - " Period=1,\n", - " Statistics=['Average'],\n", - " Unit='None'\n", - " )\n", - " if 'Datapoints' in response and len(response['Datapoints']) > 0: \n", - " return response['Datapoints'][0]['Average']\n", - " return 0 \n", - "\n", - "print('Simluate drift on endpoint: {}'.format(prd_endpoint_name))\n", - "\n", - "while True:\n", - " put_drift_metric(round(random.uniform(metric_threshold, 1.0), 4))\n", - " drift_stats = get_drift_stats()\n", - " print('Average drift amount: {}'.format(get_drift_stats()))\n", - " if drift_stats > metric_threshold:\n", - " break\n", - " time.sleep(1)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Click through to the Alarm and CodePipeline Execution history with the links below." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Output a html link to the cloudwatch dashboard\n", - "metric_alarm_name = 'mlops-{}-metric-gt-threshold'.format(model_name)\n", - "HTML('''CloudWatch Alarm triggers\n", - " Code Pipeline Execution'''.format(region, metric_alarm_name, pipeline_name))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Once the pipeline is running again you can jump back up to [Inspect Training Job](#Inspect-Training-Job)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Create Synthetic Monitoring\n", - "\n", - "[Amazon CloudWatch Synthetics](https://aws.amazon.com/blogs/aws/new-use-cloudwatch-synthetics-to-monitor-sites-api-endpoints-web-workflows-and-more/) allows you to monitor sites, REST APIs, and other services deployed on AWS. You can set up a canary to test that your REST API is returning an expected value at a regular interval. This is a great way to validate that the blue/green deployment is not causing any downtime for your end-users.\n", - "\n", - "Use the code below to set up a canary to continuously test the production deployment. This canary simply pings the REST API to test if it is live, using code from `notebook/canary.js`." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from urllib.parse import urlparse\n", - "from string import Template\n", - "from io import BytesIO\n", - "import zipfile\n", - "\n", - "# Format the canary_js with rest_api and payload\n", - "rest_url = urlparse(rest_api)\n", - "\n", - "with open('canary.js') as f:\n", - " canary_js = Template(f.read()).substitute(hostname=rest_url.netloc, path=rest_url.path, \n", - " data=payload.decode('utf-8').strip())\n", - "# Write the zip file\n", - "zip_buffer = BytesIO()\n", - "with zipfile.ZipFile(zip_buffer, 'w') as zf:\n", - " zip_path = 'nodejs/node_modules/apiCanaryBlueprint.js' # Set a valid path\n", - " zip_info = zipfile.ZipInfo(zip_path)\n", - " zip_info.external_attr = 0o0755 << 16 # Ensure the file is readable\n", - " zf.writestr(zip_info, canary_js)\n", - "zip_buffer.seek(0)\n", - "\n", - "# Create the canary\n", - "synth = boto3.client('synthetics')\n", - "\n", - "role = sagemaker.get_execution_role()\n", - "s3_canary_uri = 's3://{}/{}'.format(artifact_bucket, model_name)\n", - "canary_name = 'mlops-{}'.format(model_name)\n", - "\n", - "try:\n", - " response = synth.create_canary(\n", - " Name=canary_name,\n", - " Code={\n", - " 'ZipFile': bytearray(zip_buffer.read()),\n", - " 'Handler': 'apiCanaryBlueprint.handler'\n", - " },\n", - " ArtifactS3Location=s3_canary_uri,\n", - " ExecutionRoleArn=role,\n", - " Schedule={ \n", - " 'Expression': 'rate(10 minutes)', \n", - " 'DurationInSeconds': 0 },\n", - " RunConfig={\n", - " 'TimeoutInSeconds': 60,\n", - " 'MemoryInMB': 960\n", - " },\n", - " SuccessRetentionPeriodInDays=31,\n", - " FailureRetentionPeriodInDays=31,\n", - " RuntimeVersion='syn-nodejs-2.0',\n", - " )\n", - " print('Creating canary: {}'.format(canary_name)) \n", - "except ClientError as e:\n", - " if e.response[\"Error\"][\"Code\"] == \"AccessDeniedException\":\n", - " print('Canary not supported.') # Not supported in event engine\n", - " else:\n", - " raise(e)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now create a CloudWatch alarm which will trigger if the success rate of the canary drops below 90%. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "cloudwatch = boto3.client('cloudwatch')\n", - "\n", - "canary_alarm_name = '{}-synth-lt-threshold'.format(canary_name)\n", - "\n", - "response = cloudwatch.put_metric_alarm(\n", - " AlarmName=canary_alarm_name,\n", - " ComparisonOperator='LessThanThreshold',\n", - " EvaluationPeriods=1,\n", - " DatapointsToAlarm=1,\n", - " Period=600, # 10 minute interval\n", - " Statistic='Average',\n", - " Threshold=90.0,\n", - " ActionsEnabled=False,\n", - " AlarmDescription='SuccessPercent LessThanThreshold 90%',\n", - " Namespace='CloudWatchSynthetics',\n", - " MetricName='SuccessPercent',\n", - " Dimensions=[\n", - " {\n", - " 'Name': 'CanaryName',\n", - " 'Value': canary_name\n", - " },\n", - " ],\n", - " Unit='Seconds'\n", - ")\n", - "\n", - "print('Creating alarm: {}'.format(canary_alarm_name))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Run the code below to check if the canary is running succesfully. The cell will output a link to your CloudWatch Canaries UI, where you can watch the results over time (see screenshot). It can take a couple of minutes for the canary to deploy.\n", - "\n", - "![Canary graph in CloudWatch](../docs/canary-green-1hr.png)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "while True:\n", - " try:\n", - " response = synth.get_canary(Name=canary_name)\n", - " status = response['Canary']['Status']['State'] \n", - " print('Canary status: {}'.format(status))\n", - " if status == 'ERROR':\n", - " raise(Exception(response['Canary']['Status']['StateReason'])) \n", - " elif status == 'READY':\n", - " synth.start_canary(Name=canary_name)\n", - " elif status == 'RUNNING':\n", - " break \n", - " except ClientError as e:\n", - " if e.response[\"Error\"][\"Code\"] == \"ResourceNotFoundException\":\n", - " print('No canary found.')\n", - " break\n", - " elif e.response[\"Error\"][\"Code\"] == \"AccessDeniedException\":\n", - " print('Canary not supported.') # Not supported in event engine\n", - " break\n", - " print(e.response[\"Error\"][\"Message\"])\n", - " time.sleep(10)\n", - "\n", - "# Output a html link to the cloudwatch console\n", - "HTML('CloudWatch Canary'.format(region, canary_name))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Create a CloudWatch dashboard\n", - "\n", - "Finally, use the code below to create a CloudWatch dashboard to visualize the key performance metrics and alarms which you have created during this demo. The cell will output a link to the dashboard. This dashboard shows 9 charts in three rows, where the first row displays Lambda metrics, the second row displays SageMaker metrics, and the third row (shown in the screenshot below) displays the alarms set up for the pipeline.\n", - "\n", - "![Graphs in CloudWatch dashboard](../docs/cloudwatch-dashboard.png)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "sts = boto3.client('sts')\n", - "account_id = sts.get_caller_identity().get('Account')\n", - "dashboard_name = 'mlops-{}'.format(model_name)\n", - "\n", - "with open('dashboard.json') as f:\n", - " dashboard_body = Template(f.read()).substitute(region=region, account_id=account_id, model_name=model_name)\n", - " response = cloudwatch.put_dashboard(\n", - " DashboardName=dashboard_name,\n", - " DashboardBody=dashboard_body\n", - " )\n", - "\n", - "# Output a html link to the cloudwatch dashboard\n", - "HTML('CloudWatch Dashboard'.format(region, canary_name))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Congratulations! You have made it to the end of this notebook, and have automated a safe MLOps pipeline using a wide range of AWS services. \n", - "\n", - "You can use the other notebook in this repository [workflow.ipynb](workflow.ipynb) to implement your own ML model and deploy it as part of this pipeline. Or, if you are finished with the content, follow the instructions in the next section to clean up the resources you have deployed." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Cleanup\n", - "\n", - "Execute the following cell to delete the stacks created in the pipeline. For a model name of **nyctaxi** these would be:\n", - "\n", - "1. *nyctaxi*-deploy-prd\n", - "2. *nyctaxi*-deploy-dev\n", - "3. *nyctaxi*-workflow\n", - "4. sagemaker-custom-resource" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "cfn = boto3.client('cloudformation')\n", - "\n", - "# Delete the prod and then dev stack\n", - "for stack_name in [f'{pipeline_name}-deploy-prd', \n", - " f'{pipeline_name}-deploy-dev',\n", - " f'{pipeline_name}-workflow',\n", - " 'sagemaker-custom-resource']:\n", - " print('Deleting stack: {}'.format(stack_name))\n", - " cfn.delete_stack(StackName=stack_name)\n", - " cfn.get_waiter('stack_delete_complete').wait(StackName=stack_name)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The following code will stop and delete the canary you created." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "while True:\n", - " try:\n", - " response = synth.get_canary(Name=canary_name)\n", - " status = response['Canary']['Status']['State'] \n", - " print('Canary status: {}'.format(status))\n", - " if status == 'ERROR':\n", - " raise(Exception(response['Canary']['Status']['StateReason'])) \n", - " elif status == 'STOPPED':\n", - " synth.delete_canary(Name=canary_name)\n", - " elif status == 'RUNNING':\n", - " synth.stop_canary(Name=canary_name)\n", - " except ClientError as e:\n", - " if e.response[\"Error\"][\"Code\"] == \"ResourceNotFoundException\":\n", - " print('Canary succesfully deleted.')\n", - " break\n", - " elif e.response[\"Error\"][\"Code\"] == \"AccessDeniedException\":\n", - " print('Canary not created.') # Not supported in event engine\n", - " break\n", - " print(e.response[\"Error\"][\"Message\"])\n", - " time.sleep(10)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The following code will delete the dashboard." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "cloudwatch.delete_alarms(AlarmNames=[canary_alarm_name])\n", - "print('Alarm deleted')\n", - "\n", - "cloudwatch.delete_dashboards(DashboardNames=[dashboard_name])\n", - "print('Dashboard deleted')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Finally, close this notebook and you can delete the CloudFormation you created to launch this MLOps sample." - ] - } - ], - "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.13" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} +{"cells": [{"cell_type": "markdown", "metadata": {}, "source": ["# Safe MLOps Deployment Pipeline\n", "\n", "\n", "## Overview\n", "\n", "In this notebook you will step through an MLOps pipeline to build, train, deploy and monitor an XGBoost regression model for predicting the expected taxi fare using the New York City Taxi [dataset](https://registry.opendata.aws/nyc-tlc-trip-records-pds/)\u21d7. This safe pipeline features a [canary deployment](https://docs.aws.amazon.com/wellarchitected/latest/machine-learning-lens/canary-deployment.html) strategy with rollback on error. You will learn how to trigger and monitor the pipeline, inspect the training workflow, use model monitor to set up alerts, and create a canary deployment.\n", "\n", "
    \n", " Note: This notebook assumes prior familiarity with the basics training ML models on Amazon SageMaker. Data preparation and visualization, although present, will be kept to a minimum. If you are not familiar with the basic concepts and features of SageMaker, we recommend reading the SageMaker documentation\u21d7 and completing the workshops and samples in AWS SageMaker Examples GitHub\u21d7 and AWS Samples GitHub\u21d7. \n", "
    \n", "\n", "### Contents\n", "\n", "This notebook has the following key sections:\n", "\n", "1. [Data Prep](#Data-Prep)\n", "2. [Build](#Build)\n", "3. [Train Model](#Train-Model)\n", "4. [Deploy Dev](#Deploy-Dev)\n", "5. [Deploy Prod](#Deploy-Prod)\n", "6. [Monitor](#Monitor)\n", "6. [Cleanup](#Cleanup)\n", "\n", "### Architecture\n", "\n", "The architecture diagram below shows the entire MLOps pipeline at a high level.\n", "\n", "Use the CloudFormation template provided in this repository (`pipeline.yml`) to build the demo in your own AWS account. If you are currently viewing this notebook from SageMaker in your AWS account, then you have already completed this step. CloudFormation deploys several resources:\n", " \n", "1. A customer-managed encryption key in in Amazon KMS for encrypting data and artifacts.\n", "1. A secret in Amazon Secrets Manager to securely store your GitHub Access Token.\n", "1. Several AWS IAM roles so CloudFormation, SageMaker, and other AWS services can perform actions in your AWS account, following the principle of [least privilege](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#grant-least-privilege)\u21d7.\n", "1. A messaging service in Amazon SNS to notify you when CodeDeploy has successfully deployed the API, and to receive alerts for retraining and drift detection (signing up for these notifications is optional).\n", "1. Two Amazon CloudWatch event rules: one which schedules the pipeline to run every month, and one which triggers the pipeline to run when SageMaker Model Monitor detects certain metrics.\n", "1. An Amazon SageMaker Jupyter notebook with this workshop content pre-loaded.\n", "1. An Amazon S3 bucket for storing model artifacts.\n", "1. An AWS CodePipeline instance with several pre-defined stages. \n", "\n", "Take a moment to look at all of these resources now deployed in your account. \n", "\n", "![MLOps pipeline architecture](../docs/mlops-architecture.png)\n", "\n", "In this notebook, you will work through the CodePipeline instance created by the CloudFormation template. It has several stages:\n", "\n", "1. **Source** - The pipeline is already configured with two sources. If you upload a new dataset to a specific location in the S3 data bucket, this will trigger the pipeline to run. The Git source can be GitHub, or CodeCommit if you don\u2019t supply your access token. If you commit new code to your repository, this will trigger the pipeline to run. \n", "1. **Build** - In this stage, CodeBuild configured by the build specification `model/buildspec.yml` will execute `model/run_pipeline.py` to generate AWS CloudFormation templates for creating the AWS Step Function (including AWS Lambda custom resources), and deployment templates used in the following stages based on the data sets and hyperparameters specified for this pipeline run. You will take a closer look at these files later in this notebook. \n", "1. **Train** The Step Functions workflow created in the Build stage is run in this stage. The workflow creates a baseline for the model monitor using a SageMaker processing job, and trains an XGBoost model on the taxi ride dataset using a SageMaker training job.\n", "1. **Deploy Dev** In this stage, a CloudFormation template created in the build stage (from `assets/deploy-model-dev.yml`) deploys a dev endpoint. This will allow you to run tests on the model and decide if the model is of sufficient quality to deploy into production.\n", "1. **Deploy Production** The final stage of the pipeline is the only stage which does not run automatically as soon as the previous stage is complete. It waits for a user to manually approve the model which was previously deployed to dev. As soon as the model is approved, a CloudFormation template (packaged from `assets/deploy-model-prod.yml` to include the Lambda functions saved and uploaded as ZIP files in S3) deploys the production endpoint. It configures autoscaling and enables data capture. It creates a model monitoring schedule and sets CloudWatch alarms for certain metrics. It also sets up an AWS CodeDeploy instance which deploys a set of AWS Lambda functions and an Amazon API Gateway to sit in front of the SageMaker endpoint. This stage can make use of canary deployment to safely switch from an old model to a new model."]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["# Replace `None` with the project name when creating SageMaker Project\n", "# You can find it from the left panel in Studio\n", "\n", "PROJECT_NAME = None\n", "\n", "assert PROJECT_NAME is not None and isinstance(\n", " PROJECT_NAME, str\n", "), \"Please specify the project name as string\""]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["import boto3\n", "from IPython.core.display import HTML, display\n", "\n", "\n", "def get_provisioned_product_name(project_name):\n", " region = boto3.Session().region_name\n", " sc = boto3.client(\"servicecatalog\")\n", " products = sc.search_provisioned_products(\n", " Filters={\n", " \"SearchQuery\": [\n", " project_name,\n", " ]\n", " }\n", " )\n", " pp = products[\"ProvisionedProducts\"]\n", " if len(pp) != 1:\n", " print(\"Invalid provisioned product name. Open the link below and search manually\")\n", " display(\n", " HTML(\n", " f'Service Catalog'\n", " )\n", " )\n", " raise ValueError(\"Invalid provisioned product\")\n", "\n", " return pp[0][\"Name\"]\n", "\n", "\n", "PROVISIONED_PRODUCT_NAME = get_provisioned_product_name(PROJECT_NAME)\n", "print(\n", " f\"The associated Service Catalog Provisioned Product Name to this SagaMaker project: {PROVISIONED_PRODUCT_NAME}\"\n", ")"]}, {"cell_type": "markdown", "metadata": {}, "source": ["In case of any errors, you can examine the Service Catalog console from the above link and find the associated provisioned product name which is something like `example-p-1v7hbpwe594n` and assigns it to `PROVISIONED_PRODUCT_NAME` manually."]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["# Import the latest sagemaker and boto3 SDKs.\n", "import sys\n", "\n", "!{sys.executable} -m pip install --upgrade pip\n", "!{sys.executable} -m pip install -qU awscli boto3 \"sagemaker>=2.1.0<3\" tqdm\n", "!{sys.executable} -m pip install -qU \"stepfunctions==2.0.0\"\n", "!{sys.executable} -m pip show sagemaker stepfunctions"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Restart your SageMaker kernel then continue with this notebook."]}, {"cell_type": "markdown", "metadata": {}, "source": ["## Data Prep\n", " \n", "In this section of the notebook, you will download the publicly available New York Taxi dataset in preparation for uploading it to S3.\n", "\n", "### Download Dataset\n", "\n", "First, download a sample of the New York City Taxi [dataset](https://registry.opendata.aws/nyc-tlc-trip-records-pds/)\u21d7 to this notebook instance. This dataset contains information on trips taken by taxis and for-hire vehicles in New York City, including pick-up and drop-off times and locations, fares, distance traveled, and more. "]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["!aws s3 cp 's3://nyc-tlc/trip data/green_tripdata_2018-02.csv' 'nyc-tlc.csv'"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Now load the dataset into a pandas data frame, taking care to parse the dates correctly."]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["import pandas as pd\n", "\n", "parse_dates = [\"lpep_dropoff_datetime\", \"lpep_pickup_datetime\"]\n", "trip_df = pd.read_csv(\"nyc-tlc.csv\", parse_dates=parse_dates)\n", "\n", "trip_df.head()"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Data manipulation\n", "\n", "Instead of the raw date and time features for pick-up and drop-off, let's use these features to calculate the total time of the trip in minutes, which will be easier to work with for our model."]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["trip_df[\"duration_minutes\"] = (\n", " trip_df[\"lpep_dropoff_datetime\"] - trip_df[\"lpep_pickup_datetime\"]\n", ").dt.seconds / 60"]}, {"cell_type": "markdown", "metadata": {}, "source": ["The dataset contains a lot of columns we don't need, so let's select a sample of columns for our machine learning model. Keep only `total_amount` (fare), `duration_minutes`, `passenger_count`, and `trip_distance`."]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["cols = [\"total_amount\", \"duration_minutes\", \"passenger_count\", \"trip_distance\"]\n", "data_df = trip_df[cols]\n", "print(data_df.shape)\n", "data_df.head()"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Generate some quick statistics for the dataset to understand the quality."]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["data_df.describe()"]}, {"cell_type": "markdown", "metadata": {}, "source": ["The table above shows some clear outliers, e.g. -400 or 2626 as fare, or 0 passengers. There are many intelligent methods for identifying and removing outliers, but data cleaning is not the focus of this notebook, so just remove the outliers by setting some min and max values which seem more reasonable. Removing the outliers results in a final dataset of 754,671 rows."]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["data_df = data_df[\n", " (data_df.total_amount > 0)\n", " & (data_df.total_amount < 200)\n", " & (data_df.duration_minutes > 0)\n", " & (data_df.duration_minutes < 120)\n", " & (data_df.trip_distance > 0)\n", " & (data_df.trip_distance < 121)\n", " & (data_df.passenger_count > 0)\n", "].dropna()\n", "print(data_df.shape)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Data visualization\n", "\n", "Since this notebook will build a regression model for the taxi data, it's a good idea to check if there is any correlation between the variables in our data. Use scatter plots on a sample of the data to compare trip distance with duration in minutes, and total amount (fare) with duration in minutes."]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["import seaborn as sns\n", "\n", "sample_df = data_df.sample(1000)\n", "sns.scatterplot(data=sample_df, x=\"duration_minutes\", y=\"trip_distance\")"]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["sns.scatterplot(data=sample_df, x=\"duration_minutes\", y=\"total_amount\")"]}, {"cell_type": "markdown", "metadata": {}, "source": ["These scatter plots look fine and show at least some correlation between our variables. \n", "\n", "### Data splitting and saving\n", "\n", "We are now ready to split the dataset into train, validation, and test sets. "]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["from sklearn.model_selection import train_test_split\n", "\n", "train_df, val_df = train_test_split(data_df, test_size=0.20, random_state=42)\n", "val_df, test_df = train_test_split(val_df, test_size=0.05, random_state=42)\n", "\n", "# Reset the index for our test dataframe\n", "test_df.reset_index(inplace=True, drop=True)\n", "\n", "print(\n", " \"Size of\\n train: {},\\n val: {},\\n test: {} \".format(\n", " train_df.shape[0], val_df.shape[0], test_df.shape[0]\n", " )\n", ")"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Save the train, validation, and test files as CSV locally on this notebook instance. Notice that you save the train file twice - once as the training data file and once as the baseline data file. The baseline data file will be used by [SageMaker Model Monitor](https://docs.aws.amazon.com/sagemaker/latest/dg/model-monitor.html)\u21d7 to detect data drift. Data drift occurs when the statistical nature of the data that your model receives while in production drifts away from the nature of the baseline data it was trained on, which means the model begins to lose accuracy in its predictions."]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["train_cols = [\"total_amount\", \"duration_minutes\", \"passenger_count\", \"trip_distance\"]\n", "train_df.to_csv(\"train.csv\", index=False, header=False)\n", "val_df.to_csv(\"validation.csv\", index=False, header=False)\n", "test_df.to_csv(\"test.csv\", index=False, header=False)\n", "\n", "# Save test and baseline with headers\n", "train_df.to_csv(\"baseline.csv\", index=False, header=True)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Now upload these CSV files to your default SageMaker S3 bucket. "]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["import sagemaker\n", "\n", "# Get the session and default bucket\n", "session = sagemaker.session.Session()\n", "bucket = session.default_bucket()\n", "\n", "# Specify data prefix and version\n", "prefix = \"nyc-tlc/v1\"\n", "\n", "s3_train_uri = session.upload_data(\"train.csv\", bucket, prefix + \"/data/training\")\n", "s3_val_uri = session.upload_data(\"validation.csv\", bucket, prefix + \"/data/validation\")\n", "s3_test_uri = session.upload_data(\"test.csv\", bucket, prefix + \"/data/test\")\n", "s3_baseline_uri = session.upload_data(\"baseline.csv\", bucket, prefix + \"/data/baseline\")"]}, {"cell_type": "markdown", "metadata": {}, "source": ["You will use the datasets which you have prepared and saved in this section to trigger the pipeline to train and deploy a model in the next section."]}, {"cell_type": "markdown", "metadata": {}, "source": ["## Build\n", "\n", "If you navigate to the CodePipeline instance created for this workshop, you will notice that the Source stage is initially in a `Failed` state. This happens because the dataset, which is one of the sources that can trigger the pipeline, has not yet been uploaded to the S3 location expected by the pipeline.\n", "\n", "![Failed code pipeline](../docs/pipeline_failed.png)\n", "\n", "### Trigger Build\n", "\n", "In this section, you will start a model build and deployment pipeline by packaging up the datasets you prepared in the previous section and uploading these to the S3 source location which triggers the CodePipeline instance created for this workshop. \n", "\n", "\n", "First, import some libraries and load some environment variables which you will need. These environment variables have been set through a [lifecycle configuration](https://docs.aws.amazon.com/sagemaker/latest/dg/notebook-lifecycle-config.html)\u21d7 script attached to this notebook."]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["import boto3\n", "from botocore.exceptions import ClientError\n", "import os\n", "import time\n", "\n", "\n", "def get_config(provisioned_product_name):\n", " sc = boto3.client(\"servicecatalog\")\n", " outputs = sc.get_provisioned_product_outputs(ProvisionedProductName=provisioned_product_name)[\n", " \"Outputs\"\n", " ]\n", " config = {}\n", " for out in outputs:\n", " config[out[\"OutputKey\"]] = out[\"OutputValue\"]\n", " return config\n", "\n", "\n", "config = get_config(PROVISIONED_PRODUCT_NAME)\n", "region = config[\"Region\"]\n", "artifact_bucket = config[\"ArtifactBucket\"]\n", "pipeline_name = config[\"PipelineName\"]\n", "model_name = config[\"ModelName\"]\n", "workflow_pipeline_arn = config[\"WorkflowPipelineARN\"]\n", "\n", "print(\"region: {}\".format(region))\n", "print(\"artifact bucket: {}\".format(artifact_bucket))\n", "print(\"pipeline: {}\".format(pipeline_name))\n", "print(\"model name: {}\".format(model_name))\n", "print(\"workflow: {}\".format(workflow_pipeline_arn))"]}, {"cell_type": "markdown", "metadata": {}, "source": ["From the AWS CodePipeline [documentation](https://docs.aws.amazon.com/codepipeline/latest/userguide/tutorials-simple-s3.html)\u21d7:\n", "\n", "> When Amazon S3 is the source provider for your pipeline, you may zip your source file or files into a single .zip and upload the .zip to your source bucket. You may also upload a single unzipped file; however, downstream actions that expect a .zip file will fail.\n", "\n", "To train a model, you need multiple datasets (train, validation, and test) along with a file specifying the hyperparameters. In this example, you will create one JSON file which contains the S3 dataset locations and one JSON file which contains the hyperparameter values. Then you compress both files into a zip package to be used as input for the pipeline run. "]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["from io import BytesIO\n", "import zipfile\n", "import json\n", "\n", "input_data = {\n", " \"TrainingUri\": s3_train_uri,\n", " \"ValidationUri\": s3_val_uri,\n", " \"TestUri\": s3_test_uri,\n", " \"BaselineUri\": s3_baseline_uri,\n", "}\n", "\n", "hyperparameters = {\"num_round\": 50}\n", "\n", "zip_buffer = BytesIO()\n", "with zipfile.ZipFile(zip_buffer, \"a\") as zf:\n", " zf.writestr(\"inputData.json\", json.dumps(input_data))\n", " zf.writestr(\"hyperparameters.json\", json.dumps(hyperparameters))\n", "zip_buffer.seek(0)\n", "\n", "data_source_key = \"{}/data-source.zip\".format(pipeline_name)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Now upload the zip package to your artifact S3 bucket - this action will trigger the pipeline to train and deploy a model."]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["s3 = boto3.client(\"s3\")\n", "s3.put_object(Bucket=artifact_bucket, Key=data_source_key, Body=bytearray(zip_buffer.read()))"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Click the link below to open the AWS console at the Code Pipeline if you don't have it open in another tab.\n", "\n", "
    \n", " Tip: You may need to wait a minute to see the DataSource stage turn green. The page will refresh automatically.\n", "
    \n", "\n", "![Source Green](../docs/datasource-after.png)"]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["from IPython.core.display import HTML\n", "\n", "HTML(\n", " 'Code Pipeline'.format(\n", " region, pipeline_name\n", " )\n", ")"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Inspect Build Logs\n", "\n", "Once the build stage is running, you will see the AWS CodeBuild job turn blue with a status of **In progress**.\n", "\n", "![Failed code pipeline](../docs/codebuild-inprogress.png)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["You can click on the **Details** link displayed in the CodePipeline UI or click the link below to jump directly to the CodeBuild logs.\n", "\n", "
    \n", " Tip: You may need to wait a few seconds for the pipeline to transition into the active (blue) state and for the build to start.\n", "
    "]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["codepipeline = boto3.client(\"codepipeline\")\n", "\n", "\n", "def get_pipeline_stage(pipeline_name, stage_name):\n", " response = codepipeline.get_pipeline_state(name=pipeline_name)\n", " for stage in response[\"stageStates\"]:\n", " if stage[\"stageName\"] == stage_name:\n", " return stage\n", "\n", "\n", "# Get last execution id\n", "build_stage = get_pipeline_stage(pipeline_name, \"Build\")\n", "if not \"latestExecution\" in build_stage:\n", " raise (Exception(\"Please wait. Build not started\"))\n", "\n", "build_url = build_stage[\"actionStates\"][0][\"latestExecution\"][\"externalExecutionUrl\"]\n", "\n", "# Out a link to the code build logs\n", "HTML('Code Build Logs'.format(build_url))"]}, {"cell_type": "markdown", "metadata": {}, "source": ["The AWS CodeBuild process is responsible for creating a number of AWS CloudFormation templates which we will explore in more detail in the next section. Two of these templates are used to set up the **Train** step by creating the AWS Step Functions worklow and the custom AWS Lambda functions used within this workflow."]}, {"cell_type": "markdown", "metadata": {}, "source": ["## Train Model\n", "\n", "### Inspect Training Job\n", "\n", "Wait until the pipeline has started running the Train step (see screenshot) before continuing with the next cells in this notebook. \n", "\n", "![Training in progress](../docs/train-in-progress.png)\n", "\n", "When the pipeline has started running the train step, you can click on the **Details** link displayed in the CodePipeline UI (see screenshot above) to view the Step Functions workflow which is running the training job. \n", "\n", "Alternatively, you can click on the Workflow link from the cell output below once it's available."]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["from stepfunctions.workflow import Workflow\n", "\n", "while True:\n", " try:\n", " workflow = Workflow.attach(workflow_pipeline_arn)\n", " break\n", " except ClientError as e:\n", " print(e.response[\"Error\"][\"Message\"])\n", " time.sleep(10)\n", "\n", "workflow"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Review Build Script\n", "\n", "While you wait for the training job to complete, let's take a look at the `run.py` code which was used by the AWS CodeBuild process.\n", "\n", "This script takes all of the input parameters, including the dataset locations and hyperparameters which you saved to JSON files earlier in this notebook, and uses them to generate the templates which the pipeline needs to run the training job. It *does not* create the actual Step Functions instance - it only generates the templates which define the Step Functions workflow, as well as the CloudFormation input templates which CodePipeline uses to instantiate the Step Functions instance.\n", "\n", "Step-by-step, the script does the following:\n", "\n", "1. It collects all the input parameters it needs to generate the templates. This includes information about the environment container needed to run the training job, the input and output data locations, IAM roles needed by various components, encryption keys, and more. It then sets up some basic parameters like the AWS region and the function names.\n", "1. If the input parameters specify an environment container stored in ECR, it fetches that container. Otherwise, it fetches the URI of the AWS managed environment container needed for the training job.\n", "1. It reads the input data JSON file which you generated earlier in this notebook (and which was included in the zip source for the pipeline), thereby fetching the locations of the train, validation, and baseline data files. Then it formats more parameters which will be needed later in the script, including version IDs and output data locations.\n", "1. It reads the hyperparameter JSON file which you generated earlier in this notebook.\n", "1. It defines the Step Functions workflow, starting with the input schema, followed by each step of the workflow (i.e. Create Experiment, Baseline Job, Training Job), and finally combines those steps into a workflow graph. \n", "1. The workflow graph is saved to file, along with a file containing all of the input parameters saved according to the schema defined in the workflow.\n", "1. It saves parameters to file which will be used by CloudFormation to instantiate the Step Functions workflow."]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["!pygmentize ../model/run_pipeline.py"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Customize Workflow (Optional)\n", "\n", "If you are interested in customising the workflow used in the Build Script, store the `input_data` to be used within the local [workflow.ipynb](workflow.ipynb) notebook. The workflow notebook can be used to experiment with the Step Functions workflow and training job definitions for your model."]}, {"cell_type": "code", "execution_count": null, "metadata": {"scrolled": true}, "outputs": [], "source": ["%store input_data PROVISIONED_PRODUCT_NAME"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Training Analytics\n", "\n", "Once the training and baseline jobs are complete (meaning they are displayed in a green color in the Step Functions workflow, this takes around 5 minutes), you can inspect the experiment metrics. The code below will display all experiments in a table. Note that the baseline processing job won't have RMSE metrics - it calculates metrics based on the training data, but does not train a machine learning model. \n", "\n", "You will [explore the baseline](#Explore-Baseline) results later in this notebook. "]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["from sagemaker import analytics\n", "\n", "experiment_name = \"mlops-{}\".format(model_name)\n", "model_analytics = analytics.ExperimentAnalytics(experiment_name=experiment_name)\n", "analytics_df = model_analytics.dataframe()\n", "\n", "if analytics_df.shape[0] == 0:\n", " raise (Exception(\"Please wait. No training or baseline jobs\"))\n", "\n", "pd.set_option(\"display.max_colwidth\", 100) # Increase column width to show full copmontent name\n", "cols = [\n", " \"TrialComponentName\",\n", " \"DisplayName\",\n", " \"SageMaker.InstanceType\",\n", " \"train:rmse - Last\",\n", " \"validation:rmse - Last\",\n", "] # return the last rmse for training and validation\n", "analytics_df[analytics_df.columns & cols].head(2)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["## Deploy Dev\n", "\n", "### Test Dev Deployment\n", "\n", "When the pipeline has finished training a model, it automatically moves to the next step, where the model is deployed as a SageMaker Endpoint. This endpoint is part of your dev deployment, therefore, in this section, you will run some tests on the endpoint to decide if you want to deploy this model into production.\n", "\n", "First, run the cell below to fetch the name of the SageMaker Endpoint."]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["codepipeline = boto3.client(\"codepipeline\")\n", "\n", "deploy_dev = get_pipeline_stage(pipeline_name, \"DeployDev\")\n", "if not \"latestExecution\" in deploy_dev:\n", " raise (Exception(\"Please wait. Deploy dev not started\"))\n", "\n", "execution_id = deploy_dev[\"latestExecution\"][\"pipelineExecutionId\"]\n", "dev_endpoint_name = \"mlops-{}-dev-{}\".format(model_name, execution_id)\n", "\n", "print(\"endpoint name: {}\".format(dev_endpoint_name))"]}, {"cell_type": "markdown", "metadata": {}, "source": ["If you moved through the previous section very quickly, you will need to wait until the dev endpoint has been successfully deployed and the pipeline is waiting for approval to deploy to production (see screenshot). It can take up to 10 minutes for SageMaker to create an endpoint.\n", "\n", "![Deploying dev endpoint in code pipeline](../docs/dev-deploy-ready.png)\n", "\n", "Alternatively, run the code below to check the status of your endpoint. Wait until the status of the endpoint is 'InService'."]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["sm = boto3.client(\"sagemaker\")\n", "\n", "while True:\n", " try:\n", " response = sm.describe_endpoint(EndpointName=dev_endpoint_name)\n", " print(\"Endpoint status: {}\".format(response[\"EndpointStatus\"]))\n", " if response[\"EndpointStatus\"] == \"InService\":\n", " break\n", " except ClientError as e:\n", " print(e.response[\"Error\"][\"Message\"])\n", " time.sleep(10)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Now that your endpoint is ready, let's write some code to run the test data (which you split off from the dataset and saved to file at the start of this notebook) through the endpoint for inference. The code below supports both v1 and v2 of the SageMaker SDK, but we recommend using v2 of the SDK in all of your future projects."]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["import numpy as np\n", "from tqdm import tqdm\n", "\n", "from sagemaker.predictor import Predictor\n", "from sagemaker.serializers import CSVSerializer\n", "\n", "\n", "def get_predictor(endpoint_name):\n", " xgb_predictor = Predictor(endpoint_name)\n", " xgb_predictor.serializer = CSVSerializer()\n", " return xgb_predictor\n", "\n", "\n", "def predict(predictor, data, rows=500):\n", " split_array = np.array_split(data, round(data.shape[0] / float(rows)))\n", " predictions = \"\"\n", " for array in tqdm(split_array):\n", " predictions = \",\".join([predictions, predictor.predict(array).decode(\"utf-8\")])\n", " return np.fromstring(predictions[1:], sep=\",\")"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Now use the `predict` function, which was defined in the code above, to run the test data through the endpoint and generate the predictions."]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["dev_predictor = get_predictor(dev_endpoint_name)\n", "predictions = predict(dev_predictor, test_df[test_df.columns[1:]].values)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Next, load the predictions into a data frame, and join it with your test data. Then, calculate absolute error as the difference between the actual taxi fare and the predicted taxi fare. Display the results in a table, sorted by the highest absolute error values."]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["pred_df = pd.DataFrame({\"total_amount_predictions\": predictions})\n", "pred_df = test_df.join(pred_df) # Join on all\n", "pred_df[\"error\"] = abs(pred_df[\"total_amount\"] - pred_df[\"total_amount_predictions\"])\n", "\n", "pred_df.sort_values(\"error\", ascending=False).head()"]}, {"cell_type": "markdown", "metadata": {}, "source": ["From this table, we note that some short trip distances have large errors because the low predicted fare does not match the high actual fare. This could be the result of a generous tip which we haven't included in this dataset.\n", "\n", "You can also analyze the results by plotting the absolute error to visualize outliers. In this graph, we see that most of the outliers are cases where the model predicted a much lower fare than the actual fare. There are only a few outliers where the model predicted a higher fare than the actual fare."]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["sns.scatterplot(data=pred_df, x=\"total_amount_predictions\", y=\"total_amount\", hue=\"error\")"]}, {"cell_type": "markdown", "metadata": {}, "source": ["If you want one overall measure of quality for the model, you can calculate the root mean square error (RMSE) for the predicted fares compared to the actual fares. Compare this to the [results calculated on the validation set](#validation-results) at the end of the 'Inspect Training Job' section."]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["from math import sqrt\n", "from sklearn.metrics import mean_squared_error\n", "\n", "\n", "def rmse(pred_df):\n", " return sqrt(mean_squared_error(pred_df[\"total_amount\"], pred_df[\"total_amount_predictions\"]))\n", "\n", "\n", "print(\"RMSE: {}\".format(rmse(pred_df)))"]}, {"cell_type": "markdown", "metadata": {}, "source": ["## Deploy Prod\n", "\n", "### Approve Deployment to Production\n", "\n", "If you are happy with the results of the model, you can go ahead and approve the model to be deployed into production. You can do so by clicking the **Review** button in the CodePipeline UI, leaving a comment to explain why you approve this model, and clicking on **Approve**. \n", "\n", "Alternatively, you can create a Jupyter widget which (when enabled) allows you to comment and approve the model directly from this notebook. Run the cell below to see this in action."]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["import ipywidgets as widgets\n", "\n", "\n", "def on_click(obj):\n", " result = {\"summary\": approval_text.value, \"status\": obj.description}\n", " response = codepipeline.put_approval_result(\n", " pipelineName=pipeline_name,\n", " stageName=\"DeployDev\",\n", " actionName=\"ApproveDeploy\",\n", " result=result,\n", " token=approval_action[\"token\"],\n", " )\n", " button_box.close()\n", " print(result)\n", "\n", "\n", "# Create the widget if we are ready for approval\n", "deploy_dev = get_pipeline_stage(pipeline_name, \"DeployDev\")\n", "if not \"latestExecution\" in deploy_dev[\"actionStates\"][-1]:\n", " raise (Exception(\"Please wait. Deploy dev not complete\"))\n", "\n", "approval_action = deploy_dev[\"actionStates\"][-1][\"latestExecution\"]\n", "if approval_action[\"status\"] == \"Succeeded\":\n", " print(\"Dev approved: {}\".format(approval_action[\"summary\"]))\n", "elif \"token\" in approval_action:\n", " approval_text = widgets.Text(placeholder=\"Optional approval message\")\n", " approve_btn = widgets.Button(description=\"Approved\", button_style=\"success\", icon=\"check\")\n", " reject_btn = widgets.Button(description=\"Rejected\", button_style=\"danger\", icon=\"close\")\n", " approve_btn.on_click(on_click)\n", " reject_btn.on_click(on_click)\n", " button_box = widgets.HBox([approval_text, approve_btn, reject_btn])\n", " display(button_box)\n", "else:\n", " raise (Exception(\"Please wait. No dev approval\"))"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Test Production Deployment\n", "\n", "Within about a minute after approving the model deployment, you should see the pipeline start on the final step: deploying your model into production. In this section, you will check the deployment status and test the production endpoint after it has been deployed.\n", "\n", "![Deploy production endpoint in code pipeline](../docs/deploy-production.png)\n", "\n", "This step of the pipeline uses CloudFormation to deploy a number of resources on your behalf. In particular, it creates:\n", "\n", "1. A production-ready SageMaker Endpoint for your model, with [data capture](https://docs.aws.amazon.com/sagemaker/latest/dg/model-monitor-data-capture.html)\u21d7 (used by SageMaker Model Monitor) and [autoscaling](https://docs.aws.amazon.com/sagemaker/latest/dg/endpoint-auto-scaling.html)\u21d7 enabled.\n", "1. A [model monitoring schedule](https://docs.aws.amazon.com/sagemaker/latest/dg/model-monitor-scheduling.html)\u21d7 which outputs the results to CloudWatch metrics, along with a [CloudWatch Alarm](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/AlarmThatSendsEmail.html)\u21d7 which will notify you when a violation occurs. \n", "1. A CodeDeploy instance which creates a simple app by deploying API Gateway, three Lambda functions, and an alarm to notify of the success or failure of this deployment. The code for the Lambda functions can be found in `api/app.py`, `api/pre_traffic_hook.py`, and `api/post_traffic_hook.py`. These functions update the endpoint to enable data capture, format and submit incoming traffic to the SageMaker endpoint, and capture the data logs.\n", "\n", "![Components of production deployment](../docs/cloud-formation.png)\n", "\n", "Let's check how the deployment is progressing. Use the code below to fetch the execution ID of the deployment step. Then generate a table which lists the resources created by the CloudFormation stack and their creation status. You can re-run the cell after a few minutes to see how the steps are progressing."]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["deploy_prd = get_pipeline_stage(pipeline_name, \"DeployPrd\")\n", "if not \"latestExecution\" in deploy_prd or not \"latestExecution\" in deploy_prd[\"actionStates\"][0]:\n", " raise (Exception(\"Please wait. Deploy prd not started\"))\n", "\n", "execution_id = deploy_prd[\"latestExecution\"][\"pipelineExecutionId\"]"]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["from datetime import datetime, timedelta\n", "from dateutil.tz import tzlocal\n", "\n", "\n", "def get_event_dataframe(events):\n", " stack_cols = [\n", " \"LogicalResourceId\",\n", " \"ResourceStatus\",\n", " \"ResourceStatusReason\",\n", " \"Timestamp\",\n", " ]\n", " stack_event_df = pd.DataFrame(events)[stack_cols].fillna(\"\")\n", " stack_event_df[\"TimeAgo\"] = datetime.now(tzlocal()) - stack_event_df[\"Timestamp\"]\n", " return stack_event_df.drop(\"Timestamp\", axis=1)\n", "\n", "\n", "cfn = boto3.client(\"cloudformation\")\n", "\n", "stack_name = stack_name = \"{}-deploy-prd\".format(pipeline_name)\n", "print(\"stack name: {}\".format(stack_name))\n", "\n", "# Get latest stack events\n", "while True:\n", " try:\n", " response = cfn.describe_stack_events(StackName=stack_name)\n", " break\n", " except ClientError as e:\n", " print(e.response[\"Error\"][\"Message\"])\n", " time.sleep(10)\n", "\n", "get_event_dataframe(response[\"StackEvents\"]).head()"]}, {"cell_type": "markdown", "metadata": {}, "source": ["The resource of most interest to us is the endpoint. This takes on average 10 minutes to deploy. In the meantime, you can take a look at the Python code used for the application. \n", "\n", "The `app.py` is the main entry point invoking the Amazon SageMaker endpoint. It returns results along with a custom header for the endpoint we invoked."]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["!pygmentize ../api/app.py"]}, {"cell_type": "markdown", "metadata": {}, "source": ["The `pre_traffic_hook.py` lambda is invoked prior to deployment and confirms the endpoint has data capture enabled."]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["!pygmentize ../api/pre_traffic_hook.py"]}, {"cell_type": "markdown", "metadata": {}, "source": ["The `post_traffic_hook.py` lambda is invoked to perform any final checks, in this case to verify that we have received log data from data capature."]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["!pygmentize ../api/post_traffic_hook.py"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Use the code below to fetch the name of the endpoint, then run a loop to wait for the endpoint to be fully deployed. You need the status to be 'InService'."]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["prd_endpoint_name = \"mlops-{}-prd-{}\".format(model_name, execution_id)\n", "print(\"prod endpoint: {}\".format(prd_endpoint_name))"]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["sm = boto3.client(\"sagemaker\")\n", "\n", "while True:\n", " try:\n", " response = sm.describe_endpoint(EndpointName=prd_endpoint_name)\n", " print(\"Endpoint status: {}\".format(response[\"EndpointStatus\"]))\n", " # Wait until the endpoint is in service with data capture enabled\n", " if (\n", " response[\"EndpointStatus\"] == \"InService\"\n", " and \"DataCaptureConfig\" in response\n", " and response[\"DataCaptureConfig\"][\"EnableCapture\"]\n", " ):\n", " break\n", " except ClientError as e:\n", " print(e.response[\"Error\"][\"Message\"])\n", " time.sleep(10)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["When the endpoint status is 'InService', you can continue. Earlier in this notebook, you created some code to send data to the dev endpoint. Reuse this code now to send a sample of the test data to the production endpoint. Since data capture is enabled on this endpoint, you want to send single records at a time, so the model monitor can map these records to the baseline. \n", "\n", "You will [inspect the model monitor](#Inspect-Model-Monitor) later in this notebook. For now, just check if you can send data to the endpoint and receive predictions in return."]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["prd_predictor = get_predictor(prd_endpoint_name)\n", "sample_values = test_df[test_df.columns[1:]].sample(100).values\n", "predictions = predict(prd_predictor, sample_values, rows=1)\n", "predictions"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Test REST API\n", "\n", "Although you already tested the SageMaker endpoint in the previous section, it is also a good idea to test the application created with API Gateway. \n", "\n", "![Traffic shift between endpoints](../docs/lambda-deploy-create.png)\n", "\n", "Follow the link below to open the Lambda Deployment where you can see the in-progress and completed deployments. You can also click to expand the **SAM template** to see the packaged CloudFormation template used in the deployment."]}, {"cell_type": "code", "execution_count": null, "metadata": {"scrolled": true}, "outputs": [], "source": ["HTML(\n", " 'Lambda Deployment'.format(\n", " region, model_name\n", " )\n", ")"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Run the code below to confirm that the endpoint is in service. It will complete once the REST API is available."]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["def get_stack_status(stack_name):\n", " response = cfn.describe_stacks(StackName=stack_name)\n", " if response[\"Stacks\"]:\n", " stack = response[\"Stacks\"][0]\n", " outputs = None\n", " if \"Outputs\" in stack:\n", " outputs = dict([(o[\"OutputKey\"], o[\"OutputValue\"]) for o in stack[\"Outputs\"]])\n", " return stack[\"StackStatus\"], outputs\n", "\n", "\n", "outputs = None\n", "while True:\n", " try:\n", " status, outputs = get_stack_status(stack_name)\n", " response = sm.describe_endpoint(EndpointName=prd_endpoint_name)\n", " print(\"Endpoint status: {}\".format(response[\"EndpointStatus\"]))\n", " if outputs:\n", " break\n", " elif status.endswith(\"FAILED\"):\n", " raise (Exception(\"Stack status: {}\".format(status)))\n", " except ClientError as e:\n", " print(e.response[\"Error\"][\"Message\"])\n", " time.sleep(10)\n", "\n", "if outputs:\n", " print(\"deployment application: {}\".format(outputs[\"DeploymentApplication\"]))\n", " print(\"rest api: {}\".format(outputs[\"RestApi\"]))"]}, {"cell_type": "markdown", "metadata": {}, "source": ["If you are performing an update on your production deployment as a result of running [Trigger Retraining](#Trigger-Retraining) you will then be able to expand the Lambda Deployment tab to reveal the resources. Click on the **ApiFunctionAliaslive** link to see the Lambda Deployment in progress. \n", "\n", "![Traffic shift between endpoints](../docs/lambda-deploy-update.png)\n", "\n", "This page will be updated to list the deployment events. It also has a link to the Deployment Application which you can access in the output of the next cell."]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["HTML(\n", " 'CodeDeploy application'.format(\n", " region, outputs[\"DeploymentApplication\"]\n", " )\n", ")"]}, {"cell_type": "markdown", "metadata": {}, "source": ["CodeDeploy will perform a canary deployment and send 10% of the traffic to the new endpoint over a 5-minute period.\n", "\n", "![Traffic shift between endpoints](../docs/code-deploy.gif)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["We can invoke the REST API and inspect the headers being returned to see which endpoint we are hitting. You will occasionally see the cell below show a different endpoint that settles to the new version once the stack is complete. "]}, {"cell_type": "code", "execution_count": null, "metadata": {"scrolled": false}, "outputs": [], "source": ["%%time\n", "\n", "from urllib import request\n", "\n", "headers = {\"Content-type\": \"text/csv\"}\n", "payload = test_df[test_df.columns[1:]].head(1).to_csv(header=False, index=False).encode(\"utf-8\")\n", "rest_api = outputs[\"RestApi\"]\n", "\n", "while True:\n", " try:\n", " resp = request.urlopen(request.Request(rest_api, data=payload, headers=headers))\n", " print(\n", " \"Response code: %d: endpoint: %s\"\n", " % (resp.getcode(), resp.getheader(\"x-sagemaker-endpoint\"))\n", " )\n", " status, outputs = get_stack_status(stack_name)\n", " if status.endswith(\"COMPLETE\"):\n", " print(\"Deployment complete\\n\")\n", " break\n", " elif status.endswith(\"FAILED\"):\n", " raise (Exception(\"Stack status: {}\".format(status)))\n", " except ClientError as e:\n", " print(e.response[\"Error\"][\"Message\"])\n", " time.sleep(10)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["## Monitor\n", "\n", "### Inspect Model Monitor\n", "\n", "When you prepared the datasets for model training at the start of this notebook, you saved a baseline dataset (a copy of the train dataset). Then, when you approved the model for deployment into production, the pipeline set up an SageMaker Endpoint with data capture enabled and a model monitoring schedule. In this section, you will take a closer look at the model monitor results.\n", "\n", "To start off, fetch the latest production deployment execution ID."]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["deploy_prd = get_pipeline_stage(pipeline_name, \"DeployPrd\")\n", "if not \"latestExecution\" in deploy_prd:\n", " raise (Exception(\"Please wait. Deploy prod not complete\"))\n", "\n", "execution_id = deploy_prd[\"latestExecution\"][\"pipelineExecutionId\"]"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Under the hood, SageMaker model monitor runs in SageMaker processing jobs. Use the execution ID to fetch the names of the processing job and the schedule."]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["processing_job_name = \"mlops-{}-pbl-{}\".format(model_name, execution_id)\n", "schedule_name = \"mlops-{}-pms\".format(model_name)\n", "\n", "print(\"processing job name: {}\".format(processing_job_name))\n", "print(\"schedule name: {}\".format(schedule_name))"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Explore Baseline\n", "\n", "Now fetch the baseline results from the processing job. This cell will throw an exception if the processing job is not complete - if that happens, just wait several minutes and try again. "]}, {"cell_type": "code", "execution_count": null, "metadata": {"scrolled": true}, "outputs": [], "source": ["import sagemaker\n", "from sagemaker.model_monitor import BaseliningJob, MonitoringExecution\n", "from sagemaker.s3 import S3Downloader\n", "\n", "sagemaker_session = sagemaker.Session()\n", "baseline_job = BaseliningJob.from_processing_name(sagemaker_session, processing_job_name)\n", "status = baseline_job.describe()[\"ProcessingJobStatus\"]\n", "if status != \"Completed\":\n", " raise (Exception(\"Please wait. Processing job not complete, status: {}\".format(status)))\n", "\n", "baseline_results_uri = baseline_job.outputs[0].destination"]}, {"cell_type": "markdown", "metadata": {}, "source": ["SageMaker model monitor generates two types of files. Take a look at the statistics file first. It calculates various statistics for each feature of the dataset, including the mean, standard deviation, minimum value, maximum value, and more. "]}, {"cell_type": "code", "execution_count": null, "metadata": {"scrolled": true}, "outputs": [], "source": ["import pandas as pd\n", "import json\n", "\n", "baseline_statistics = baseline_job.baseline_statistics().body_dict\n", "schema_df = pd.json_normalize(baseline_statistics[\"features\"])\n", "schema_df[\n", " [\n", " \"name\",\n", " \"numerical_statistics.mean\",\n", " \"numerical_statistics.std_dev\",\n", " \"numerical_statistics.min\",\n", " \"numerical_statistics.max\",\n", " ]\n", "].head()"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Now look at the suggested [constraints files](https://docs.aws.amazon.com/sagemaker/latest/dg/model-monitor-byoc-constraints.html)\u21d7. As the name implies, these are constraints which SageMaker model monitor recommends. If the live data which is sent to your production SageMaker Endpoint violates these constraints, this indicates data drift, and model monitor can raise an alert to trigger retraining. Of course, you can set different constraints based on the statistics which you viewed previously."]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["baseline_constraints = baseline_job.suggested_constraints().body_dict\n", "constraints_df = pd.json_normalize(baseline_constraints[\"features\"])\n", "constraints_df.head()"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### View data capture\n", "\n", "When the \"Deploy Production\" stage of the MLOps pipeline deploys a SageMaker endpoint, it also enables data capture. This means the incoming requests to the endpoint, as well as the results from the ML model, are stored in an S3 location. Model monitor can analyze this data and compare it to the baseline to ensure that no constraints are violated. \n", "\n", "Use the code below to check how many files have been created by the data capture, and view the latest file in detail. Note, data capture relies on data being sent to the production endpoint. If you don't see any files yet, wait several minutes and try again."]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["bucket = sagemaker_session.default_bucket()\n", "data_capture_logs_uri = \"s3://{}/mlops-{}/datacapture/{}\".format(\n", " bucket, model_name, prd_endpoint_name\n", ")\n", "\n", "capture_files = S3Downloader.list(data_capture_logs_uri)\n", "print(\"Found {} files\".format(len(capture_files)))\n", "\n", "if capture_files:\n", " # Get the first line of the most recent file\n", " event = json.loads(S3Downloader.read_file(capture_files[-1]).split(\"\\n\")[0])\n", " print(\"\\nLast file:\\n{}\".format(json.dumps(event, indent=2)))"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### View monitoring schedule\n", "\n", "There are some useful functions for plotting and rendering distribution statistics or constraint violations provided in a `utils` file in the [SageMaker Examples GitHub](https://github.com/aws/amazon-sagemaker-examples/tree/master/sagemaker_model_monitor/visualization)\u21d7. Grab a copy of this code to use in this notebook. "]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["!wget -O utils.py --quiet https://raw.githubusercontent.com/awslabs/amazon-sagemaker-examples/master/sagemaker_model_monitor/visualization/utils.py\n", "import utils as mu"]}, {"cell_type": "markdown", "metadata": {}, "source": ["The [minimum scheduled run time](https://docs.aws.amazon.com/sagemaker/latest/dg/model-monitor-scheduling.html)\u21d7 for model monitor is one hour, which means you will need to wait at least an hour to see any results. Use the code below to check the schedule status and list the next run. If you are completing this notebook as part of a workshop, your host will have activities which you can complete while you wait. "]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["sm = boto3.client(\"sagemaker\")\n", "\n", "response = sm.describe_monitoring_schedule(MonitoringScheduleName=schedule_name)\n", "print(\"Schedule Status: {}\".format(response[\"MonitoringScheduleStatus\"]))\n", "\n", "now = datetime.now(tzlocal())\n", "next_hour = (now + timedelta(hours=1)).replace(minute=0)\n", "scheduled_diff = (next_hour - now).seconds // 60\n", "print(\"Next schedule in {} minutes\".format(scheduled_diff))"]}, {"cell_type": "markdown", "metadata": {}, "source": ["While you wait, you can take a look at the CloudFormation template which is used as a base for the CloudFormation template built by CodeDeploy to deploy the production application. \n", "\n", "Alterntively, you can jump ahead to [Trigger Retraining](#Trigger-Retraining) which will kick off another run of the code pipeline whilst you wait."]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["!cat ../assets/deploy-model-prd.yml"]}, {"cell_type": "markdown", "metadata": {}, "source": ["A couple of minutes after the model monitoring schedule has run, you can use the code below to fetch the latest schedule status. A completed schedule run may have found violations. "]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["processing_job_arn = None\n", "\n", "while processing_job_arn is None:\n", " try:\n", " response = sm.list_monitoring_executions(MonitoringScheduleName=schedule_name)\n", " except ClientError as e:\n", " print(e.response[\"Error\"][\"Message\"])\n", " for mon in response[\"MonitoringExecutionSummaries\"]:\n", " status = mon[\"MonitoringExecutionStatus\"]\n", " now = datetime.now(tzlocal())\n", " created_diff = (now - mon[\"CreationTime\"]).seconds // 60\n", " print(\"Schedule status: {}, Created: {} minutes ago\".format(status, created_diff))\n", " if status in [\"Completed\", \"CompletedWithViolations\"]:\n", " processing_job_arn = mon[\"ProcessingJobArn\"]\n", " break\n", " if status == \"InProgress\":\n", " break\n", " else:\n", " raise (Exception(\"Please wait. No Schedules executing\"))\n", " time.sleep(10)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### View monitoring results\n", "\n", "Once the model monitoring schedule has had a chance to run at least once, you can take a look at the results. First, load the monitoring execution results from the latest scheduled run."]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["if processing_job_arn:\n", " execution = MonitoringExecution.from_processing_arn(\n", " sagemaker_session=sagemaker.Session(), processing_job_arn=processing_job_arn\n", " )\n", " exec_inputs = {inp[\"InputName\"]: inp for inp in execution.describe()[\"ProcessingInputs\"]}\n", " exec_results_uri = execution.output.destination\n", "\n", " print(\"Monitoring Execution results: {}\".format(exec_results_uri))"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Take a look at the files which have been saved in the S3 output location. If violations were found, you should see a constraint violations file in addition to the statistics and constraints file which you viewed before."]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["!aws s3 ls $exec_results_uri/"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Now, fetch the monitoring statistics and violations. Then use the utils code to visualize the results in a table. It will highlight any baseline drift found by the model monitor. Drift can happen for categorical features (for inferred string styles) or for numerical features (e.g. total fare amount)."]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["# Get the baseline and monitoring statistics & violations\n", "baseline_statistics = baseline_job.baseline_statistics().body_dict\n", "execution_statistics = execution.statistics().body_dict\n", "violations = execution.constraint_violations().body_dict[\"violations\"]"]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["mu.show_violation_df(\n", " baseline_statistics=baseline_statistics,\n", " latest_statistics=execution_statistics,\n", " violations=violations,\n", ")"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Trigger Retraining\n", "\n", "The CodePipeline instance is configured with [CloudWatch Events](https://docs.aws.amazon.com/codepipeline/latest/userguide/create-cloudtrail-S3-source.html)\u21d7 to start the pipeline for retraining when the drift detection triggers specific metric alarms.\n", "\n", "You can simulate drift by putting a metric value above the threshold of `0.2` directly into CloudWatch. This will trigger the alarm, and start the code pipeline.\n", "\n", "
    \n", " Tip: This alarm is configured only for the latest production endpoint, so re-training will only occur if you are putting metrics against the latest endpoint.\n", "
    \n", "\n", "![Metric graph in CloudWatch](../docs/cloudwatch-alarm.png)\n", "\n", "Run the code below to trigger the metric alarm. The cell output will be a link to CloudWatch, where you can see the alarm (similar to the screenshot above), and a link to CodePipeline which you will see run again. Note that it can take a couple of minutes for everything to trigger."]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["from datetime import datetime\n", "import random\n", "\n", "cloudwatch = boto3.client(\"cloudwatch\")\n", "\n", "# Define the metric name and threshold\n", "metric_name = \"feature_baseline_drift_total_amount\"\n", "metric_threshold = 0.2\n", "\n", "# Put a new metric to trigger an alaram\n", "def put_drift_metric(value):\n", " print(\"Putting metric: {}\".format(value))\n", " response = cloudwatch.put_metric_data(\n", " Namespace=\"aws/sagemaker/Endpoints/data-metrics\",\n", " MetricData=[\n", " {\n", " \"MetricName\": metric_name,\n", " \"Dimensions\": [\n", " {\"Name\": \"MonitoringSchedule\", \"Value\": schedule_name},\n", " {\"Name\": \"Endpoint\", \"Value\": prd_endpoint_name},\n", " ],\n", " \"Timestamp\": datetime.now(),\n", " \"Value\": value,\n", " \"Unit\": \"None\",\n", " },\n", " ],\n", " )\n", "\n", "\n", "def get_drift_stats():\n", " response = cloudwatch.get_metric_statistics(\n", " Namespace=\"aws/sagemaker/Endpoints/data-metrics\",\n", " MetricName=metric_name,\n", " Dimensions=[\n", " {\"Name\": \"MonitoringSchedule\", \"Value\": schedule_name},\n", " {\"Name\": \"Endpoint\", \"Value\": prd_endpoint_name},\n", " ],\n", " StartTime=datetime.now() - timedelta(minutes=2),\n", " EndTime=datetime.now(),\n", " Period=1,\n", " Statistics=[\"Average\"],\n", " Unit=\"None\",\n", " )\n", " if \"Datapoints\" in response and len(response[\"Datapoints\"]) > 0:\n", " return response[\"Datapoints\"][0][\"Average\"]\n", " return 0\n", "\n", "\n", "print(\"Simluate drift on endpoint: {}\".format(prd_endpoint_name))\n", "\n", "while True:\n", " put_drift_metric(round(random.uniform(metric_threshold, 1.0), 4))\n", " drift_stats = get_drift_stats()\n", " print(\"Average drift amount: {}\".format(get_drift_stats()))\n", " if drift_stats > metric_threshold:\n", " break\n", " time.sleep(1)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Click through to the Alarm and CodePipeline Execution history with the links below."]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["# Output a html link to the cloudwatch dashboard\n", "metric_alarm_name = \"mlops-{}-metric-gt-threshold\".format(model_name)\n", "HTML(\n", " \"\"\"CloudWatch Alarm triggers\n", " Code Pipeline Execution\"\"\".format(\n", " region, metric_alarm_name, pipeline_name\n", " )\n", ")"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Once the pipeline is running again you can jump back up to [Inspect Training Job](#Inspect-Training-Job)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Create a CloudWatch dashboard\n", "\n", "Finally, use the code below to create a CloudWatch dashboard to visualize the key performance metrics and alarms which you have created during this demo. The cell will output a link to the dashboard. This dashboard shows 9 charts in three rows, where the first row displays Lambda metrics, the second row displays SageMaker metrics, and the third row (shown in the screenshot below) displays the alarms set up for the pipeline.\n", "\n", "![Graphs in CloudWatch dashboard](../docs/cloudwatch-dashboard.png)"]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["from string import Template\n", "\n", "sts = boto3.client(\"sts\")\n", "account_id = sts.get_caller_identity().get(\"Account\")\n", "dashboard_name = \"mlops-{0}-{1}\".format(model_name, config[\"SageMakerProjectId\"])\n", "\n", "with open(\"dashboard.json\") as f:\n", " dashboard_body = Template(f.read()).substitute(\n", " region=region, account_id=account_id, model_name=model_name\n", " )\n", " response = cloudwatch.put_dashboard(DashboardName=dashboard_name, DashboardBody=dashboard_body)\n", "\n", "# Output a html link to the cloudwatch dashboard\n", "HTML(\n", " 'CloudWatch Dashboard'.format(\n", " region, dashboard_name\n", " )\n", ")"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Congratulations! You have made it to the end of this notebook, and have automated a safe MLOps pipeline using a wide range of AWS services. \n", "\n", "You can use the other notebook in this repository [workflow.ipynb](workflow.ipynb) to implement your own ML model and deploy it as part of this pipeline. Or, if you are finished with the content, follow the instructions in the next section to clean up the resources you have deployed."]}, {"cell_type": "markdown", "metadata": {}, "source": ["## Cleanup\n", "\n", "Execute the following cell to delete the stacks created in the pipeline. For a model name of **nyctaxi** these would be:\n", "\n", "1. *nyctaxi*-deploy-prd\n", "2. *nyctaxi*-deploy-dev\n", "3. *nyctaxi*-workflow\n", "4. sagemaker-custom-resource"]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["cfn = boto3.client(\"cloudformation\")\n", "\n", "# Delete the prod and then dev stack\n", "for stack_name in [\n", " f\"{pipeline_name}-deploy-prd\",\n", " f\"{pipeline_name}-deploy-dev\",\n", " f\"{pipeline_name}-workflow\",\n", " f\"mlops-{model_name}-{config['SageMakerProjectId']}-sagemaker-custom-resource\",\n", "]:\n", " print(\"Deleting stack: {}\".format(stack_name))\n", " cfn.delete_stack(StackName=stack_name)\n", " cfn.get_waiter(\"stack_delete_complete\").wait(StackName=stack_name)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["The following code will delete the dashboard."]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["cloudwatch.delete_dashboards(DashboardNames=[dashboard_name])\n", "print(\"Dashboard deleted\")"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Finally, close this notebook and you can delete the CloudFormation you created to launch this MLOps sample."]}], "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.7.10"}}, "nbformat": 4, "nbformat_minor": 4} \ No newline at end of file diff --git a/notebook/workflow.ipynb b/notebook/workflow.ipynb index aaaa305..8f23fd3 100644 --- a/notebook/workflow.ipynb +++ b/notebook/workflow.ipynb @@ -1,1186 +1 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Workflow\n", - "\n", - "The following notebook contains the step functions workflow definition for training and baseline jobs.\n", - "\n", - "This can be run after you have started the [mlops](mlops.ipynb) build and have stored `input_data`." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Import the latest sagemaker, stepfunctions and boto3 SDKs\n", - "import sys\n", - "!{sys.executable} -m pip install --upgrade pip\n", - "!{sys.executable} -m pip install -qU awscli boto3 \"sagemaker>=2.1.0<3\"\n", - "!{sys.executable} -m pip install -qU \"stepfunctions==2.0.0\"\n", - "!{sys.executable} -m pip show sagemaker stepfunctions" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import boto3\n", - "import json\n", - "import os\n", - "import time\n", - "import uuid\n", - "\n", - "import sagemaker\n", - "from sagemaker.image_uris import retrieve \n", - "from sagemaker.processing import Processor, ProcessingInput, ProcessingOutput\n", - "from sagemaker.model_monitor.dataset_format import DatasetFormat\n", - "\n", - "import stepfunctions\n", - "from stepfunctions import steps\n", - "from stepfunctions.inputs import ExecutionInput\n", - "from stepfunctions.workflow import Workflow" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Load variables from environment" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "region = boto3.Session().region_name\n", - "role = sagemaker.get_execution_role()\n", - "pipeline_name = os.environ['PIPELINE_NAME']\n", - "model_name = os.environ['MODEL_NAME']\n", - "workflow_role_arn = os.environ['WORKFLOW_ROLE_ARN']\n", - "\n", - "# Define the lambda function names for steps\n", - "create_experiment_function_name = 'mlops-create-experiment'\n", - "query_training_function_name = 'mlops-query-training'\n", - "transform_header_function_name = 'mlops-add-transform-header'\n", - "query_drift_function_name = 'mlops-query-drift'\n", - "\n", - "# Get the session and default bucket\n", - "session = sagemaker.session.Session()\n", - "bucket = session.default_bucket()\n", - "\n", - "print('region: {}'.format(region))\n", - "print('pipeline: {}'.format(pipeline_name))\n", - "print('model name: {}'.format(model_name))\n", - "print('bucket: {}'.format(bucket))\n", - "print('sagemaker role: {}'.format(role))\n", - "print('workflow role: {}'.format(workflow_role_arn))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Load the input data from the mlops notebook and print values" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "%store -r input_data \n", - "input_data " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Specify the training model and transform output base uri" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "output_data = {\n", - " 'ModelOutputUri': 's3://{}/{}/model'.format(bucket, model_name), \n", - "}" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Define Training Resources\n", - "\n", - "### Input Schema\n", - "\n", - "Define the input schema for the step functions which can then be used as arguments to resources" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "execution_input = ExecutionInput(\n", - " schema={\n", - " \"GitBranch\": str,\n", - " \"GitCommitHash\": str,\n", - " \"DataVersionId\": str,\n", - " \"ExperimentName\": str,\n", - " \"TrialName\": str,\n", - " \"BaselineJobName\": str,\n", - " \"BaselineOutputUri\": str,\n", - " \"TrainingJobName\": str,\n", - " \"ModelName\": str\n", - " }\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Define the model monitor baseline\n", - "\n", - "Define the environment variables" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "dataset_format = DatasetFormat.csv()\n", - "env = {\n", - " \"dataset_format\": json.dumps(dataset_format),\n", - " \"dataset_source\": \"/opt/ml/processing/input/baseline_dataset_input\",\n", - " \"output_path\": \"/opt/ml/processing/output\",\n", - " \"publish_cloudwatch_metrics\": \"Disabled\", # Have to be disabled from processing job?\n", - "}" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Define the processing inputs and outputs " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "inputs = [\n", - " ProcessingInput(\n", - " source=input_data['BaselineUri'],\n", - " destination=\"/opt/ml/processing/input/baseline_dataset_input\",\n", - " input_name=\"baseline_dataset_input\",\n", - " ),\n", - "]\n", - "outputs = [\n", - " ProcessingOutput(\n", - " source=\"/opt/ml/processing/output\",\n", - " destination=execution_input[\"BaselineOutputUri\"],\n", - " output_name=\"monitoring_output\",\n", - " ),\n", - "]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Create the baseline processing job using the sagemaker [model monitor](https://sagemaker.readthedocs.io/en/stable/amazon_sagemaker_model_monitoring.html) container." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Get the default model monitor container\n", - "region = boto3.Session().region_name\n", - "monor_monitor_container_uri = retrieve(region=region, framework=\"model-monitor\", version=\"latest\")\n", - "\n", - "# Use the base processing where we pass through the \n", - "monitor_analyzer = Processor(\n", - " image_uri=monor_monitor_container_uri,\n", - " role=role, \n", - " instance_count=1,\n", - " instance_type=\"ml.m5.xlarge\",\n", - " max_runtime_in_seconds=1800,\n", - " env=env\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Test the model baseline processing job by running inline" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#monitor_analyzer.run(inputs=inputs, outputs=outputs, wait=True)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Defining the Training Job\n", - "\n", - "Define the training job to run in paralell with the processing job" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "image_uri = sagemaker.image_uris.retrieve(region=region, framework=\"xgboost\", version=\"latest\")\n", - "\n", - "# Create the estimator\n", - "xgb = sagemaker.estimator.Estimator(\n", - " image_uri,\n", - " role,\n", - " instance_count=1,\n", - " instance_type=\"ml.m4.xlarge\",\n", - " output_path=output_data['ModelOutputUri'], # NOTE: Can't use execution_input here\n", - ")\n", - "\n", - "# Set the hyperparameters overriding with any defaults\n", - "hyperparameters = {\n", - " \"max_depth\": \"9\",\n", - " \"eta\": \"0.2\",\n", - " \"gamma\": \"4\",\n", - " \"min_child_weight\": \"300\",\n", - " \"subsample\": \"0.8\",\n", - " \"objective\": \"reg:linear\",\n", - " \"early_stopping_rounds\": \"10\",\n", - " \"num_round\": \"50\", # Don't stop to early or results are bad\n", - "}\n", - "xgb.set_hyperparameters(**hyperparameters)\n", - "\n", - "# Specify the data source\n", - "s3_input_train = sagemaker.inputs.TrainingInput(s3_data=input_data['TrainingUri'], content_type=\"csv\")\n", - "s3_input_val = sagemaker.inputs.TrainingInput(s3_data=input_data['ValidationUri'], content_type=\"csv\")\n", - "data = {\"train\": s3_input_train, \"validation\": s3_input_val}" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Test the estimator directly in the notebook" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#xgb.fit(inputs=data)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Define Training Workflow\n", - "\n", - "### 1. Create the Experiment\n", - "\n", - "Define the create experiment lambda.\n", - "\n", - "In future add [ResultsPath](https://docs.aws.amazon.com/step-functions/latest/dg/input-output-resultpath.html) to filter the results." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "create_experiment_step = steps.compute.LambdaStep(\n", - " 'Create Experiment',\n", - " parameters={ \n", - " \"FunctionName\": create_experiment_function_name,\n", - " 'Payload': {\n", - " \"ExperimentName.$\": '$.ExperimentName',\n", - " \"TrialName.$\": '$.TrialName',\n", - " }\n", - " },\n", - " result_path='$.CreateTrialResults'\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 2a. Run processing Job\n", - "\n", - "Define the processing job with a specific failure handling" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "baseline_step = steps.sagemaker.ProcessingStep(\n", - " \"Baseline Job\",\n", - " processor=monitor_analyzer,\n", - " job_name=execution_input[\"BaselineJobName\"],\n", - " inputs=inputs,\n", - " outputs=outputs,\n", - " experiment_config={\n", - " 'ExperimentName': execution_input[\"ExperimentName\"], # '$.ExperimentName', \n", - " 'TrialName': execution_input[\"TrialName\"],\n", - " 'TrialComponentDisplayName': \"Baseline\",\n", - " },\n", - " tags={\n", - " \"GitBranch\": execution_input[\"GitBranch\"],\n", - " \"GitCommitHash\": execution_input[\"GitCommitHash\"],\n", - " \"DataVersionId\": execution_input[\"DataVersionId\"],\n", - " },\n", - " result_path='$.BaselineJobResults'\n", - ")\n", - "\n", - "baseline_step.add_catch(steps.states.Catch(\n", - " error_equals=[\"States.TaskFailed\"],\n", - " next_step=stepfunctions.steps.states.Fail(\n", - " \"Baseline failed\", cause=\"SageMakerBaselineJobFailed\"\n", - " ),\n", - "))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 2b. Run and query training Job\n", - "\n", - "Define the training job and add a validation step" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "training_step = steps.TrainingStep(\n", - " \"Training Job\",\n", - " estimator=xgb,\n", - " data=data,\n", - " job_name=execution_input[\"TrainingJobName\"],\n", - " experiment_config={\n", - " 'ExperimentName': execution_input[\"ExperimentName\"],\n", - " 'TrialName': execution_input[\"TrialName\"],\n", - " 'TrialComponentDisplayName': \"Training\",\n", - " },\n", - " tags={\n", - " \"GitBranch\": execution_input[\"GitBranch\"],\n", - " \"GitCommitHash\": execution_input[\"GitCommitHash\"],\n", - " \"DataVersionId\": execution_input[\"DataVersionId\"],\n", - " },\n", - " result_path='$.TrainingResults'\n", - ")\n", - "\n", - "training_step.add_catch(stepfunctions.steps.states.Catch(\n", - " error_equals=[\"States.TaskFailed\"],\n", - " next_step=stepfunctions.steps.states.Fail(\n", - " \"Training failed\", cause=\"SageMakerTrainingJobFailed\"\n", - " ),\n", - "))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Create a model from the training job, note this must follow training to retrieve the expected model" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "scrolled": true - }, - "outputs": [], - "source": [ - "# Must follow the training test\n", - "model_step = steps.sagemaker.ModelStep(\n", - " 'Save Model',\n", - " input_path='$.TrainingResults',\n", - " model=training_step.get_expected_model(),\n", - " model_name=execution_input['ModelName'],\n", - " result_path='$.ModelStepResults'\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Query training results, and validate that the RMSE error is within an acceptable range " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "training_query_step = steps.compute.LambdaStep(\n", - " 'Query Training Results',\n", - " parameters={ \n", - " \"FunctionName\": query_training_function_name,\n", - " 'Payload':{\n", - " \"TrainingJobName.$\": '$.TrainingJobName'\n", - " }\n", - " },\n", - " result_path='$.QueryTrainingResults'\n", - ")\n", - "\n", - "check_accuracy_fail_step = steps.states.Fail(\n", - " 'Model Error Too Low',\n", - " comment='RMSE accuracy higher than threshold'\n", - ")\n", - "\n", - "check_accuracy_succeed_step = steps.states.Succeed('Model Error Acceptable')\n", - "\n", - "# TODO: Update query method to query validation error using better result path\n", - "threshold_rule = steps.choice_rule.ChoiceRule.NumericLessThan(\n", - " variable=training_query_step.output()['QueryTrainingResults']['Payload']['results']['TrainingMetrics'][0]['Value'], value=10\n", - ")\n", - "\n", - "check_accuracy_step = steps.states.Choice(\n", - " 'RMSE < 10'\n", - ")\n", - "\n", - "check_accuracy_step.add_choice(rule=threshold_rule, next_step=check_accuracy_succeed_step)\n", - "check_accuracy_step.default_choice(next_step=check_accuracy_fail_step)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 3. Add the Error handling in the workflow\n", - "\n", - "We will use the [Catch Block](https://aws-step-functions-data-science-sdk.readthedocs.io/en/stable/states.html#stepfunctions.steps.states.Catch) to perform error handling. If the Processing Job Step or Training Step fails, the flow will go into failure state." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "sagemaker_jobs = steps.states.Parallel(\"SageMaker Jobs\")\n", - "sagemaker_jobs.add_branch(baseline_step)\n", - "sagemaker_jobs.add_branch(steps.states.Chain([training_step, model_step, training_query_step, check_accuracy_step]))\n", - "\n", - "# Do we need specific failure for the jobs for group?\n", - "sagemaker_jobs.add_catch(stepfunctions.steps.states.Catch(\n", - " error_equals=[\"States.TaskFailed\"],\n", - " next_step=stepfunctions.steps.states.Fail(\n", - " \"SageMaker Jobs failed\", cause=\"SageMakerJobsFailed\"\n", - " ),\n", - "))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Execute Training Workflow\n", - "\n", - "Create the training workflow." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "training_workflow_definition = steps.states.Chain([\n", - " create_experiment_step,\n", - " sagemaker_jobs\n", - "])\n", - "\n", - "training_workflow_name = '{}-training'.format(model_name)\n", - "training_workflow = Workflow(training_workflow_name, training_workflow_definition, workflow_role_arn)\n", - "training_workflow.create()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Render the graph of the workflow as defined by the graph" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "training_workflow.render_graph()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We can also inspect the raw workflow definition and verify the execution variables are correctly passed in" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "scrolled": true - }, - "outputs": [], - "source": [ - "print(training_workflow.definition.to_json(pretty=True))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - " Now we define the inputs for the workflow" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Define some dummy job and git params\n", - "job_id = uuid.uuid1().hex\n", - "git_branch = 'master'\n", - "git_commit_hash = 'xxx' \n", - "data_verison_id = 'yyy'\n", - "\n", - "# Define the experiment and trial name based on model name and job id\n", - "experiment_name = \"mlops-{}\".format(model_name)\n", - "trial_name = \"mlops-{}-{}\".format(model_name, job_id)\n", - "\n", - "workflow_inputs = {\n", - " \"ExperimentName\": experiment_name,\n", - " \"TrialName\": trial_name,\n", - " \"GitBranch\": git_branch,\n", - " \"GitCommitHash\": git_commit_hash, \n", - " \"DataVersionId\": data_verison_id, \n", - " \"BaselineJobName\": trial_name, \n", - " \"BaselineOutputUri\": f\"s3://{bucket}/{model_name}/monitoring/baseline/mlops-{model_name}-pbl-{job_id}\",\n", - " \"TrainingJobName\": trial_name,\n", - " \"ModelName\": trial_name,\n", - "}\n", - "print(json.dumps(workflow_inputs))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Then execute the workflow" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "execution = training_workflow.execute(\n", - " inputs=workflow_inputs\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Render workflow progress with the [render_progress](https://aws-step-functions-data-science-sdk.readthedocs.io/en/latest/workflow.html#stepfunctions.workflow.Execution.render_progress).\n", - "\n", - "This generates a snapshot of the current state of your workflow as it executes. Run the cell again to refresh progress or jump to step functions in the console." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "execution.render_progress()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Wait for the execution to complete, and output the last step." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "execution_output = execution.get_output(wait=True)\n", - "execution.list_events()[-1]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Use [list_events](https://aws-step-functions-data-science-sdk.readthedocs.io/en/latest/workflow.html#stepfunctions.workflow.Execution.list_events) to list all events in the workflow execution." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "scrolled": true - }, - "outputs": [], - "source": [ - "# execution.list_events(html=True) # Bug" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Execute Batch Transform\n", - "\n", - "Take the model we have trained and run a batch transform on the validation dataset.\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "execution_input = ExecutionInput(\n", - " schema={\n", - " \"GitBranch\": str,\n", - " \"GitCommitHash\": str,\n", - " \"DataVersionId\": str,\n", - " \"ExperimentName\": str,\n", - " \"TrialName\": str,\n", - " \"ModelName\": str,\n", - " \"TransformJobName\": str,\n", - " \"MonitorJobName\": str,\n", - " \"MonitorOutputUri\": str,\n", - " }\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Define some new output paths for the transform and monitoring jobs" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "output_data['TransformOutputUri'] = f\"s3://{bucket}/{model_name}/transform/mlops-{model_name}-{job_id}\"\n", - "output_data['MonitoringOutputUri'] = f\"s3://{bucket}/{model_name}/monitoring/mlops-{model_name}-{job_id}\"\n", - "output_data['BaselineOutputUri'] = workflow_inputs['BaselineOutputUri']" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 1. Run the Transform Job\n", - "\n", - "Define a transform job to take the test dataset as input. \n", - "\n", - "We can configured the batch transform to [associate prediction results](https://aws.amazon.com/blogs/machine-learning/associating-prediction-results-with-input-data-using-amazon-sagemaker-batch-transform/) with the input based in the `input_filter` and `output_filter` arguments." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "transform_step = steps.TransformStep(\n", - " 'Transform Input Dataset',\n", - " transformer=xgb.transformer(\n", - " instance_count=1,\n", - " instance_type='ml.m5.large',\n", - " assemble_with='Line', \n", - " accept = 'text/csv',\n", - " output_path=output_data['TransformOutputUri'], # NOTE: Can't use execution_input here\n", - " ),\n", - " job_name=execution_input['TransformJobName'], # TEMP\n", - " model_name=execution_input['ModelName'], \n", - " data=input_data['TestUri'],\n", - " content_type='text/csv',\n", - " split_type='Line',\n", - " input_filter='$[1:]', # Skip the first target column output_amount\n", - " join_source='Input',\n", - " output_filter='$[1:]', # Output all inputs excluding output_amount, followed by the predicted_output_amount\n", - " result_path='$.TransformJobResults'\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 2. Add the Transform Header\n", - "\n", - "The batch transform output does not include the header, so add this back to be able to run baseline." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "transform_file_name = 'test.csv'\n", - "header = 'duration_minutes,passenger_count,trip_distance,total_amount'" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "transform_header_step = steps.compute.LambdaStep(\n", - " 'Add Transform Header',\n", - " parameters={ \n", - " \"FunctionName\": transform_header_function_name,\n", - " 'Payload': {\n", - " \"TransformOutputUri\": output_data['TransformOutputUri'],\n", - " \"FileName\": transform_file_name,\n", - " \"Header\": header,\n", - " }\n", - " },\n", - " result_path='$.TransformHeaderResults'\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 3. Run the Model Monitor Processing Job\n", - "\n", - "Create a model monitor processing job that takes the output of the transform job.\n", - "\n", - "Reference the `constraints.json` and `statistics.json` from the output form the training baseline." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "dataset_format = DatasetFormat.csv()\n", - "env = {\n", - " \"dataset_format\": json.dumps(dataset_format),\n", - " \"dataset_source\": \"/opt/ml/processing/input/baseline_dataset_input\",\n", - " \"output_path\": \"/opt/ml/processing/output\",\n", - " \"publish_cloudwatch_metrics\": \"Disabled\", # Have to be disabled from processing job?\n", - " \"baseline_constraints\": \"/opt/ml/processing/baseline/constraints/constraints.json\",\n", - " \"baseline_statistics\": \"/opt/ml/processing/baseline/stats/statistics.json\"\n", - "}\n", - "inputs = [\n", - " ProcessingInput(\n", - " source=os.path.join(output_data['TransformOutputUri'], transform_file_name), # Transform with header\n", - " destination=\"/opt/ml/processing/input/baseline_dataset_input\",\n", - " input_name=\"baseline_dataset_input\",\n", - " ),\n", - " ProcessingInput(\n", - " source=os.path.join(output_data['BaselineOutputUri'], 'constraints.json'),\n", - " destination=\"/opt/ml/processing/baseline/constraints\",\n", - " input_name=\"constraints\",\n", - " ),\n", - " ProcessingInput(\n", - " source=os.path.join(output_data['BaselineOutputUri'], 'statistics.json'),\n", - " destination=\"/opt/ml/processing/baseline/stats\",\n", - " input_name=\"baseline\",\n", - " ),\n", - "]\n", - "outputs = [\n", - " ProcessingOutput(\n", - " source=\"/opt/ml/processing/output\",\n", - " destination=output_data['MonitoringOutputUri'],\n", - " output_name=\"monitoring_output\",\n", - " ),\n", - "]\n", - "\n", - "# Get the default model monitor container\n", - "region = boto3.Session().region_name\n", - "monor_monitor_container_uri = retrieve(region=region, framework=\"model-monitor\", version=\"latest\")\n", - "\n", - "# Use the base processing where we pass through the \n", - "monitor_analyzer = Processor(\n", - " image_uri=monor_monitor_container_uri,\n", - " role=role, \n", - " instance_count=1,\n", - " instance_type=\"ml.m5.xlarge\",\n", - " max_runtime_in_seconds=1800,\n", - " env=env\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Test the monitor baseline" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# monitor_analyzer.run(inputs=inputs, outputs=outputs, wait=True)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Add the monitor step" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "monitor_step = steps.sagemaker.ProcessingStep(\n", - " \"Monitor Job\",\n", - " processor=monitor_analyzer,\n", - " job_name=execution_input[\"MonitorJobName\"],\n", - " inputs=inputs,\n", - " outputs=outputs,\n", - " experiment_config={\n", - " 'ExperimentName': execution_input[\"ExperimentName\"],\n", - " 'TrialName': execution_input[\"TrialName\"],\n", - " 'TrialComponentDisplayName': \"Baseline\",\n", - " },\n", - " tags={\n", - " \"GitBranch\": execution_input[\"GitBranch\"],\n", - " \"GitCommitHash\": execution_input[\"GitCommitHash\"],\n", - " \"DataVersionId\": execution_input[\"DataVersionId\"],\n", - " },\n", - " result_path='$.MonitorJobResults'\n", - ")\n", - "\n", - "monitor_step.add_catch(stepfunctions.steps.states.Catch(\n", - " error_equals=[\"States.TaskFailed\"],\n", - " next_step=stepfunctions.steps.states.Fail(\n", - " \"Monitor failed\", cause=\"SageMakerMonitorJobFailed\"\n", - " ),\n", - "))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Add the lambda step to query for violations in the processing job." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "monitor_query_step = steps.compute.LambdaStep(\n", - " 'Query Monitoring Results',\n", - " parameters={ \n", - " \"FunctionName\": query_drift_function_name,\n", - " 'Payload':{\n", - " \"ProcessingJobName.$\": '$.MonitorJobName'\n", - " }\n", - " },\n", - " result_path='$.QueryMonitorResults'\n", - ")\n", - "\n", - "check_violations_fail_step = steps.states.Fail(\n", - " 'Completed with Violations',\n", - " comment='Processing job completed with violations'\n", - ")\n", - "\n", - "check_violations_succeed_step = steps.states.Succeed('Completed')\n", - "\n", - "# TODO: Check specific drift in violations\n", - "status_rule = steps.choice_rule.ChoiceRule.StringEquals(\n", - " variable=monitor_query_step.output()['QueryMonitorResults']['Payload']['results']['ProcessingJobStatus'], value='Completed'\n", - ")\n", - "\n", - "check_violations_step = steps.states.Choice(\n", - " 'Check Violations'\n", - ")\n", - "\n", - "check_violations_step.add_choice(rule=status_rule, next_step=check_violations_succeed_step)\n", - "check_violations_step.default_choice(next_step=check_violations_fail_step)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Create the transform workflow definition" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "transform_workflow_definition = steps.states.Chain([\n", - " transform_step,\n", - " transform_header_step,\n", - " monitor_step, \n", - " monitor_query_step, \n", - " check_violations_step\n", - "])\n", - "\n", - "transform_workflow_name = '{}-transform'.format(model_name)\n", - "transform_workflow = Workflow(transform_workflow_name, transform_workflow_definition, workflow_role_arn)\n", - "transform_workflow.create()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Render the graph of the workflow as defined by the graph" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "transform_workflow.render_graph()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Define the workflow inputs based on the previous training run" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Define unique names for the transform and monitor baseline jobs\n", - "transform_job_name = \"mlops-{}-trn-{}\".format(model_name, job_id)\n", - "monitor_job_name = \"mlops-{}-mbl-{}\".format(model_name, job_id)\n", - "\n", - "workflow_inputs = {\n", - " \"ExperimentName\": experiment_name,\n", - " \"TrialName\": trial_name,\n", - " \"GitBranch\": git_branch,\n", - " \"GitCommitHash\": git_commit_hash, \n", - " \"DataVersionId\": data_verison_id, \n", - " \"ModelName\": trial_name,\n", - " \"TransformJobName\": transform_job_name, \n", - " \"MonitorJobName\": monitor_job_name,\n", - "}\n", - "print(json.dumps(workflow_inputs))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Execute the workflow and render the progress. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "execution = transform_workflow.execute(\n", - " inputs=workflow_inputs\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "execution.render_progress()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Wait for the execution to finish and list the last event." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "execution_output = execution.get_output(wait=True)\n", - "execution.list_events()[-1]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Inspect Transform Results\n", - "\n", - "Verify that we can load the transform output with header" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from io import StringIO\n", - "import pandas as pd\n", - "from sagemaker.s3 import S3Downloader\n", - "\n", - "# Get the output, and add header\n", - "transform_output_uri = os.path.join(output_data['TransformOutputUri'], transform_file_name)\n", - "transform_body = S3Downloader.read_file(transform_output_uri)\n", - "pred_df = pd.read_csv(StringIO(transform_body), sep=\",\")\n", - "pred_df.head()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Query monitoring output\n", - "\n", - "If this completed with violations, let's inspect the output to see why that is the case." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "violiations_uri = os.path.join(output_data['MonitoringOutputUri'], 'constraint_violations.json')\n", - "violiations = json.loads(S3Downloader.read_file(violiations_uri))\n", - "violiations" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Cleanup\n", - "\n", - "Delete the workflows that we created as part of this notebook" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "training_workflow.delete()\n", - "transform_workflow.delete()" - ] - } - ], - "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.13" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} +{"cells": [{"cell_type": "markdown", "metadata": {}, "source": ["# Workflow\n", "\n", "The following notebook contains the step functions workflow definition for training and baseline jobs.\n", "\n", "This can be run after you have started the [mlops](mlops.ipynb) build and have stored `input_data`."]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["# Import the latest sagemaker, stepfunctions and boto3 SDKs\n", "import sys\n", "!{sys.executable} -m pip install --upgrade pip\n", "!{sys.executable} -m pip install -qU awscli boto3 \"sagemaker>=2.1.0<3\"\n", "!{sys.executable} -m pip install -qU \"stepfunctions==2.0.0\"\n", "!{sys.executable} -m pip show sagemaker stepfunctions"]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["import boto3\n", "import json\n", "import os\n", "import time\n", "import uuid\n", "from botocore.exceptions import ClientError\n", "\n", "import sagemaker\n", "from sagemaker.image_uris import retrieve \n", "from sagemaker.processing import Processor, ProcessingInput, ProcessingOutput\n", "from sagemaker.model_monitor.dataset_format import DatasetFormat\n", "\n", "import stepfunctions\n", "from stepfunctions import steps\n", "from stepfunctions.inputs import ExecutionInput\n", "from stepfunctions.workflow import Workflow"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Load the input data from the `mlops.ipynb` notebook and print values"]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["%store -r input_data PROVISIONED_PRODUCT_NAME\n", "input_data, PROVISIONED_PRODUCT_NAME"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Load variables from environment"]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["def get_config(provisioned_product_name):\n", " sc = boto3.client(\"servicecatalog\")\n", " outputs = sc.get_provisioned_product_outputs(ProvisionedProductName=provisioned_product_name)[\n", " \"Outputs\"\n", " ]\n", " config = {}\n", " for out in outputs:\n", " config[out[\"OutputKey\"]] = out[\"OutputValue\"]\n", " return config\n", "\n", "\n", "config = get_config(PROVISIONED_PRODUCT_NAME)\n", "region = config[\"Region\"]\n", "model_name = config[\"ModelName\"]\n", "role = config[\"SageMakerRoleARN\"]\n", "workflow_role_arn = config[\"WorkflowRoleARN\"]\n", "\n", "\n", "# Define the lambda function names for steps\n", "create_experiment_function_name = 'mlops-create-experiment'\n", "query_training_function_name = 'mlops-query-training'\n", "transform_header_function_name = 'mlops-add-transform-header'\n", "query_drift_function_name = 'mlops-query-drift'\n", "\n", "# Get the session and default bucket\n", "session = sagemaker.session.Session()\n", "bucket = session.default_bucket()\n", "\n", "print('region: {}'.format(region))\n", "print('bucket: {}'.format(bucket))\n", "print('sagemaker role: {}'.format(role))\n", "print('workflow role: {}'.format(workflow_role_arn))"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Specify the training model and transform output base uri"]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["output_data = {\n", " 'ModelOutputUri': 's3://{}/{}/model'.format(bucket, model_name), \n", "}"]}, {"cell_type": "markdown", "metadata": {}, "source": ["## Define Training Resources\n", "\n", "### Input Schema\n", "\n", "Define the input schema for the step functions which can then be used as arguments to resources"]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["execution_input = ExecutionInput(\n", " schema={\n", " \"GitBranch\": str,\n", " \"GitCommitHash\": str,\n", " \"DataVersionId\": str,\n", " \"ExperimentName\": str,\n", " \"TrialName\": str,\n", " \"BaselineJobName\": str,\n", " \"BaselineOutputUri\": str,\n", " \"TrainingJobName\": str,\n", " \"ModelName\": str\n", " }\n", ")"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Define the model monitor baseline\n", "\n", "Define the environment variables"]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["dataset_format = DatasetFormat.csv()\n", "env = {\n", " \"dataset_format\": json.dumps(dataset_format),\n", " \"dataset_source\": \"/opt/ml/processing/input/baseline_dataset_input\",\n", " \"output_path\": \"/opt/ml/processing/output\",\n", " \"publish_cloudwatch_metrics\": \"Disabled\", # Have to be disabled from processing job?\n", "}"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Define the processing inputs and outputs "]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["inputs = [\n", " ProcessingInput(\n", " source=input_data['BaselineUri'],\n", " destination=\"/opt/ml/processing/input/baseline_dataset_input\",\n", " input_name=\"baseline_dataset_input\",\n", " ),\n", "]\n", "outputs = [\n", " ProcessingOutput(\n", " source=\"/opt/ml/processing/output\",\n", " destination=execution_input[\"BaselineOutputUri\"],\n", " output_name=\"monitoring_output\",\n", " ),\n", "]"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Create the baseline processing job using the sagemaker [model monitor](https://sagemaker.readthedocs.io/en/stable/amazon_sagemaker_model_monitoring.html) container."]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["# Get the default model monitor container\n", "monor_monitor_container_uri = retrieve(region=region, framework=\"model-monitor\", version=\"latest\")\n", "\n", "# Use the base processing where we pass through the \n", "monitor_analyzer = Processor(\n", " image_uri=monor_monitor_container_uri,\n", " role=role, \n", " instance_count=1,\n", " instance_type=\"ml.m5.xlarge\",\n", " max_runtime_in_seconds=1800,\n", " env=env\n", ")"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Test the model baseline processing job by running inline"]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["# monitor_analyzer.run(inputs=inputs, outputs=outputs, wait=True)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Defining the Training Job\n", "\n", "Define the training job to run in paralell with the processing job"]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["image_uri = sagemaker.image_uris.retrieve(region=region, framework=\"xgboost\", version=\"latest\")\n", "\n", "# Create the estimator\n", "xgb = sagemaker.estimator.Estimator(\n", " image_uri,\n", " role,\n", " instance_count=1,\n", " instance_type=\"ml.m4.xlarge\",\n", " output_path=output_data['ModelOutputUri'], # NOTE: Can't use execution_input here\n", ")\n", "\n", "# Set the hyperparameters overriding with any defaults\n", "hyperparameters = {\n", " \"max_depth\": \"9\",\n", " \"eta\": \"0.2\",\n", " \"gamma\": \"4\",\n", " \"min_child_weight\": \"300\",\n", " \"subsample\": \"0.8\",\n", " \"objective\": \"reg:linear\",\n", " \"early_stopping_rounds\": \"10\",\n", " \"num_round\": \"50\", # Don't stop to early or results are bad\n", "}\n", "xgb.set_hyperparameters(**hyperparameters)\n", "\n", "# Specify the data source\n", "s3_input_train = sagemaker.inputs.TrainingInput(s3_data=input_data['TrainingUri'], content_type=\"csv\")\n", "s3_input_val = sagemaker.inputs.TrainingInput(s3_data=input_data['ValidationUri'], content_type=\"csv\")\n", "data = {\"train\": s3_input_train, \"validation\": s3_input_val}"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Test the estimator directly in the notebook"]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["# xgb.fit(inputs=data)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["## Define Training Workflow\n", "\n", "### 1. Create the Experiment\n", "\n", "Define the create experiment lambda.\n", "\n", "In future add [ResultsPath](https://docs.aws.amazon.com/step-functions/latest/dg/input-output-resultpath.html) to filter the results."]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["create_experiment_step = steps.compute.LambdaStep(\n", " 'Create Experiment',\n", " parameters={ \n", " \"FunctionName\": create_experiment_function_name,\n", " 'Payload': {\n", " \"ExperimentName.$\": '$.ExperimentName',\n", " \"TrialName.$\": '$.TrialName',\n", " }\n", " },\n", " result_path='$.CreateTrialResults'\n", ")"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### 2a. Run processing Job\n", "\n", "Define the processing job with a specific failure handling"]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["baseline_step = steps.sagemaker.ProcessingStep(\n", " \"Baseline Job\",\n", " processor=monitor_analyzer,\n", " job_name=execution_input[\"BaselineJobName\"],\n", " inputs=inputs,\n", " outputs=outputs,\n", " experiment_config={\n", " 'ExperimentName': execution_input[\"ExperimentName\"], # '$.ExperimentName', \n", " 'TrialName': execution_input[\"TrialName\"],\n", " 'TrialComponentDisplayName': \"Baseline\",\n", " },\n", " tags={\n", " \"GitBranch\": execution_input[\"GitBranch\"],\n", " \"GitCommitHash\": execution_input[\"GitCommitHash\"],\n", " \"DataVersionId\": execution_input[\"DataVersionId\"],\n", " },\n", " result_path='$.BaselineJobResults'\n", ")\n", "\n", "baseline_step.add_catch(steps.states.Catch(\n", " error_equals=[\"States.TaskFailed\"],\n", " next_step=stepfunctions.steps.states.Fail(\n", " \"Baseline failed\", cause=\"SageMakerBaselineJobFailed\"\n", " ),\n", "))"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### 2b. Run and query training Job\n", "\n", "Define the training job and add a validation step"]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["training_step = steps.TrainingStep(\n", " \"Training Job\",\n", " estimator=xgb,\n", " data=data,\n", " job_name=execution_input[\"TrainingJobName\"],\n", " experiment_config={\n", " 'ExperimentName': execution_input[\"ExperimentName\"],\n", " 'TrialName': execution_input[\"TrialName\"],\n", " 'TrialComponentDisplayName': \"Training\",\n", " },\n", " tags={\n", " \"GitBranch\": execution_input[\"GitBranch\"],\n", " \"GitCommitHash\": execution_input[\"GitCommitHash\"],\n", " \"DataVersionId\": execution_input[\"DataVersionId\"],\n", " },\n", " result_path='$.TrainingResults'\n", ")\n", "\n", "training_step.add_catch(stepfunctions.steps.states.Catch(\n", " error_equals=[\"States.TaskFailed\"],\n", " next_step=stepfunctions.steps.states.Fail(\n", " \"Training failed\", cause=\"SageMakerTrainingJobFailed\"\n", " ),\n", "))"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Create a model from the training job, note this must follow training to retrieve the expected model"]}, {"cell_type": "code", "execution_count": null, "metadata": {"scrolled": true}, "outputs": [], "source": ["# Must follow the training test\n", "model_step = steps.sagemaker.ModelStep(\n", " 'Save Model',\n", " input_path='$.TrainingResults',\n", " model=training_step.get_expected_model(),\n", " model_name=execution_input['ModelName'],\n", " result_path='$.ModelStepResults'\n", ")"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Query training results, and validate that the RMSE error is within an acceptable range "]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["training_query_step = steps.compute.LambdaStep(\n", " 'Query Training Results',\n", " parameters={ \n", " \"FunctionName\": query_training_function_name,\n", " 'Payload':{\n", " \"TrainingJobName.$\": '$.TrainingJobName'\n", " }\n", " },\n", " result_path='$.QueryTrainingResults'\n", ")\n", "\n", "check_accuracy_fail_step = steps.states.Fail(\n", " 'Model Error Too Low',\n", " comment='RMSE accuracy higher than threshold'\n", ")\n", "\n", "check_accuracy_succeed_step = steps.states.Succeed('Model Error Acceptable')\n", "\n", "# TODO: Update query method to query validation error using better result path\n", "threshold_rule = steps.choice_rule.ChoiceRule.NumericLessThan(\n", " variable=training_query_step.output()['QueryTrainingResults']['Payload']['results']['TrainingMetrics'][0]['Value'], value=10\n", ")\n", "\n", "check_accuracy_step = steps.states.Choice(\n", " 'RMSE < 10'\n", ")\n", "\n", "check_accuracy_step.add_choice(rule=threshold_rule, next_step=check_accuracy_succeed_step)\n", "check_accuracy_step.default_choice(next_step=check_accuracy_fail_step)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### 3. Add the Error handling in the workflow\n", "\n", "We will use the [Catch Block](https://aws-step-functions-data-science-sdk.readthedocs.io/en/stable/states.html#stepfunctions.steps.states.Catch) to perform error handling. If the Processing Job Step or Training Step fails, the flow will go into failure state."]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["sagemaker_jobs = steps.states.Parallel(\"SageMaker Jobs\")\n", "sagemaker_jobs.add_branch(baseline_step)\n", "sagemaker_jobs.add_branch(steps.states.Chain([training_step, model_step, training_query_step, check_accuracy_step]))\n", "\n", "# Do we need specific failure for the jobs for group?\n", "sagemaker_jobs.add_catch(stepfunctions.steps.states.Catch(\n", " error_equals=[\"States.TaskFailed\"],\n", " next_step=stepfunctions.steps.states.Fail(\n", " \"SageMaker Jobs failed\", cause=\"SageMakerJobsFailed\"\n", " ),\n", "))"]}, {"cell_type": "markdown", "metadata": {}, "source": ["## Execute Training Workflow\n", "\n", "Create the training workflow."]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["training_workflow_definition = steps.states.Chain([\n", " create_experiment_step,\n", " sagemaker_jobs\n", "])\n", "\n", "training_workflow_name = 'mlops-{}-training'.format(model_name)\n", "training_workflow = Workflow(training_workflow_name, training_workflow_definition, workflow_role_arn)\n", "training_workflow.create()\n", "training_workflow"]}, {"cell_type": "markdown", "metadata": {}, "source": ["We can also inspect the raw workflow definition and verify the execution variables are correctly passed in"]}, {"cell_type": "code", "execution_count": null, "metadata": {"scrolled": true}, "outputs": [], "source": ["print(training_workflow.definition.to_json(pretty=True))"]}, {"cell_type": "markdown", "metadata": {}, "source": [" Now we define the inputs for the workflow"]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["# Define some dummy job and git params\n", "job_id = uuid.uuid1().hex\n", "git_branch = 'main'\n", "git_commit_hash = 'xxx' \n", "data_verison_id = 'yyy'\n", "\n", "# Define the experiment and trial name based on model name and job id\n", "experiment_name = \"mlops-{}\".format(model_name)\n", "trial_name = \"mlops-{}-{}\".format(model_name, job_id)\n", "\n", "workflow_inputs = {\n", " \"ExperimentName\": experiment_name,\n", " \"TrialName\": trial_name,\n", " \"GitBranch\": git_branch,\n", " \"GitCommitHash\": git_commit_hash, \n", " \"DataVersionId\": data_verison_id, \n", " \"BaselineJobName\": trial_name, \n", " \"BaselineOutputUri\": f\"s3://{bucket}/{model_name}/monitoring/baseline/mlops-{model_name}-pbl-{job_id}\",\n", " \"TrainingJobName\": trial_name,\n", " \"ModelName\": trial_name,\n", "}\n", "print(json.dumps(workflow_inputs))"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Then execute the workflow"]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["execution = training_workflow.execute(\n", " inputs=workflow_inputs\n", ")"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Wait for the execution to complete, and output the last step."]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["execution_output = execution.get_output(wait=True)\n", "execution.list_events()[-1]"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Use [list_events](https://aws-step-functions-data-science-sdk.readthedocs.io/en/latest/workflow.html#stepfunctions.workflow.Execution.list_events) to list all events in the workflow execution."]}, {"cell_type": "code", "execution_count": null, "metadata": {"scrolled": true}, "outputs": [], "source": ["# execution.list_events(html=True) # Bug"]}, {"cell_type": "markdown", "metadata": {}, "source": ["## Execute Batch Transform\n", "\n", "Take the model we have trained and run a batch transform on the validation dataset.\n"]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["execution_input = ExecutionInput(\n", " schema={\n", " \"GitBranch\": str,\n", " \"GitCommitHash\": str,\n", " \"DataVersionId\": str,\n", " \"ExperimentName\": str,\n", " \"TrialName\": str,\n", " \"ModelName\": str,\n", " \"TransformJobName\": str,\n", " \"MonitorJobName\": str,\n", " \"MonitorOutputUri\": str,\n", " }\n", ")"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Define some new output paths for the transform and monitoring jobs"]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["output_data['TransformOutputUri'] = f\"s3://{bucket}/{model_name}/transform/mlops-{model_name}-{job_id}\"\n", "output_data['MonitoringOutputUri'] = f\"s3://{bucket}/{model_name}/monitoring/mlops-{model_name}-{job_id}\"\n", "output_data['BaselineOutputUri'] = workflow_inputs['BaselineOutputUri']"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### 1. Run the Transform Job\n", "\n", "Define a transform job to take the test dataset as input. \n", "\n", "We can configured the batch transform to [associate prediction results](https://aws.amazon.com/blogs/machine-learning/associating-prediction-results-with-input-data-using-amazon-sagemaker-batch-transform/) with the input based in the `input_filter` and `output_filter` arguments."]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["transform_step = steps.TransformStep(\n", " 'Transform Input Dataset',\n", " transformer=xgb.transformer(\n", " instance_count=1,\n", " instance_type='ml.m5.large',\n", " assemble_with='Line', \n", " accept = 'text/csv',\n", " output_path=output_data['TransformOutputUri'], # NOTE: Can't use execution_input here\n", " ),\n", " job_name=execution_input['TransformJobName'], # TEMP\n", " model_name=execution_input['ModelName'], \n", " data=input_data['TestUri'],\n", " content_type='text/csv',\n", " split_type='Line',\n", " input_filter='$[1:]', # Skip the first target column output_amount\n", " join_source='Input',\n", " output_filter='$[1:]', # Output all inputs excluding output_amount, followed by the predicted_output_amount\n", " result_path='$.TransformJobResults'\n", ")"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### 2. Add the Transform Header\n", "\n", "The batch transform output does not include the header, so add this back to be able to run baseline."]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["transform_file_name = 'test.csv'\n", "header = 'duration_minutes,passenger_count,trip_distance,total_amount'"]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["transform_header_step = steps.compute.LambdaStep(\n", " 'Add Transform Header',\n", " parameters={ \n", " \"FunctionName\": transform_header_function_name,\n", " 'Payload': {\n", " \"TransformOutputUri\": output_data['TransformOutputUri'],\n", " \"FileName\": transform_file_name,\n", " \"Header\": header,\n", " }\n", " },\n", " result_path='$.TransformHeaderResults'\n", ")"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### 3. Run the Model Monitor Processing Job\n", "\n", "Create a model monitor processing job that takes the output of the transform job.\n", "\n", "Reference the `constraints.json` and `statistics.json` from the output form the training baseline."]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["dataset_format = DatasetFormat.csv()\n", "env = {\n", " \"dataset_format\": json.dumps(dataset_format),\n", " \"dataset_source\": \"/opt/ml/processing/input/baseline_dataset_input\",\n", " \"output_path\": \"/opt/ml/processing/output\",\n", " \"publish_cloudwatch_metrics\": \"Disabled\", # Have to be disabled from processing job?\n", " \"baseline_constraints\": \"/opt/ml/processing/baseline/constraints/constraints.json\",\n", " \"baseline_statistics\": \"/opt/ml/processing/baseline/stats/statistics.json\"\n", "}\n", "inputs = [\n", " ProcessingInput(\n", " source=os.path.join(output_data['TransformOutputUri'], transform_file_name), # Transform with header\n", " destination=\"/opt/ml/processing/input/baseline_dataset_input\",\n", " input_name=\"baseline_dataset_input\",\n", " ),\n", " ProcessingInput(\n", " source=os.path.join(output_data['BaselineOutputUri'], 'constraints.json'),\n", " destination=\"/opt/ml/processing/baseline/constraints\",\n", " input_name=\"constraints\",\n", " ),\n", " ProcessingInput(\n", " source=os.path.join(output_data['BaselineOutputUri'], 'statistics.json'),\n", " destination=\"/opt/ml/processing/baseline/stats\",\n", " input_name=\"baseline\",\n", " ),\n", "]\n", "outputs = [\n", " ProcessingOutput(\n", " source=\"/opt/ml/processing/output\",\n", " destination=output_data['MonitoringOutputUri'],\n", " output_name=\"monitoring_output\",\n", " ),\n", "]\n", "\n", "# Get the default model monitor container\n", "monor_monitor_container_uri = retrieve(region=region, framework=\"model-monitor\", version=\"latest\")\n", "\n", "# Use the base processing where we pass through the \n", "monitor_analyzer = Processor(\n", " image_uri=monor_monitor_container_uri,\n", " role=role, \n", " instance_count=1,\n", " instance_type=\"ml.m5.xlarge\",\n", " max_runtime_in_seconds=1800,\n", " env=env\n", ")"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Test the monitor baseline"]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["# monitor_analyzer.run(inputs=inputs, outputs=outputs, wait=True)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Add the monitor step"]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["monitor_step = steps.sagemaker.ProcessingStep(\n", " \"Monitor Job\",\n", " processor=monitor_analyzer,\n", " job_name=execution_input[\"MonitorJobName\"],\n", " inputs=inputs,\n", " outputs=outputs,\n", " experiment_config={\n", " 'ExperimentName': execution_input[\"ExperimentName\"],\n", " 'TrialName': execution_input[\"TrialName\"],\n", " 'TrialComponentDisplayName': \"Baseline\",\n", " },\n", " tags={\n", " \"GitBranch\": execution_input[\"GitBranch\"],\n", " \"GitCommitHash\": execution_input[\"GitCommitHash\"],\n", " \"DataVersionId\": execution_input[\"DataVersionId\"],\n", " },\n", " result_path='$.MonitorJobResults'\n", ")\n", "\n", "monitor_step.add_catch(stepfunctions.steps.states.Catch(\n", " error_equals=[\"States.TaskFailed\"],\n", " next_step=stepfunctions.steps.states.Fail(\n", " \"Monitor failed\", cause=\"SageMakerMonitorJobFailed\"\n", " ),\n", "))"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Add the lambda step to query for violations in the processing job."]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["monitor_query_step = steps.compute.LambdaStep(\n", " 'Query Monitoring Results',\n", " parameters={ \n", " \"FunctionName\": query_drift_function_name,\n", " 'Payload':{\n", " \"ProcessingJobName.$\": '$.MonitorJobName'\n", " }\n", " },\n", " result_path='$.QueryMonitorResults'\n", ")\n", "\n", "check_violations_fail_step = steps.states.Fail(\n", " 'Completed with Violations',\n", " comment='Processing job completed with violations'\n", ")\n", "\n", "check_violations_succeed_step = steps.states.Succeed('Completed')\n", "\n", "# TODO: Check specific drift in violations\n", "status_rule = steps.choice_rule.ChoiceRule.StringEquals(\n", " variable=monitor_query_step.output()['QueryMonitorResults']['Payload']['results']['ProcessingJobStatus'], value='Completed'\n", ")\n", "\n", "check_violations_step = steps.states.Choice(\n", " 'Check Violations'\n", ")\n", "\n", "check_violations_step.add_choice(rule=status_rule, next_step=check_violations_succeed_step)\n", "check_violations_step.default_choice(next_step=check_violations_fail_step)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Create the transform workflow definition"]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["transform_workflow_definition = steps.states.Chain([\n", " transform_step,\n", " transform_header_step,\n", " monitor_step, \n", " monitor_query_step, \n", " check_violations_step\n", "])\n", "\n", "transform_workflow_name = 'mlops-{}-transform'.format(model_name)\n", "transform_workflow = Workflow(transform_workflow_name, transform_workflow_definition, workflow_role_arn)\n", "transform_workflow.create()\n", "transform_workflow"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Define the workflow inputs based on the previous training run"]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["# Define unique names for the transform and monitor baseline jobs\n", "transform_job_name = \"mlops-{}-trn-{}\".format(model_name, job_id)\n", "monitor_job_name = \"mlops-{}-mbl-{}\".format(model_name, job_id)\n", "\n", "workflow_inputs = {\n", " \"ExperimentName\": experiment_name,\n", " \"TrialName\": trial_name,\n", " \"GitBranch\": git_branch,\n", " \"GitCommitHash\": git_commit_hash, \n", " \"DataVersionId\": data_verison_id, \n", " \"ModelName\": trial_name,\n", " \"TransformJobName\": transform_job_name, \n", " \"MonitorJobName\": monitor_job_name,\n", "}\n", "print(json.dumps(workflow_inputs))"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Execute the workflow and render the progress. "]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["execution = transform_workflow.execute(\n", " inputs=workflow_inputs\n", ")"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Wait for the execution to finish and list the last event."]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["execution_output = execution.get_output(wait=True)\n", "execution.list_events()[-1]"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Inspect Transform Results\n", "\n", "Verify that we can load the transform output with header"]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["from io import StringIO\n", "import pandas as pd\n", "from sagemaker.s3 import S3Downloader\n", "\n", "# Get the output, and add header\n", "transform_output_uri = os.path.join(output_data['TransformOutputUri'], transform_file_name)\n", "transform_body = S3Downloader.read_file(transform_output_uri)\n", "pred_df = pd.read_csv(StringIO(transform_body), sep=\",\")\n", "pred_df.head()"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Query monitoring output\n", "\n", "If this completed with violations, let's inspect the output to see why that is the case."]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["violiations_uri = os.path.join(output_data['MonitoringOutputUri'], 'constraint_violations.json')\n", "violiations = json.loads(S3Downloader.read_file(violiations_uri))\n", "violiations"]}, {"cell_type": "markdown", "metadata": {}, "source": ["## Cleanup\n", "\n", "Delete the workflows that we created as part of this notebook"]}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": ["training_workflow.delete()\n", "transform_workflow.delete()"]}], "metadata": {"instance_type": "ml.t3.medium", "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.7.10"}}, "nbformat": 4, "nbformat_minor": 4} \ No newline at end of file diff --git a/pipeline.yml b/pipeline.yml index 0a57e23..0c530b6 100644 --- a/pipeline.yml +++ b/pipeline.yml @@ -1,17 +1,4 @@ -# Delete the stack: -# -# aws cloudformation delete-stack --stack-name sagemaker-safe-deployment -# -# Create the stack: -# -# aws cloudformation create-stack --stack-name sagemaker-safe-deployment \ -# --template-body file://pipeline.yml \ -# --capabilities CAPABILITY_IAM \ -# --parameters \ -# ParameterKey=GitHubUser,ParameterValue= \ -# ParameterKey=GitHubToken,ParameterValue= \ -# ParameterKey=ModelName,ParameterValue= - +AWSTemplateFormatVersion: "2010-09-09" Description: Create an Amazon SageMaker safe deployment pipeline Metadata: AWS::CloudFormation::Interface: @@ -21,37 +8,47 @@ Metadata: Parameters: - ModelName - DatasetBucket - - NotebookInstanceType - Label: - default: Optional GitHub Parameters + default: Git Config Parameters: - - GitHubRepo - - GitHubBranch - - GitHubUser - - GitHubToken + - GitBranch - Label: default: Optional Notification Settings Parameters: - EmailAddress ParameterLabels: + SageMakerProjectName: + default: Project Name + SageMakerProjectId: + default: Project ID + ProjectPrefix: + default: Unique prefix to bind the components ModelName: default: Model Name DatasetBucket: default: S3 Bucket for Dataset - NotebookInstanceType: - default: Notebook Instance Type - GitHubRepo: - default: GitHub Repository - GitHubBranch: - default: GitHub Branch - GitHubUser: - default: GitHub Username - GitHubToken: - default: GitHub Access Token + GitBranch: + default: Git Branch EmailAddress: default: Email Address + TimeoutInMinutes: + default: Train and build timeout Parameters: + SageMakerProjectName: + Type: String + Description: Name of the project + MinLength: 1 + AllowedPattern: ^[a-zA-Z](-*[a-zA-Z0-9])* + SageMakerProjectId: + Type: String + Description: Service generated Id of the project + ProjectPrefix: + Type: String + Description: | + Unique prefix to make resource privileges scoped-limited. + Changing the default must be done with care + Default: PROJECT_PREFIX ModelName: Default: nyctaxi Type: String @@ -60,57 +57,35 @@ Parameters: MaxLength: 15 # Limited to this due to mlops-{model}-{dev/prd}-{pipeline-executionid} AllowedPattern: ^[a-z0-9](-*[a-z0-9])* # no UPPERCASE due to S3 naming restrictions ConstraintDescription: Must be lowercase or numbers with a length of 1-15 characters. - NotebookInstanceType: - Type: String - Default: ml.t3.medium - Description: Select Instance type for the SageMaker Notebook - AllowedValues: - - ml.t3.medium - - ml.t3.large - - ml.t3.2xlarge - - ml.m5.large - - ml.m5.xlarge - - ml.m5.2xlarge - ConstraintDescription: Must select a valid notebook instance type. DatasetBucket: Default: nyc-tlc Description: S3 dataset bucket. Type: String - GitHubUser: - Default: aws-samples - Description: Your GitHub username - Type: String - GitHubRepo: - Default: amazon-sagemaker-safe-deployment-pipeline - Type: String - Description: Name of the GitHub repository. - GitHubBranch: - Default: master + GitBranch: + Default: main Type: String Description: Name of the GitHub branch where the code is located. - GitHubToken: - Default: "" - NoEcho: true - Description: Optional Github OAuthToken with access to your Repo. Leave blank to pull the public repository into local CodeCommit. - Type: String EmailAddress: - Default: "" + Default: "example@example.com" Description: Email address to notify on successful or failed deployments. Type: String + TimeoutInMinutes: + Default: 30 + Description: Train and build timeout in minutes + Type: String Conditions: EmailAddressNotEmpty: !Not [!Equals [!Ref EmailAddress, ""]] - GitHubTokenEmpty: !Equals [!Ref GitHubToken, ""] Resources: KMSKey: Type: AWS::KMS::Key Properties: - Description: !Sub KMS Key for mlops pipeline ${ModelName} + Description: !Sub KMS Key for mlops pipeline ${ProjectPrefix}-${ModelName}-${SageMakerProjectId} EnableKeyRotation: true KeyPolicy: Version: "2012-10-17" - Id: !Ref ModelName + Id: !Sub ${ProjectPrefix}-${ModelName} Statement: - Sid: Allows admin of the key Effect: Allow @@ -123,13 +98,13 @@ Resources: KMSAlias: Type: AWS::KMS::Alias Properties: - AliasName: !Sub alias/mlops-${ModelName} + AliasName: !Sub alias/${ProjectPrefix}-${ModelName}-${SageMakerProjectId} TargetKeyId: !Ref KMSKey ArtifactBucket: Type: AWS::S3::Bucket Properties: - BucketName: !Sub mlops-${ModelName}-artifact-${AWS::Region}-${AWS::AccountId} + BucketName: !Sub ${ProjectPrefix}-${ModelName}-${SageMakerProjectId} AccessControl: Private VersioningConfiguration: Status: Enabled @@ -161,13 +136,13 @@ Resources: DependsOn: ArtifactBucketPolicy Type: AWS::CloudTrail::Trail Properties: - TrailName: !Sub mlops-${ModelName} + TrailName: !Sub ${ProjectPrefix}-${ModelName}-${SageMakerProjectId} S3BucketName: !Ref ArtifactBucket EventSelectors: - DataResources: - Type: AWS::S3::Object Values: - - !Sub ${ArtifactBucket.Arn}/${ModelName}/data-source.zip + - !Sub ${ArtifactBucket.Arn}/${ProjectPrefix}-${ModelName}-${SageMakerProjectId}/data-source.zip ReadWriteType: WriteOnly IncludeGlobalServiceEvents: true IsLogging: true @@ -176,7 +151,7 @@ Resources: NotificationTopic: Type: AWS::SNS::Topic Properties: - TopicName: !Sub mlops-${ModelName}-notification + TopicName: !Sub ${ProjectPrefix}-${ModelName}-${SageMakerProjectId}-notification NotificationTopicPolicy: Type: AWS::SNS::TopicPolicy @@ -198,89 +173,24 @@ Resources: Condition: EmailAddressNotEmpty Properties: Endpoint: !Ref EmailAddress - Protocol: Email + Protocol: "email" TopicArn: !Ref NotificationTopic - GitHubSecret: - Type: AWS::SecretsManager::Secret - Properties: - Description: !Sub GitHub Secret for ${GitHubRepo} - KmsKeyId: !Ref KMSKey - SecretString: !Sub '{"username":"${GitHubUser}","password":"${GitHubToken}"}' - CodeCommitRepository: Type: AWS::CodeCommit::Repository - Condition: GitHubTokenEmpty - Properties: - RepositoryName: !Ref GitHubRepo - RepositoryDescription: !Sub SageMaker safe deployment pipeline for ${ModelName} - - SageMakerCodeRepository: - Type: AWS::SageMaker::CodeRepository Properties: - CodeRepositoryName: !Join ["-", !Split ["_", !Ref GitHubRepo]] - GitConfig: - RepositoryUrl: - Fn::If: - - GitHubTokenEmpty - - !GetAtt CodeCommitRepository.CloneUrlHttp - - !Sub https://github.com/${GitHubUser}/${GitHubRepo}.git - Branch: !Ref GitHubBranch - SecretArn: - Fn::If: - - GitHubTokenEmpty - - !Ref "AWS::NoValue" - - !Ref GitHubSecret - - NotebookInstanceLifecycleConfig: - Type: AWS::SageMaker::NotebookInstanceLifecycleConfig - Properties: - NotebookInstanceLifecycleConfigName: !Sub ${ModelName}-lifecycle-config - OnCreate: - - Content: - Fn::If: - - GitHubTokenEmpty - - Fn::Base64: - Fn::Sub: | - #!/bin/bash - # Clone the public github repo, and push it to a local codecommit branch - export HOME=/root/ - echo "Configuring github for AWS credentials" - git config --global credential.helper '!aws codecommit credential-helper $@' - git config --global credential.UseHttpPath true - cp /root/.gitconfig /home/ec2-user/ && chown ec2-user:ec2-user /home/ec2-user/.gitconfig - echo "Clone the public repo and push it to codecommit repo" - git clone -b ${GitHubBranch} "https://github.com/${GitHubUser}/${GitHubRepo}.git" /tmp/mlops-repo - cd /tmp/mlops-repo - git remote add codecommit ${CodeCommitRepository.CloneUrlHttp} - git push --set-upstream codecommit ${GitHubBranch} - - Ref: AWS::NoValue - OnStart: - - Content: - Fn::Base64: - Fn::Sub: | - #!/bin/bash - touch /etc/profile.d/jupyter-env.sh - echo "export ARTIFACT_BUCKET=${ArtifactBucket}" >> /etc/profile.d/jupyter-env.sh - echo "export PIPELINE_NAME=${ModelName}" >> /etc/profile.d/jupyter-env.sh - echo "export MODEL_NAME=${ModelName}" >> /etc/profile.d/jupyter-env.sh - echo "export WORKFLOW_PIPELINE_ARN=arn:aws:states:${AWS::Region}:${AWS::AccountId}:stateMachine:${ModelName}" >> /etc/profile.d/jupyter-env.sh - echo "export WORKFLOW_ROLE_ARN=${WorkflowExecutionRole.Arn}" >> /etc/profile.d/jupyter-env.sh - - NotebookInstance: - Type: AWS::SageMaker::NotebookInstance - Properties: - NotebookInstanceName: !Sub ${ModelName}-notebook - InstanceType: !Ref NotebookInstanceType - LifecycleConfigName: !GetAtt NotebookInstanceLifecycleConfig.NotebookInstanceLifecycleConfigName - DefaultCodeRepository: !GetAtt SageMakerCodeRepository.CodeRepositoryName - KmsKeyId: !Ref KMSKey - RoleArn: !GetAtt SageMakerRole.Arn + RepositoryName: !Sub "amazon-sagemaker-safe-deployment-pipeline-${SageMakerProjectName}-${SageMakerProjectId}" # !Sub ${GitHubRepo} + RepositoryDescription: !Sub SageMaker safe deployment pipeline for project ${SageMakerProjectName} with id ${SageMakerProjectId}, prefix ${ProjectPrefix} and model name ${ModelName} + Code: + S3: + Bucket: "S3_BUCKET_NAME" + Key: "project.zip" + BranchName: !Ref GitBranch BuildProject: Type: AWS::CodeBuild::Project Properties: - Name: !Sub ${ModelName}-build + Name: !Sub ${ProjectPrefix}-${ModelName}-${SageMakerProjectId}-build Description: Builds the assets required for executing the rest of pipeline ServiceRole: !GetAtt SageMakerRole.Arn Artifacts: @@ -290,12 +200,33 @@ Resources: ComputeType: BUILD_GENERAL1_SMALL Image: aws/codebuild/amazonlinux2-x86_64-standard:3.0 EnvironmentVariables: + - Name: SAGEMAKER_PROJECT_NAME + Type: PLAINTEXT + Value: !Ref SageMakerProjectName + - Name: SAGEMAKER_PROJECT_ID + Type: PLAINTEXT + Value: !Ref SageMakerProjectId + - Name: AWS_REGION + Type: PLAINTEXT + Value: !Ref AWS::Region + - Name: AWS_ACCOUNT_ID + Type: PLAINTEXT + Value: !Ref AWS::AccountId + - Name: IMAGE_TAG + Type: PLAINTEXT + Value: "latest" - Name: GIT_BRANCH Type: PLAINTEXT - Value: !Ref GitHubBranch + Value: !Ref GitBranch + - Name: PREFIX + Type: PLAINTEXT + Value: !Ref ProjectPrefix - Name: MODEL_NAME Type: PLAINTEXT Value: !Ref ModelName + - Name: PIPELINE_NAME + Type: PLAINTEXT + Value: !Sub ${ModelName}-${SageMakerProjectId} - Name: ARTIFACT_BUCKET Type: PLAINTEXT Value: !Ref ArtifactBucket @@ -313,19 +244,19 @@ Resources: Value: !GetAtt SageMakerRole.Arn - Name: SAGEMAKER_BUCKET Type: PLAINTEXT - Value: !Sub "sagemaker-${AWS::Region}-${AWS::AccountId}" + Value: !Sub "sagemaker-${AWS::Region}-${AWS::AccountId}" # match ArtifactBucket - Name: WORKFLOW_ROLE_ARN Type: PLAINTEXT Value: !GetAtt WorkflowExecutionRole.Arn Source: Type: CODEPIPELINE BuildSpec: model/buildspec.yml - TimeoutInMinutes: 30 + TimeoutInMinutes: !Ref TimeoutInMinutes DeployPipeline: Type: "AWS::CodePipeline::Pipeline" Properties: - Name: !Sub ${ModelName} + Name: !Sub ${ProjectPrefix}-${ModelName}-${SageMakerProjectId} RoleArn: !GetAtt PipelineRole.Arn ArtifactStore: Type: S3 @@ -337,33 +268,18 @@ Resources: Stages: - Name: Source Actions: - - Fn::If: - - GitHubTokenEmpty - - Name: GitSource - ActionTypeId: - Category: Source - Owner: AWS - Version: "1" - Provider: CodeCommit - Configuration: - PollForSourceChanges: false # Triggered by CodeCommitEventRule - RepositoryName: !Ref GitHubRepo - BranchName: !Ref GitHubBranch - OutputArtifacts: - - Name: ModelSourceOutput - - Name: GitSource - ActionTypeId: - Category: Source - Owner: ThirdParty - Version: "1" - Provider: GitHub # Explore CodeStarSourceConnection: https://docs.aws.amazon.com/codepipeline/latest/userguide/update-github-action-connections.html - OutputArtifacts: - - Name: ModelSourceOutput - Configuration: - Owner: !Ref GitHubUser - Repo: !Ref GitHubRepo - Branch: !Ref GitHubBranch - OAuthToken: !Ref GitHubToken + - Name: GitSource + ActionTypeId: + Category: Source + Owner: AWS + Version: "1" + Provider: CodeCommit + Configuration: + PollForSourceChanges: false # Triggered by CodeCommitEventRule + RepositoryName: !GetAtt CodeCommitRepository.Name + BranchName: !Ref GitBranch + OutputArtifacts: + - Name: ModelSourceOutput - Name: DataSource ActionTypeId: Category: Source @@ -375,8 +291,7 @@ Resources: Configuration: PollForSourceChanges: false # Triggered by S3EventRule S3Bucket: !Ref ArtifactBucket - S3ObjectKey: !Sub ${ModelName}/data-source.zip - PollForSourceChanges: false + S3ObjectKey: !Sub ${ProjectPrefix}-${ModelName}-${SageMakerProjectId}/data-source.zip RunOrder: 1 - Name: Build Actions: @@ -407,7 +322,7 @@ Resources: ActionMode: REPLACE_ON_FAILURE RoleArn: !GetAtt DeployRole.Arn Capabilities: CAPABILITY_NAMED_IAM - StackName: !Sub ${ModelName}-workflow + StackName: !Sub ${ProjectPrefix}-${ModelName}-${SageMakerProjectId}-workflow TemplatePath: BuildOutput::workflow-graph.yml RunOrder: 2 - Name: CreateCustomResources @@ -422,7 +337,7 @@ Resources: ActionMode: REPLACE_ON_FAILURE RoleArn: !GetAtt DeployRole.Arn Capabilities: CAPABILITY_NAMED_IAM,CAPABILITY_AUTO_EXPAND - StackName: sagemaker-custom-resource # Use global name to re-use across templates + StackName: !Sub ${ProjectPrefix}-${ModelName}-${SageMakerProjectId}-sagemaker-custom-resource # Use global name to re-use across templates TemplatePath: BuildOutput::packaged-custom-resource.yml RunOrder: 2 - Name: Train @@ -433,12 +348,12 @@ Resources: ActionTypeId: Category: Invoke Owner: AWS - Version: 1 + Version: "1" Provider: StepFunctions OutputArtifacts: - Name: TrainWorkflow Configuration: - StateMachineArn: !Sub "arn:aws:states:${AWS::Region}:${AWS::AccountId}:stateMachine:${ModelName}" + StateMachineArn: !Sub "arn:aws:states:${AWS::Region}:${AWS::AccountId}:stateMachine:${ProjectPrefix}-${ModelName}" InputType: FilePath Input: workflow-input.json RunOrder: 1 @@ -455,7 +370,7 @@ Resources: Configuration: ActionMode: REPLACE_ON_FAILURE RoleArn: !GetAtt DeployRole.Arn - StackName: !Sub ${ModelName}-deploy-dev + StackName: !Sub ${ProjectPrefix}-${ModelName}-${SageMakerProjectId}-deploy-dev TemplateConfiguration: BuildOutput::deploy-model-dev.json TemplatePath: BuildOutput::deploy-model-dev.yml RunOrder: 1 @@ -466,7 +381,6 @@ Resources: Version: "1" Provider: Manual Configuration: - ExternalEntityLink: !Sub https://${ModelName}-notebook.notebook.${AWS::Region}.sagemaker.aws/notebooks/${GitHubRepo}/notebook/mlops.ipynb CustomData: "Shall this model be put into production?" RunOrder: 2 - Name: DeployPrd @@ -485,16 +399,15 @@ Resources: ActionMode: CREATE_UPDATE RoleArn: !GetAtt DeployRole.Arn Capabilities: CAPABILITY_IAM,CAPABILITY_AUTO_EXPAND - StackName: !Sub ${ModelName}-deploy-prd + StackName: !Sub ${ProjectPrefix}-${ModelName}-${SageMakerProjectId}-deploy-prd TemplateConfiguration: BuildOutput::deploy-model-prd.json TemplatePath: BuildOutput::packaged-model-prd.yml RunOrder: 1 CodeCommitEventRule: Type: AWS::Events::Rule - Condition: GitHubTokenEmpty Properties: - Name: !Sub mlops-${ModelName}-codecommit-pipeline + Name: !Sub ${ProjectPrefix}-${ModelName}-${SageMakerProjectId}-codecommit-pipeline Description: "AWS CodeCommit change to trigger AWS Code Pipeline" EventPattern: source: @@ -507,7 +420,7 @@ Resources: referenceType: - "branch" referenceName: - - !Ref GitHubBranch + - !Ref GitBranch Targets: - Arn: !Sub "arn:aws:codepipeline:${AWS::Region}:${AWS::AccountId}:${DeployPipeline}" RoleArn: !GetAtt CloudWatchEventRole.Arn @@ -518,6 +431,7 @@ Resources: S3EventRule: Type: AWS::Events::Rule Properties: + Name: !Sub ${ProjectPrefix}-${ModelName}-${SageMakerProjectId}-s3-event-rule EventPattern: source: - aws.s3 @@ -534,7 +448,7 @@ Resources: bucketName: - !Ref ArtifactBucket key: - - !Sub ${ModelName}/data-source.zip + - !Sub ${ProjectPrefix}-${ModelName}-${SageMakerProjectId}/data-source.zip Targets: - Arn: !Sub "arn:aws:codepipeline:${AWS::Region}:${AWS::AccountId}:${DeployPipeline}" RoleArn: !GetAtt CloudWatchEventRole.Arn @@ -543,7 +457,7 @@ Resources: RetrainRule: Type: AWS::Events::Rule Properties: - Name: !Sub mlops-${ModelName}-retrain-pipeline + Name: !Sub ${ProjectPrefix}-${ModelName}-${SageMakerProjectId}-retrain-pipeline Description: "Retrain rule for the AWS Code Pipeline" EventPattern: source: @@ -552,7 +466,7 @@ Resources: - "CloudWatch Alarm State Change" detail: alarmName: - - !Sub mlops-${ModelName}-metric-gt-threshold + - !Sub ${ProjectPrefix}-${ModelName}-metric-gt-threshold state: value: - "ALARM" @@ -560,20 +474,23 @@ Resources: - Arn: !Sub "arn:aws:codepipeline:${AWS::Region}:${AWS::AccountId}:${DeployPipeline}" RoleArn: !GetAtt CloudWatchEventRole.Arn Id: !Sub codepipeline-${DeployPipeline} - - Arn: !Ref NotificationTopic - Id: "RetrainRule" - InputTransformer: - InputPathsMap: - alarmName: $.detail.alarmName - reason: $.detail.state.reason - InputTemplate: | - "The retrain rule for alarm: has been triggered." - "Reason: ." + # TODO: Studio doesn't accept empty CFT parameter so the SNS email + # if not verified prevents the retraining to complete + # enable SNS when studio accepts empty parameter + # - Arn: !Ref NotificationTopic + # Id: "RetrainRule" + # InputTransformer: + # InputPathsMap: + # alarmName: $.detail.alarmName + # reason: $.detail.state.reason + # InputTemplate: | + # "The retrain rule for alarm: has been triggered." + # "Reason: ." ScheduledRule: Type: AWS::Events::Rule Properties: - Name: !Sub mlops-${ModelName}-schedule-pipeline + Name: !Sub ${ProjectPrefix}-${ModelName}-${SageMakerProjectId}-schedule-pipeline Description: "Scheduled rule for the AWS Code Pipeline" ScheduleExpression: "cron(0 12 1 * ? *)" # 1 day of month State: DISABLED # Disable by default @@ -589,9 +506,8 @@ Resources: CodeCommitPolicy: Type: AWS::IAM::Policy - Condition: GitHubTokenEmpty Properties: - PolicyName: !Sub mlops-codecommit-policy + PolicyName: !Sub ${ProjectPrefix}-codecommit-policy PolicyDocument: Version: "2012-10-17" Statement: @@ -607,7 +523,7 @@ Resources: StepFunctionsPolicy: Type: AWS::IAM::Policy Properties: - PolicyName: !Sub mlops-sfn-policy + PolicyName: !Sub ${ProjectPrefix}-sfn-policy PolicyDocument: Version: "2012-10-17" Statement: @@ -616,8 +532,8 @@ Resources: Action: - states:* Resource: - - !Sub "arn:aws:states:${AWS::Region}:${AWS::AccountId}:stateMachine:${ModelName}*" - - !Sub "arn:aws:states:${AWS::Region}:${AWS::AccountId}:execution:${ModelName}*:*" + - !Sub "arn:aws:states:${AWS::Region}:${AWS::AccountId}:stateMachine:${ProjectPrefix}-${ModelName}*" + - !Sub "arn:aws:states:${AWS::Region}:${AWS::AccountId}:execution:${ProjectPrefix}-${ModelName}*:*" - Sid: AllowPassRoleStepFunctions Effect: Allow Action: @@ -634,7 +550,7 @@ Resources: CodePipelinePolicy: Type: AWS::IAM::Policy Properties: - PolicyName: !Sub mlops-codepipeline-policy + PolicyName: !Sub ${ProjectPrefix}-codepipeline-policy PolicyDocument: Version: "2012-10-17" Statement: @@ -651,7 +567,7 @@ Resources: SageMakerPolicy: Type: AWS::IAM::Policy Properties: - PolicyName: !Sub mlops-sagemaker-policy + PolicyName: !Sub ${ProjectPrefix}-sagemaker-policy PolicyDocument: Version: "2012-10-17" Statement: @@ -683,8 +599,8 @@ Resources: - sagemaker:StopTransformJob - kms:CreateGrant Resource: - - !Sub arn:aws:sagemaker:${AWS::Region}:${AWS::AccountId}:*/mlops-${ModelName}* - - !Sub arn:aws:sagemaker:${AWS::Region}:${AWS::AccountId}:*/model-monitoring-* + - !Sub arn:aws:sagemaker:${AWS::Region}:${AWS::AccountId}:*/${ProjectPrefix}-${ModelName}* + - !Sub arn:aws:sagemaker:${AWS::Region}:${AWS::AccountId}:*/${ProjectPrefix}-model-monitoring-* - Sid: AllowSageMakerSearch Effect: Allow Action: @@ -699,7 +615,7 @@ Resources: S3Policy: Type: AWS::IAM::Policy Properties: - PolicyName: !Sub mlops-s3-policy + PolicyName: !Sub ${ProjectPrefix}-s3-policy PolicyDocument: Version: "2012-10-17" Statement: @@ -747,7 +663,7 @@ Resources: CloudWatchEventRole: Type: AWS::IAM::Role Properties: - RoleName: !Sub mlops-${ModelName}-cwe-role + RoleName: !Sub ${ProjectPrefix}-${ModelName}-${SageMakerProjectId}-cwe-role AssumeRolePolicyDocument: Version: "2012-10-17" Statement: @@ -758,7 +674,7 @@ Resources: Action: sts:AssumeRole Path: / Policies: - - PolicyName: "mlops-cwe-pipeline-execution" + - PolicyName: !Sub "${ProjectPrefix}-cwe-pipeline-execution" PolicyDocument: Version: "2012-10-17" Statement: @@ -769,7 +685,7 @@ Resources: SageMakerRole: Type: AWS::IAM::Role Properties: - RoleName: !Sub mlops-${ModelName}-sagemaker-role + RoleName: !Sub ${ProjectPrefix}-${ModelName}-${SageMakerProjectId}-sagemaker-role AssumeRolePolicyDocument: Version: "2012-10-17" Statement: @@ -794,7 +710,7 @@ Resources: ManagedPolicyArns: - "arn:aws:iam::aws:policy/CloudWatchSyntheticsFullAccess" Policies: - - PolicyName: "mlops-notebook-policy" + - PolicyName: !Sub ${ProjectPrefix}-sagemaker-policy PolicyDocument: Version: "2012-10-17" Statement: @@ -803,8 +719,7 @@ Resources: Action: - cloudformation:* Resource: - - !Sub arn:aws:cloudformation:${AWS::Region}:${AWS::AccountId}:stack/${ModelName}* - - !Sub arn:aws:cloudformation:${AWS::Region}:${AWS::AccountId}:stack/sagemaker-custom-resource* + - !Sub arn:aws:cloudformation:${AWS::Region}:${AWS::AccountId}:stack/${ProjectPrefix}-${ModelName}* - Sid: AllowCloudWatch Effect: Allow Action: @@ -812,7 +727,6 @@ Resources: - cloudwatch:PutMetricData - cloudwatch:PutMetricAlarm - cloudwatch:DeleteAlarms - - cloudwatch:PutDashboard - cloudwatch:DeleteDashboards - iam:GetRole Resource: "*" @@ -829,7 +743,7 @@ Resources: WorkflowExecutionRole: Type: AWS::IAM::Role Properties: - RoleName: !Sub mlops-${ModelName}-sfn-execution-role + RoleName: !Sub ${ProjectPrefix}-${ModelName}-${SageMakerProjectId}-sfn-execution-role AssumeRolePolicyDocument: Statement: - Action: @@ -842,7 +756,7 @@ Resources: ManagedPolicyArns: - "arn:aws:iam::aws:policy/CloudWatchEventsFullAccess" Policies: - - PolicyName: "mlops-sfn-sagemaker" + - PolicyName: !Sub ${ProjectPrefix}-sfn-sagemaker PolicyDocument: Statement: - Sid: AllowLambda @@ -850,7 +764,7 @@ Resources: Action: - lambda:InvokeFunction Resource: - - arn:aws:lambda:*:*:function:mlops-* + - !Sub "arn:aws:lambda:*:*:function:${ProjectPrefix}-*" - Sid: AllowEvents Effect: Allow Action: @@ -874,7 +788,7 @@ Resources: PipelineRole: Type: "AWS::IAM::Role" Properties: - RoleName: !Sub mlops-${ModelName}-pipeline-role + RoleName: !Sub ${ProjectPrefix}-${ModelName}-${SageMakerProjectId}-pipeline-role AssumeRolePolicyDocument: Version: "2012-10-17" Statement: @@ -886,7 +800,7 @@ Resources: - "sts:AssumeRole" Path: "/" Policies: - - PolicyName: "mlops-pipeline" + - PolicyName: !Sub "${ProjectPrefix}-pipeline" PolicyDocument: Version: "2012-10-17" Statement: @@ -909,11 +823,16 @@ Resources: Action: - iam:PassRole Resource: !GetAtt DeployRole.Arn + - Sid: AllowCodeCommit + Effect: Allow + Action: + - codecommit:GetBranch + Resource: !GetAtt CodeCommitRepository.Arn DeployRole: Type: "AWS::IAM::Role" Properties: - RoleName: !Sub mlops-${ModelName}-deploy-role + RoleName: !Sub ${ProjectPrefix}-${ModelName}-${SageMakerProjectId}-deploy-role AssumeRolePolicyDocument: Version: "2012-10-17" Statement: @@ -933,7 +852,7 @@ Resources: ManagedPolicyArns: - Fn::Sub: "arn:${AWS::Partition}:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly" Policies: - - PolicyName: "mlops-deploy" + - PolicyName: !Sub ${ProjectPrefix}-deploy PolicyDocument: Version: "2012-10-17" Statement: @@ -1026,6 +945,25 @@ Outputs: DeployPipeline: Description: The deployment pipeline Value: !Ref DeployPipeline - NotebookInstance: - Description: The sagemaker notebook - Value: !Ref NotebookInstance + SageMakerProjectName: + Value: !Ref SageMakerProjectName + SageMakerProjectId: + Value: !Ref SageMakerProjectId + ArtifactBucket: + Value: !Ref ArtifactBucket + PipelineName: + Value: !Ref DeployPipeline + ModelName: + Value: !Ref ModelName + WorkflowPipelineARN: + Value: !Sub "arn:aws:states:${AWS::Region}:${AWS::AccountId}:stateMachine:${ProjectPrefix}-${ModelName}" + WorkflowRoleARN: + Value: !GetAtt WorkflowExecutionRole.Arn + SageMakerRoleARN: + Value: !GetAtt SageMakerRole.Arn + Region: + Value: !Ref AWS::Region + KMSKey: + Value: !Ref KMSKey + NotificationTopic: + Value: !Ref NotificationTopic diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..c265102 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,3 @@ +[tool.black] +line-length = 100 +target-version = ['py36', 'py37', 'py38'] diff --git a/scripts/build.sh b/scripts/build.sh new file mode 100755 index 0000000..d44204f --- /dev/null +++ b/scripts/build.sh @@ -0,0 +1,52 @@ +#!/bin/bash +set -euxo pipefail + +NOW=$(date +"%x %r %Z") +echo "Time: $NOW" + +if [ $# -lt 4 ]; then + echo "Please provide the solution name as well as the base S3 bucket name and the region to run build script." + echo "For example: chmod a+x build.sh && ./build.sh S3_BUCKET_NAME STACK_NAME REGION STUDIO_ROLE_NAME" + echo "STUDIO_ROLE_NAME is just the name not ARN from studio console example: AmazonSageMaker-ExecutionRole-20210112T085906" + exit 1 +fi + +PREFIX="mlops" # should match the ProjectPrefix parameter in pipeline.yml and studio.yml additional ARN privileges +BUCKET="$PREFIX-$1" +STACK_NAME="$PREFIX-$2" +REGION=$3 +ROLE=$4 + +aws cloudformation delete-stack --stack-name "$STACK_NAME" + +rm -rf build +mkdir build +rsync -av --progress . build \ + --exclude build \ + --exclude "*.git*" \ + --exclude .pre-commit-config.yaml +cd build +# binding resources of pipeline.yml and studio.yml together with common PREFIX +sed -i -e "s/PROJECT_PREFIX/$PREFIX/g" assets/*.yml pipeline.yml +sed -i -e "s/S3_BUCKET_NAME/$BUCKET/g" pipeline.yml +find . -type f -iname "*.yml-e" -delete + +bash scripts/lint.sh || exit 1 + +rm -rf scripts # used in development only + +zip -r project.zip . + +aws s3 mb "s3://$BUCKET" --region "$REGION" +aws s3 cp --region "$REGION" project.zip "s3://$BUCKET/" +aws s3 cp --region "$REGION" pipeline.yml "s3://$BUCKET/" +aws s3 cp --region "$REGION" studio.yml "s3://$BUCKET/" + +aws cloudformation wait stack-delete-complete --stack-name "$STACK_NAME" + +aws cloudformation create-stack --stack-name "$STACK_NAME" \ + --template-url "https://$BUCKET.s3.$REGION.amazonaws.com/studio.yml" \ + --capabilities CAPABILITY_IAM \ + --parameters ParameterKey=ProjectPrefix,ParameterValue="$PREFIX" \ + ParameterKey=SageMakerStudioRoleName,ParameterValue="$ROLE" \ + ParameterKey=PipelineBucket,ParameterValue="$BUCKET" diff --git a/scripts/lint.sh b/scripts/lint.sh new file mode 100755 index 0000000..93bba76 --- /dev/null +++ b/scripts/lint.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +BASE_DIR="$(pwd)" + +python -m pip install black==21.5b1 black-nb==0.5.0 -q +black . +black-nb --exclude "/(outputs|\.ipynb_checkpoints)/" --include "$BASE_DIR"/notebook/mlops.ipynb # workflow.ipynb fails + +for nb in "$BASE_DIR"/notebook/*.ipynb; do + python "$BASE_DIR"/scripts/set_kernelspec.py --notebook "$nb" --display-name "conda_python3" --kernel "conda_python3" +done diff --git a/scripts/set_kernelspec.py b/scripts/set_kernelspec.py new file mode 100644 index 0000000..00a11ee --- /dev/null +++ b/scripts/set_kernelspec.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python3 + +import argparse +import json + + +def set_kernel_spec(notebook_filepath, display_name, kernel_name): + with open(notebook_filepath, "r") as openfile: + notebook = json.load(openfile) + kernel_spec = {"display_name": display_name, "language": "python", "name": kernel_name} + if "metadata" not in notebook: + notebook["metadata"] = {} + notebook["metadata"]["kernelspec"] = kernel_spec + with open(notebook_filepath, "w") as openfile: + json.dump(notebook, openfile) + + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("--notebook") + parser.add_argument("--display-name") + parser.add_argument("--kernel") + args = parser.parse_args() + set_kernel_spec(args.notebook, args.display_name, args.kernel) diff --git a/studio.yml b/studio.yml new file mode 100644 index 0000000..e2777dd --- /dev/null +++ b/studio.yml @@ -0,0 +1,208 @@ +AWSTemplateFormatVersion: "2010-09-09" +Parameters: + ProjectPrefix: + Type: String + Description: | + Unique prefix to make resource privileges scoped-limited. + Changing the default must be done with care + Default: mlops + SageMakerStudioRoleName: + Type: String + Description: Name of the role used by SageMaker Studio + MinLength: 1 + AllowedPattern: ^[a-zA-Z](-*[a-zA-Z0-9])* + PortfolioName: + Type: String + Default: SageMaker Safe Deployment Pipeline Templates + TemplateName: + Type: String + Default: SageMaker Safe Deployment Pipeline + PipelineBucket: + Type: String + Default: S3 bucket to store the pipeline cloudformation template + +Resources: + SageMakerStudioOrganizationProjectsPortfolio: + Type: AWS::ServiceCatalog::Portfolio + Properties: + Description: "Creates a new portfolio with a template for SageMakerProjects" + DisplayName: !Ref PortfolioName + ProviderName: "SageMaker Safe Deployment Pipeline Templates" + + SageMakerSafeDeploymentProduct: + Type: AWS::ServiceCatalog::CloudFormationProduct + Properties: + Description: Deploys the template for creating a new SageMaker setup + Name: !Ref TemplateName + Owner: MLOps + ProvisioningArtifactParameters: + - Description: "SageMaker Safe Deployment Pipeline Project Templates" + DisableTemplateValidation: false + Info: + LoadTemplateFromURL: !Sub "https://${PipelineBucket}.s3.${AWS::Region}.amazonaws.com/pipeline.yml" + Tags: + - Key: sagemaker:studio-visibility + Value: "true" + + LaunchRoleConstraint: + Type: AWS::ServiceCatalog::LaunchRoleConstraint + Properties: + Description: "This is a launch constraint restriction for the SageMaker Launch Role" + PortfolioId: !Ref SageMakerStudioOrganizationProjectsPortfolio + ProductId: !Ref SageMakerSafeDeploymentProduct + RoleArn: !Sub "arn:aws:iam::${AWS::AccountId}:role/service-role/AmazonSageMakerServiceCatalogProductsLaunchRole" + DependsOn: + - ProductAssociation + - AdditionalPrivilegesForStudio + + PrincipalAssociation: + Type: AWS::ServiceCatalog::PortfolioPrincipalAssociation + Properties: + PortfolioId: !Ref SageMakerStudioOrganizationProjectsPortfolio + PrincipalType: IAM + PrincipalARN: !Sub arn:aws:iam::${AWS::AccountId}:role/${SageMakerStudioRoleName} + + ProductAssociation: + Type: AWS::ServiceCatalog::PortfolioProductAssociation + Properties: + PortfolioId: !Ref SageMakerStudioOrganizationProjectsPortfolio + ProductId: !Ref SageMakerSafeDeploymentProduct + + AdditionalPrivilegesForStudio: + Type: AWS::IAM::Policy + Properties: + PolicyName: SageMakerSafeDeploymentAdditional + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Action: + - "cloudtrail:*" + Resource: + - "*" + - Effect: Allow + Action: + - "cloudformation:DescribeStacks" + - "cloudformation:DescribeStackEvents" + - "cloudformation:DeleteStack" + Resource: + - !Sub "arn:aws:cloudformation:${AWS::Region}:${AWS::AccountId}:stack/${ProjectPrefix}-*" + - Effect: Allow + Action: + - "codecommit:CreateRepository" + - "codecommit:GetRepository" + - "codecommit:GetBranch" + - "codecommit:DeleteRepository" + - "codecommit:TagResource" + - "codecommit:CreateCommit" + Resource: + - !Sub "arn:aws:codecommit:${AWS::Region}:${AWS::AccountId}:amazon-sagemaker-safe-deployment-pipeline*" + - Effect: Allow + Action: + - "codebuild:CreateProject" + - "codebuild:DeleteProject" + Resource: + - !Sub "arn:aws:codebuild:${AWS::Region}:${AWS::AccountId}:project/${ProjectPrefix}-*" + - Effect: Allow + Action: + - "codepipeline:CreatePipeline" + - "codepipeline:DeletePipeline" + - "codepipeline:GetPipeline" + - "codepipeline:GetPipelineState" + - "codepipeline:TagResource" + - "codepipeline:StartPipelineExecution" + Resource: + - !Sub "arn:aws:codepipeline:${AWS::Region}:${AWS::AccountId}:${ProjectPrefix}-*" + - Effect: Allow + Action: + - "codepipeline:PutApprovalResult" + Resource: + - !Sub "arn:aws:codepipeline:${AWS::Region}:${AWS::AccountId}:${ProjectPrefix}-*/DeployDev/ApproveDeploy" + - Effect: Allow + Action: + - "kms:*" + Resource: + - "*" + - Effect: Allow + Action: + - "iam:GetRole" + - "iam:PassRole" + - "iam:CreateRole" + - "iam:DeleteRole" + - "iam:GetRolePolicy" + - "iam:PutRolePolicy" + - "iam:AttachRolePolicy" + - "iam:DetachRolePolicy" + - "iam:DeleteRolePolicy" + - "iam:ListRoleTags" + - "iam:TagRole" + Resource: + - !Sub "arn:aws:iam::${AWS::AccountId}:role/${ProjectPrefix}-*" + - Effect: Allow + Action: + - "sns:GetTopicAttributes" + - "sns:SetTopicAttributes" + - "sns:CreateTopic" + - "sns:DeleteTopic" + - "sns:TagResource" + - "sns:UntagResource" + - "sns:Subscribe" + - "sns:Unsubscribe" + Resource: + !Sub "arn:aws:sns:${AWS::Region}:${AWS::AccountId}:${ProjectPrefix}-*" + - Effect: Allow + Action: + - "s3:*" + Resource: + - !Sub "arn:aws:s3:::${ProjectPrefix}-*" + - Effect: Allow + Action: + - "events:PutRule" + - "events:DescribeRule" + - "events:PutTargets" + Resource: + - !Sub "arn:aws:events:${AWS::Region}:${AWS::AccountId}:rule/${ProjectPrefix}-*" + - !Sub "arn:aws:events:${AWS::Region}:${AWS::AccountId}:rule/SC-${AWS::AccountId}*" + - Effect: Allow + Action: + - "servicecatalog:GetProvisionedProductOutputs" + Resource: + - !Sub "arn:aws:servicecatalog:${AWS::Region}:${AWS::AccountId}:*" + - Effect: Allow + Action: + - "states:DescribeStateMachine" + - "states:ListExecutions" + - "states:GetExecutionHistory" + - "states:CreateStateMachine" + - "states:StartExecution" + - "states:DescribeExecution" + - "states:DeleteStateMachine" + Resource: + - !Sub "arn:aws:states:${AWS::Region}:${AWS::AccountId}:*:${ProjectPrefix}-*" + - Effect: Allow + Action: + - "cloudwatch:PutDashboard" + - "cloudwatch:GetDashboard" + - "cloudwatch:DeleteAlarms" + - "cloudwatch:DeleteDashboards" + Resource: + - !Sub "arn:aws:cloudwatch::${AWS::AccountId}:dashboard/${ProjectPrefix}-*" + - Effect: Allow + Action: + - "cloudwatch:PutMetricData" + - "cloudwatch:GetMetricStatistics" + Resource: + "*" + Condition: + StringEquals: + cloudwatch:namespace: "aws/sagemaker/Endpoints/data-metrics" + - Effect: Allow + Action: + - "lambda:CreateFunction" + - "lambda:InvokeFunction" + - "lambda:PublishLayerVersion" + Resource: + - !Sub "arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:*:${ProjectPrefix}-*" + Roles: + - !Ref SageMakerStudioRoleName + - AmazonSageMakerServiceCatalogProductsLaunchRole