├── .gitignore ├── 00-start-here.ipynb ├── 01-idea-development.ipynb ├── 02-sagemaker-containers.ipynb ├── 03-sagemaker-pipeline.ipynb ├── 04-sagemaker-project.ipynb ├── 05-deploy.ipynb ├── 06-monitoring.ipynb ├── 99-clean-up.ipynb ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── Makefile ├── README.md ├── additional-topics └── A-B-testing.ipynb ├── assignments ├── 00-assignment-setup.ipynb ├── 01-assignment-local-development.ipynb ├── 02-assignment-sagemaker-containers.ipynb ├── 03-assignment-sagemaker-pipeline.ipynb ├── 04-assignment-sagemaker-project.ipynb ├── 05-assignment-deploy.ipynb └── 06-assignment-monitoring.ipynb ├── cfn-templates ├── sagemaker-domain.yaml └── sagemaker-project-templates-roles.yaml ├── design ├── data-monitoring.drawio.svg ├── mlops-model-build-train.drawio.svg ├── mlops-model-deploy.drawio.svg ├── model-monitoring.drawio.svg └── workshop-flow.drawio.svg ├── img ├── MLOps-with-SageMaker-small.png ├── ab-testing.png ├── approve-deployment.png ├── aws-console-sagemaker.png ├── cfn-ack.png ├── cfn-stack.png ├── cicd-project-e2e.png ├── code-connection-arn.png ├── code-connection-tags.png ├── codebuild-buildspec-edit.png ├── codebuild-env-variables.png ├── comparing-runs.png ├── connection-permissions.png ├── container-anatomy.png ├── create-mlops-project-2.png ├── create-mlops-project-deploy.png ├── create-mlops-project.png ├── crete-connection.png ├── data-monitoring-architecture.png ├── data-processing.png ├── deploy-staging-review.png ├── deploystaging-config.png ├── enable-sagemaker-projects.png ├── endpoint-details-data-capture.png ├── endpoint-prod-creating.png ├── endpoint-staging-creating.png ├── experiment-mlflow-2.png ├── experiment-mlflow.png ├── experiments-studio.png ├── feature-store-studio-ui.png ├── github-connection.png ├── github-model-build.png ├── github-model-deploy.png ├── github-repo-qrcode.png ├── install-github-app.png ├── jupyterlab-app-image.png ├── jupyterlab-app.png ├── launch-studio-classic.png ├── launch-studio.png ├── mlflow-open.png ├── mlflow-pipeline-executions.png ├── mlops-model-build-train.png ├── mlops-model-deploy.png ├── mlops-project-name.png ├── model-fig-mlflow.png ├── model-monitor.png ├── model-monitoring-architecture.png ├── model-quality-monitor-execution.png ├── model-registry-version-approved.png ├── model-version-details-annotated.png ├── model-version-details.png ├── models-mlflow-2.png ├── models-mlflow.png ├── notebook-as-sm-job-parameters.png ├── notebook-as-sm-job-run.png ├── pipeline-execution-graph.png ├── pipeline-graph-with-transform.png ├── pipeline-graph.png ├── pipelines-list.png ├── pipelines-pane.png ├── project-endpoints.png ├── python-sdk-estimators.png ├── python-sdk-processors.png ├── sagemaker-mlops-building-blocks.png ├── sagemaker-processing.png ├── sagemaker-training-options.png ├── select-project.png ├── six-steps.png ├── space-run.png ├── studio-open-notebook.png ├── warm-pools-mlflow.png ├── warm-pools-training-jobs.png ├── workshop-flow.png └── workshop-qrcode.png ├── pipeline_steps ├── evaluate.py ├── extract.py ├── ingest.py ├── preprocess.py └── register.py ├── record_preprocessor.py ├── sagemaker-project-templates-roles.md └── utils └── monitoring_utils.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # IPython 81 | profile_default/ 82 | ipython_config.py 83 | 84 | # pyenv 85 | .python-version 86 | 87 | # pipenv 88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 91 | # install all needed dependencies. 92 | #Pipfile.lock 93 | 94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 95 | __pypackages__/ 96 | 97 | # Celery stuff 98 | celerybeat-schedule 99 | celerybeat.pid 100 | 101 | # SageMath parsed files 102 | *.sage.py 103 | 104 | # Environments 105 | .env 106 | .venv 107 | env/ 108 | venv/ 109 | ENV/ 110 | env.bak/ 111 | venv.bak/ 112 | 113 | # Spyder project settings 114 | .spyderproject 115 | .spyproject 116 | 117 | # Rope project settings 118 | .ropeproject 119 | 120 | # mkdocs documentation 121 | /site 122 | 123 | # mypy 124 | .mypy_cache/ 125 | .dmypy.json 126 | dmypy.json 127 | 128 | # Pyre type checker 129 | .pyre/ 130 | 131 | # Project-specific 132 | deploy 133 | 134 | # Build folder 135 | 136 | */build/* 137 | 138 | # SAM 139 | .aws-sam/* 140 | samconfig.* 141 | .DS_Store 142 | .environment 143 | .not-used-snippets 144 | 145 | .gp2/* 146 | *.pdf 147 | *snapshot.json 148 | .test* 149 | *.zip -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | ## Code of Conduct 2 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 3 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 4 | opensource-codeofconduct@amazon.com with any additional questions or comments. 5 | 6 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 7 | SPDX-License-Identifier: MIT-0 -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | Thank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional 4 | documentation, we greatly value feedback and contributions from our community. 5 | 6 | Please read through this document before submitting any issues or pull requests to ensure we have all the necessary 7 | information to effectively respond to your bug report or contribution. 8 | 9 | 10 | ## Reporting Bugs/Feature Requests 11 | 12 | We welcome you to use the GitHub issue tracker to report bugs or suggest features. 13 | 14 | When filing an issue, please check [existing open](https://github.com/aws-samples/amazon-sagemaker-from-idea-to-production/issues), or [recently closed](https://github.com/aws-samples/amazon-sagemaker-from-idea-to-production/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aclosed%20), issues to make sure somebody else hasn't already 15 | reported the issue. Please try to include as much information as you can. Details like these are incredibly useful: 16 | 17 | * A reproducible test case or series of steps 18 | * The version of our code being used 19 | * Any modifications you've made relevant to the bug 20 | * Anything unusual about your environment or deployment 21 | 22 | 23 | ## Contributing via Pull Requests 24 | Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that: 25 | 26 | 1. You are working against the latest source on the *master* branch. 27 | 2. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already. 28 | 3. You open an issue to discuss any significant work - we would hate for your time to be wasted. 29 | 30 | To send us a pull request, please: 31 | 32 | 1. Fork the repository. 33 | 2. Modify the source; please focus on the specific change you are contributing. If you also reformat all the code, it will be hard for us to focus on your change. 34 | 3. Ensure local tests pass. 35 | 4. Commit to your fork using clear commit messages. 36 | 5. Send us a pull request, answering any default questions in the pull request interface. 37 | 6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation. 38 | 39 | GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and 40 | [creating a pull request](https://help.github.com/articles/creating-a-pull-request/). 41 | 42 | 43 | ## Finding contributions to work on 44 | Looking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels (enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any ['help wanted'](https://github.com/aws-samples/amazon-sagemaker-from-idea-to-production/labels/help%20wanted) issues is a great place to start. 45 | 46 | 47 | ## Code of Conduct 48 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 49 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 50 | opensource-codeofconduct@amazon.com with any additional questions or comments. 51 | 52 | 53 | ## Security issue notifications 54 | If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public github issue. 55 | 56 | 57 | ## Licensing 58 | 59 | See the [LICENSE](./LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution. 60 | 61 | We may ask you to sign a [Contributor License Agreement (CLA)](http://en.wikipedia.org/wiki/Contributor_License_Agreement) for larger changes. 62 | 63 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 64 | SPDX-License-Identifier: MIT-0 -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | SPDX-License-Identifier: MIT-0 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this 5 | software and associated documentation files (the "Software"), to deal in the Software 6 | without restriction, including without limitation the rights to use, copy, modify, 7 | merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so. 9 | 10 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 11 | INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 12 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 13 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 14 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 15 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | deploy-domain: 2 | aws cloudformation deploy \ 3 | --template-file cfn-templates/sagemaker-domain.yaml \ 4 | --stack-name sm-domain-workshop \ 5 | --capabilities CAPABILITY_IAM CAPABILITY_NAMED_IAM \ 6 | --parameter-overrides \ 7 | DomainNamePrefix='sm-domain-projects-enabled' 8 | 9 | destroy-domain: 10 | aws cloudformation delete-stack \ 11 | --stack-name sm-domain-workshop && \ 12 | aws cloudformation wait stack-delete-complete \ 13 | --stack-name sm-domain-workshop 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Amazon SageMaker AI MLOps: from idea to production in six steps 2 | 3 | ![](./img/MLOps-with-SageMaker-small.png) 4 | 5 | This repository contains a sequence of Jupyter notebooks demonstrating how to move from an ML idea to production by using [Amazon SageMaker AI](https://aws.amazon.com/sagemaker-ai). 6 | 7 | The notebooks make use of SageMaker AI [processing](https://docs.aws.amazon.com/sagemaker/latest/dg/processing-job.html) and [training](https://docs.aws.amazon.com/sagemaker/latest/dg/train-model.html) jobs, and SageMaker AI MLOps features such as [SageMaker Pipelines](https://aws.amazon.com/sagemaker/pipelines/), [SageMaker Feature Store](https://aws.amazon.com/sagemaker/feature-store/), [SageMaker Model Registry](https://docs.aws.amazon.com/sagemaker/latest/dg/model-registry.html), [SageMaker managed MLflow experiments](https://docs.aws.amazon.com/sagemaker/latest/dg/mlflow.html), and [SageMaker Model Monitor](https://aws.amazon.com/sagemaker/model-monitor/). 8 | 9 | You start with a notebook with basic ML code for data preprocessing, feature engineering, and model training, all local to the notebook. Each subsequent notebook builds on top of the previous and introduces one or several SageMaker AI MLOps features: 10 | 11 | ![](img/sagemaker-mlops-building-blocks.png) 12 | 13 | Each notebook also provides links to useful hands-on resources and proposes real-world ideas for additional development. 14 | 15 | You follow along the six notebooks and develop your ML idea from an experimental notebook to a production-ready solution following the recommended MLOps practices: 16 | 17 | |Step|What|Notebook| 18 | |---|---|---| 19 | |1. |Experiment in a notebook |[01-idea-development](01-idea-development.ipynb)| 20 | |2. |Scale with SageMaker AI processing jobs and Python SDK |[02-sagemaker-containers](02-sagemaker-containers.ipynb)| 21 | |3. |Operationalize with ML pipeline, model registry, and feature store |[03-sagemaker-pipeline](03-sagemaker-pipeline.ipynb)| 22 | |4. |Add a model building CI/CD pipeline |[04-sagemaker-project](04-sagemaker-project.ipynb)| 23 | |5. |Add a model deployment pipeline |[05-deploy](05-deploy.ipynb)| 24 | |6. |Add model and data monitoring |[06-monitoring](06-monitoring.ipynb)| 25 | 26 | ## Additional topics 27 | There are also additional hands-on examples of other SageMaker AI features and ML topics, like [A/B testing](https://docs.aws.amazon.com/sagemaker/latest/dg/model-validation.html), custom [processing](https://docs.aws.amazon.com/sagemaker/latest/dg/build-your-own-processing-container.html), [training](https://docs.aws.amazon.com/sagemaker/latest/dg/your-algorithms-training-algo.html) and [inference](https://docs.aws.amazon.com/sagemaker/latest/dg/your-algorithms-inference-main.html) containers, [debugging and profiling](https://docs.aws.amazon.com/sagemaker/latest/dg/train-debugger.html), [security](https://docs.aws.amazon.com/sagemaker/latest/dg/security.html), [multi-model](https://docs.aws.amazon.com/sagemaker/latest/dg/multi-model-endpoints.html) and [multi-container](https://docs.aws.amazon.com/sagemaker/latest/dg/multi-container-endpoints.html) endpoints, and [serial inference pipelines](https://docs.aws.amazon.com/sagemaker/latest/dg/inference-pipelines.html). 28 | 29 | ## Getting started 30 | For the full version of the instructions and detailed setup of the account refer to the public AWS workshop [Amazon SageMaker MLOps: from idea to production in six steps](https://catalog.workshops.aws/mlops-from-idea-to-production). 31 | 32 | ### Prerequisites 33 | You need an **AWS account**. If you don't already have an account, follow the [Setting Up Your AWS Environment](https://aws.amazon.com/getting-started/guides/setup-environment/) getting started guide for a quick overview. 34 | 35 | ### AWS Instructor-led workshop 36 | If you participating in an AWS Immersion Day or a similar instructor-led event or workshop and would like to use a provided AWS account, please follow this [instructions](https://catalog.workshops.aws/mlops-from-idea-to-production/en-US/00-introduction/20-getting-started-workshop-studio) how to claim your temporary AWS account and how to start SageMaker AI Studio. 37 | 38 | ❗ Skip the following steps **Set up Amazon SageMaker AI domain** and **Deploy CloudFormation template** if you use an AWS-provisioned account. 39 | 40 | ### Set up Amazon SageMaker AI domain 41 | To run the notebooks you must use [SageMaker AI Studio](https://aws.amazon.com/sagemaker/studio/) which requires a [SageMaker AI domain](https://docs.aws.amazon.com/sagemaker/latest/dg/studio-entity-status.html). 42 | 43 | #### Existing SageMaker AI domain 44 | If you already have a SageMaker AI domain and would like to use it to run the workshop, follow the [SageMaker AI Studio setup guide](https://aws.amazon.com/getting-started/hands-on/machine-learning-tutorial-set-up-sagemaker-studio-account-permissions/) to attach the required AWS IAM policies to the IAM execution role used by your Studio user profile. For this workshop you must attach the following managed IAM policies to the IAM execution role of the user profile you use to run the workshop: 45 | - `AmazonSageMakerFullAccess` 46 | - `AWSCloudFormationFullAccess` 47 | - `AWSCodePipeline_FullAccess` 48 | - `AmazonSageMakerPipelinesIntegrations` 49 | - `AWSCodeStarFullAccess` 50 | 51 | You can also [create a new user profile](https://docs.aws.amazon.com/sagemaker/latest/dg/domain-user-profile-add-remove.html) with a dedicated IAM execution role to use for this workshop. 52 | 53 | #### Provision a new SageMaker AI domain 54 | If you don't have a SageMaker AI domain or would like to use a dedicated domain for the workshop, you must create a new domain. 55 | 56 | ❗ If you have more than one domain in your account, consider the limit of the active domains in a Region in an account. 57 | 58 | To create a new domain, you can follow the onboarding [instructions](https://docs.aws.amazon.com/sagemaker/latest/dg/onboard-quick-start.html) in the Developer Guide or use the provided AWS CloudFormation [template](https://github.com/aws-samples/amazon-sagemaker-from-idea-to-production/blob/master/cfn-templates/sagemaker-domain.yaml) that creates a SageMaker AI domain, a user profile, and adds the IAM roles required for executing the provided notebooks. 59 | 60 | ❗ If you create a new domain via AWS Console, make sure you attach the following policies to the IAM execution role of the user profile: 61 | - `AmazonSageMakerFullAccess` 62 | - `AWSCloudFormationFullAccess` 63 | - `AWSCodePipeline_FullAccess` 64 | - `AmazonSageMakerPipelinesIntegrations` 65 | - `AWSCodeStarFullAccess` 66 | 67 | ❗ If you use the provided CloudFormation template for domain creation, the template creates an IAM execution role with the following policies attached: 68 | - `AmazonSageMakerFullAccess` 69 | - `AmazonS3FullAccess` 70 | - `AWSCloudFormationFullAccess` 71 | - `AWSCodePipeline_FullAccess` 72 | - `AmazonSageMakerPipelinesIntegrations` 73 | - `AWSCodeStarFullAccess` 74 | 75 | Download the [`sagemaker-domain.yaml` CloudFormation template](https://github.com/aws-samples/amazon-sagemaker-from-idea-to-production/blob/master/cfn-templates/sagemaker-domain.yaml). 76 | 77 | This template creates a new SageMaker AI domain and a user profile named `studio-user-`. It also creates the required IAM execution role for the domain. 78 | 79 | ❗ This stack assumes that you already have a public VPC set up in your account. If you do not have a public VPC, see [VPC with a single public subnet](https://docs.aws.amazon.com/vpc/latest/userguide/VPC_Scenario1.html) to learn how to create a public VPC. 80 | 81 | ❗ The template supports only `us-east-1`, `us-west-2`, and `eu-central-1` Regions. Select one of those regions for deployment. 82 | 83 | Open [AWS CloudFormation console](https://us-east-1.console.aws.amazon.com/cloudformation/home?region=us-east-1#/stacks/create). The link opens the AWS CloudFormation console in your AWS account. Check the selected region and change it if needed. 84 | - Select **Upload a template file** and upload the downloaded CloudFormation template, click **Next** 85 | - Enter the stack name, for example `sagemaker-from-idea-to-prod`, click **Next** 86 | - Leave all defaults on this pane, click **Next** 87 | - Select **I acknowledge that AWS CloudFormation might create IAM resources**, click **Submit** 88 | 89 | ![](img/cfn-ack.png) 90 | 91 | On the **CloudFormation** pane, choose **Stacks**. It takes about 15 minutes for the stack to be created. When the stack is created, the status of the stack changes from `CREATE_IN_PROGRESS` to `CREATE_COMPLETE`. 92 | 93 | ![](img/cfn-stack.png) 94 | 95 | ### Start SageMaker AI Studio 96 | After signing into the AWS account, follow [Launch Amazon SageMaker AI Studio](https://docs.aws.amazon.com/sagemaker/latest/dg/studio-updated-launch.html#studio-updated-launch-console) instructions to open Studio. 97 | 98 | ### Open JupyterLab space 99 | You use a JupyterLab space as our IDE for this workshop. 100 | After launching the Studio: 101 | 102 | 1. To launch a JupyterLab space, select the `JupyterLab` app in the top left 103 | 104 | ![JupyterLab selector](img/jupyterlab-app.png) 105 | 106 | 2. Each application in SageMaker AI studio gets its own space. Spaces are used to manage the storage and resource needs of each application. If you're participating in an AWS-led workshop or used the provided CloudFormation template, the required space is already created for you, otherwise you must create a new JupyterLab space as described in the [the Developer Guide](ttps://docs.aws.amazon.com/sagemaker/latest/dg/studio-updated-jl-user-guide.html) or re-use an existing one 107 | 108 | 3. Run the space by selecting the run button on the right. This process can take a few seconds. 109 | 110 | ![JupyterLab selector](img/space-run.png) 111 | 112 | 4. Once the space is running select `Open` to navigate to the JupyterLab application. 113 | 114 | ### Start the workshop 115 | If you're participating in an AWS-led workshop or used the provided CloudFormation template, the workshop content is cloned on the space EBS volume automatically, no action required from you. If you use your own domain and user profile or created a domain via AWS Console UI, follow the instructions in the next section **Download notebooks into your JupyterLab space** to clone the content. 116 | 117 | The public GitHub repository [Amazon SageMaker MLOps: from idea to production in six steps](https://github.com/aws-samples/amazon-sagemaker-from-idea-to-production) contains all source code. 118 | 119 | #### Download notebooks into your JupyterLab space 120 | You only need to clone the notebooks into your space if you use your own domain and user profile. To do this select `Terminal` in the JupyterLab Launcher window or select **File** > **New** > **Terminal** to open up a terminal and run the `git clone`: 121 | 122 | ```sh 123 | git clone https://github.com/aws-samples/amazon-sagemaker-from-idea-to-production.git 124 | ``` 125 | 126 | This will clone the repository into the local JupyterLab file system. 127 | 128 | #### Open and execute a setup notebook 129 | As the final preparatory step, make sure to run and execute the `00-start-here.ipynb` notebook. To do this 130 | 131 | 1. In the file browser open the `amazon-sagemaker-from-idea-to-production` folder by double clicking it 132 | 2. Open `00-start-here.ipynb` notebook and follow the instructions in the notebook 133 | 134 | ![](img/studio-open-notebook.png) 135 | 136 | Note: we recommend you read and then execute each cell by using the `Shift + Enter`command. 137 | 138 | After executing the `00-start-here.ipynb` notebook, you can move to the first notebook [`01-idea-development`](01-idea-development.ipynb). 139 | 140 | ## How to use this workshop 141 | You can do this workshop in two ways: 142 | - Go through the provided notebooks, execute code cells sequentially, and follow the instructions and execution flow 143 | - Write your own code with hands-on assignments and exercises 144 | 145 | The following diagram shows the possible flows of the workshop: 146 | 147 | ![](design/workshop-flow.drawio.svg) 148 | 149 | ### Execution mode 150 | Use this mode if you're not familiar with Python programming and new to Jupyter notebooks. You follow each notebook `00-...`, `01-...`, ..., `06-...`and execute all code cells with `Shift` + `Enter`. The given instructions explain what code is doing and why. You need about two and half hours to run through all code cells in all notebooks. 151 | All notebooks and all code cells are idempotent. Make sure you run all code cells sequentially, top to bottom. 152 | 153 | ### Assignment mode 154 | Use this mode if you have experience working with Jupyter notebooks and would like to write own code to have a deeper hands-on understanding of SageMaker AI features and Python SDK. 155 | Each foundational instruction notebook `00-...`, `01-...`, ..., `06-...` in the workshop root folder has a corresponding "assignment" notebook with exercises in the `assignments` folder. First, go through the instructions in the root folder notebook and then complete the exercises in the corresponding assignment notebook. The notebooks are mapped as follows: 156 | - `00-start-here` > `./assignments/00-assignment-setup` 157 | - `01-idea-development` > `./assignments/01-assignment-local-development` 158 | - `02-sagemaker-containers` > `./assignments/02-assignment-sagemaker-containers` 159 | - `03-sagemaker-pipeline` > `./assignments/03-assignment-sagemaker-pipeline` 160 | - `04-sagemaker-projects` > `./assignments/04-assignment-sagemaker-project` 161 | - `05-deploy` > `./assignments/05-assignment-deploy` 162 | - `06-monitoring` > `./assignments/06-assignment-monitoring` 163 | 164 | ## Clean-up 165 | ❗ You don't need to perform a clean-up if you run an AWS-instructor led workshop. 166 | 167 | To avoid charges, you must remove all project-provisioned and generated resources from your AWS account. 168 | 169 | First, run all steps in the provided [clean-up notebook](99-clean-up.ipynb). 170 | Second, if you used the AWS Console to provision a domain for this workshop, and don't need the domain, you can delete the domain by following [this instructions](https://docs.aws.amazon.com/sagemaker/latest/dg/gs-studio-delete-domain.html). 171 | 172 | If you provisioned a domain use a CloudFormation template, you can delete the CloudFormation stack in the AWS console. 173 | 174 | If you provisioned a new VPC for the domain, go to the [VPC console](https://console.aws.amazon.com/vpc/home?#vpcs) and delete the provisioned VPC. 175 | 176 | ## Dataset 177 | This example uses the [direct marketing dataset](https://archive.ics.uci.edu/ml/datasets/bank+marketing) from UCI's ML Repository: 178 | > [Moro et al., 2014] S. Moro, P. Cortez and P. Rita. A Data-Driven Approach to Predict the Success of Bank Telemarketing. Decision Support Systems, Elsevier, 62:22-31, June 2014 179 | 180 | ## Resources 181 | The following list presents some useful hands-on resources to help you to get started with ML development on Amazon SageMaker AI. 182 | 183 | - [Get started with Amazon SageMaker](https://aws.amazon.com/sagemaker/getting-started/) 184 | - [Deep Learning MLOps workshop with Amazon SageMaker](https://catalog.us-east-1.prod.workshops.aws/workshops/47906c57-854e-4c73-abdb-6b49fe364370/en-US) 185 | - [Scale complete ML development with Amazon SageMaker Studio](https://catalog.us-east-1.prod.workshops.aws/workshops/ffc82198-8918-44c3-8b06-2c934f73fe50/en-US) 186 | - [Amazon SageMaker 101 workshop](https://catalog.us-east-1.prod.workshops.aws/workshops/0c6b8a23-b837-4e0f-b2e2-4a3ffd7d645b/en-US) 187 | - [Amazon SageMaker 101 workshop code repository](https://github.com/aws-samples/sagemaker-101-workshop) 188 | - [Amazon SageMaker Immersion Day](https://catalog.us-east-1.prod.workshops.aws/workshops/63069e26-921c-4ce1-9cc7-dd882ff62575/en-US) 189 | - [Amazon SageMaker End to End Workshop](https://github.com/aws-samples/sagemaker-end-to-end-workshop) 190 | - [Amazon SageMaker workshop with BYOM and BYOC examples](https://sagemaker-workshop.com/) 191 | - [End to end Machine Learning with Amazon SageMaker](https://github.com/aws-samples/amazon-sagemaker-build-train-deploy) 192 | - [SageMaker MLOps Workshop](https://catalog.us-east-1.prod.workshops.aws/workshops/1bb7ba03-e533-464f-8726-91a74513b1a1/en-US) 193 | - [Amazon SageMaker MLOps Workshop](https://catalog.us-east-1.prod.workshops.aws/workshops/7acdc7d8-0ac0-44de-bd9b-e3407147a59c/en-US) 194 | - [A curated list of awesome references for Amazon SageMaker](https://github.com/aws-samples/awesome-sagemaker) 195 | - [AWS Multi-Account Data & ML Governance Workshop](https://catalog.us-east-1.prod.workshops.aws/workshops/367f5c92-0764-4959-9279-e6f105f0c670/en-US) 196 | 197 | --- 198 | 199 | ## QR code for this repository 200 | Use the following QR code to link this repository. 201 | 202 | ![](img/github-repo-qrcode.png) 203 | 204 | [https://bit.ly/3KkhzYW](https://bit.ly/3KkhzYW) 205 | 206 | ## QR code for the workshop 207 | Use the following QR code to link the public AWS [workshop](https://catalog.workshops.aws/mlops-from-idea-to-production/en-US). 208 | 209 | ![](img/workshop-qrcode.png) 210 | 211 | [https://bit.ly/3zjk07S](https://bit.ly/3zjk07S) 212 | 213 | --- 214 | 215 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 216 | SPDX-License-Identifier: MIT-0 217 | -------------------------------------------------------------------------------- /additional-topics/A-B-testing.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "d713160e-39df-4d13-98ac-2c4f779b7d7b", 6 | "metadata": {}, 7 | "source": [ 8 | "# Add A/B testing of the models" 9 | ] 10 | }, 11 | { 12 | "cell_type": "code", 13 | "execution_count": null, 14 | "id": "6f1eb3c8-0911-491d-a7d3-db5dffcc32a1", 15 | "metadata": {}, 16 | "outputs": [], 17 | "source": [] 18 | }, 19 | { 20 | "cell_type": "markdown", 21 | "id": "c8fadcae-5bfe-47b3-91ee-6374eaa09512", 22 | "metadata": {}, 23 | "source": [ 24 | "## Prerequisites\n", 25 | "To run this notebook you must have:\n", 26 | "1. Complete the **Hyperparameter optimization** section from the [`02-sagemaker-containers`](../02-sagemaker-containers.ipynb) notebook\n", 27 | "\n", 28 | "Alternatively you can create a new model that you would like to A/B test against the model trained by the [`step 3`](../03-sagemaker-pipeline.ipynb) pipeline." 29 | ] 30 | }, 31 | { 32 | "cell_type": "code", 33 | "execution_count": null, 34 | "id": "0b5906db-2b5b-4980-9f6b-fdb8dcc552d1", 35 | "metadata": {}, 36 | "outputs": [], 37 | "source": [] 38 | }, 39 | { 40 | "cell_type": "code", 41 | "execution_count": null, 42 | "id": "dfbc3aae-964c-42d1-bf88-990bd7e87bd4", 43 | "metadata": {}, 44 | "outputs": [], 45 | "source": [] 46 | }, 47 | { 48 | "cell_type": "code", 49 | "execution_count": null, 50 | "id": "ccb91061-03f1-4d98-9609-95224f12de71", 51 | "metadata": {}, 52 | "outputs": [], 53 | "source": [] 54 | }, 55 | { 56 | "cell_type": "code", 57 | "execution_count": 3, 58 | "id": "2a29a30a-f515-432a-852d-1978b7a8513c", 59 | "metadata": { 60 | "tags": [] 61 | }, 62 | "outputs": [ 63 | { 64 | "name": "stdout", 65 | "output_type": "stream", 66 | "text": [ 67 | "Stored variables and their in-db values:\n", 68 | "baseline_s3_url -> 's3://sagemaker-us-east-1-906545278380/from-idea-t\n", 69 | "bucket_name -> 'sagemaker-us-east-1-906545278380'\n", 70 | "bucket_prefix -> 'from-idea-to-prod/xgboost'\n", 71 | "domain_id -> 'd-hrcfizeddzyj'\n", 72 | "evaluation_s3_url -> 's3://sagemaker-us-east-1-906545278380/from-idea-t\n", 73 | "experiment_name -> 'from-idea-to-prod-experiment-18-22-41-27'\n", 74 | "initialized -> True\n", 75 | "input_s3_url -> 's3://sagemaker-us-east-1-906545278380/from-idea-t\n", 76 | "model_package_group_name -> 'from-idea-to-prod-model-group'\n", 77 | "output_s3_url -> 's3://sagemaker-us-east-1-906545278380/from-idea-t\n", 78 | "prediction_baseline_s3_url -> 's3://sagemaker-us-east-1-906545278380/from-idea-t\n", 79 | "region -> 'us-east-1'\n", 80 | "sm_role -> 'arn:aws:iam::906545278380:role/service-role/Amazo\n", 81 | "target_col -> 'y'\n", 82 | "test_s3_url -> 's3://sagemaker-us-east-1-906545278380/from-idea-t\n", 83 | "train_s3_url -> 's3://sagemaker-us-east-1-906545278380/from-idea-t\n", 84 | "training_job_name -> 'from-idea-to-prod-training-2022-12-16-21-36-33-53\n", 85 | "validation_s3_url -> 's3://sagemaker-us-east-1-906545278380/from-idea-t\n" 86 | ] 87 | } 88 | ], 89 | "source": [ 90 | "%store -r \n", 91 | "\n", 92 | "%store\n", 93 | "\n", 94 | "try:\n", 95 | " initialized\n", 96 | "except NameError:\n", 97 | " print(\"+++++++++++++++++++++++++++++++++++++++++++++++++\")\n", 98 | " print(\"[ERROR] YOU HAVE TO RUN 00-start-here notebook \")\n", 99 | " print(\"+++++++++++++++++++++++++++++++++++++++++++++++++\")" 100 | ] 101 | }, 102 | { 103 | "cell_type": "code", 104 | "execution_count": null, 105 | "id": "4e684e72-21ba-4ded-b6c6-2eccedb8d008", 106 | "metadata": {}, 107 | "outputs": [], 108 | "source": [] 109 | }, 110 | { 111 | "cell_type": "markdown", 112 | "id": "a54dbde5-15a2-4cf1-b2a8-6874fe36d6da", 113 | "metadata": {}, 114 | "source": [ 115 | "## Further development ideas for your real-world projects" 116 | ] 117 | }, 118 | { 119 | "cell_type": "markdown", 120 | "id": "4b5b8d21-26cc-49a8-a4f3-51d911c734d3", 121 | "metadata": {}, 122 | "source": [ 123 | "## Additional resources\n", 124 | "- [Safely validate models in production](https://docs.aws.amazon.com/sagemaker/latest/dg/model-validation.html)\n", 125 | "- [A/B Testing with Amazon SageMaker](https://sagemaker-examples.readthedocs.io/en/latest/sagemaker_endpoints/a_b_testing/a_b_testing.html)\n", 126 | "- [A/B Testing ML models in production using Amazon SageMaker](https://aws.amazon.com/blogs/machine-learning/a-b-testing-ml-models-in-production-using-amazon-sagemaker/)" 127 | ] 128 | }, 129 | { 130 | "cell_type": "markdown", 131 | "id": "07855d7c-b8c5-4dcb-92dd-827826598bd4", 132 | "metadata": { 133 | "tags": [] 134 | }, 135 | "source": [ 136 | "# Shutdown kernel" 137 | ] 138 | }, 139 | { 140 | "cell_type": "code", 141 | "execution_count": null, 142 | "id": "839acc36-64ce-4a05-b15b-2c203e6184c1", 143 | "metadata": {}, 144 | "outputs": [], 145 | "source": [ 146 | "%%html\n", 147 | "\n", 148 | "

Shutting down your kernel for this notebook to release resources.

\n", 149 | "\n", 150 | " \n", 151 | "" 160 | ] 161 | } 162 | ], 163 | "metadata": { 164 | "instance_type": "ml.t3.medium", 165 | "kernelspec": { 166 | "display_name": "Python 3 (Data Science)", 167 | "language": "python", 168 | "name": "python3__SAGEMAKER_INTERNAL__arn:aws:sagemaker:us-east-1:081325390199:image/datascience-1.0" 169 | }, 170 | "language_info": { 171 | "codemirror_mode": { 172 | "name": "ipython", 173 | "version": 3 174 | }, 175 | "file_extension": ".py", 176 | "mimetype": "text/x-python", 177 | "name": "python", 178 | "nbconvert_exporter": "python", 179 | "pygments_lexer": "ipython3", 180 | "version": "3.7.10" 181 | } 182 | }, 183 | "nbformat": 4, 184 | "nbformat_minor": 5 185 | } 186 | -------------------------------------------------------------------------------- /assignments/00-assignment-setup.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "8443fc4d-a88a-4da6-bd55-761b478fcb30", 6 | "metadata": {}, 7 | "source": [ 8 | "# Assignment: setup\n", 9 | "This series of the notebooks takes you through assignments while you're following ML development process using Amazon SageMaker MLOps building blocks. \n", 10 | "\n", 11 | "The assignments are based on the provided notebooks and you can use the code in the notebooks to complete exercises.\n", 12 | "\n", 13 | "Refer to the notebook [`00-start-here.ipynb`](../00-start-here.ipynb) for code snippets and a general guidance for the exercises in this assignment." 14 | ] 15 | }, 16 | { 17 | "cell_type": "markdown", 18 | "id": "b82d3164-e32f-4479-afa9-edbc24f02bf6", 19 | "metadata": {}, 20 | "source": [ 21 | "## Import packages" 22 | ] 23 | }, 24 | { 25 | "cell_type": "code", 26 | "execution_count": null, 27 | "id": "941c4a49-6f46-4b7e-9b54-88358253994e", 28 | "metadata": {}, 29 | "outputs": [], 30 | "source": [ 31 | "import time\n", 32 | "import os\n", 33 | "import json\n", 34 | "import boto3\n", 35 | "import numpy as np \n", 36 | "import pandas as pd \n", 37 | "import sagemaker\n", 38 | "\n", 39 | "sagemaker.__version__" 40 | ] 41 | }, 42 | { 43 | "cell_type": "markdown", 44 | "id": "8cbac2a5-0505-4932-8a86-23db4ccfdf87", 45 | "metadata": {}, 46 | "source": [ 47 | "## Exercise 1: AWS and SageMaker environment\n", 48 | "- Instantiate a [sagemaker session](https://sagemaker.readthedocs.io/en/stable/api/utility/session.html)\n", 49 | "- Get the name of the default bucket to use in relevant Amazon SageMaker interactions\n", 50 | "- Get the SageMaker execution role\n", 51 | "- Get the AWS region\n", 52 | "- Instantiate a boto3 [sagemaker client](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/sagemaker.html)\n" 53 | ] 54 | }, 55 | { 56 | "cell_type": "code", 57 | "execution_count": null, 58 | "id": "a27e9a06-ec1c-4be3-ae14-21ea3a3b2129", 59 | "metadata": {}, 60 | "outputs": [], 61 | "source": [ 62 | "# Exercise 1 - write code here\n" 63 | ] 64 | }, 65 | { 66 | "cell_type": "markdown", 67 | "id": "5278c09d-ed09-47fc-aa1c-3d7838ac847d", 68 | "metadata": {}, 69 | "source": [ 70 | "## Exercise 2: Studio environment\n", 71 | "- Explore the notebook metadata file `/opt/ml/metadata/resource-metadata.json`\n", 72 | "- Get the SageMaker `domain_id`\n", 73 | "- Get the Studio user profile name\n", 74 | "- Get the notebook image name" 75 | ] 76 | }, 77 | { 78 | "cell_type": "code", 79 | "execution_count": null, 80 | "id": "862581ca-0bf7-4cd5-9e92-6e5302269820", 81 | "metadata": {}, 82 | "outputs": [], 83 | "source": [ 84 | "# Exercise 2 - write code here\n", 85 | "NOTEBOOK_METADATA_FILE = \"/opt/ml/metadata/resource-metadata.json\"\n" 86 | ] 87 | }, 88 | { 89 | "cell_type": "markdown", 90 | "id": "6cb23d06-5aa8-462e-a7f5-de3ee6c385ae", 91 | "metadata": {}, 92 | "source": [ 93 | "## Exercise 3: Data\n", 94 | "- Download a dataset. You can use your own dataset and download it from your local storage or from internet\n", 95 | "- Load data into a Pandas dataframe and view the data" 96 | ] 97 | }, 98 | { 99 | "cell_type": "code", 100 | "execution_count": null, 101 | "id": "bc5863cd-9d79-43df-ab64-ee39cc3e3fed", 102 | "metadata": {}, 103 | "outputs": [], 104 | "source": [ 105 | "!wget -P data/ -N https://archive.ics.uci.edu/ml/machine-learning-databases/00222/bank-additional.zip" 106 | ] 107 | }, 108 | { 109 | "cell_type": "code", 110 | "execution_count": null, 111 | "id": "e9a9ee59-291a-46e2-8798-93a169b67332", 112 | "metadata": {}, 113 | "outputs": [], 114 | "source": [ 115 | "# Exercise 3 - write code here\n", 116 | "# df_data = pd.read_csv()" 117 | ] 118 | }, 119 | { 120 | "cell_type": "markdown", 121 | "id": "652c62f4-2913-455c-9a4d-479947339f28", 122 | "metadata": {}, 123 | "source": [ 124 | "## Continue with the assignment 1\n", 125 | "Navigate to the [assignment 1](01-assignment-local-development.ipynb) notebook." 126 | ] 127 | } 128 | ], 129 | "metadata": { 130 | "availableInstances": [ 131 | { 132 | "_defaultOrder": 0, 133 | "_isFastLaunch": true, 134 | "category": "General purpose", 135 | "gpuNum": 0, 136 | "hideHardwareSpecs": false, 137 | "memoryGiB": 4, 138 | "name": "ml.t3.medium", 139 | "vcpuNum": 2 140 | }, 141 | { 142 | "_defaultOrder": 1, 143 | "_isFastLaunch": false, 144 | "category": "General purpose", 145 | "gpuNum": 0, 146 | "hideHardwareSpecs": false, 147 | "memoryGiB": 8, 148 | "name": "ml.t3.large", 149 | "vcpuNum": 2 150 | }, 151 | { 152 | "_defaultOrder": 2, 153 | "_isFastLaunch": false, 154 | "category": "General purpose", 155 | "gpuNum": 0, 156 | "hideHardwareSpecs": false, 157 | "memoryGiB": 16, 158 | "name": "ml.t3.xlarge", 159 | "vcpuNum": 4 160 | }, 161 | { 162 | "_defaultOrder": 3, 163 | "_isFastLaunch": false, 164 | "category": "General purpose", 165 | "gpuNum": 0, 166 | "hideHardwareSpecs": false, 167 | "memoryGiB": 32, 168 | "name": "ml.t3.2xlarge", 169 | "vcpuNum": 8 170 | }, 171 | { 172 | "_defaultOrder": 4, 173 | "_isFastLaunch": true, 174 | "category": "General purpose", 175 | "gpuNum": 0, 176 | "hideHardwareSpecs": false, 177 | "memoryGiB": 8, 178 | "name": "ml.m5.large", 179 | "vcpuNum": 2 180 | }, 181 | { 182 | "_defaultOrder": 5, 183 | "_isFastLaunch": false, 184 | "category": "General purpose", 185 | "gpuNum": 0, 186 | "hideHardwareSpecs": false, 187 | "memoryGiB": 16, 188 | "name": "ml.m5.xlarge", 189 | "vcpuNum": 4 190 | }, 191 | { 192 | "_defaultOrder": 6, 193 | "_isFastLaunch": false, 194 | "category": "General purpose", 195 | "gpuNum": 0, 196 | "hideHardwareSpecs": false, 197 | "memoryGiB": 32, 198 | "name": "ml.m5.2xlarge", 199 | "vcpuNum": 8 200 | }, 201 | { 202 | "_defaultOrder": 7, 203 | "_isFastLaunch": false, 204 | "category": "General purpose", 205 | "gpuNum": 0, 206 | "hideHardwareSpecs": false, 207 | "memoryGiB": 64, 208 | "name": "ml.m5.4xlarge", 209 | "vcpuNum": 16 210 | }, 211 | { 212 | "_defaultOrder": 8, 213 | "_isFastLaunch": false, 214 | "category": "General purpose", 215 | "gpuNum": 0, 216 | "hideHardwareSpecs": false, 217 | "memoryGiB": 128, 218 | "name": "ml.m5.8xlarge", 219 | "vcpuNum": 32 220 | }, 221 | { 222 | "_defaultOrder": 9, 223 | "_isFastLaunch": false, 224 | "category": "General purpose", 225 | "gpuNum": 0, 226 | "hideHardwareSpecs": false, 227 | "memoryGiB": 192, 228 | "name": "ml.m5.12xlarge", 229 | "vcpuNum": 48 230 | }, 231 | { 232 | "_defaultOrder": 10, 233 | "_isFastLaunch": false, 234 | "category": "General purpose", 235 | "gpuNum": 0, 236 | "hideHardwareSpecs": false, 237 | "memoryGiB": 256, 238 | "name": "ml.m5.16xlarge", 239 | "vcpuNum": 64 240 | }, 241 | { 242 | "_defaultOrder": 11, 243 | "_isFastLaunch": false, 244 | "category": "General purpose", 245 | "gpuNum": 0, 246 | "hideHardwareSpecs": false, 247 | "memoryGiB": 384, 248 | "name": "ml.m5.24xlarge", 249 | "vcpuNum": 96 250 | }, 251 | { 252 | "_defaultOrder": 12, 253 | "_isFastLaunch": false, 254 | "category": "General purpose", 255 | "gpuNum": 0, 256 | "hideHardwareSpecs": false, 257 | "memoryGiB": 8, 258 | "name": "ml.m5d.large", 259 | "vcpuNum": 2 260 | }, 261 | { 262 | "_defaultOrder": 13, 263 | "_isFastLaunch": false, 264 | "category": "General purpose", 265 | "gpuNum": 0, 266 | "hideHardwareSpecs": false, 267 | "memoryGiB": 16, 268 | "name": "ml.m5d.xlarge", 269 | "vcpuNum": 4 270 | }, 271 | { 272 | "_defaultOrder": 14, 273 | "_isFastLaunch": false, 274 | "category": "General purpose", 275 | "gpuNum": 0, 276 | "hideHardwareSpecs": false, 277 | "memoryGiB": 32, 278 | "name": "ml.m5d.2xlarge", 279 | "vcpuNum": 8 280 | }, 281 | { 282 | "_defaultOrder": 15, 283 | "_isFastLaunch": false, 284 | "category": "General purpose", 285 | "gpuNum": 0, 286 | "hideHardwareSpecs": false, 287 | "memoryGiB": 64, 288 | "name": "ml.m5d.4xlarge", 289 | "vcpuNum": 16 290 | }, 291 | { 292 | "_defaultOrder": 16, 293 | "_isFastLaunch": false, 294 | "category": "General purpose", 295 | "gpuNum": 0, 296 | "hideHardwareSpecs": false, 297 | "memoryGiB": 128, 298 | "name": "ml.m5d.8xlarge", 299 | "vcpuNum": 32 300 | }, 301 | { 302 | "_defaultOrder": 17, 303 | "_isFastLaunch": false, 304 | "category": "General purpose", 305 | "gpuNum": 0, 306 | "hideHardwareSpecs": false, 307 | "memoryGiB": 192, 308 | "name": "ml.m5d.12xlarge", 309 | "vcpuNum": 48 310 | }, 311 | { 312 | "_defaultOrder": 18, 313 | "_isFastLaunch": false, 314 | "category": "General purpose", 315 | "gpuNum": 0, 316 | "hideHardwareSpecs": false, 317 | "memoryGiB": 256, 318 | "name": "ml.m5d.16xlarge", 319 | "vcpuNum": 64 320 | }, 321 | { 322 | "_defaultOrder": 19, 323 | "_isFastLaunch": false, 324 | "category": "General purpose", 325 | "gpuNum": 0, 326 | "hideHardwareSpecs": false, 327 | "memoryGiB": 384, 328 | "name": "ml.m5d.24xlarge", 329 | "vcpuNum": 96 330 | }, 331 | { 332 | "_defaultOrder": 20, 333 | "_isFastLaunch": false, 334 | "category": "General purpose", 335 | "gpuNum": 0, 336 | "hideHardwareSpecs": true, 337 | "memoryGiB": 0, 338 | "name": "ml.geospatial.interactive", 339 | "supportedImageNames": [ 340 | "sagemaker-geospatial-v1-0" 341 | ], 342 | "vcpuNum": 0 343 | }, 344 | { 345 | "_defaultOrder": 21, 346 | "_isFastLaunch": true, 347 | "category": "Compute optimized", 348 | "gpuNum": 0, 349 | "hideHardwareSpecs": false, 350 | "memoryGiB": 4, 351 | "name": "ml.c5.large", 352 | "vcpuNum": 2 353 | }, 354 | { 355 | "_defaultOrder": 22, 356 | "_isFastLaunch": false, 357 | "category": "Compute optimized", 358 | "gpuNum": 0, 359 | "hideHardwareSpecs": false, 360 | "memoryGiB": 8, 361 | "name": "ml.c5.xlarge", 362 | "vcpuNum": 4 363 | }, 364 | { 365 | "_defaultOrder": 23, 366 | "_isFastLaunch": false, 367 | "category": "Compute optimized", 368 | "gpuNum": 0, 369 | "hideHardwareSpecs": false, 370 | "memoryGiB": 16, 371 | "name": "ml.c5.2xlarge", 372 | "vcpuNum": 8 373 | }, 374 | { 375 | "_defaultOrder": 24, 376 | "_isFastLaunch": false, 377 | "category": "Compute optimized", 378 | "gpuNum": 0, 379 | "hideHardwareSpecs": false, 380 | "memoryGiB": 32, 381 | "name": "ml.c5.4xlarge", 382 | "vcpuNum": 16 383 | }, 384 | { 385 | "_defaultOrder": 25, 386 | "_isFastLaunch": false, 387 | "category": "Compute optimized", 388 | "gpuNum": 0, 389 | "hideHardwareSpecs": false, 390 | "memoryGiB": 72, 391 | "name": "ml.c5.9xlarge", 392 | "vcpuNum": 36 393 | }, 394 | { 395 | "_defaultOrder": 26, 396 | "_isFastLaunch": false, 397 | "category": "Compute optimized", 398 | "gpuNum": 0, 399 | "hideHardwareSpecs": false, 400 | "memoryGiB": 96, 401 | "name": "ml.c5.12xlarge", 402 | "vcpuNum": 48 403 | }, 404 | { 405 | "_defaultOrder": 27, 406 | "_isFastLaunch": false, 407 | "category": "Compute optimized", 408 | "gpuNum": 0, 409 | "hideHardwareSpecs": false, 410 | "memoryGiB": 144, 411 | "name": "ml.c5.18xlarge", 412 | "vcpuNum": 72 413 | }, 414 | { 415 | "_defaultOrder": 28, 416 | "_isFastLaunch": false, 417 | "category": "Compute optimized", 418 | "gpuNum": 0, 419 | "hideHardwareSpecs": false, 420 | "memoryGiB": 192, 421 | "name": "ml.c5.24xlarge", 422 | "vcpuNum": 96 423 | }, 424 | { 425 | "_defaultOrder": 29, 426 | "_isFastLaunch": true, 427 | "category": "Accelerated computing", 428 | "gpuNum": 1, 429 | "hideHardwareSpecs": false, 430 | "memoryGiB": 16, 431 | "name": "ml.g4dn.xlarge", 432 | "vcpuNum": 4 433 | }, 434 | { 435 | "_defaultOrder": 30, 436 | "_isFastLaunch": false, 437 | "category": "Accelerated computing", 438 | "gpuNum": 1, 439 | "hideHardwareSpecs": false, 440 | "memoryGiB": 32, 441 | "name": "ml.g4dn.2xlarge", 442 | "vcpuNum": 8 443 | }, 444 | { 445 | "_defaultOrder": 31, 446 | "_isFastLaunch": false, 447 | "category": "Accelerated computing", 448 | "gpuNum": 1, 449 | "hideHardwareSpecs": false, 450 | "memoryGiB": 64, 451 | "name": "ml.g4dn.4xlarge", 452 | "vcpuNum": 16 453 | }, 454 | { 455 | "_defaultOrder": 32, 456 | "_isFastLaunch": false, 457 | "category": "Accelerated computing", 458 | "gpuNum": 1, 459 | "hideHardwareSpecs": false, 460 | "memoryGiB": 128, 461 | "name": "ml.g4dn.8xlarge", 462 | "vcpuNum": 32 463 | }, 464 | { 465 | "_defaultOrder": 33, 466 | "_isFastLaunch": false, 467 | "category": "Accelerated computing", 468 | "gpuNum": 4, 469 | "hideHardwareSpecs": false, 470 | "memoryGiB": 192, 471 | "name": "ml.g4dn.12xlarge", 472 | "vcpuNum": 48 473 | }, 474 | { 475 | "_defaultOrder": 34, 476 | "_isFastLaunch": false, 477 | "category": "Accelerated computing", 478 | "gpuNum": 1, 479 | "hideHardwareSpecs": false, 480 | "memoryGiB": 256, 481 | "name": "ml.g4dn.16xlarge", 482 | "vcpuNum": 64 483 | }, 484 | { 485 | "_defaultOrder": 35, 486 | "_isFastLaunch": false, 487 | "category": "Accelerated computing", 488 | "gpuNum": 1, 489 | "hideHardwareSpecs": false, 490 | "memoryGiB": 61, 491 | "name": "ml.p3.2xlarge", 492 | "vcpuNum": 8 493 | }, 494 | { 495 | "_defaultOrder": 36, 496 | "_isFastLaunch": false, 497 | "category": "Accelerated computing", 498 | "gpuNum": 4, 499 | "hideHardwareSpecs": false, 500 | "memoryGiB": 244, 501 | "name": "ml.p3.8xlarge", 502 | "vcpuNum": 32 503 | }, 504 | { 505 | "_defaultOrder": 37, 506 | "_isFastLaunch": false, 507 | "category": "Accelerated computing", 508 | "gpuNum": 8, 509 | "hideHardwareSpecs": false, 510 | "memoryGiB": 488, 511 | "name": "ml.p3.16xlarge", 512 | "vcpuNum": 64 513 | }, 514 | { 515 | "_defaultOrder": 38, 516 | "_isFastLaunch": false, 517 | "category": "Accelerated computing", 518 | "gpuNum": 8, 519 | "hideHardwareSpecs": false, 520 | "memoryGiB": 768, 521 | "name": "ml.p3dn.24xlarge", 522 | "vcpuNum": 96 523 | }, 524 | { 525 | "_defaultOrder": 39, 526 | "_isFastLaunch": false, 527 | "category": "Memory Optimized", 528 | "gpuNum": 0, 529 | "hideHardwareSpecs": false, 530 | "memoryGiB": 16, 531 | "name": "ml.r5.large", 532 | "vcpuNum": 2 533 | }, 534 | { 535 | "_defaultOrder": 40, 536 | "_isFastLaunch": false, 537 | "category": "Memory Optimized", 538 | "gpuNum": 0, 539 | "hideHardwareSpecs": false, 540 | "memoryGiB": 32, 541 | "name": "ml.r5.xlarge", 542 | "vcpuNum": 4 543 | }, 544 | { 545 | "_defaultOrder": 41, 546 | "_isFastLaunch": false, 547 | "category": "Memory Optimized", 548 | "gpuNum": 0, 549 | "hideHardwareSpecs": false, 550 | "memoryGiB": 64, 551 | "name": "ml.r5.2xlarge", 552 | "vcpuNum": 8 553 | }, 554 | { 555 | "_defaultOrder": 42, 556 | "_isFastLaunch": false, 557 | "category": "Memory Optimized", 558 | "gpuNum": 0, 559 | "hideHardwareSpecs": false, 560 | "memoryGiB": 128, 561 | "name": "ml.r5.4xlarge", 562 | "vcpuNum": 16 563 | }, 564 | { 565 | "_defaultOrder": 43, 566 | "_isFastLaunch": false, 567 | "category": "Memory Optimized", 568 | "gpuNum": 0, 569 | "hideHardwareSpecs": false, 570 | "memoryGiB": 256, 571 | "name": "ml.r5.8xlarge", 572 | "vcpuNum": 32 573 | }, 574 | { 575 | "_defaultOrder": 44, 576 | "_isFastLaunch": false, 577 | "category": "Memory Optimized", 578 | "gpuNum": 0, 579 | "hideHardwareSpecs": false, 580 | "memoryGiB": 384, 581 | "name": "ml.r5.12xlarge", 582 | "vcpuNum": 48 583 | }, 584 | { 585 | "_defaultOrder": 45, 586 | "_isFastLaunch": false, 587 | "category": "Memory Optimized", 588 | "gpuNum": 0, 589 | "hideHardwareSpecs": false, 590 | "memoryGiB": 512, 591 | "name": "ml.r5.16xlarge", 592 | "vcpuNum": 64 593 | }, 594 | { 595 | "_defaultOrder": 46, 596 | "_isFastLaunch": false, 597 | "category": "Memory Optimized", 598 | "gpuNum": 0, 599 | "hideHardwareSpecs": false, 600 | "memoryGiB": 768, 601 | "name": "ml.r5.24xlarge", 602 | "vcpuNum": 96 603 | }, 604 | { 605 | "_defaultOrder": 47, 606 | "_isFastLaunch": false, 607 | "category": "Accelerated computing", 608 | "gpuNum": 1, 609 | "hideHardwareSpecs": false, 610 | "memoryGiB": 16, 611 | "name": "ml.g5.xlarge", 612 | "vcpuNum": 4 613 | }, 614 | { 615 | "_defaultOrder": 48, 616 | "_isFastLaunch": false, 617 | "category": "Accelerated computing", 618 | "gpuNum": 1, 619 | "hideHardwareSpecs": false, 620 | "memoryGiB": 32, 621 | "name": "ml.g5.2xlarge", 622 | "vcpuNum": 8 623 | }, 624 | { 625 | "_defaultOrder": 49, 626 | "_isFastLaunch": false, 627 | "category": "Accelerated computing", 628 | "gpuNum": 1, 629 | "hideHardwareSpecs": false, 630 | "memoryGiB": 64, 631 | "name": "ml.g5.4xlarge", 632 | "vcpuNum": 16 633 | }, 634 | { 635 | "_defaultOrder": 50, 636 | "_isFastLaunch": false, 637 | "category": "Accelerated computing", 638 | "gpuNum": 1, 639 | "hideHardwareSpecs": false, 640 | "memoryGiB": 128, 641 | "name": "ml.g5.8xlarge", 642 | "vcpuNum": 32 643 | }, 644 | { 645 | "_defaultOrder": 51, 646 | "_isFastLaunch": false, 647 | "category": "Accelerated computing", 648 | "gpuNum": 1, 649 | "hideHardwareSpecs": false, 650 | "memoryGiB": 256, 651 | "name": "ml.g5.16xlarge", 652 | "vcpuNum": 64 653 | }, 654 | { 655 | "_defaultOrder": 52, 656 | "_isFastLaunch": false, 657 | "category": "Accelerated computing", 658 | "gpuNum": 4, 659 | "hideHardwareSpecs": false, 660 | "memoryGiB": 192, 661 | "name": "ml.g5.12xlarge", 662 | "vcpuNum": 48 663 | }, 664 | { 665 | "_defaultOrder": 53, 666 | "_isFastLaunch": false, 667 | "category": "Accelerated computing", 668 | "gpuNum": 4, 669 | "hideHardwareSpecs": false, 670 | "memoryGiB": 384, 671 | "name": "ml.g5.24xlarge", 672 | "vcpuNum": 96 673 | }, 674 | { 675 | "_defaultOrder": 54, 676 | "_isFastLaunch": false, 677 | "category": "Accelerated computing", 678 | "gpuNum": 8, 679 | "hideHardwareSpecs": false, 680 | "memoryGiB": 768, 681 | "name": "ml.g5.48xlarge", 682 | "vcpuNum": 192 683 | }, 684 | { 685 | "_defaultOrder": 55, 686 | "_isFastLaunch": false, 687 | "category": "Accelerated computing", 688 | "gpuNum": 8, 689 | "hideHardwareSpecs": false, 690 | "memoryGiB": 1152, 691 | "name": "ml.p4d.24xlarge", 692 | "vcpuNum": 96 693 | }, 694 | { 695 | "_defaultOrder": 56, 696 | "_isFastLaunch": false, 697 | "category": "Accelerated computing", 698 | "gpuNum": 8, 699 | "hideHardwareSpecs": false, 700 | "memoryGiB": 1152, 701 | "name": "ml.p4de.24xlarge", 702 | "vcpuNum": 96 703 | }, 704 | { 705 | "_defaultOrder": 57, 706 | "_isFastLaunch": false, 707 | "category": "Accelerated computing", 708 | "gpuNum": 0, 709 | "hideHardwareSpecs": false, 710 | "memoryGiB": 32, 711 | "name": "ml.trn1.2xlarge", 712 | "vcpuNum": 8 713 | }, 714 | { 715 | "_defaultOrder": 58, 716 | "_isFastLaunch": false, 717 | "category": "Accelerated computing", 718 | "gpuNum": 0, 719 | "hideHardwareSpecs": false, 720 | "memoryGiB": 512, 721 | "name": "ml.trn1.32xlarge", 722 | "vcpuNum": 128 723 | }, 724 | { 725 | "_defaultOrder": 59, 726 | "_isFastLaunch": false, 727 | "category": "Accelerated computing", 728 | "gpuNum": 0, 729 | "hideHardwareSpecs": false, 730 | "memoryGiB": 512, 731 | "name": "ml.trn1n.32xlarge", 732 | "vcpuNum": 128 733 | } 734 | ], 735 | "instance_type": "ml.t3.medium", 736 | "kernelspec": { 737 | "display_name": "Python 3 (Data Science 3.0)", 738 | "language": "python", 739 | "name": "python3__SAGEMAKER_INTERNAL__arn:aws:sagemaker:us-east-1:081325390199:image/sagemaker-data-science-310-v1" 740 | }, 741 | "language_info": { 742 | "codemirror_mode": { 743 | "name": "ipython", 744 | "version": 3 745 | }, 746 | "file_extension": ".py", 747 | "mimetype": "text/x-python", 748 | "name": "python", 749 | "nbconvert_exporter": "python", 750 | "pygments_lexer": "ipython3", 751 | "version": "3.10.6" 752 | } 753 | }, 754 | "nbformat": 4, 755 | "nbformat_minor": 5 756 | } 757 | -------------------------------------------------------------------------------- /assignments/01-assignment-local-development.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "c803e4f2-0416-4471-b5ff-11073ef8ab55", 6 | "metadata": {}, 7 | "source": [ 8 | "# Assignment 1: local development in a notebook\n", 9 | "In this assignment you write code to process data, do feature engineering, train a model, and evaluate the model on the test dataset. You do all processing in the local notebook, trading scalability and reproducibility for the speed of deployment and fast interations to experiment with different feature engineering approaches and model types.\n", 10 | "\n", 11 | "Optionally you can run this notebook headlessly as a SageMaker on-demand or scheduled notebook job. \n", 12 | "\n", 13 | "Refer to the notebook [`01-idea-development.ipynb`](../01-idea-development.ipynb) for code snippets and a general guidance for the exercises in this assignment.\n", 14 | "\n", 15 | "Feel free to implement your own specific use case with your own dataset and a model." 16 | ] 17 | }, 18 | { 19 | "cell_type": "markdown", 20 | "id": "e9d935df-3b71-4918-af10-66a9efbafbc3", 21 | "metadata": {}, 22 | "source": [ 23 | "## Install and import packages\n", 24 | "You can use `%` commands and `pip install` to install any packages in the notebook kernel." 25 | ] 26 | }, 27 | { 28 | "cell_type": "code", 29 | "execution_count": null, 30 | "id": "0d789051-1d5e-44c0-a1e6-c1d4c9f1981a", 31 | "metadata": {}, 32 | "outputs": [], 33 | "source": [ 34 | "%pip install --upgrade pip\n", 35 | "%pip install -q xgboost sagemaker-experiments" 36 | ] 37 | }, 38 | { 39 | "cell_type": "code", 40 | "execution_count": null, 41 | "id": "9e35063a-4fa2-4424-a96d-e0726232188a", 42 | "metadata": {}, 43 | "outputs": [], 44 | "source": [ 45 | "import pandas as pd\n", 46 | "import numpy as np \n", 47 | "import json\n", 48 | "import joblib\n", 49 | "import xgboost as xgb\n", 50 | "import sagemaker\n", 51 | "import boto3\n", 52 | "import os\n", 53 | "from time import gmtime, strftime, sleep\n", 54 | "from sklearn.metrics import roc_auc_score\n", 55 | "from smexperiments.experiment import Experiment\n", 56 | "from smexperiments.trial import Trial\n", 57 | "from smexperiments.trial_component import TrialComponent\n", 58 | "from smexperiments.tracker import Tracker\n", 59 | "\n", 60 | "sagemaker.__version__" 61 | ] 62 | }, 63 | { 64 | "cell_type": "code", 65 | "execution_count": null, 66 | "id": "1727a718-a26d-47b2-9779-ffa786913234", 67 | "metadata": {}, 68 | "outputs": [], 69 | "source": [ 70 | "session = sagemaker.Session()\n", 71 | "sm = session.sagemaker_client" 72 | ] 73 | }, 74 | { 75 | "cell_type": "markdown", 76 | "id": "ab0f32c5-24a6-4478-9296-c3105d8bde8d", 77 | "metadata": { 78 | "tags": [] 79 | }, 80 | "source": [ 81 | "## Load data\n", 82 | "- Create variables to keep literal constants, like file names and paths\n", 83 | "- Load data from a local file to a Pandas dataframe\n", 84 | "- Explore the data" 85 | ] 86 | }, 87 | { 88 | "cell_type": "code", 89 | "execution_count": null, 90 | "id": "74dc043b-c289-4432-8d2a-f1e63c678066", 91 | "metadata": {}, 92 | "outputs": [], 93 | "source": [ 94 | "# Write data load code\n" 95 | ] 96 | }, 97 | { 98 | "cell_type": "markdown", 99 | "id": "359453ab-879e-47ee-840a-337c63d5744f", 100 | "metadata": {}, 101 | "source": [ 102 | "## [Optional] create an experiment\n", 103 | "Use [Amazon SageMaker Experiments Python SDK](https://sagemaker-experiments.readthedocs.io/en/latest/) to create and manage your experiments." 104 | ] 105 | }, 106 | { 107 | "cell_type": "code", 108 | "execution_count": null, 109 | "id": "39587aaf-b120-46ab-a70f-fc98c5119804", 110 | "metadata": {}, 111 | "outputs": [], 112 | "source": [ 113 | "# Wirte code to create an experiment" 114 | ] 115 | }, 116 | { 117 | "cell_type": "markdown", 118 | "id": "67e49a2a-6119-446f-a69c-eba9024f4a6e", 119 | "metadata": {}, 120 | "source": [ 121 | "## Exercise 1: EDA and feature engineering\n", 122 | "- Implement data processing\n", 123 | "- Implement EDA\n", 124 | "- Implement feature engineering" 125 | ] 126 | }, 127 | { 128 | "cell_type": "code", 129 | "execution_count": null, 130 | "id": "c6cce611-1195-4e32-bf10-5ff04bf0e402", 131 | "metadata": {}, 132 | "outputs": [], 133 | "source": [ 134 | "# Exercise 1 - write code here\n" 135 | ] 136 | }, 137 | { 138 | "cell_type": "markdown", 139 | "id": "7aa8469d-3081-40f6-ad1b-720204cdff81", 140 | "metadata": {}, 141 | "source": [ 142 | "## Exercise 2: Split data\n", 143 | "- Prepare data for training, split the dataset" 144 | ] 145 | }, 146 | { 147 | "cell_type": "code", 148 | "execution_count": null, 149 | "id": "a96d86c8-b351-4d20-81f4-2b9993dd9fa6", 150 | "metadata": {}, 151 | "outputs": [], 152 | "source": [ 153 | "# Exercise 2 - write code here\n", 154 | "# train_data, validation_data, test_data = np.split()" 155 | ] 156 | }, 157 | { 158 | "cell_type": "markdown", 159 | "id": "e334dec8-5c00-4d2d-a873-d0fa4d8d4722", 160 | "metadata": {}, 161 | "source": [ 162 | "## Exercise 3: Model training\n", 163 | "- Train the model\n", 164 | "- Optional: track your model training runs as trials and trials components" 165 | ] 166 | }, 167 | { 168 | "cell_type": "code", 169 | "execution_count": null, 170 | "id": "81b7858d-e868-43cd-ae09-3ca88ee3f48d", 171 | "metadata": {}, 172 | "outputs": [], 173 | "source": [ 174 | "# Exercise 3 - write code here\n" 175 | ] 176 | }, 177 | { 178 | "cell_type": "markdown", 179 | "id": "8985f391-6a02-403a-8cee-3c08dd9476a4", 180 | "metadata": {}, 181 | "source": [ 182 | "## Exercise 4: Validate model\n", 183 | "- Validate the model on the test dataset" 184 | ] 185 | }, 186 | { 187 | "cell_type": "code", 188 | "execution_count": null, 189 | "id": "0c607fb1-2dcf-4064-8fd8-4e435ef8a2bd", 190 | "metadata": {}, 191 | "outputs": [], 192 | "source": [ 193 | "# Exercise 4 - write code here\n", 194 | "\n", 195 | "# test_auc = roc_auc_score(test_label, test_pred)\n", 196 | "# train_auc = roc_auc_score(train_label, train_pred)\n", 197 | "# print(f\"Train-auc:{train_auc:.2f}, Test-auc:{test_auc:.2f}\")" 198 | ] 199 | }, 200 | { 201 | "cell_type": "markdown", 202 | "id": "ed640f3b-1fc9-4079-abd6-824250f50e58", 203 | "metadata": {}, 204 | "source": [ 205 | "## Exercise 5: [Optional] explore your experiment in Studio\n", 206 | "Refer to [View and Compare Amazon SageMaker Experiments, Trials, and Trial Components](https://docs.aws.amazon.com/sagemaker/latest/dg/experiments-view-compare.html) developer guide to understand how to work with experiments and trials." 207 | ] 208 | }, 209 | { 210 | "cell_type": "markdown", 211 | "id": "0958c08f-2b9b-452b-bdc1-ebb4b9d01f3c", 212 | "metadata": {}, 213 | "source": [ 214 | "## Exercise 6: [Optional] run the notebook as a SageMaker job\n", 215 | "Adapt your notebook code and follow the instructions in [Notebook-based Workflows](https://docs.aws.amazon.com/sagemaker/latest/dg/notebook-auto-run.html) to run this notebook on-demand headlessly a SageMaker job." 216 | ] 217 | }, 218 | { 219 | "cell_type": "markdown", 220 | "id": "3178a2a7-ccec-41b4-a186-77e0343713f8", 221 | "metadata": {}, 222 | "source": [ 223 | "## Continue with the assignment 2\n", 224 | "Navigate to the [assignment 2](02-assignment-sagemaker-containers.ipynb) notebook." 225 | ] 226 | } 227 | ], 228 | "metadata": { 229 | "instance_type": "ml.t3.medium", 230 | "kernelspec": { 231 | "display_name": "Python 3 (Data Science)", 232 | "language": "python", 233 | "name": "python3__SAGEMAKER_INTERNAL__arn:aws:sagemaker:us-east-1:081325390199:image/datascience-1.0" 234 | }, 235 | "language_info": { 236 | "codemirror_mode": { 237 | "name": "ipython", 238 | "version": 3 239 | }, 240 | "file_extension": ".py", 241 | "mimetype": "text/x-python", 242 | "name": "python", 243 | "nbconvert_exporter": "python", 244 | "pygments_lexer": "ipython3", 245 | "version": "3.7.10" 246 | } 247 | }, 248 | "nbformat": 4, 249 | "nbformat_minor": 5 250 | } 251 | -------------------------------------------------------------------------------- /assignments/03-assignment-sagemaker-pipeline.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "8fbc18ab-c1e2-42bd-826e-55e021f8ea6f", 6 | "metadata": {}, 7 | "source": [ 8 | "# Assignment 3: Create a SageMaker pipeline\n", 9 | "In this assignment you create an end-to-end ML workflow using [SageMaker Pipelines](https://aws.amazon.com/sagemaker/pipelines/).\n", 10 | "\n", 11 | "Refer to the notebook [`03-sagemaker-pipeline.ipynb`](../03-sagemaker-pipeline.ipynb) for code snippets and a general guidance for the exercises in this assignment." 12 | ] 13 | }, 14 | { 15 | "cell_type": "markdown", 16 | "id": "2dbe0d9b-7ee7-409d-9aea-df74b9f9ac96", 17 | "metadata": {}, 18 | "source": [ 19 | "## Import packages" 20 | ] 21 | }, 22 | { 23 | "cell_type": "code", 24 | "execution_count": null, 25 | "id": "7521ae34-e933-43ee-9375-02344bf1c94e", 26 | "metadata": {}, 27 | "outputs": [], 28 | "source": [ 29 | "import pandas as pd\n", 30 | "import json\n", 31 | "import boto3\n", 32 | "import pathlib\n", 33 | "import io\n", 34 | "import sagemaker\n", 35 | "from time import gmtime, strftime, sleep\n", 36 | "from sagemaker.deserializers import CSVDeserializer\n", 37 | "from sagemaker.serializers import CSVSerializer\n", 38 | "\n", 39 | "from sagemaker.workflow.pipeline_context import PipelineSession\n", 40 | "from sagemaker.xgboost.estimator import XGBoost\n", 41 | "from sagemaker.sklearn.processing import SKLearnProcessor\n", 42 | "from sagemaker.processing import (\n", 43 | " ProcessingInput, \n", 44 | " ProcessingOutput, \n", 45 | " ScriptProcessor\n", 46 | ")\n", 47 | "from sagemaker.inputs import TrainingInput\n", 48 | "\n", 49 | "from sagemaker.workflow.pipeline import Pipeline\n", 50 | "from sagemaker.workflow.steps import (\n", 51 | " ProcessingStep, \n", 52 | " TrainingStep, \n", 53 | " CreateModelStep\n", 54 | ")\n", 55 | "from sagemaker.workflow.check_job_config import CheckJobConfig\n", 56 | "from sagemaker.workflow.parameters import (\n", 57 | " ParameterInteger, \n", 58 | " ParameterFloat, \n", 59 | " ParameterString, \n", 60 | " ParameterBoolean\n", 61 | ")\n", 62 | "from sagemaker.workflow.clarify_check_step import (\n", 63 | " ModelBiasCheckConfig, \n", 64 | " ClarifyCheckStep, \n", 65 | " ModelExplainabilityCheckConfig\n", 66 | ")\n", 67 | "from sagemaker import Model\n", 68 | "from sagemaker.inputs import CreateModelInput\n", 69 | "from sagemaker.workflow.model_step import ModelStep\n", 70 | "from sagemaker.workflow.fail_step import FailStep\n", 71 | "from sagemaker.workflow.conditions import (\n", 72 | " ConditionGreaterThan,\n", 73 | " ConditionGreaterThanOrEqualTo\n", 74 | ")\n", 75 | "from sagemaker.workflow.pipeline_experiment_config import PipelineExperimentConfig\n", 76 | "from sagemaker.workflow.properties import PropertyFile\n", 77 | "from sagemaker.workflow.condition_step import ConditionStep\n", 78 | "from sagemaker.workflow.functions import (\n", 79 | " Join,\n", 80 | " JsonGet\n", 81 | ")\n", 82 | "from sagemaker.workflow.lambda_step import (\n", 83 | " LambdaStep,\n", 84 | " LambdaOutput,\n", 85 | " LambdaOutputTypeEnum,\n", 86 | ")\n", 87 | "from sagemaker.lambda_helper import Lambda\n", 88 | "\n", 89 | "from sagemaker.model_metrics import (\n", 90 | " MetricsSource, \n", 91 | " ModelMetrics, \n", 92 | " FileSource\n", 93 | ")\n", 94 | "from sagemaker.drift_check_baselines import DriftCheckBaselines\n", 95 | "\n", 96 | "from sagemaker.image_uris import retrieve\n", 97 | "\n", 98 | "sagemaker.__version__" 99 | ] 100 | }, 101 | { 102 | "cell_type": "markdown", 103 | "id": "fb7ca538-ef85-4e44-a72d-a9123875f7b9", 104 | "metadata": {}, 105 | "source": [ 106 | "## Set constants\n", 107 | "You need some fixed string literals to simplify coding. Create these literals here." 108 | ] 109 | }, 110 | { 111 | "cell_type": "code", 112 | "execution_count": null, 113 | "id": "15dd57c9-a5b4-4211-a849-6a5ee1daf639", 114 | "metadata": {}, 115 | "outputs": [], 116 | "source": [ 117 | "# Set names of pipeline objects\n", 118 | "project = \"from-idea-to-prod\"\n", 119 | "\n", 120 | "pipeline_name = f\"{project}-pipeline\"\n", 121 | "pipeline_model_name = f\"{project}-model-xgb\"\n", 122 | "model_package_group_name = f\"{project}-model-group\"\n", 123 | "endpoint_config_name = f\"{project}-endpoint-config\"\n", 124 | "endpoint_name = f\"{project}-endpoint\"\n", 125 | "\n", 126 | "# Set instance types and counts\n", 127 | "process_instance_type = \"ml.c5.xlarge\"\n", 128 | "train_instance_count = 1\n", 129 | "train_instance_type = \"ml.m5.xlarge\"\n", 130 | "\n", 131 | "# Set S3 urls for processed data\n", 132 | "# train_s3_url = \n", 133 | "# validation_s3_url = \n", 134 | "# test_s3_url = \n", 135 | "# baseline_s3_url = \n", 136 | "# evaluation_s3_url = " 137 | ] 138 | }, 139 | { 140 | "cell_type": "markdown", 141 | "id": "d983c1e8-9d03-47f7-8eb6-7c3e4d4b9dba", 142 | "metadata": {}, 143 | "source": [ 144 | "## Exercise 1: Create pipeline\n", 145 | "Follow the steps to create a SageMaker pipeline with your ML workflow:\n", 146 | "- Setup pipeline [parameters](https://sagemaker.readthedocs.io/en/stable/workflows/pipelines/sagemaker.workflow.pipelines.html#parameters)\n", 147 | "- Build the pipeline [steps](https://sagemaker.readthedocs.io/en/stable/workflows/pipelines/sagemaker.workflow.pipelines.html#steps)\n", 148 | "- Construct the [pipeline](https://sagemaker.readthedocs.io/en/stable/workflows/pipelines/sagemaker.workflow.pipelines.html#sagemaker.workflow.pipeline.Pipeline)\n", 149 | "- [Upsert](https://sagemaker.readthedocs.io/en/stable/workflows/pipelines/sagemaker.workflow.pipelines.html#sagemaker.workflow.pipeline.Pipeline.upsert) the pipeline\n", 150 | "\n", 151 | "Configure outputs and inputs for each pipeline step." 152 | ] 153 | }, 154 | { 155 | "cell_type": "code", 156 | "execution_count": null, 157 | "id": "647c0747-e819-480f-b5c9-700d051beb39", 158 | "metadata": {}, 159 | "outputs": [], 160 | "source": [ 161 | "# Setup pipeline parameters\n", 162 | "# Set S3 url for input dataset\n", 163 | "# input_s3_url_param = ParameterString()\n" 164 | ] 165 | }, 166 | { 167 | "cell_type": "code", 168 | "execution_count": null, 169 | "id": "6baac889-7589-4090-aa94-1d5f798ea6eb", 170 | "metadata": {}, 171 | "outputs": [], 172 | "source": [ 173 | "# Processing step\n", 174 | "# sklearn_processor = SKLearnProcessor()\n", 175 | "\n", 176 | "# processing_inputs=[]\n", 177 | "\n", 178 | "# processing_outputs=[]\n", 179 | "\n", 180 | "# processor_args = sklearn_processor.run()\n", 181 | "\n", 182 | "# step_process = ProcessingStep()" 183 | ] 184 | }, 185 | { 186 | "cell_type": "code", 187 | "execution_count": null, 188 | "id": "ac75f1f1-48b4-4048-88d1-c9d9bb96ab18", 189 | "metadata": {}, 190 | "outputs": [], 191 | "source": [ 192 | "# Training step\n", 193 | "# estimator = sagemaker.estimator.Estimator()\n", 194 | "\n", 195 | "# estimator.set_hyperparameters()\n", 196 | "\n", 197 | "# training_inputs = {}\n", 198 | "\n", 199 | "# training_args = estimator.fit(training_inputs)\n", 200 | "\n", 201 | "# step_train = TrainingStep()" 202 | ] 203 | }, 204 | { 205 | "cell_type": "markdown", 206 | "id": "4b646429-b3d2-48ab-9fb5-53fd17e2a0a4", 207 | "metadata": {}, 208 | "source": [ 209 | "Create an executable Python script for the evaluation step" 210 | ] 211 | }, 212 | { 213 | "cell_type": "code", 214 | "execution_count": null, 215 | "id": "8855a7cf-0316-4dab-b03d-c08adceda6d3", 216 | "metadata": {}, 217 | "outputs": [], 218 | "source": [ 219 | "%%writefile evaluation_assignment.py\n", 220 | "\n", 221 | "import json\n", 222 | "import pathlib\n", 223 | "import pickle as pkl\n", 224 | "import tarfile\n", 225 | "import joblib\n", 226 | "import numpy as np\n", 227 | "import pandas as pd\n", 228 | "import xgboost as xgb\n", 229 | "import datetime as dt\n", 230 | "from sklearn.metrics import roc_curve, auc\n", 231 | "\n", 232 | "if __name__ == \"__main__\": \n", 233 | " # All paths are local for the processing container\n", 234 | " \n", 235 | " # Read model tar file\n", 236 | "\n", 237 | " # Load model\n", 238 | " \n", 239 | " # Read test data\n", 240 | "\n", 241 | " # Run predictions\n", 242 | "\n", 243 | " # Evaluate predictions\n", 244 | "\n", 245 | " # Save evaluation report" 246 | ] 247 | }, 248 | { 249 | "cell_type": "markdown", 250 | "id": "1570e4a4-8665-4e1b-b867-527cc10749b2", 251 | "metadata": {}, 252 | "source": [ 253 | "Use this script to setup a [ScriptProcessor](https://sagemaker.readthedocs.io/en/stable/api/training/processing.html#sagemaker.processing.ScriptProcessor) object. Don't forget to pass the [PropertyFile](https://sagemaker.readthedocs.io/en/stable/workflows/pipelines/sagemaker.workflow.pipelines.html#sagemaker.workflow.properties.PropertyFile) where the evaluation script outputs the metrics to the [ProcessingStep](https://sagemaker.readthedocs.io/en/stable/workflows/pipelines/sagemaker.workflow.pipelines.html#sagemaker.workflow.steps.ProcessingStep) constructor." 254 | ] 255 | }, 256 | { 257 | "cell_type": "code", 258 | "execution_count": null, 259 | "id": "e819f50d-f825-4aeb-9758-c6ebe16d8a2f", 260 | "metadata": {}, 261 | "outputs": [], 262 | "source": [ 263 | "# Evaluation step\n", 264 | "# script_processor = ScriptProcessor()\n", 265 | "\n", 266 | "# eval_inputs=[]\n", 267 | "\n", 268 | "# eval_outputs=[]\n", 269 | "\n", 270 | "# eval_args = script_processor.run()\n", 271 | "\n", 272 | "# evaluation_report = PropertyFile()\n", 273 | "\n", 274 | "# step_eval = ProcessingStep()" 275 | ] 276 | }, 277 | { 278 | "cell_type": "markdown", 279 | "id": "f2ad2f70-36a1-4331-b3d2-ebef7bd403ca", 280 | "metadata": {}, 281 | "source": [ 282 | "Use a model artifact from the training step and a property file from the evaluation step to create a [Model](https://sagemaker.readthedocs.io/en/stable/api/inference/model.html#sagemaker.model.Model) and [ModelMetrics](https://sagemaker.readthedocs.io/en/stable/api/inference/model_monitor.html#sagemaker.model_metrics.ModelMetrics) objects. Use these objects to construct a [ModelStep](https://sagemaker.readthedocs.io/en/stable/workflows/pipelines/sagemaker.workflow.pipelines.html#sagemaker.workflow.model_step.ModelStep)." 283 | ] 284 | }, 285 | { 286 | "cell_type": "code", 287 | "execution_count": null, 288 | "id": "1ea5b2ad-b292-4d5b-8a85-59aa9e5c796c", 289 | "metadata": {}, 290 | "outputs": [], 291 | "source": [ 292 | "# Register step\n", 293 | "# model = Model()\n", 294 | "\n", 295 | "# model_metrics = ModelMetrics()\n", 296 | "\n", 297 | "# register_args = model.register()\n", 298 | "\n", 299 | "# step_register = ModelStep()" 300 | ] 301 | }, 302 | { 303 | "cell_type": "markdown", 304 | "id": "b12c70ba-9846-42ec-b4aa-e246138ca767", 305 | "metadata": {}, 306 | "source": [ 307 | "Add a [FailStep](https://sagemaker.readthedocs.io/en/stable/workflows/pipelines/sagemaker.workflow.pipelines.html#sagemaker.workflow.fail_step.FailStep) to stop the pipeline execution if the model performance metric doesn't meet the specified threshold. " 308 | ] 309 | }, 310 | { 311 | "cell_type": "code", 312 | "execution_count": null, 313 | "id": "4b150364-140e-4265-91dc-7ca8cdc0463b", 314 | "metadata": {}, 315 | "outputs": [], 316 | "source": [ 317 | "# Fail step\n", 318 | "# step_fail = FailStep()" 319 | ] 320 | }, 321 | { 322 | "cell_type": "markdown", 323 | "id": "9d934db9-067a-4964-a887-d72d4d9fc1fa", 324 | "metadata": {}, 325 | "source": [ 326 | "Use [Conditions](https://sagemaker.readthedocs.io/en/stable/workflows/pipelines/sagemaker.workflow.pipelines.html#conditions) and `JsonGet` to construct a condition and the condition step." 327 | ] 328 | }, 329 | { 330 | "cell_type": "code", 331 | "execution_count": null, 332 | "id": "4ee7c777-480f-4b39-baf9-dcc29c42d1ce", 333 | "metadata": {}, 334 | "outputs": [], 335 | "source": [ 336 | "# Condition step\n", 337 | "# cond_lte = ConditionGreaterThan()\n", 338 | "\n", 339 | "# step_cond = ConditionStep()" 340 | ] 341 | }, 342 | { 343 | "cell_type": "markdown", 344 | "id": "1775b8f4-fc5d-44e9-976e-0fff234af859", 345 | "metadata": {}, 346 | "source": [ 347 | "Use step array to create a [Pipeline](https://sagemaker.readthedocs.io/en/stable/workflows/pipelines/sagemaker.workflow.pipelines.html#sagemaker.workflow.pipeline.Pipeline) object." 348 | ] 349 | }, 350 | { 351 | "cell_type": "code", 352 | "execution_count": null, 353 | "id": "e5fb76fb-adfd-4ed4-9594-c05c946432e5", 354 | "metadata": {}, 355 | "outputs": [], 356 | "source": [ 357 | "# Create pipeline\n", 358 | "# pipeline = Pipeline()" 359 | ] 360 | }, 361 | { 362 | "cell_type": "code", 363 | "execution_count": null, 364 | "id": "f0f7e64a-b9c7-41c1-bccf-f544f94eab6f", 365 | "metadata": {}, 366 | "outputs": [], 367 | "source": [ 368 | "# Create a new or update existing Pipeline\n", 369 | "# pipeline.upsert(role_arn=sm_role)" 370 | ] 371 | }, 372 | { 373 | "cell_type": "code", 374 | "execution_count": null, 375 | "id": "24dacd7b-4b07-4232-a511-22beb800f399", 376 | "metadata": {}, 377 | "outputs": [], 378 | "source": [ 379 | "# Print the pipeline definition\n", 380 | "# pipeline_definition = json.loads(pipeline.describe()['PipelineDefinition'])\n", 381 | "# pipeline_definition" 382 | ] 383 | }, 384 | { 385 | "cell_type": "markdown", 386 | "id": "85d42219-1841-4ec5-a979-4128a4aa47a7", 387 | "metadata": {}, 388 | "source": [ 389 | "## Exercise 2: Execute the pipeline" 390 | ] 391 | }, 392 | { 393 | "cell_type": "code", 394 | "execution_count": null, 395 | "id": "6f31a8c4-051b-49a3-9e5e-3a9f1e840e59", 396 | "metadata": {}, 397 | "outputs": [], 398 | "source": [ 399 | "# Start an execution\n", 400 | "# execution = pipeline.start()" 401 | ] 402 | }, 403 | { 404 | "cell_type": "code", 405 | "execution_count": null, 406 | "id": "daad2121-d51d-4bbd-be48-5f87ca36e4a4", 407 | "metadata": {}, 408 | "outputs": [], 409 | "source": [ 410 | "# Un-comment this call if you want the notebook to wait until the pipeline's execution finished\n", 411 | "# Execution time of this pipeline is about 13 minutes\n", 412 | "# execution.wait()" 413 | ] 414 | }, 415 | { 416 | "cell_type": "code", 417 | "execution_count": null, 418 | "id": "e5d8440f-65c5-430a-a045-33cc53e3453e", 419 | "metadata": {}, 420 | "outputs": [], 421 | "source": [ 422 | "# List execution steps\n", 423 | "# execution.list_steps()" 424 | ] 425 | }, 426 | { 427 | "cell_type": "markdown", 428 | "id": "73032865-34d3-4723-bc62-32fb80d1b1e1", 429 | "metadata": {}, 430 | "source": [ 431 | "## Continue with the assignment 4\n", 432 | "Navigate to the [assignment 4](04-assignment-sagemaker-project.ipynb) notebook." 433 | ] 434 | }, 435 | { 436 | "cell_type": "code", 437 | "execution_count": null, 438 | "id": "85e35bab-f8ff-4def-92b5-ca20c84343b7", 439 | "metadata": {}, 440 | "outputs": [], 441 | "source": [] 442 | } 443 | ], 444 | "metadata": { 445 | "instance_type": "ml.t3.medium", 446 | "kernelspec": { 447 | "display_name": "Python 3 (Data Science)", 448 | "language": "python", 449 | "name": "python3__SAGEMAKER_INTERNAL__arn:aws:sagemaker:us-east-1:081325390199:image/datascience-1.0" 450 | }, 451 | "language_info": { 452 | "codemirror_mode": { 453 | "name": "ipython", 454 | "version": 3 455 | }, 456 | "file_extension": ".py", 457 | "mimetype": "text/x-python", 458 | "name": "python", 459 | "nbconvert_exporter": "python", 460 | "pygments_lexer": "ipython3", 461 | "version": "3.7.10" 462 | } 463 | }, 464 | "nbformat": 4, 465 | "nbformat_minor": 5 466 | } 467 | -------------------------------------------------------------------------------- /assignments/04-assignment-sagemaker-project.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "d08dc292-00f2-4264-a3d2-3ff9b42dc8cc", 6 | "metadata": {}, 7 | "source": [ 8 | "# Assignment 4: Create a SageMaker project\n", 9 | "In this assignment you create a CI/CD pipeline using [SageMaker Projects](https://docs.aws.amazon.com/sagemaker/latest/dg/sagemaker-projects.html). \n", 10 | "\n", 11 | "SageMaker Project are Cloud Formation-based templates which you can provision via Studio UX or SageMaker API into your environment. These templates are managed in Service Catalog. You can use the [provided project templates](https://docs.aws.amazon.com/sagemaker/latest/dg/sagemaker-projects-templates-sm.html) or create [custom ones](https://docs.aws.amazon.com/sagemaker/latest/dg/sagemaker-projects-templates-custom.html).\n", 12 | "\n", 13 | "Projects are recommended pattern to deliver re-usable, tested, and governed components or solution blueprints into your ML environments.\n", 14 | "\n", 15 | "Refer to the notebook [`04-sagemaker-project.ipynb`](../04-sagemaker-project.ipynb) for code snippets and a general guidance for the exercises in this assignment." 16 | ] 17 | }, 18 | { 19 | "cell_type": "markdown", 20 | "id": "82f1d136-8bf3-4763-9c2f-8a8f0ff33d95", 21 | "metadata": {}, 22 | "source": [ 23 | "## Import packages" 24 | ] 25 | }, 26 | { 27 | "cell_type": "code", 28 | "execution_count": null, 29 | "id": "38fe7c5a-7862-486b-acbd-b0541835c873", 30 | "metadata": {}, 31 | "outputs": [], 32 | "source": [ 33 | "import boto3\n", 34 | "import sagemaker \n", 35 | "from time import gmtime, strftime, sleep" 36 | ] 37 | }, 38 | { 39 | "cell_type": "code", 40 | "execution_count": null, 41 | "id": "7ab00f9a-f428-4f05-b8f9-61e42b746896", 42 | "metadata": {}, 43 | "outputs": [], 44 | "source": [ 45 | "sm = boto3.client(\"sagemaker\")\n", 46 | "sc = boto3.client(\"servicecatalog\")\n", 47 | "\n", 48 | "sc_provider_name = \"Amazon SageMaker\"\n", 49 | "sc_product_name = \"MLOps template for model building and training\"" 50 | ] 51 | }, 52 | { 53 | "cell_type": "markdown", 54 | "id": "44950263-a204-4367-9ea1-467c96c4bfac", 55 | "metadata": {}, 56 | "source": [ 57 | "## Exercise 1: Create an MLOps project\n", 58 | "You can re-use code from [`04-sagemaker-project.ipynb`](../04-sagemaker-project.ipynb) notebook to programmatically create a project using Python SDK `boto3`.\n", 59 | "\n", 60 | "Alternatively you can provision a new project via Studio UX." 61 | ] 62 | }, 63 | { 64 | "cell_type": "code", 65 | "execution_count": null, 66 | "id": "ff82f428-95a4-4826-982f-84d0f8f0eeee", 67 | "metadata": {}, 68 | "outputs": [], 69 | "source": [ 70 | "# Get project details after you created the project\n", 71 | "# project_name = \n", 72 | "# sm.describe_project(ProjectName=project_name)" 73 | ] 74 | }, 75 | { 76 | "cell_type": "markdown", 77 | "id": "07432f5e-879c-479c-95ce-8befa083f055", 78 | "metadata": {}, 79 | "source": [ 80 | "## Exercise 2: Configure the project\n", 81 | "The provisioned project is a template with a default structure and seed code in a CodeCommit repository. You must change source code and some parameters to reflect your environment and use case, for example the names of Amazon S3 buckets, specific IAM execution roles, and ML workflow.\n", 82 | "\n", 83 | "The project template is not compulsory construct, it just gives you a jump start for creating your own custom project template with a better fit for your environment.\n", 84 | "\n", 85 | "To configure the provisioned project:\n", 86 | "1. Clone the project CodeCommit repository to your home directory on Studio EFS\n", 87 | "2. Replace the ML pipeline implementation sample code with your pipeline construction code, as implemented in the previous assignment\n", 88 | "3. Modify the `codebuild-buildspec.yml` file to reference the correct Python module name and to set project parameters\n", 89 | "4. Fix a wrong package version requirement in `setup.py` file\n", 90 | "\n", 91 | "You don't need to write any code to complete this exercise, it's configuration work only." 92 | ] 93 | }, 94 | { 95 | "cell_type": "markdown", 96 | "id": "7f0a0f7f-ee36-4418-9366-53917cc419d6", 97 | "metadata": {}, 98 | "source": [ 99 | "### Clone the project seed code to the Studio file system\n", 100 | "When clone operation is complete, navigate to the project folder in your home directory." 101 | ] 102 | }, 103 | { 104 | "cell_type": "markdown", 105 | "id": "335a1752-de53-4798-903c-210bd9f42d56", 106 | "metadata": {}, 107 | "source": [ 108 | "### Copy processing and evaluation scripts to pipeline folder\n", 109 | "Follow the instructions in the [`04-sagemaker-project.ipynb`](../04-sagemaker-project.ipynb) notebook. \n", 110 | "\n", 111 | "Navigate to the `pipelines` folder inside the project's code repository folder and rename the `abalone` folder to `fromideatoprod`.\n", 112 | "\n", 113 | "Copy the `preprocessing_assignment.py` and `evaluation_assignment.py` scripts that you created in two previous assignments to the `pipelines/fromideatoprod` folder in the project's code repository folder." 114 | ] 115 | }, 116 | { 117 | "cell_type": "markdown", 118 | "id": "fcf19292-fc86-436d-8dcf-0999affeabb4", 119 | "metadata": {}, 120 | "source": [ 121 | "### Replace pipeline construction code\n", 122 | "Follow the instructions in the [`04-sagemaker-project.ipynb`](../04-sagemaker-project.ipynb) notebook. Create a `pipeline.py` file with the pipeline construction code.\n", 123 | "\n", 124 | "Copy this `pipeline.py` file from the current folder to the `pipelines/fromideatoprod` folder in the project's code repository folder." 125 | ] 126 | }, 127 | { 128 | "cell_type": "code", 129 | "execution_count": null, 130 | "id": "94e2b89a-0a64-48df-a9b2-ac76ed53f61c", 131 | "metadata": {}, 132 | "outputs": [], 133 | "source": [ 134 | "%%writefile pipeline.py\n", 135 | "\n", 136 | "# You can re-use source code from ../04-sagemaker-project.ipynb notebook\n" 137 | ] 138 | }, 139 | { 140 | "cell_type": "markdown", 141 | "id": "f10cfe73-f7d1-4537-abfc-196cbb1f0c94", 142 | "metadata": {}, 143 | "source": [ 144 | "### Modify the build specification file\n", 145 | "Create a new build specification file as described in [`04-sagemaker-project.ipynb`](../04-sagemaker-project.ipynb) notebook.\n", 146 | "\n", 147 | "Don't forget to update the S3 path to the input dataset with your specific S3 path.\n", 148 | "\n", 149 | "Copy the build specification file into the project folder." 150 | ] 151 | }, 152 | { 153 | "cell_type": "code", 154 | "execution_count": null, 155 | "id": "f438b192-a94d-4942-90ed-b8e38e439ae1", 156 | "metadata": {}, 157 | "outputs": [], 158 | "source": [ 159 | "%%writefile codebuild-buildspec.yml\n", 160 | "\n", 161 | "# Buildspec file" 162 | ] 163 | }, 164 | { 165 | "cell_type": "markdown", 166 | "id": "dbaeec5b-2487-4df5-a50d-ce771009c98f", 167 | "metadata": {}, 168 | "source": [ 169 | "### Fix a wrong package version in `setup.py` file\n", 170 | "The project template's `setup.py` file contains a wrong version requirement for `sagemaker` package. If you don't remove the version number, the project build fails.\n", 171 | "\n", 172 | "Follow the instructions in the [`04-sagemaker-project.ipynb`](../04-sagemaker-project.ipynb) notebook." 173 | ] 174 | }, 175 | { 176 | "cell_type": "markdown", 177 | "id": "0eba83d3-00cc-4118-b588-dd3ceb854e7b", 178 | "metadata": {}, 179 | "source": [ 180 | "## Exercise 3: Run CI/CD model building pipeline\n", 181 | "\n", 182 | "### CodePipeline pipeline\n", 183 | "The project template provisioned a CodePipeline pipeline in your AWS Account. Navigate to CodePipeline [console](https://console.aws.amazon.com/codesuite/codepipeline/pipelines) and explore the model building pipeline and its stages. \n", 184 | "\n", 185 | "### EventBridge rule to launch the pipeline\n", 186 | "Navigate to the rules in the EventBridge [console](https://console.aws.amazon.com/events/home?#/rules) and find a rule with the name `sagemaker---build`. This rule launches the CodePipeline pipeline on each change in the project's CodeCommit git repository. \n", 187 | "\n", 188 | "### Launching the pipeline\n", 189 | "You launch the CI/CD pipeline by pushing your code changes into the repository. You can also start the pipeline manually from the console.\n", 190 | "\n", 191 | "### Commit code\n", 192 | "To commit and push the code changes you've made, you can use Git sidepane in Studio or run `git add`, `git commit`, and `git push` commands from Studio terminal.\n", 193 | "\n", 194 | "### Follow up the pipeline execution\n", 195 | "After you pushed changes into the repository, the pipeline starts. Navigate to CodePipeline [console](https://console.aws.amazon.com/codesuite/codepipeline/pipelines) and view the execution. Explore how different pipeline stages works together to build and execute your ML pipeline." 196 | ] 197 | }, 198 | { 199 | "cell_type": "markdown", 200 | "id": "6785f22d-8377-4165-b397-76b212dfa278", 201 | "metadata": {}, 202 | "source": [ 203 | "## Exercise 4: Explore Model Registry\n", 204 | "A successful execution of both CI/CD and ML pipelines registeres a new model version in SageMaker Model Registry. \n", 205 | "\n", 206 | "Navigate to **Model registry** in the **SageMaker resources** dropdown list and view the model details:\n", 207 | "\n", 208 | "![](../img/model-package-group.png)\n", 209 | "\n", 210 | "Double-click on the latest version of the model. Explore all tabs in the model detail screen. For example, you can see the full lineage of how this model version was built and explore version meta data:\n", 211 | "\n", 212 | "![](../img/model-version-details-annotated.png)" 213 | ] 214 | }, 215 | { 216 | "cell_type": "markdown", 217 | "id": "9861510a-c6c8-4de0-b817-1a56d35e9858", 218 | "metadata": {}, 219 | "source": [ 220 | "In the following assignment you implement a model deployment pipeline." 221 | ] 222 | }, 223 | { 224 | "cell_type": "markdown", 225 | "id": "61765e5c-fc86-4a10-ab87-4ec23c21489a", 226 | "metadata": {}, 227 | "source": [ 228 | "## Continue with the assignment 5\n", 229 | "Navigate to the [assignment 5](05-assignment-deploy.ipynb) notebook." 230 | ] 231 | }, 232 | { 233 | "cell_type": "code", 234 | "execution_count": null, 235 | "id": "79820306-ff4a-42eb-83c5-7af158684f41", 236 | "metadata": {}, 237 | "outputs": [], 238 | "source": [] 239 | } 240 | ], 241 | "metadata": { 242 | "availableInstances": [ 243 | { 244 | "_defaultOrder": 0, 245 | "_isFastLaunch": true, 246 | "category": "General purpose", 247 | "gpuNum": 0, 248 | "hideHardwareSpecs": false, 249 | "memoryGiB": 4, 250 | "name": "ml.t3.medium", 251 | "vcpuNum": 2 252 | }, 253 | { 254 | "_defaultOrder": 1, 255 | "_isFastLaunch": false, 256 | "category": "General purpose", 257 | "gpuNum": 0, 258 | "hideHardwareSpecs": false, 259 | "memoryGiB": 8, 260 | "name": "ml.t3.large", 261 | "vcpuNum": 2 262 | }, 263 | { 264 | "_defaultOrder": 2, 265 | "_isFastLaunch": false, 266 | "category": "General purpose", 267 | "gpuNum": 0, 268 | "hideHardwareSpecs": false, 269 | "memoryGiB": 16, 270 | "name": "ml.t3.xlarge", 271 | "vcpuNum": 4 272 | }, 273 | { 274 | "_defaultOrder": 3, 275 | "_isFastLaunch": false, 276 | "category": "General purpose", 277 | "gpuNum": 0, 278 | "hideHardwareSpecs": false, 279 | "memoryGiB": 32, 280 | "name": "ml.t3.2xlarge", 281 | "vcpuNum": 8 282 | }, 283 | { 284 | "_defaultOrder": 4, 285 | "_isFastLaunch": true, 286 | "category": "General purpose", 287 | "gpuNum": 0, 288 | "hideHardwareSpecs": false, 289 | "memoryGiB": 8, 290 | "name": "ml.m5.large", 291 | "vcpuNum": 2 292 | }, 293 | { 294 | "_defaultOrder": 5, 295 | "_isFastLaunch": false, 296 | "category": "General purpose", 297 | "gpuNum": 0, 298 | "hideHardwareSpecs": false, 299 | "memoryGiB": 16, 300 | "name": "ml.m5.xlarge", 301 | "vcpuNum": 4 302 | }, 303 | { 304 | "_defaultOrder": 6, 305 | "_isFastLaunch": false, 306 | "category": "General purpose", 307 | "gpuNum": 0, 308 | "hideHardwareSpecs": false, 309 | "memoryGiB": 32, 310 | "name": "ml.m5.2xlarge", 311 | "vcpuNum": 8 312 | }, 313 | { 314 | "_defaultOrder": 7, 315 | "_isFastLaunch": false, 316 | "category": "General purpose", 317 | "gpuNum": 0, 318 | "hideHardwareSpecs": false, 319 | "memoryGiB": 64, 320 | "name": "ml.m5.4xlarge", 321 | "vcpuNum": 16 322 | }, 323 | { 324 | "_defaultOrder": 8, 325 | "_isFastLaunch": false, 326 | "category": "General purpose", 327 | "gpuNum": 0, 328 | "hideHardwareSpecs": false, 329 | "memoryGiB": 128, 330 | "name": "ml.m5.8xlarge", 331 | "vcpuNum": 32 332 | }, 333 | { 334 | "_defaultOrder": 9, 335 | "_isFastLaunch": false, 336 | "category": "General purpose", 337 | "gpuNum": 0, 338 | "hideHardwareSpecs": false, 339 | "memoryGiB": 192, 340 | "name": "ml.m5.12xlarge", 341 | "vcpuNum": 48 342 | }, 343 | { 344 | "_defaultOrder": 10, 345 | "_isFastLaunch": false, 346 | "category": "General purpose", 347 | "gpuNum": 0, 348 | "hideHardwareSpecs": false, 349 | "memoryGiB": 256, 350 | "name": "ml.m5.16xlarge", 351 | "vcpuNum": 64 352 | }, 353 | { 354 | "_defaultOrder": 11, 355 | "_isFastLaunch": false, 356 | "category": "General purpose", 357 | "gpuNum": 0, 358 | "hideHardwareSpecs": false, 359 | "memoryGiB": 384, 360 | "name": "ml.m5.24xlarge", 361 | "vcpuNum": 96 362 | }, 363 | { 364 | "_defaultOrder": 12, 365 | "_isFastLaunch": false, 366 | "category": "General purpose", 367 | "gpuNum": 0, 368 | "hideHardwareSpecs": false, 369 | "memoryGiB": 8, 370 | "name": "ml.m5d.large", 371 | "vcpuNum": 2 372 | }, 373 | { 374 | "_defaultOrder": 13, 375 | "_isFastLaunch": false, 376 | "category": "General purpose", 377 | "gpuNum": 0, 378 | "hideHardwareSpecs": false, 379 | "memoryGiB": 16, 380 | "name": "ml.m5d.xlarge", 381 | "vcpuNum": 4 382 | }, 383 | { 384 | "_defaultOrder": 14, 385 | "_isFastLaunch": false, 386 | "category": "General purpose", 387 | "gpuNum": 0, 388 | "hideHardwareSpecs": false, 389 | "memoryGiB": 32, 390 | "name": "ml.m5d.2xlarge", 391 | "vcpuNum": 8 392 | }, 393 | { 394 | "_defaultOrder": 15, 395 | "_isFastLaunch": false, 396 | "category": "General purpose", 397 | "gpuNum": 0, 398 | "hideHardwareSpecs": false, 399 | "memoryGiB": 64, 400 | "name": "ml.m5d.4xlarge", 401 | "vcpuNum": 16 402 | }, 403 | { 404 | "_defaultOrder": 16, 405 | "_isFastLaunch": false, 406 | "category": "General purpose", 407 | "gpuNum": 0, 408 | "hideHardwareSpecs": false, 409 | "memoryGiB": 128, 410 | "name": "ml.m5d.8xlarge", 411 | "vcpuNum": 32 412 | }, 413 | { 414 | "_defaultOrder": 17, 415 | "_isFastLaunch": false, 416 | "category": "General purpose", 417 | "gpuNum": 0, 418 | "hideHardwareSpecs": false, 419 | "memoryGiB": 192, 420 | "name": "ml.m5d.12xlarge", 421 | "vcpuNum": 48 422 | }, 423 | { 424 | "_defaultOrder": 18, 425 | "_isFastLaunch": false, 426 | "category": "General purpose", 427 | "gpuNum": 0, 428 | "hideHardwareSpecs": false, 429 | "memoryGiB": 256, 430 | "name": "ml.m5d.16xlarge", 431 | "vcpuNum": 64 432 | }, 433 | { 434 | "_defaultOrder": 19, 435 | "_isFastLaunch": false, 436 | "category": "General purpose", 437 | "gpuNum": 0, 438 | "hideHardwareSpecs": false, 439 | "memoryGiB": 384, 440 | "name": "ml.m5d.24xlarge", 441 | "vcpuNum": 96 442 | }, 443 | { 444 | "_defaultOrder": 20, 445 | "_isFastLaunch": false, 446 | "category": "General purpose", 447 | "gpuNum": 0, 448 | "hideHardwareSpecs": true, 449 | "memoryGiB": 0, 450 | "name": "ml.geospatial.interactive", 451 | "supportedImageNames": [ 452 | "sagemaker-geospatial-v1-0" 453 | ], 454 | "vcpuNum": 0 455 | }, 456 | { 457 | "_defaultOrder": 21, 458 | "_isFastLaunch": true, 459 | "category": "Compute optimized", 460 | "gpuNum": 0, 461 | "hideHardwareSpecs": false, 462 | "memoryGiB": 4, 463 | "name": "ml.c5.large", 464 | "vcpuNum": 2 465 | }, 466 | { 467 | "_defaultOrder": 22, 468 | "_isFastLaunch": false, 469 | "category": "Compute optimized", 470 | "gpuNum": 0, 471 | "hideHardwareSpecs": false, 472 | "memoryGiB": 8, 473 | "name": "ml.c5.xlarge", 474 | "vcpuNum": 4 475 | }, 476 | { 477 | "_defaultOrder": 23, 478 | "_isFastLaunch": false, 479 | "category": "Compute optimized", 480 | "gpuNum": 0, 481 | "hideHardwareSpecs": false, 482 | "memoryGiB": 16, 483 | "name": "ml.c5.2xlarge", 484 | "vcpuNum": 8 485 | }, 486 | { 487 | "_defaultOrder": 24, 488 | "_isFastLaunch": false, 489 | "category": "Compute optimized", 490 | "gpuNum": 0, 491 | "hideHardwareSpecs": false, 492 | "memoryGiB": 32, 493 | "name": "ml.c5.4xlarge", 494 | "vcpuNum": 16 495 | }, 496 | { 497 | "_defaultOrder": 25, 498 | "_isFastLaunch": false, 499 | "category": "Compute optimized", 500 | "gpuNum": 0, 501 | "hideHardwareSpecs": false, 502 | "memoryGiB": 72, 503 | "name": "ml.c5.9xlarge", 504 | "vcpuNum": 36 505 | }, 506 | { 507 | "_defaultOrder": 26, 508 | "_isFastLaunch": false, 509 | "category": "Compute optimized", 510 | "gpuNum": 0, 511 | "hideHardwareSpecs": false, 512 | "memoryGiB": 96, 513 | "name": "ml.c5.12xlarge", 514 | "vcpuNum": 48 515 | }, 516 | { 517 | "_defaultOrder": 27, 518 | "_isFastLaunch": false, 519 | "category": "Compute optimized", 520 | "gpuNum": 0, 521 | "hideHardwareSpecs": false, 522 | "memoryGiB": 144, 523 | "name": "ml.c5.18xlarge", 524 | "vcpuNum": 72 525 | }, 526 | { 527 | "_defaultOrder": 28, 528 | "_isFastLaunch": false, 529 | "category": "Compute optimized", 530 | "gpuNum": 0, 531 | "hideHardwareSpecs": false, 532 | "memoryGiB": 192, 533 | "name": "ml.c5.24xlarge", 534 | "vcpuNum": 96 535 | }, 536 | { 537 | "_defaultOrder": 29, 538 | "_isFastLaunch": true, 539 | "category": "Accelerated computing", 540 | "gpuNum": 1, 541 | "hideHardwareSpecs": false, 542 | "memoryGiB": 16, 543 | "name": "ml.g4dn.xlarge", 544 | "vcpuNum": 4 545 | }, 546 | { 547 | "_defaultOrder": 30, 548 | "_isFastLaunch": false, 549 | "category": "Accelerated computing", 550 | "gpuNum": 1, 551 | "hideHardwareSpecs": false, 552 | "memoryGiB": 32, 553 | "name": "ml.g4dn.2xlarge", 554 | "vcpuNum": 8 555 | }, 556 | { 557 | "_defaultOrder": 31, 558 | "_isFastLaunch": false, 559 | "category": "Accelerated computing", 560 | "gpuNum": 1, 561 | "hideHardwareSpecs": false, 562 | "memoryGiB": 64, 563 | "name": "ml.g4dn.4xlarge", 564 | "vcpuNum": 16 565 | }, 566 | { 567 | "_defaultOrder": 32, 568 | "_isFastLaunch": false, 569 | "category": "Accelerated computing", 570 | "gpuNum": 1, 571 | "hideHardwareSpecs": false, 572 | "memoryGiB": 128, 573 | "name": "ml.g4dn.8xlarge", 574 | "vcpuNum": 32 575 | }, 576 | { 577 | "_defaultOrder": 33, 578 | "_isFastLaunch": false, 579 | "category": "Accelerated computing", 580 | "gpuNum": 4, 581 | "hideHardwareSpecs": false, 582 | "memoryGiB": 192, 583 | "name": "ml.g4dn.12xlarge", 584 | "vcpuNum": 48 585 | }, 586 | { 587 | "_defaultOrder": 34, 588 | "_isFastLaunch": false, 589 | "category": "Accelerated computing", 590 | "gpuNum": 1, 591 | "hideHardwareSpecs": false, 592 | "memoryGiB": 256, 593 | "name": "ml.g4dn.16xlarge", 594 | "vcpuNum": 64 595 | }, 596 | { 597 | "_defaultOrder": 35, 598 | "_isFastLaunch": false, 599 | "category": "Accelerated computing", 600 | "gpuNum": 1, 601 | "hideHardwareSpecs": false, 602 | "memoryGiB": 61, 603 | "name": "ml.p3.2xlarge", 604 | "vcpuNum": 8 605 | }, 606 | { 607 | "_defaultOrder": 36, 608 | "_isFastLaunch": false, 609 | "category": "Accelerated computing", 610 | "gpuNum": 4, 611 | "hideHardwareSpecs": false, 612 | "memoryGiB": 244, 613 | "name": "ml.p3.8xlarge", 614 | "vcpuNum": 32 615 | }, 616 | { 617 | "_defaultOrder": 37, 618 | "_isFastLaunch": false, 619 | "category": "Accelerated computing", 620 | "gpuNum": 8, 621 | "hideHardwareSpecs": false, 622 | "memoryGiB": 488, 623 | "name": "ml.p3.16xlarge", 624 | "vcpuNum": 64 625 | }, 626 | { 627 | "_defaultOrder": 38, 628 | "_isFastLaunch": false, 629 | "category": "Accelerated computing", 630 | "gpuNum": 8, 631 | "hideHardwareSpecs": false, 632 | "memoryGiB": 768, 633 | "name": "ml.p3dn.24xlarge", 634 | "vcpuNum": 96 635 | }, 636 | { 637 | "_defaultOrder": 39, 638 | "_isFastLaunch": false, 639 | "category": "Memory Optimized", 640 | "gpuNum": 0, 641 | "hideHardwareSpecs": false, 642 | "memoryGiB": 16, 643 | "name": "ml.r5.large", 644 | "vcpuNum": 2 645 | }, 646 | { 647 | "_defaultOrder": 40, 648 | "_isFastLaunch": false, 649 | "category": "Memory Optimized", 650 | "gpuNum": 0, 651 | "hideHardwareSpecs": false, 652 | "memoryGiB": 32, 653 | "name": "ml.r5.xlarge", 654 | "vcpuNum": 4 655 | }, 656 | { 657 | "_defaultOrder": 41, 658 | "_isFastLaunch": false, 659 | "category": "Memory Optimized", 660 | "gpuNum": 0, 661 | "hideHardwareSpecs": false, 662 | "memoryGiB": 64, 663 | "name": "ml.r5.2xlarge", 664 | "vcpuNum": 8 665 | }, 666 | { 667 | "_defaultOrder": 42, 668 | "_isFastLaunch": false, 669 | "category": "Memory Optimized", 670 | "gpuNum": 0, 671 | "hideHardwareSpecs": false, 672 | "memoryGiB": 128, 673 | "name": "ml.r5.4xlarge", 674 | "vcpuNum": 16 675 | }, 676 | { 677 | "_defaultOrder": 43, 678 | "_isFastLaunch": false, 679 | "category": "Memory Optimized", 680 | "gpuNum": 0, 681 | "hideHardwareSpecs": false, 682 | "memoryGiB": 256, 683 | "name": "ml.r5.8xlarge", 684 | "vcpuNum": 32 685 | }, 686 | { 687 | "_defaultOrder": 44, 688 | "_isFastLaunch": false, 689 | "category": "Memory Optimized", 690 | "gpuNum": 0, 691 | "hideHardwareSpecs": false, 692 | "memoryGiB": 384, 693 | "name": "ml.r5.12xlarge", 694 | "vcpuNum": 48 695 | }, 696 | { 697 | "_defaultOrder": 45, 698 | "_isFastLaunch": false, 699 | "category": "Memory Optimized", 700 | "gpuNum": 0, 701 | "hideHardwareSpecs": false, 702 | "memoryGiB": 512, 703 | "name": "ml.r5.16xlarge", 704 | "vcpuNum": 64 705 | }, 706 | { 707 | "_defaultOrder": 46, 708 | "_isFastLaunch": false, 709 | "category": "Memory Optimized", 710 | "gpuNum": 0, 711 | "hideHardwareSpecs": false, 712 | "memoryGiB": 768, 713 | "name": "ml.r5.24xlarge", 714 | "vcpuNum": 96 715 | }, 716 | { 717 | "_defaultOrder": 47, 718 | "_isFastLaunch": false, 719 | "category": "Accelerated computing", 720 | "gpuNum": 1, 721 | "hideHardwareSpecs": false, 722 | "memoryGiB": 16, 723 | "name": "ml.g5.xlarge", 724 | "vcpuNum": 4 725 | }, 726 | { 727 | "_defaultOrder": 48, 728 | "_isFastLaunch": false, 729 | "category": "Accelerated computing", 730 | "gpuNum": 1, 731 | "hideHardwareSpecs": false, 732 | "memoryGiB": 32, 733 | "name": "ml.g5.2xlarge", 734 | "vcpuNum": 8 735 | }, 736 | { 737 | "_defaultOrder": 49, 738 | "_isFastLaunch": false, 739 | "category": "Accelerated computing", 740 | "gpuNum": 1, 741 | "hideHardwareSpecs": false, 742 | "memoryGiB": 64, 743 | "name": "ml.g5.4xlarge", 744 | "vcpuNum": 16 745 | }, 746 | { 747 | "_defaultOrder": 50, 748 | "_isFastLaunch": false, 749 | "category": "Accelerated computing", 750 | "gpuNum": 1, 751 | "hideHardwareSpecs": false, 752 | "memoryGiB": 128, 753 | "name": "ml.g5.8xlarge", 754 | "vcpuNum": 32 755 | }, 756 | { 757 | "_defaultOrder": 51, 758 | "_isFastLaunch": false, 759 | "category": "Accelerated computing", 760 | "gpuNum": 1, 761 | "hideHardwareSpecs": false, 762 | "memoryGiB": 256, 763 | "name": "ml.g5.16xlarge", 764 | "vcpuNum": 64 765 | }, 766 | { 767 | "_defaultOrder": 52, 768 | "_isFastLaunch": false, 769 | "category": "Accelerated computing", 770 | "gpuNum": 4, 771 | "hideHardwareSpecs": false, 772 | "memoryGiB": 192, 773 | "name": "ml.g5.12xlarge", 774 | "vcpuNum": 48 775 | }, 776 | { 777 | "_defaultOrder": 53, 778 | "_isFastLaunch": false, 779 | "category": "Accelerated computing", 780 | "gpuNum": 4, 781 | "hideHardwareSpecs": false, 782 | "memoryGiB": 384, 783 | "name": "ml.g5.24xlarge", 784 | "vcpuNum": 96 785 | }, 786 | { 787 | "_defaultOrder": 54, 788 | "_isFastLaunch": false, 789 | "category": "Accelerated computing", 790 | "gpuNum": 8, 791 | "hideHardwareSpecs": false, 792 | "memoryGiB": 768, 793 | "name": "ml.g5.48xlarge", 794 | "vcpuNum": 192 795 | }, 796 | { 797 | "_defaultOrder": 55, 798 | "_isFastLaunch": false, 799 | "category": "Accelerated computing", 800 | "gpuNum": 8, 801 | "hideHardwareSpecs": false, 802 | "memoryGiB": 1152, 803 | "name": "ml.p4d.24xlarge", 804 | "vcpuNum": 96 805 | }, 806 | { 807 | "_defaultOrder": 56, 808 | "_isFastLaunch": false, 809 | "category": "Accelerated computing", 810 | "gpuNum": 8, 811 | "hideHardwareSpecs": false, 812 | "memoryGiB": 1152, 813 | "name": "ml.p4de.24xlarge", 814 | "vcpuNum": 96 815 | }, 816 | { 817 | "_defaultOrder": 57, 818 | "_isFastLaunch": false, 819 | "category": "Accelerated computing", 820 | "gpuNum": 0, 821 | "hideHardwareSpecs": false, 822 | "memoryGiB": 32, 823 | "name": "ml.trn1.2xlarge", 824 | "vcpuNum": 8 825 | }, 826 | { 827 | "_defaultOrder": 58, 828 | "_isFastLaunch": false, 829 | "category": "Accelerated computing", 830 | "gpuNum": 0, 831 | "hideHardwareSpecs": false, 832 | "memoryGiB": 512, 833 | "name": "ml.trn1.32xlarge", 834 | "vcpuNum": 128 835 | }, 836 | { 837 | "_defaultOrder": 59, 838 | "_isFastLaunch": false, 839 | "category": "Accelerated computing", 840 | "gpuNum": 0, 841 | "hideHardwareSpecs": false, 842 | "memoryGiB": 512, 843 | "name": "ml.trn1n.32xlarge", 844 | "vcpuNum": 128 845 | } 846 | ], 847 | "instance_type": "ml.t3.medium", 848 | "kernelspec": { 849 | "display_name": "Python 3 (Data Science 3.0)", 850 | "language": "python", 851 | "name": "python3__SAGEMAKER_INTERNAL__arn:aws:sagemaker:us-east-1:081325390199:image/sagemaker-data-science-310-v1" 852 | }, 853 | "language_info": { 854 | "codemirror_mode": { 855 | "name": "ipython", 856 | "version": 3 857 | }, 858 | "file_extension": ".py", 859 | "mimetype": "text/x-python", 860 | "name": "python", 861 | "nbconvert_exporter": "python", 862 | "pygments_lexer": "ipython3", 863 | "version": "3.10.6" 864 | } 865 | }, 866 | "nbformat": 4, 867 | "nbformat_minor": 5 868 | } 869 | -------------------------------------------------------------------------------- /assignments/05-assignment-deploy.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "6c699c04-d2d4-4480-955d-60c264e19997", 6 | "metadata": {}, 7 | "source": [ 8 | "# Assignment 5: Create a model deployment CI/CD pipeline\n", 9 | "In this assignment you implement a model deployment pipeline. \n", 10 | "\n", 11 | "There are many possible patterns how you can deploy ML models into production. These patterns are dependent on your environment, for example, use of multi-account structures, testing and approval workflows, number and type of environment stages. In this lab you implement a simple single-account model deployment. However, it has all main elements of a real-world deployment pipeline, such as an automated CI/CD process, model unit testing, a two-stage deployment with a test and a production stages, and an additional approval before deployment into production.\n", 12 | "\n", 13 | "To provision all required infrastructure and components into your AWS account, you use again a built-in [MLOps Project template](https://docs.aws.amazon.com/sagemaker/latest/dg/sagemaker-projects-templates.html).\n", 14 | "\n", 15 | "The following diagram shows the end-to-end architecture of the composed CI/CD pipeline comprising a model building and a model deployment pipelines.\n", 16 | "\n", 17 | "![](../img/cicd-project-e2e.png)\n", 18 | "\n", 19 | "The left part of the diagram, is a **model building pipeline**, which you provisioned and configured in the previous notebook. In this notebook, you are going to provision the right part, a **model deployment pipeline**. These two pipelines are connected via the Model Registry. The model building pipeline registers a new version of the model after a successful execution of the pipeline. To launch the model deployment pipeline, you must approve the model version in the Model Registry. The model deployment pipeline first deploys the approved model version into a staging environment, runs model unit tests, and waits for a manual approval. After you approve the **DeployStaging** stage of the CI/CD pipeline, the pipeline continues and deploys the model into a production environment.\n", 20 | "\n", 21 | "The model deployment project follows Infrastructure as Code (IaC) approach by using [AWS Cloud Formation](https://aws.amazon.com/cloudformation/) templates for model deployment. The project also deploys a source code repository with inference endpoint configuration and model unit test code.\n", 22 | "\n", 23 | "Refer to the notebook [`05-deploy.ipynb`](../05-deploy.ipynb) for code snippets and a general guidance for the exercises in this assignment." 24 | ] 25 | }, 26 | { 27 | "cell_type": "markdown", 28 | "id": "12b0f975-75f5-4d87-a156-4b08fe4197c9", 29 | "metadata": {}, 30 | "source": [ 31 | "## Import packages" 32 | ] 33 | }, 34 | { 35 | "cell_type": "code", 36 | "execution_count": null, 37 | "id": "7c10502e-86c0-4e67-a12f-cafff96eea50", 38 | "metadata": {}, 39 | "outputs": [], 40 | "source": [ 41 | "import boto3\n", 42 | "import sagemaker \n", 43 | "from time import gmtime, strftime, sleep" 44 | ] 45 | }, 46 | { 47 | "cell_type": "markdown", 48 | "id": "9bbf8f7d-32d5-4cdb-85f3-4f073fb9a880", 49 | "metadata": {}, 50 | "source": [ 51 | "## Exercise 1: Create a model deployment project\n", 52 | "You can re-use code from [`05-deploy.ipynb`](../05-deploy.ipynb) notebook to programmatically create a project using Python SDK `boto3`.\n", 53 | "\n", 54 | "Alternatively you can provision a new project via Studio UX." 55 | ] 56 | }, 57 | { 58 | "cell_type": "code", 59 | "execution_count": null, 60 | "id": "1f62d97d-8228-4df4-9c3d-f8ba3ae0aa80", 61 | "metadata": {}, 62 | "outputs": [], 63 | "source": [ 64 | "# Get project details after you created the project\n", 65 | "# project_name = \n", 66 | "# sm.describe_project(ProjectName=project_name)" 67 | ] 68 | }, 69 | { 70 | "cell_type": "markdown", 71 | "id": "109a0b1e-1d9f-4212-8879-df76ddd77e5c", 72 | "metadata": {}, 73 | "source": [ 74 | "## Exercise 2: Explore project components\n", 75 | "The SageMaker MLOps project provisions an end-to-end CI/CD model deployment pipeline in your AWS account:\n", 76 | "\n", 77 | "![](../img/mlops-model-deploy-2.png)\n", 78 | "\n", 79 | "The main components are:\n", 80 | "1. An AWS CodeCommit repository with configuration, testing, and workflow code\n", 81 | "2. An AWS CodePipeline deployment pipeline with four stages\n", 82 | "3. An Amazon EventBridge rule to launch a CodePipeline pipeline execution when a model package version is approved or rejected\n", 83 | "4. A manual approval step after the model unit tests to deploy the production inference endpoint\n", 84 | "\n", 85 | "Explore each of the pipeline components in AWS console." 86 | ] 87 | }, 88 | { 89 | "cell_type": "markdown", 90 | "id": "70af03c4-bdf1-4e08-9ab5-222aed317a50", 91 | "metadata": {}, 92 | "source": [ 93 | "### AWS CodeCommit repository\n", 94 | "[Clone](https://docs.aws.amazon.com/sagemaker/latest/dg/sagemaker-projects-walkthrough.html#sagemaker-proejcts-walkthrough-clone) the project code repository to the Studio home directory and explore the source code. Navigate to the project folder on Studio file system.\n", 95 | "\n", 96 | "The `README.md` file provides a detailed overview of the repository structure and the description of each file. The main components of the source code:\n", 97 | "- Two build stages each with own `buildspec.yml` file: for retrieving the latest approved model package and building the configuration files, and for unit tests\n", 98 | "- Two Python scripts `build.py` and `test/test.py` with executable code for each of the build stages\n", 99 | "- A CloudFormation template `endpoint-config-template.yml` for IaC model deployment as real-time inference endpoints\n", 100 | "- Two configuration files `staging-config.json` and `prod-config.json`. Pipeline's deployment steps use these files to configure parameters of the inference endpoints, such as compute instance type, data capture configuration, tags\n", 101 | "\n", 102 | "The MLOps project implements only one possible approach for an automated deployment pipeline. You can implement a different approach using a different technology stack depending on your specific environment. You can still use SageMaker Project templates to package any components and technology stack to create a pre-defined CI/CD pipeline templates." 103 | ] 104 | }, 105 | { 106 | "cell_type": "markdown", 107 | "id": "7bbf72bc-8490-4682-b009-dc6ac4ecb384", 108 | "metadata": {}, 109 | "source": [ 110 | "### AWS CodePipeline pipeline\n", 111 | "Open [AWS CodePipeline console](https://console.aws.amazon.com/codesuite/codepipeline/pipelines) and explore the model deployment pipeline named `sagemaker---modeldeploy`. There are four stages in the pipeline. Explore the transitions between stages and artifacts created by each stage.\n", 112 | "\n", 113 | "For example, explore the build stage. Navigate to [AWS CodeBuild console](https://console.aws.amazon.com/codesuite/codebuild/projects) and open a build project with the name `sagemaker---modeldeploy`, open **Environment variables** pane. You can see the environment variables set by the MLOps project template:\n", 114 | "\n", 115 | "![](../img/codebuild-env-variables.png)\n", 116 | "\n", 117 | "Open the `build.py` file in the project folder. Explore the execution flow and how the implementation uses the passed arguments to set configuration parameters and to create the configuration files.\n", 118 | "\n", 119 | "Explore **DeployStaging** stage of the CodePipeline pipeline. Click on the pipeline name in the pipeline list and then click on \"i\" icon next to **DeployResourceStaging** action of the **DeployStaging** stage. You see how the CloudFormation deploy action is configured:\n", 120 | "\n", 121 | "![](../img/deploystaging-config.png)\n", 122 | "\n", 123 | "Open the `/test/test.py` file in the project folder. Explore how the endpoint tests are done. You can implement `invoke_endpoint` function and send a payload to the endpoint to test it.\n", 124 | "\n", 125 | "Continue exploring other stages of the pipeline, such as manual approval, deployment of the production endpoint." 126 | ] 127 | }, 128 | { 129 | "cell_type": "markdown", 130 | "id": "ef523532-63de-4012-9706-5c496f908e37", 131 | "metadata": {}, 132 | "source": [ 133 | "### Amazon EventBridge rule\n", 134 | "Navigate to the rules in the EventBridge [console](https://console.aws.amazon.com/events/home?#/rules) and find rules with the names `sagemaker---code` and `sagemaker---model`. The first rule `...-code` launches the pipeline on each push into the source code repository. The second rule `...-model` launches the pipeline on any model package state change, see the **Event pattern**:\n", 135 | "\n", 136 | "```\n", 137 | "{\n", 138 | " \"detail-type\": [\"SageMaker Model Package State Change\"],\n", 139 | " \"source\": [\"aws.sagemaker\"],\n", 140 | " \"detail\": {\n", 141 | " \"ModelPackageGroupName\": [\"from-idea-to-prod-model-group\"]\n", 142 | " }\n", 143 | "}\n", 144 | "```" 145 | ] 146 | }, 147 | { 148 | "cell_type": "markdown", 149 | "id": "f29e2f3e-5add-4836-8e0c-658b1d2c1ebb", 150 | "metadata": {}, 151 | "source": [ 152 | "## Exercise 3: Execute the model deployment pipeline\n", 153 | "To launch the deployment pipeline you need to approve a model version in the model registry. \n", 154 | "\n", 155 | "You can approve the model version either in Studio UX in the Model registry or do it programmatically in the notebook.\n", 156 | "\n", 157 | "Follow the pipeline execution in [AWS CodePipeline console](https://console.aws.amazon.com/codesuite/codepipeline/pipelines). After the pipeline deployed the staging inference endpoint, manually approve the deployment of the production endpoint. See the [`05-deploy.ipynb`](../05-deploy.ipynb) notebook for instructions.\n", 158 | "\n", 159 | "Verify that you have two `InService` endpoints after a successful completion of the deployment pipeline:\n", 160 | "\n", 161 | "" 162 | ] 163 | }, 164 | { 165 | "cell_type": "markdown", 166 | "id": "36f6b139-25d0-4e85-b95e-d775bb4a8052", 167 | "metadata": {}, 168 | "source": [ 169 | "## Continue with the assignment 6\n", 170 | "Navigate to the [assignment 6](06-assignment-monitoring.ipynb) notebook." 171 | ] 172 | }, 173 | { 174 | "cell_type": "code", 175 | "execution_count": null, 176 | "id": "ad5d2a4f-da70-4f52-aca9-2bcfcb25e90f", 177 | "metadata": {}, 178 | "outputs": [], 179 | "source": [] 180 | } 181 | ], 182 | "metadata": { 183 | "availableInstances": [ 184 | { 185 | "_defaultOrder": 0, 186 | "_isFastLaunch": true, 187 | "category": "General purpose", 188 | "gpuNum": 0, 189 | "hideHardwareSpecs": false, 190 | "memoryGiB": 4, 191 | "name": "ml.t3.medium", 192 | "vcpuNum": 2 193 | }, 194 | { 195 | "_defaultOrder": 1, 196 | "_isFastLaunch": false, 197 | "category": "General purpose", 198 | "gpuNum": 0, 199 | "hideHardwareSpecs": false, 200 | "memoryGiB": 8, 201 | "name": "ml.t3.large", 202 | "vcpuNum": 2 203 | }, 204 | { 205 | "_defaultOrder": 2, 206 | "_isFastLaunch": false, 207 | "category": "General purpose", 208 | "gpuNum": 0, 209 | "hideHardwareSpecs": false, 210 | "memoryGiB": 16, 211 | "name": "ml.t3.xlarge", 212 | "vcpuNum": 4 213 | }, 214 | { 215 | "_defaultOrder": 3, 216 | "_isFastLaunch": false, 217 | "category": "General purpose", 218 | "gpuNum": 0, 219 | "hideHardwareSpecs": false, 220 | "memoryGiB": 32, 221 | "name": "ml.t3.2xlarge", 222 | "vcpuNum": 8 223 | }, 224 | { 225 | "_defaultOrder": 4, 226 | "_isFastLaunch": true, 227 | "category": "General purpose", 228 | "gpuNum": 0, 229 | "hideHardwareSpecs": false, 230 | "memoryGiB": 8, 231 | "name": "ml.m5.large", 232 | "vcpuNum": 2 233 | }, 234 | { 235 | "_defaultOrder": 5, 236 | "_isFastLaunch": false, 237 | "category": "General purpose", 238 | "gpuNum": 0, 239 | "hideHardwareSpecs": false, 240 | "memoryGiB": 16, 241 | "name": "ml.m5.xlarge", 242 | "vcpuNum": 4 243 | }, 244 | { 245 | "_defaultOrder": 6, 246 | "_isFastLaunch": false, 247 | "category": "General purpose", 248 | "gpuNum": 0, 249 | "hideHardwareSpecs": false, 250 | "memoryGiB": 32, 251 | "name": "ml.m5.2xlarge", 252 | "vcpuNum": 8 253 | }, 254 | { 255 | "_defaultOrder": 7, 256 | "_isFastLaunch": false, 257 | "category": "General purpose", 258 | "gpuNum": 0, 259 | "hideHardwareSpecs": false, 260 | "memoryGiB": 64, 261 | "name": "ml.m5.4xlarge", 262 | "vcpuNum": 16 263 | }, 264 | { 265 | "_defaultOrder": 8, 266 | "_isFastLaunch": false, 267 | "category": "General purpose", 268 | "gpuNum": 0, 269 | "hideHardwareSpecs": false, 270 | "memoryGiB": 128, 271 | "name": "ml.m5.8xlarge", 272 | "vcpuNum": 32 273 | }, 274 | { 275 | "_defaultOrder": 9, 276 | "_isFastLaunch": false, 277 | "category": "General purpose", 278 | "gpuNum": 0, 279 | "hideHardwareSpecs": false, 280 | "memoryGiB": 192, 281 | "name": "ml.m5.12xlarge", 282 | "vcpuNum": 48 283 | }, 284 | { 285 | "_defaultOrder": 10, 286 | "_isFastLaunch": false, 287 | "category": "General purpose", 288 | "gpuNum": 0, 289 | "hideHardwareSpecs": false, 290 | "memoryGiB": 256, 291 | "name": "ml.m5.16xlarge", 292 | "vcpuNum": 64 293 | }, 294 | { 295 | "_defaultOrder": 11, 296 | "_isFastLaunch": false, 297 | "category": "General purpose", 298 | "gpuNum": 0, 299 | "hideHardwareSpecs": false, 300 | "memoryGiB": 384, 301 | "name": "ml.m5.24xlarge", 302 | "vcpuNum": 96 303 | }, 304 | { 305 | "_defaultOrder": 12, 306 | "_isFastLaunch": false, 307 | "category": "General purpose", 308 | "gpuNum": 0, 309 | "hideHardwareSpecs": false, 310 | "memoryGiB": 8, 311 | "name": "ml.m5d.large", 312 | "vcpuNum": 2 313 | }, 314 | { 315 | "_defaultOrder": 13, 316 | "_isFastLaunch": false, 317 | "category": "General purpose", 318 | "gpuNum": 0, 319 | "hideHardwareSpecs": false, 320 | "memoryGiB": 16, 321 | "name": "ml.m5d.xlarge", 322 | "vcpuNum": 4 323 | }, 324 | { 325 | "_defaultOrder": 14, 326 | "_isFastLaunch": false, 327 | "category": "General purpose", 328 | "gpuNum": 0, 329 | "hideHardwareSpecs": false, 330 | "memoryGiB": 32, 331 | "name": "ml.m5d.2xlarge", 332 | "vcpuNum": 8 333 | }, 334 | { 335 | "_defaultOrder": 15, 336 | "_isFastLaunch": false, 337 | "category": "General purpose", 338 | "gpuNum": 0, 339 | "hideHardwareSpecs": false, 340 | "memoryGiB": 64, 341 | "name": "ml.m5d.4xlarge", 342 | "vcpuNum": 16 343 | }, 344 | { 345 | "_defaultOrder": 16, 346 | "_isFastLaunch": false, 347 | "category": "General purpose", 348 | "gpuNum": 0, 349 | "hideHardwareSpecs": false, 350 | "memoryGiB": 128, 351 | "name": "ml.m5d.8xlarge", 352 | "vcpuNum": 32 353 | }, 354 | { 355 | "_defaultOrder": 17, 356 | "_isFastLaunch": false, 357 | "category": "General purpose", 358 | "gpuNum": 0, 359 | "hideHardwareSpecs": false, 360 | "memoryGiB": 192, 361 | "name": "ml.m5d.12xlarge", 362 | "vcpuNum": 48 363 | }, 364 | { 365 | "_defaultOrder": 18, 366 | "_isFastLaunch": false, 367 | "category": "General purpose", 368 | "gpuNum": 0, 369 | "hideHardwareSpecs": false, 370 | "memoryGiB": 256, 371 | "name": "ml.m5d.16xlarge", 372 | "vcpuNum": 64 373 | }, 374 | { 375 | "_defaultOrder": 19, 376 | "_isFastLaunch": false, 377 | "category": "General purpose", 378 | "gpuNum": 0, 379 | "hideHardwareSpecs": false, 380 | "memoryGiB": 384, 381 | "name": "ml.m5d.24xlarge", 382 | "vcpuNum": 96 383 | }, 384 | { 385 | "_defaultOrder": 20, 386 | "_isFastLaunch": false, 387 | "category": "General purpose", 388 | "gpuNum": 0, 389 | "hideHardwareSpecs": true, 390 | "memoryGiB": 0, 391 | "name": "ml.geospatial.interactive", 392 | "supportedImageNames": [ 393 | "sagemaker-geospatial-v1-0" 394 | ], 395 | "vcpuNum": 0 396 | }, 397 | { 398 | "_defaultOrder": 21, 399 | "_isFastLaunch": true, 400 | "category": "Compute optimized", 401 | "gpuNum": 0, 402 | "hideHardwareSpecs": false, 403 | "memoryGiB": 4, 404 | "name": "ml.c5.large", 405 | "vcpuNum": 2 406 | }, 407 | { 408 | "_defaultOrder": 22, 409 | "_isFastLaunch": false, 410 | "category": "Compute optimized", 411 | "gpuNum": 0, 412 | "hideHardwareSpecs": false, 413 | "memoryGiB": 8, 414 | "name": "ml.c5.xlarge", 415 | "vcpuNum": 4 416 | }, 417 | { 418 | "_defaultOrder": 23, 419 | "_isFastLaunch": false, 420 | "category": "Compute optimized", 421 | "gpuNum": 0, 422 | "hideHardwareSpecs": false, 423 | "memoryGiB": 16, 424 | "name": "ml.c5.2xlarge", 425 | "vcpuNum": 8 426 | }, 427 | { 428 | "_defaultOrder": 24, 429 | "_isFastLaunch": false, 430 | "category": "Compute optimized", 431 | "gpuNum": 0, 432 | "hideHardwareSpecs": false, 433 | "memoryGiB": 32, 434 | "name": "ml.c5.4xlarge", 435 | "vcpuNum": 16 436 | }, 437 | { 438 | "_defaultOrder": 25, 439 | "_isFastLaunch": false, 440 | "category": "Compute optimized", 441 | "gpuNum": 0, 442 | "hideHardwareSpecs": false, 443 | "memoryGiB": 72, 444 | "name": "ml.c5.9xlarge", 445 | "vcpuNum": 36 446 | }, 447 | { 448 | "_defaultOrder": 26, 449 | "_isFastLaunch": false, 450 | "category": "Compute optimized", 451 | "gpuNum": 0, 452 | "hideHardwareSpecs": false, 453 | "memoryGiB": 96, 454 | "name": "ml.c5.12xlarge", 455 | "vcpuNum": 48 456 | }, 457 | { 458 | "_defaultOrder": 27, 459 | "_isFastLaunch": false, 460 | "category": "Compute optimized", 461 | "gpuNum": 0, 462 | "hideHardwareSpecs": false, 463 | "memoryGiB": 144, 464 | "name": "ml.c5.18xlarge", 465 | "vcpuNum": 72 466 | }, 467 | { 468 | "_defaultOrder": 28, 469 | "_isFastLaunch": false, 470 | "category": "Compute optimized", 471 | "gpuNum": 0, 472 | "hideHardwareSpecs": false, 473 | "memoryGiB": 192, 474 | "name": "ml.c5.24xlarge", 475 | "vcpuNum": 96 476 | }, 477 | { 478 | "_defaultOrder": 29, 479 | "_isFastLaunch": true, 480 | "category": "Accelerated computing", 481 | "gpuNum": 1, 482 | "hideHardwareSpecs": false, 483 | "memoryGiB": 16, 484 | "name": "ml.g4dn.xlarge", 485 | "vcpuNum": 4 486 | }, 487 | { 488 | "_defaultOrder": 30, 489 | "_isFastLaunch": false, 490 | "category": "Accelerated computing", 491 | "gpuNum": 1, 492 | "hideHardwareSpecs": false, 493 | "memoryGiB": 32, 494 | "name": "ml.g4dn.2xlarge", 495 | "vcpuNum": 8 496 | }, 497 | { 498 | "_defaultOrder": 31, 499 | "_isFastLaunch": false, 500 | "category": "Accelerated computing", 501 | "gpuNum": 1, 502 | "hideHardwareSpecs": false, 503 | "memoryGiB": 64, 504 | "name": "ml.g4dn.4xlarge", 505 | "vcpuNum": 16 506 | }, 507 | { 508 | "_defaultOrder": 32, 509 | "_isFastLaunch": false, 510 | "category": "Accelerated computing", 511 | "gpuNum": 1, 512 | "hideHardwareSpecs": false, 513 | "memoryGiB": 128, 514 | "name": "ml.g4dn.8xlarge", 515 | "vcpuNum": 32 516 | }, 517 | { 518 | "_defaultOrder": 33, 519 | "_isFastLaunch": false, 520 | "category": "Accelerated computing", 521 | "gpuNum": 4, 522 | "hideHardwareSpecs": false, 523 | "memoryGiB": 192, 524 | "name": "ml.g4dn.12xlarge", 525 | "vcpuNum": 48 526 | }, 527 | { 528 | "_defaultOrder": 34, 529 | "_isFastLaunch": false, 530 | "category": "Accelerated computing", 531 | "gpuNum": 1, 532 | "hideHardwareSpecs": false, 533 | "memoryGiB": 256, 534 | "name": "ml.g4dn.16xlarge", 535 | "vcpuNum": 64 536 | }, 537 | { 538 | "_defaultOrder": 35, 539 | "_isFastLaunch": false, 540 | "category": "Accelerated computing", 541 | "gpuNum": 1, 542 | "hideHardwareSpecs": false, 543 | "memoryGiB": 61, 544 | "name": "ml.p3.2xlarge", 545 | "vcpuNum": 8 546 | }, 547 | { 548 | "_defaultOrder": 36, 549 | "_isFastLaunch": false, 550 | "category": "Accelerated computing", 551 | "gpuNum": 4, 552 | "hideHardwareSpecs": false, 553 | "memoryGiB": 244, 554 | "name": "ml.p3.8xlarge", 555 | "vcpuNum": 32 556 | }, 557 | { 558 | "_defaultOrder": 37, 559 | "_isFastLaunch": false, 560 | "category": "Accelerated computing", 561 | "gpuNum": 8, 562 | "hideHardwareSpecs": false, 563 | "memoryGiB": 488, 564 | "name": "ml.p3.16xlarge", 565 | "vcpuNum": 64 566 | }, 567 | { 568 | "_defaultOrder": 38, 569 | "_isFastLaunch": false, 570 | "category": "Accelerated computing", 571 | "gpuNum": 8, 572 | "hideHardwareSpecs": false, 573 | "memoryGiB": 768, 574 | "name": "ml.p3dn.24xlarge", 575 | "vcpuNum": 96 576 | }, 577 | { 578 | "_defaultOrder": 39, 579 | "_isFastLaunch": false, 580 | "category": "Memory Optimized", 581 | "gpuNum": 0, 582 | "hideHardwareSpecs": false, 583 | "memoryGiB": 16, 584 | "name": "ml.r5.large", 585 | "vcpuNum": 2 586 | }, 587 | { 588 | "_defaultOrder": 40, 589 | "_isFastLaunch": false, 590 | "category": "Memory Optimized", 591 | "gpuNum": 0, 592 | "hideHardwareSpecs": false, 593 | "memoryGiB": 32, 594 | "name": "ml.r5.xlarge", 595 | "vcpuNum": 4 596 | }, 597 | { 598 | "_defaultOrder": 41, 599 | "_isFastLaunch": false, 600 | "category": "Memory Optimized", 601 | "gpuNum": 0, 602 | "hideHardwareSpecs": false, 603 | "memoryGiB": 64, 604 | "name": "ml.r5.2xlarge", 605 | "vcpuNum": 8 606 | }, 607 | { 608 | "_defaultOrder": 42, 609 | "_isFastLaunch": false, 610 | "category": "Memory Optimized", 611 | "gpuNum": 0, 612 | "hideHardwareSpecs": false, 613 | "memoryGiB": 128, 614 | "name": "ml.r5.4xlarge", 615 | "vcpuNum": 16 616 | }, 617 | { 618 | "_defaultOrder": 43, 619 | "_isFastLaunch": false, 620 | "category": "Memory Optimized", 621 | "gpuNum": 0, 622 | "hideHardwareSpecs": false, 623 | "memoryGiB": 256, 624 | "name": "ml.r5.8xlarge", 625 | "vcpuNum": 32 626 | }, 627 | { 628 | "_defaultOrder": 44, 629 | "_isFastLaunch": false, 630 | "category": "Memory Optimized", 631 | "gpuNum": 0, 632 | "hideHardwareSpecs": false, 633 | "memoryGiB": 384, 634 | "name": "ml.r5.12xlarge", 635 | "vcpuNum": 48 636 | }, 637 | { 638 | "_defaultOrder": 45, 639 | "_isFastLaunch": false, 640 | "category": "Memory Optimized", 641 | "gpuNum": 0, 642 | "hideHardwareSpecs": false, 643 | "memoryGiB": 512, 644 | "name": "ml.r5.16xlarge", 645 | "vcpuNum": 64 646 | }, 647 | { 648 | "_defaultOrder": 46, 649 | "_isFastLaunch": false, 650 | "category": "Memory Optimized", 651 | "gpuNum": 0, 652 | "hideHardwareSpecs": false, 653 | "memoryGiB": 768, 654 | "name": "ml.r5.24xlarge", 655 | "vcpuNum": 96 656 | }, 657 | { 658 | "_defaultOrder": 47, 659 | "_isFastLaunch": false, 660 | "category": "Accelerated computing", 661 | "gpuNum": 1, 662 | "hideHardwareSpecs": false, 663 | "memoryGiB": 16, 664 | "name": "ml.g5.xlarge", 665 | "vcpuNum": 4 666 | }, 667 | { 668 | "_defaultOrder": 48, 669 | "_isFastLaunch": false, 670 | "category": "Accelerated computing", 671 | "gpuNum": 1, 672 | "hideHardwareSpecs": false, 673 | "memoryGiB": 32, 674 | "name": "ml.g5.2xlarge", 675 | "vcpuNum": 8 676 | }, 677 | { 678 | "_defaultOrder": 49, 679 | "_isFastLaunch": false, 680 | "category": "Accelerated computing", 681 | "gpuNum": 1, 682 | "hideHardwareSpecs": false, 683 | "memoryGiB": 64, 684 | "name": "ml.g5.4xlarge", 685 | "vcpuNum": 16 686 | }, 687 | { 688 | "_defaultOrder": 50, 689 | "_isFastLaunch": false, 690 | "category": "Accelerated computing", 691 | "gpuNum": 1, 692 | "hideHardwareSpecs": false, 693 | "memoryGiB": 128, 694 | "name": "ml.g5.8xlarge", 695 | "vcpuNum": 32 696 | }, 697 | { 698 | "_defaultOrder": 51, 699 | "_isFastLaunch": false, 700 | "category": "Accelerated computing", 701 | "gpuNum": 1, 702 | "hideHardwareSpecs": false, 703 | "memoryGiB": 256, 704 | "name": "ml.g5.16xlarge", 705 | "vcpuNum": 64 706 | }, 707 | { 708 | "_defaultOrder": 52, 709 | "_isFastLaunch": false, 710 | "category": "Accelerated computing", 711 | "gpuNum": 4, 712 | "hideHardwareSpecs": false, 713 | "memoryGiB": 192, 714 | "name": "ml.g5.12xlarge", 715 | "vcpuNum": 48 716 | }, 717 | { 718 | "_defaultOrder": 53, 719 | "_isFastLaunch": false, 720 | "category": "Accelerated computing", 721 | "gpuNum": 4, 722 | "hideHardwareSpecs": false, 723 | "memoryGiB": 384, 724 | "name": "ml.g5.24xlarge", 725 | "vcpuNum": 96 726 | }, 727 | { 728 | "_defaultOrder": 54, 729 | "_isFastLaunch": false, 730 | "category": "Accelerated computing", 731 | "gpuNum": 8, 732 | "hideHardwareSpecs": false, 733 | "memoryGiB": 768, 734 | "name": "ml.g5.48xlarge", 735 | "vcpuNum": 192 736 | }, 737 | { 738 | "_defaultOrder": 55, 739 | "_isFastLaunch": false, 740 | "category": "Accelerated computing", 741 | "gpuNum": 8, 742 | "hideHardwareSpecs": false, 743 | "memoryGiB": 1152, 744 | "name": "ml.p4d.24xlarge", 745 | "vcpuNum": 96 746 | }, 747 | { 748 | "_defaultOrder": 56, 749 | "_isFastLaunch": false, 750 | "category": "Accelerated computing", 751 | "gpuNum": 8, 752 | "hideHardwareSpecs": false, 753 | "memoryGiB": 1152, 754 | "name": "ml.p4de.24xlarge", 755 | "vcpuNum": 96 756 | }, 757 | { 758 | "_defaultOrder": 57, 759 | "_isFastLaunch": false, 760 | "category": "Accelerated computing", 761 | "gpuNum": 0, 762 | "hideHardwareSpecs": false, 763 | "memoryGiB": 32, 764 | "name": "ml.trn1.2xlarge", 765 | "vcpuNum": 8 766 | }, 767 | { 768 | "_defaultOrder": 58, 769 | "_isFastLaunch": false, 770 | "category": "Accelerated computing", 771 | "gpuNum": 0, 772 | "hideHardwareSpecs": false, 773 | "memoryGiB": 512, 774 | "name": "ml.trn1.32xlarge", 775 | "vcpuNum": 128 776 | }, 777 | { 778 | "_defaultOrder": 59, 779 | "_isFastLaunch": false, 780 | "category": "Accelerated computing", 781 | "gpuNum": 0, 782 | "hideHardwareSpecs": false, 783 | "memoryGiB": 512, 784 | "name": "ml.trn1n.32xlarge", 785 | "vcpuNum": 128 786 | } 787 | ], 788 | "instance_type": "ml.t3.medium", 789 | "kernelspec": { 790 | "display_name": "Python 3 (Data Science 3.0)", 791 | "language": "python", 792 | "name": "python3__SAGEMAKER_INTERNAL__arn:aws:sagemaker:us-east-1:081325390199:image/sagemaker-data-science-310-v1" 793 | }, 794 | "language_info": { 795 | "codemirror_mode": { 796 | "name": "ipython", 797 | "version": 3 798 | }, 799 | "file_extension": ".py", 800 | "mimetype": "text/x-python", 801 | "name": "python", 802 | "nbconvert_exporter": "python", 803 | "pygments_lexer": "ipython3", 804 | "version": "3.10.6" 805 | } 806 | }, 807 | "nbformat": 4, 808 | "nbformat_minor": 5 809 | } 810 | -------------------------------------------------------------------------------- /cfn-templates/sagemaker-project-templates-roles.yaml: -------------------------------------------------------------------------------- 1 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # SPDX-License-Identifier: MIT-0 3 | 4 | AWSTemplateFormatVersion: 2010-09-09 5 | Description: This template creates the required IAM roles for SageMaker project templates 6 | 7 | Outputs: 8 | AmazonSageMakerServiceCatalogProductsLaunchRoleArn: 9 | Description: ProductsLaunchRole ARN 10 | Value: !If 11 | - ProductsLaunchRoleCondition 12 | - !GetAtt ProductsLaunchRole.Arn 13 | - !Sub 'arn:${AWS::Partition}:iam::${AWS::AccountId}:role/service-role/AmazonSageMakerServiceCatalogProductsLaunchRole' 14 | 15 | AmazonSageMakerServiceCatalogProductsUseRoleArn: 16 | Description: ProductsUseRole ARN 17 | Value: !If 18 | - ProductsUseRoleCondition 19 | - !GetAtt ProductsUseRole.Arn 20 | - !Sub 'arn:${AWS::Partition}:iam::${AWS::AccountId}:role/service-role/AmazonSageMakerServiceCatalogProductsUseRole' 21 | 22 | AmazonSageMakerServiceCatalogProductsCloudformationRoleArn: 23 | Description: AmazonSageMakerServiceCatalogProductsCloudformationRole ARN 24 | Value: !If 25 | - CloudFormationRoleCondition 26 | - !GetAtt CloudFormationRole.Arn 27 | - !Sub 'arn:${AWS::Partition}:iam::${AWS::AccountId}:role/service-role/AmazonSageMakerServiceCatalogProductsCloudformationRole' 28 | 29 | AmazonSageMakerServiceCatalogProductsCodeBuildRoleArn: 30 | Description: CodeBuildRole ARN 31 | Value: !If 32 | - CodeBuildRoleCondition 33 | - !GetAtt CodeBuildRole.Arn 34 | - !Sub 'arn:${AWS::Partition}:iam::${AWS::AccountId}:role/service-role/AmazonSageMakerServiceCatalogProductsCodeBuildRole' 35 | 36 | AmazonSageMakerServiceCatalogProductsCodePipelineRoleArn: 37 | Description: CodePipelineRole ARN 38 | Value: !If 39 | - CodePipelineRoleCondition 40 | - !GetAtt CodePipelineRole.Arn 41 | - !Sub 'arn:${AWS::Partition}:iam::${AWS::AccountId}:role/service-role/AmazonSageMakerServiceCatalogProductsCodePipelineRole' 42 | 43 | AmazonSageMakerServiceCatalogProductsEventsRoleArn: 44 | Description: EventsRole ARN 45 | Value: !If 46 | - EventsRoleCondition 47 | - !GetAtt EventsRole.Arn 48 | - !Sub 'arn:${AWS::Partition}:iam::${AWS::AccountId}:role/service-role/AmazonSageMakerServiceCatalogProductsEventsRole' 49 | 50 | AmazonSageMakerServiceCatalogProductsApiGatewayRoleArn: 51 | Description: ApiGatewayRole ARN 52 | Value: !If 53 | - ApiGatewayRoleCondition 54 | - !GetAtt ApiGatewayRole.Arn 55 | - !Sub 'arn:${AWS::Partition}:iam::${AWS::AccountId}:role/service-role/AmazonSageMakerServiceCatalogProductsApiGatewayRole' 56 | 57 | AmazonSageMakerServiceCatalogProductsFirehoseRoleArn: 58 | Description: FirehoseRole ARN 59 | Value: !If 60 | - FirehoseRoleCondition 61 | - !GetAtt FirehoseRole.Arn 62 | - !Sub 'arn:${AWS::Partition}:iam::${AWS::AccountId}:role/service-role/AmazonSageMakerServiceCatalogProductsFirehoseRole' 63 | 64 | AmazonSageMakerServiceCatalogProductsGlueRoleArn: 65 | Description: GlueRole ARN 66 | Value: !If 67 | - GlueRoleCondition 68 | - !GetAtt GlueRole.Arn 69 | - !Sub 'arn:${AWS::Partition}:iam::${AWS::AccountId}:role/service-role/AmazonSageMakerServiceCatalogProductsGlueRole' 70 | 71 | AmazonSageMakerServiceCatalogProductsLambdaRoleArn: 72 | Description: LambdaRole ARN 73 | Value: !If 74 | - LambdaRoleCondition 75 | - !GetAtt LambdaRole.Arn 76 | - !Sub 'arn:${AWS::Partition}:iam::${AWS::AccountId}:role/service-role/AmazonSageMakerServiceCatalogProductsLambdaRole' 77 | 78 | AmazonSageMakerServiceCatalogProductsExecutionRoleArn: 79 | Description: ProductsExecutionRole ARN 80 | Value: !If 81 | - ProductsExecutionRoleCondition 82 | - !GetAtt ProductsExecutionRole.Arn 83 | - !Sub 'arn:${AWS::Partition}:iam::${AWS::AccountId}:role/service-role/AmazonSageMakerServiceCatalogProductsExecutionRole' 84 | 85 | Parameters: 86 | 87 | CreateProductsLaunchRole: 88 | Description: Create AmazonSageMakerServiceCatalogProductsLaunchRole 89 | Type: String 90 | AllowedValues: 91 | - 'YES' 92 | - 'NO' 93 | Default: 'NO' 94 | 95 | CreateProductsUseRole: 96 | Description: Create AmazonSageMakerServiceCatalogProductsUseRole 97 | Type: String 98 | AllowedValues: 99 | - 'YES' 100 | - 'NO' 101 | Default: 'NO' 102 | 103 | CreateCloudFormationRole: 104 | Description: Create AmazonSageMakerServiceCatalogProductsCloudformationRole 105 | Type: String 106 | AllowedValues: 107 | - 'YES' 108 | - 'NO' 109 | Default: 'YES' 110 | 111 | CreateCodeBuildRole: 112 | Description: Create AmazonSageMakerServiceCatalogProductsCodeBuildRole 113 | Type: String 114 | AllowedValues: 115 | - 'YES' 116 | - 'NO' 117 | Default: 'YES' 118 | 119 | CreateCodePipelineRole: 120 | Description: Create AmazonSageMakerServiceCatalogProductsCodePipelineRole 121 | Type: String 122 | AllowedValues: 123 | - 'YES' 124 | - 'NO' 125 | Default: 'YES' 126 | 127 | CreateEventsRole: 128 | Description: Create AmazonSageMakerServiceCatalogProductsEventsRole 129 | Type: String 130 | AllowedValues: 131 | - 'YES' 132 | - 'NO' 133 | Default: 'YES' 134 | 135 | CreateApiGatewayRole: 136 | Description: Create AmazonSageMakerServiceCatalogProductsApiGatewayRole 137 | Type: String 138 | AllowedValues: 139 | - 'YES' 140 | - 'NO' 141 | Default: 'YES' 142 | 143 | CreateFirehoseRole: 144 | Description: Create AmazonSageMakerServiceCatalogProductsFirehoseRole 145 | Type: String 146 | AllowedValues: 147 | - 'YES' 148 | - 'NO' 149 | Default: 'YES' 150 | 151 | CreateGlueRole: 152 | Description: Create AmazonSageMakerServiceCatalogProductsGlueRole 153 | Type: String 154 | AllowedValues: 155 | - 'YES' 156 | - 'NO' 157 | Default: 'YES' 158 | 159 | CreateLambdaRole: 160 | Description: Create AmazonSageMakerServiceCatalogProductsLambdaRole 161 | Type: String 162 | AllowedValues: 163 | - 'YES' 164 | - 'NO' 165 | Default: 'YES' 166 | 167 | CreateProductsExecutionRole: 168 | Description: Create AmazonSageMakerServiceCatalogProductsExecutionRole 169 | Type: String 170 | AllowedValues: 171 | - 'YES' 172 | - 'NO' 173 | Default: 'YES' 174 | 175 | Conditions: 176 | ProductsLaunchRoleCondition: !Equals [ !Ref CreateProductsLaunchRole, 'YES' ] 177 | ProductsUseRoleCondition: !Equals [ !Ref CreateProductsUseRole, 'YES' ] 178 | CloudFormationRoleCondition: !Equals [ !Ref CreateCloudFormationRole, 'YES' ] 179 | CodeBuildRoleCondition: !Equals [ !Ref CreateCodeBuildRole, 'YES' ] 180 | CodePipelineRoleCondition: !Equals [ !Ref CreateCodePipelineRole, 'YES' ] 181 | EventsRoleCondition: !Equals [ !Ref CreateEventsRole, 'YES' ] 182 | ApiGatewayRoleCondition: !Equals [ !Ref CreateApiGatewayRole, 'YES' ] 183 | FirehoseRoleCondition: !Equals [ !Ref CreateFirehoseRole, 'YES' ] 184 | GlueRoleCondition: !Equals [ !Ref CreateGlueRole, 'YES' ] 185 | LambdaRoleCondition: !Equals [ !Ref CreateLambdaRole, 'YES' ] 186 | ProductsExecutionRoleCondition: !Equals [ !Ref CreateProductsExecutionRole, 'YES' ] 187 | 188 | Resources: 189 | 190 | ProductsLaunchRole: 191 | Type: "AWS::IAM::Role" 192 | Condition: ProductsLaunchRoleCondition 193 | DeletionPolicy: Retain 194 | UpdateReplacePolicy: Retain 195 | Properties: 196 | RoleName: AmazonSageMakerServiceCatalogProductsLaunchRole 197 | Description: "SageMaker role created from the SageMaker AWS Management Console. This role has the permissions required to launch the Amazon SageMaker portfolio of products from AWS ServiceCatalog." 198 | AssumeRolePolicyDocument: 199 | Version: "2012-10-17" 200 | Statement: 201 | - Effect: "Allow" 202 | Principal: 203 | Service: 204 | - servicecatalog.amazonaws.com 205 | - codepipeline.amazonaws.com 206 | - lambda.amazonaws.com 207 | Action: "sts:AssumeRole" 208 | Policies: 209 | - PolicyName: SageMakerAddTags 210 | PolicyDocument: 211 | Version: "2012-10-17" 212 | Statement: 213 | - 214 | Effect: Allow 215 | Action: 216 | - sagemaker:AddTags 217 | Resource: "*" 218 | - PolicyName: CodeStarConnectionsPass 219 | PolicyDocument: 220 | Version: '2012-10-17' 221 | Statement: 222 | - 223 | Effect: Allow 224 | Action: 225 | - codestar-connections:PassConnection 226 | Resource: "*" 227 | Condition: 228 | ForAllValues:StringEquals: 229 | codestar-connections:PassedToService: codepipeline.amazonaws.com 230 | Path: "/service-role/" 231 | MaxSessionDuration: 3600 232 | ManagedPolicyArns: 233 | - 'arn:aws:iam::aws:policy/AmazonSageMakerAdmin-ServiceCatalogProductsServiceRolePolicy' 234 | - 'arn:aws:iam::aws:policy/AWSCodeStarFullAccess' 235 | 236 | ProductsUseRole: 237 | Type: "AWS::IAM::Role" 238 | Condition: ProductsUseRoleCondition 239 | DeletionPolicy: Retain 240 | UpdateReplacePolicy: Retain 241 | Properties: 242 | RoleName: AmazonSageMakerServiceCatalogProductsUseRole 243 | Description: "SageMaker role created from the SageMaker AWS Management Console. This role has the permissions required to use the Amazon SageMaker portfolio of products from AWS ServiceCatalog." 244 | Path: "/service-role/" 245 | MaxSessionDuration: 3600 246 | ManagedPolicyArns: 247 | - 'arn:aws:iam::aws:policy/AmazonEC2ReadOnlyAccess' 248 | - 'arn:aws:iam::aws:policy/AWSCodeStarFullAccess' 249 | AssumeRolePolicyDocument: 250 | Version: "2012-10-17" 251 | Statement: 252 | - Effect: "Allow" 253 | Principal: 254 | Service: 255 | - "codepipeline.amazonaws.com" 256 | - "cloudformation.amazonaws.com" 257 | - "firehose.amazonaws.com" 258 | - "codebuild.amazonaws.com" 259 | - "sagemaker.amazonaws.com" 260 | - "states.amazonaws.com" 261 | - "lambda.amazonaws.com" 262 | - "events.amazonaws.com" 263 | - "apigateway.amazonaws.com" 264 | - "glue.amazonaws.com" 265 | Action: "sts:AssumeRole" 266 | Policies: 267 | - PolicyName: AmazonSageMakerServiceCatalogProductsUseRolePolicy 268 | PolicyDocument: 269 | Version: 2012-10-17 270 | Statement: 271 | - 272 | Action: 273 | - sts:AssumeRole 274 | Resource: 275 | - 'arn:aws:iam::*:role/*SageMakerModelExecution*' 276 | Effect: Allow 277 | - 278 | Action: 279 | - cloudformation:Delete* 280 | - cloudformation:Get* 281 | - cloudformation:Create* 282 | - cloudformation:Update* 283 | - cloudformation:List* 284 | - cloudformation:Describe* 285 | - cloudformation:ExecuteChangeSet 286 | - cloudformation:SetStackPolicy 287 | Resource: 288 | - arn:aws:cloudformation:*:*:stack/sagemaker-* 289 | - arn:aws:cloudformation:*:*:stackset/sagemaker-* 290 | - arn:aws:cloudformation:*:*:type/resource/* 291 | - arn:aws:cloudformation:*:*:stackset-target/sagemaker-* 292 | Effect: Allow 293 | - 294 | Action: 295 | - cloudformation:GetTemplate 296 | - cloudformation:GetTemplateSummary 297 | - cloudformation:TagResource 298 | Resource: 299 | - '*' 300 | Effect: Allow 301 | - 302 | Action: 303 | - cloudwatch:PutMetricData 304 | Resource: 305 | - !Sub 'arn:aws:cloudwatch:*:${AWS::AccountId}:*' 306 | Effect: Allow 307 | - 308 | Action: 309 | - codebuild:BatchGetBuilds 310 | - codebuild:StartBuild 311 | Resource: 312 | - arn:aws:codebuild:*:*:project/sagemaker-* 313 | - arn:aws:codebuild:*:*:build/sagemaker-* 314 | Effect: Allow 315 | - 316 | Action: 317 | - codebuild:ListCuratedEnvironmentImages 318 | Resource: 319 | - '*' 320 | Effect: Allow 321 | - 322 | Action: 323 | - codebuild:CreateReportGroup 324 | - codebuild:CreateReport 325 | - codebuild:UpdateReport 326 | - codebuild:BatchPutTestCases 327 | - codebuild:BatchPutCodeCoverages 328 | Resource: !Sub 'arn:aws:codebuild:*:${AWS::AccountId}:report-group/sagemaker*' 329 | Effect: Allow 330 | - 331 | Action: 332 | - codecommit:CancelUploadArchive 333 | - codecommit:GetBranch 334 | - codecommit:GetCommit 335 | - codecommit:GetUploadArchiveStatus 336 | - codecommit:UploadArchive 337 | Resource: arn:aws:codecommit:*:*:sagemaker-* 338 | Effect: Allow 339 | - 340 | Action: 341 | - codepipeline:StartPipelineExecution 342 | Resource: arn:aws:codepipeline:*:*:sagemaker-* 343 | Effect: Allow 344 | - 345 | Action: 346 | - ec2:CreateNetworkInterface 347 | - ec2:DeleteNetworkInterface 348 | Resource: 349 | - !Sub 'arn:aws:ec2:*:${AWS::AccountId}:*' 350 | Effect: Allow 351 | - 352 | Action: 353 | - ec2:CreateNetworkInterfacePermission 354 | Resource: !Sub "arn:aws:ec2:*:${AWS::AccountId}:network-interface/*" 355 | Effect: Allow 356 | - 357 | Action: 358 | - ecr:BatchCheckLayerAvailability 359 | - ecr:BatchGetImage 360 | - ecr:Describe* 361 | - ecr:ListImages 362 | - ecr:GetAuthorizationToken 363 | - ecr:GetDownloadUrlForLayer 364 | Resource: 365 | - '*' 366 | Effect: Allow 367 | - 368 | Effect: Allow 369 | Action: 370 | - ecr:BatchDeleteImage 371 | - ecr:CompleteLayerUpload 372 | - ecr:CreateRepository 373 | - ecr:DeleteRepository 374 | - ecr:InitiateLayerUpload 375 | - ecr:PutImage 376 | - ecr:UploadLayerPart 377 | Resource: 378 | - arn:aws:ecr:*:*:repository/sagemaker-* 379 | - 380 | Action: 381 | - events:DeleteRule 382 | - events:DescribeRule 383 | - events:PutRule 384 | - events:PutTargets 385 | - events:RemoveTargets 386 | Resource: 387 | - arn:aws:events:*:*:rule/sagemaker-* 388 | Effect: Allow 389 | - 390 | Action: 391 | - firehose:PutRecord 392 | - firehose:PutRecordBatch 393 | Resource: arn:aws:firehose:*:*:deliverystream/sagemaker-* 394 | Effect: Allow 395 | - 396 | Action: 397 | - glue:BatchCreatePartition 398 | - glue:BatchDeletePartition 399 | - glue:BatchDeleteTable 400 | - glue:BatchDeleteTableVersion 401 | - glue:BatchGetPartition 402 | - glue:CreateDatabase 403 | - glue:CreatePartition 404 | - glue:CreateTable 405 | - glue:DeletePartition 406 | - glue:DeleteTable 407 | - glue:DeleteTableVersion 408 | - glue:GetDatabase 409 | - glue:GetPartition 410 | - glue:GetPartitions 411 | - glue:GetTable 412 | - glue:GetTables 413 | - glue:GetTableVersion 414 | - glue:GetTableVersions 415 | - glue:SearchTables 416 | - glue:UpdatePartition 417 | - glue:UpdateTable 418 | Resource: 419 | - arn:aws:glue:*:*:catalog 420 | - arn:aws:glue:*:*:database/default 421 | - arn:aws:glue:*:*:database/global_temp 422 | - arn:aws:glue:*:*:database/sagemaker-* 423 | - arn:aws:glue:*:*:table/sagemaker-* 424 | - arn:aws:glue:*:*:tableVersion/sagemaker-* 425 | Effect: Allow 426 | - 427 | Action: 428 | - iam:PassRole 429 | Resource: 430 | - arn:aws:iam::*:role/service-role/AmazonSageMakerServiceCatalog* 431 | Effect: Allow 432 | - 433 | Effect: Allow 434 | Action: 435 | - lambda:InvokeFunction 436 | Resource: 437 | - arn:aws:lambda:*:*:function:sagemaker-* 438 | - 439 | Action: 440 | - logs:CreateLogDelivery 441 | - logs:CreateLogGroup 442 | - logs:CreateLogStream 443 | - logs:DeleteLogDelivery 444 | - logs:Describe* 445 | - logs:GetLogDelivery 446 | - logs:GetLogEvents 447 | - logs:ListLogDeliveries 448 | - logs:PutLogEvents 449 | - logs:PutResourcePolicy 450 | - logs:UpdateLogDelivery 451 | Resource: 452 | - !Sub 'arn:aws:logs:*:${AWS::AccountId}:*' 453 | Effect: Allow 454 | - 455 | Effect: Allow 456 | Action: 457 | - s3:CreateBucket 458 | - s3:GetBucketAcl 459 | - s3:GetBucketCors 460 | - s3:GetBucketLocation 461 | - s3:ListAllMyBuckets 462 | - s3:ListBucket 463 | - s3:ListBucketMultipartUploads 464 | - s3:PutBucketCors 465 | - s3:AbortMultipartUpload 466 | - s3:DeleteObject 467 | - s3:GetObject 468 | - s3:GetObjectVersion 469 | - s3:PutObject 470 | Resource: 471 | - 'arn:aws:s3:::aws-glue-*' 472 | - 'arn:aws:s3:::sagemaker-*' 473 | - 'arn:aws:s3:::sm-mlops-cp-*' 474 | - !Sub 'arn:aws:s3:::*-${AWS::AccountId}-data*' 475 | - !Sub 'arn:aws:s3:::*-${AWS::AccountId}-data*/*' 476 | - !Sub 'arn:aws:s3:::*-${AWS::AccountId}-models*' 477 | - !Sub 'arn:aws:s3:::*-${AWS::AccountId}-models*/*' 478 | - 479 | Effect: Allow 480 | Action: 481 | - sagemaker:* 482 | NotResource: 483 | - arn:aws:sagemaker:*:*:domain/* 484 | - arn:aws:sagemaker:*:*:user-profile/* 485 | - arn:aws:sagemaker:*:*:app/* 486 | - arn:aws:sagemaker:*:*:flow-definition/* 487 | - 488 | Action: 489 | - 'sagemaker:List*' 490 | Resource: 491 | - '*' 492 | Effect: Allow 493 | - 494 | Effect: Allow 495 | Action: 496 | - sagemaker:Describe* 497 | - sagemaker:ListTags 498 | Resource: 499 | - arn:aws:sagemaker:*:*:domain/* 500 | - 501 | Action: 502 | - states:DescribeExecution 503 | - states:DescribeStateMachine 504 | - states:DescribeStateMachineForExecution 505 | - states:GetExecutionHistory 506 | - states:ListExecutions 507 | - states:ListTagsForResource 508 | - states:StartExecution 509 | - states:StopExecution 510 | - states:TagResource 511 | - states:UntagResource 512 | - states:UpdateStateMachine 513 | Resource: 514 | - arn:aws:states:*:*:stateMachine:sagemaker-* 515 | - arn:aws:states:*:*:execution:sagemaker-*:* 516 | Effect: Allow 517 | - 518 | Action: 519 | - states:ListStateMachines 520 | Resource: 521 | - '*' 522 | Effect: Allow 523 | - 524 | Action: 525 | - codestar-connections:UseConnection 526 | Resource: 527 | - arn:aws:codestar-connections:*:*:connection/* 528 | Condition: 529 | StringEqualsIgnoreCase: 530 | 'aws:ResourceTag/sagemaker': 'true' 531 | Effect: Allow 532 | - 533 | Action: 534 | - 'kms:CreateGrant' 535 | - 'kms:Decrypt' 536 | - 'kms:DescribeKey' 537 | - 'kms:Encrypt' 538 | - 'kms:GenerateDataKey' 539 | - 'kms:ListAliases' 540 | Resource: 541 | - '*' 542 | Effect: Allow 543 | - 544 | Action: 545 | - 'ssm:GetParameter*' 546 | Resource: !Sub 'arn:aws:ssm:*:${AWS::AccountId}:parameter/*' 547 | Effect: Allow 548 | 549 | 550 | CloudFormationRole: 551 | Type: "AWS::IAM::Role" 552 | Condition: CloudFormationRoleCondition 553 | Properties: 554 | RoleName: AmazonSageMakerServiceCatalogProductsCloudformationRole 555 | Description: "CloudFormationRole" 556 | AssumeRolePolicyDocument: 557 | Version: "2012-10-17" 558 | Statement: 559 | - Effect: "Allow" 560 | Principal: 561 | Service: "cloudformation.amazonaws.com" 562 | Action: "sts:AssumeRole" 563 | Path: "/service-role/" 564 | MaxSessionDuration: 3600 565 | ManagedPolicyArns: 566 | - !Sub "arn:${AWS::Partition}:iam::aws:policy/service-role/AmazonSageMakerServiceCatalogProductsCloudformationServiceRolePolicy" 567 | 568 | CodeBuildRole: 569 | Type: "AWS::IAM::Role" 570 | Condition: CodeBuildRoleCondition 571 | Properties: 572 | RoleName: AmazonSageMakerServiceCatalogProductsCodeBuildRole 573 | Description: "CodeBuildRole" 574 | AssumeRolePolicyDocument: 575 | Version: "2012-10-17" 576 | Statement: 577 | - Effect: "Allow" 578 | Principal: 579 | Service: "codebuild.amazonaws.com" 580 | Action: "sts:AssumeRole" 581 | Path: "/service-role/" 582 | MaxSessionDuration: 3600 583 | ManagedPolicyArns: 584 | - !Sub "arn:${AWS::Partition}:iam::aws:policy/AmazonSageMakerServiceCatalogProductsCodeBuildServiceRolePolicy" 585 | 586 | CodePipelineRole: 587 | Type: "AWS::IAM::Role" 588 | Condition: CodePipelineRoleCondition 589 | Properties: 590 | RoleName: AmazonSageMakerServiceCatalogProductsCodePipelineRole 591 | Description: "CodePipelineRole" 592 | AssumeRolePolicyDocument: 593 | Version: "2012-10-17" 594 | Statement: 595 | - Effect: "Allow" 596 | Principal: 597 | Service: "codepipeline.amazonaws.com" 598 | Action: "sts:AssumeRole" 599 | Policies: 600 | - PolicyName: CodeStar 601 | PolicyDocument: 602 | Version: "2012-10-17" 603 | Statement: 604 | - 605 | Effect: Allow 606 | Action: 607 | - codestar-connections:UseConnection 608 | Resource: "*" 609 | Path: "/service-role/" 610 | MaxSessionDuration: 3600 611 | ManagedPolicyArns: 612 | - !Sub "arn:${AWS::Partition}:iam::aws:policy/service-role/AmazonSageMakerServiceCatalogProductsCodePipelineServiceRolePolicy" 613 | - 'arn:aws:iam::aws:policy/AWSCodeStarFullAccess' 614 | 615 | EventsRole: 616 | Type: "AWS::IAM::Role" 617 | Condition: EventsRoleCondition 618 | Properties: 619 | RoleName: AmazonSageMakerServiceCatalogProductsEventsRole 620 | Description: "EventsRole" 621 | AssumeRolePolicyDocument: 622 | Version: "2012-10-17" 623 | Statement: 624 | - Effect: "Allow" 625 | Principal: 626 | Service: "events.amazonaws.com" 627 | Action: "sts:AssumeRole" 628 | Path: "/service-role/" 629 | MaxSessionDuration: 3600 630 | ManagedPolicyArns: 631 | - !Sub "arn:${AWS::Partition}:iam::aws:policy/service-role/AmazonSageMakerServiceCatalogProductsEventsServiceRolePolicy" 632 | 633 | ApiGatewayRole: 634 | Type: "AWS::IAM::Role" 635 | Condition: ApiGatewayRoleCondition 636 | Properties: 637 | RoleName: AmazonSageMakerServiceCatalogProductsApiGatewayRole 638 | Description: "ApiGatewayRole" 639 | AssumeRolePolicyDocument: 640 | Version: "2012-10-17" 641 | Statement: 642 | - Effect: "Allow" 643 | Principal: 644 | Service: "apigateway.amazonaws.com" 645 | Action: "sts:AssumeRole" 646 | Path: "/service-role/" 647 | MaxSessionDuration: 3600 648 | ManagedPolicyArns: 649 | - !Sub "arn:${AWS::Partition}:iam::aws:policy/service-role/AmazonSageMakerServiceCatalogProductsApiGatewayServiceRolePolicy" 650 | 651 | FirehoseRole: 652 | Type: "AWS::IAM::Role" 653 | Condition: FirehoseRoleCondition 654 | Properties: 655 | RoleName: AmazonSageMakerServiceCatalogProductsFirehoseRole 656 | Description: "FirehoseRole" 657 | AssumeRolePolicyDocument: 658 | Version: "2012-10-17" 659 | Statement: 660 | - Effect: "Allow" 661 | Principal: 662 | Service: "firehose.amazonaws.com" 663 | Action: "sts:AssumeRole" 664 | Path: "/service-role/" 665 | MaxSessionDuration: 3600 666 | ManagedPolicyArns: 667 | - !Sub "arn:${AWS::Partition}:iam::aws:policy/service-role/AmazonSageMakerServiceCatalogProductsFirehoseServiceRolePolicy" 668 | 669 | GlueRole: 670 | Type: "AWS::IAM::Role" 671 | Condition: GlueRoleCondition 672 | Properties: 673 | RoleName: AmazonSageMakerServiceCatalogProductsGlueRole 674 | Description: "GlueRole" 675 | AssumeRolePolicyDocument: 676 | Version: "2012-10-17" 677 | Statement: 678 | - Effect: "Allow" 679 | Principal: 680 | Service: "glue.amazonaws.com" 681 | Action: "sts:AssumeRole" 682 | Path: "/service-role/" 683 | MaxSessionDuration: 3600 684 | ManagedPolicyArns: 685 | - !Sub "arn:${AWS::Partition}:iam::aws:policy/service-role/AmazonSageMakerServiceCatalogProductsGlueServiceRolePolicy" 686 | 687 | LambdaRole: 688 | Type: "AWS::IAM::Role" 689 | Condition: LambdaRoleCondition 690 | Properties: 691 | RoleName: AmazonSageMakerServiceCatalogProductsLambdaRole 692 | Description: "LambdaRole" 693 | AssumeRolePolicyDocument: 694 | Version: "2012-10-17" 695 | Statement: 696 | - Effect: "Allow" 697 | Principal: 698 | Service: "lambda.amazonaws.com" 699 | Action: "sts:AssumeRole" 700 | Path: "/service-role/" 701 | MaxSessionDuration: 3600 702 | ManagedPolicyArns: 703 | - !Sub "arn:${AWS::Partition}:iam::aws:policy/service-role/AmazonSageMakerServiceCatalogProductsLambdaServiceRolePolicy" 704 | 705 | ProductsExecutionRole: 706 | Type: "AWS::IAM::Role" 707 | Condition: ProductsExecutionRoleCondition 708 | Properties: 709 | RoleName: AmazonSageMakerServiceCatalogProductsExecutionRole 710 | Description: "ProductsExecutionRole" 711 | AssumeRolePolicyDocument: 712 | Version: "2012-10-17" 713 | Statement: 714 | - Effect: "Allow" 715 | Principal: 716 | Service: "sagemaker.amazonaws.com" 717 | Action: "sts:AssumeRole" 718 | Path: "/service-role/" 719 | MaxSessionDuration: 3600 720 | ManagedPolicyArns: 721 | - !Sub "arn:${AWS::Partition}:iam::aws:policy/AmazonSageMakerFullAccess" -------------------------------------------------------------------------------- /img/MLOps-with-SageMaker-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-from-idea-to-production/b5323e2ed799c93e1391f240698803b9f8b80d62/img/MLOps-with-SageMaker-small.png -------------------------------------------------------------------------------- /img/ab-testing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-from-idea-to-production/b5323e2ed799c93e1391f240698803b9f8b80d62/img/ab-testing.png -------------------------------------------------------------------------------- /img/approve-deployment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-from-idea-to-production/b5323e2ed799c93e1391f240698803b9f8b80d62/img/approve-deployment.png -------------------------------------------------------------------------------- /img/aws-console-sagemaker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-from-idea-to-production/b5323e2ed799c93e1391f240698803b9f8b80d62/img/aws-console-sagemaker.png -------------------------------------------------------------------------------- /img/cfn-ack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-from-idea-to-production/b5323e2ed799c93e1391f240698803b9f8b80d62/img/cfn-ack.png -------------------------------------------------------------------------------- /img/cfn-stack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-from-idea-to-production/b5323e2ed799c93e1391f240698803b9f8b80d62/img/cfn-stack.png -------------------------------------------------------------------------------- /img/cicd-project-e2e.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-from-idea-to-production/b5323e2ed799c93e1391f240698803b9f8b80d62/img/cicd-project-e2e.png -------------------------------------------------------------------------------- /img/code-connection-arn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-from-idea-to-production/b5323e2ed799c93e1391f240698803b9f8b80d62/img/code-connection-arn.png -------------------------------------------------------------------------------- /img/code-connection-tags.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-from-idea-to-production/b5323e2ed799c93e1391f240698803b9f8b80d62/img/code-connection-tags.png -------------------------------------------------------------------------------- /img/codebuild-buildspec-edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-from-idea-to-production/b5323e2ed799c93e1391f240698803b9f8b80d62/img/codebuild-buildspec-edit.png -------------------------------------------------------------------------------- /img/codebuild-env-variables.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-from-idea-to-production/b5323e2ed799c93e1391f240698803b9f8b80d62/img/codebuild-env-variables.png -------------------------------------------------------------------------------- /img/comparing-runs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-from-idea-to-production/b5323e2ed799c93e1391f240698803b9f8b80d62/img/comparing-runs.png -------------------------------------------------------------------------------- /img/connection-permissions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-from-idea-to-production/b5323e2ed799c93e1391f240698803b9f8b80d62/img/connection-permissions.png -------------------------------------------------------------------------------- /img/container-anatomy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-from-idea-to-production/b5323e2ed799c93e1391f240698803b9f8b80d62/img/container-anatomy.png -------------------------------------------------------------------------------- /img/create-mlops-project-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-from-idea-to-production/b5323e2ed799c93e1391f240698803b9f8b80d62/img/create-mlops-project-2.png -------------------------------------------------------------------------------- /img/create-mlops-project-deploy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-from-idea-to-production/b5323e2ed799c93e1391f240698803b9f8b80d62/img/create-mlops-project-deploy.png -------------------------------------------------------------------------------- /img/create-mlops-project.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-from-idea-to-production/b5323e2ed799c93e1391f240698803b9f8b80d62/img/create-mlops-project.png -------------------------------------------------------------------------------- /img/crete-connection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-from-idea-to-production/b5323e2ed799c93e1391f240698803b9f8b80d62/img/crete-connection.png -------------------------------------------------------------------------------- /img/data-monitoring-architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-from-idea-to-production/b5323e2ed799c93e1391f240698803b9f8b80d62/img/data-monitoring-architecture.png -------------------------------------------------------------------------------- /img/data-processing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-from-idea-to-production/b5323e2ed799c93e1391f240698803b9f8b80d62/img/data-processing.png -------------------------------------------------------------------------------- /img/deploy-staging-review.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-from-idea-to-production/b5323e2ed799c93e1391f240698803b9f8b80d62/img/deploy-staging-review.png -------------------------------------------------------------------------------- /img/deploystaging-config.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-from-idea-to-production/b5323e2ed799c93e1391f240698803b9f8b80d62/img/deploystaging-config.png -------------------------------------------------------------------------------- /img/enable-sagemaker-projects.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-from-idea-to-production/b5323e2ed799c93e1391f240698803b9f8b80d62/img/enable-sagemaker-projects.png -------------------------------------------------------------------------------- /img/endpoint-details-data-capture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-from-idea-to-production/b5323e2ed799c93e1391f240698803b9f8b80d62/img/endpoint-details-data-capture.png -------------------------------------------------------------------------------- /img/endpoint-prod-creating.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-from-idea-to-production/b5323e2ed799c93e1391f240698803b9f8b80d62/img/endpoint-prod-creating.png -------------------------------------------------------------------------------- /img/endpoint-staging-creating.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-from-idea-to-production/b5323e2ed799c93e1391f240698803b9f8b80d62/img/endpoint-staging-creating.png -------------------------------------------------------------------------------- /img/experiment-mlflow-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-from-idea-to-production/b5323e2ed799c93e1391f240698803b9f8b80d62/img/experiment-mlflow-2.png -------------------------------------------------------------------------------- /img/experiment-mlflow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-from-idea-to-production/b5323e2ed799c93e1391f240698803b9f8b80d62/img/experiment-mlflow.png -------------------------------------------------------------------------------- /img/experiments-studio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-from-idea-to-production/b5323e2ed799c93e1391f240698803b9f8b80d62/img/experiments-studio.png -------------------------------------------------------------------------------- /img/feature-store-studio-ui.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-from-idea-to-production/b5323e2ed799c93e1391f240698803b9f8b80d62/img/feature-store-studio-ui.png -------------------------------------------------------------------------------- /img/github-connection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-from-idea-to-production/b5323e2ed799c93e1391f240698803b9f8b80d62/img/github-connection.png -------------------------------------------------------------------------------- /img/github-model-build.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-from-idea-to-production/b5323e2ed799c93e1391f240698803b9f8b80d62/img/github-model-build.png -------------------------------------------------------------------------------- /img/github-model-deploy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-from-idea-to-production/b5323e2ed799c93e1391f240698803b9f8b80d62/img/github-model-deploy.png -------------------------------------------------------------------------------- /img/github-repo-qrcode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-from-idea-to-production/b5323e2ed799c93e1391f240698803b9f8b80d62/img/github-repo-qrcode.png -------------------------------------------------------------------------------- /img/install-github-app.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-from-idea-to-production/b5323e2ed799c93e1391f240698803b9f8b80d62/img/install-github-app.png -------------------------------------------------------------------------------- /img/jupyterlab-app-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-from-idea-to-production/b5323e2ed799c93e1391f240698803b9f8b80d62/img/jupyterlab-app-image.png -------------------------------------------------------------------------------- /img/jupyterlab-app.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-from-idea-to-production/b5323e2ed799c93e1391f240698803b9f8b80d62/img/jupyterlab-app.png -------------------------------------------------------------------------------- /img/launch-studio-classic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-from-idea-to-production/b5323e2ed799c93e1391f240698803b9f8b80d62/img/launch-studio-classic.png -------------------------------------------------------------------------------- /img/launch-studio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-from-idea-to-production/b5323e2ed799c93e1391f240698803b9f8b80d62/img/launch-studio.png -------------------------------------------------------------------------------- /img/mlflow-open.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-from-idea-to-production/b5323e2ed799c93e1391f240698803b9f8b80d62/img/mlflow-open.png -------------------------------------------------------------------------------- /img/mlflow-pipeline-executions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-from-idea-to-production/b5323e2ed799c93e1391f240698803b9f8b80d62/img/mlflow-pipeline-executions.png -------------------------------------------------------------------------------- /img/mlops-model-build-train.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-from-idea-to-production/b5323e2ed799c93e1391f240698803b9f8b80d62/img/mlops-model-build-train.png -------------------------------------------------------------------------------- /img/mlops-model-deploy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-from-idea-to-production/b5323e2ed799c93e1391f240698803b9f8b80d62/img/mlops-model-deploy.png -------------------------------------------------------------------------------- /img/mlops-project-name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-from-idea-to-production/b5323e2ed799c93e1391f240698803b9f8b80d62/img/mlops-project-name.png -------------------------------------------------------------------------------- /img/model-fig-mlflow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-from-idea-to-production/b5323e2ed799c93e1391f240698803b9f8b80d62/img/model-fig-mlflow.png -------------------------------------------------------------------------------- /img/model-monitor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-from-idea-to-production/b5323e2ed799c93e1391f240698803b9f8b80d62/img/model-monitor.png -------------------------------------------------------------------------------- /img/model-monitoring-architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-from-idea-to-production/b5323e2ed799c93e1391f240698803b9f8b80d62/img/model-monitoring-architecture.png -------------------------------------------------------------------------------- /img/model-quality-monitor-execution.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-from-idea-to-production/b5323e2ed799c93e1391f240698803b9f8b80d62/img/model-quality-monitor-execution.png -------------------------------------------------------------------------------- /img/model-registry-version-approved.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-from-idea-to-production/b5323e2ed799c93e1391f240698803b9f8b80d62/img/model-registry-version-approved.png -------------------------------------------------------------------------------- /img/model-version-details-annotated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-from-idea-to-production/b5323e2ed799c93e1391f240698803b9f8b80d62/img/model-version-details-annotated.png -------------------------------------------------------------------------------- /img/model-version-details.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-from-idea-to-production/b5323e2ed799c93e1391f240698803b9f8b80d62/img/model-version-details.png -------------------------------------------------------------------------------- /img/models-mlflow-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-from-idea-to-production/b5323e2ed799c93e1391f240698803b9f8b80d62/img/models-mlflow-2.png -------------------------------------------------------------------------------- /img/models-mlflow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-from-idea-to-production/b5323e2ed799c93e1391f240698803b9f8b80d62/img/models-mlflow.png -------------------------------------------------------------------------------- /img/notebook-as-sm-job-parameters.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-from-idea-to-production/b5323e2ed799c93e1391f240698803b9f8b80d62/img/notebook-as-sm-job-parameters.png -------------------------------------------------------------------------------- /img/notebook-as-sm-job-run.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-from-idea-to-production/b5323e2ed799c93e1391f240698803b9f8b80d62/img/notebook-as-sm-job-run.png -------------------------------------------------------------------------------- /img/pipeline-execution-graph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-from-idea-to-production/b5323e2ed799c93e1391f240698803b9f8b80d62/img/pipeline-execution-graph.png -------------------------------------------------------------------------------- /img/pipeline-graph-with-transform.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-from-idea-to-production/b5323e2ed799c93e1391f240698803b9f8b80d62/img/pipeline-graph-with-transform.png -------------------------------------------------------------------------------- /img/pipeline-graph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-from-idea-to-production/b5323e2ed799c93e1391f240698803b9f8b80d62/img/pipeline-graph.png -------------------------------------------------------------------------------- /img/pipelines-list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-from-idea-to-production/b5323e2ed799c93e1391f240698803b9f8b80d62/img/pipelines-list.png -------------------------------------------------------------------------------- /img/pipelines-pane.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-from-idea-to-production/b5323e2ed799c93e1391f240698803b9f8b80d62/img/pipelines-pane.png -------------------------------------------------------------------------------- /img/project-endpoints.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-from-idea-to-production/b5323e2ed799c93e1391f240698803b9f8b80d62/img/project-endpoints.png -------------------------------------------------------------------------------- /img/python-sdk-estimators.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-from-idea-to-production/b5323e2ed799c93e1391f240698803b9f8b80d62/img/python-sdk-estimators.png -------------------------------------------------------------------------------- /img/python-sdk-processors.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-from-idea-to-production/b5323e2ed799c93e1391f240698803b9f8b80d62/img/python-sdk-processors.png -------------------------------------------------------------------------------- /img/sagemaker-mlops-building-blocks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-from-idea-to-production/b5323e2ed799c93e1391f240698803b9f8b80d62/img/sagemaker-mlops-building-blocks.png -------------------------------------------------------------------------------- /img/sagemaker-processing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-from-idea-to-production/b5323e2ed799c93e1391f240698803b9f8b80d62/img/sagemaker-processing.png -------------------------------------------------------------------------------- /img/sagemaker-training-options.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-from-idea-to-production/b5323e2ed799c93e1391f240698803b9f8b80d62/img/sagemaker-training-options.png -------------------------------------------------------------------------------- /img/select-project.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-from-idea-to-production/b5323e2ed799c93e1391f240698803b9f8b80d62/img/select-project.png -------------------------------------------------------------------------------- /img/six-steps.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-from-idea-to-production/b5323e2ed799c93e1391f240698803b9f8b80d62/img/six-steps.png -------------------------------------------------------------------------------- /img/space-run.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-from-idea-to-production/b5323e2ed799c93e1391f240698803b9f8b80d62/img/space-run.png -------------------------------------------------------------------------------- /img/studio-open-notebook.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-from-idea-to-production/b5323e2ed799c93e1391f240698803b9f8b80d62/img/studio-open-notebook.png -------------------------------------------------------------------------------- /img/warm-pools-mlflow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-from-idea-to-production/b5323e2ed799c93e1391f240698803b9f8b80d62/img/warm-pools-mlflow.png -------------------------------------------------------------------------------- /img/warm-pools-training-jobs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-from-idea-to-production/b5323e2ed799c93e1391f240698803b9f8b80d62/img/warm-pools-training-jobs.png -------------------------------------------------------------------------------- /img/workshop-flow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-from-idea-to-production/b5323e2ed799c93e1391f240698803b9f8b80d62/img/workshop-flow.png -------------------------------------------------------------------------------- /img/workshop-qrcode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-from-idea-to-production/b5323e2ed799c93e1391f240698803b9f8b80d62/img/workshop-qrcode.png -------------------------------------------------------------------------------- /pipeline_steps/evaluate.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import pandas as pd 3 | import xgboost as xgb 4 | import mlflow 5 | from time import gmtime, strftime 6 | from sklearn.metrics import roc_curve, auc 7 | import matplotlib.pyplot as plt 8 | import tarfile 9 | import pickle as pkl 10 | import boto3 11 | 12 | # helper function to load XGBoost model into xgboost.Booster 13 | def load_model(model_data_s3_uri): 14 | model_file = "./xgboost-model.tar.gz" 15 | bucket, key = model_data_s3_uri.replace("s3://", "").split("/", 1) 16 | boto3.client("s3").download_file(bucket, key, model_file) 17 | 18 | with tarfile.open(model_file, "r:gz") as t: 19 | t.extractall(path=".") 20 | 21 | # Load model 22 | model = xgb.Booster() 23 | model.load_model("xgboost-model") 24 | 25 | return model 26 | 27 | def plot_roc_curve(fpr, tpr): 28 | fn = "roc-curve.png" 29 | fig = plt.figure(figsize=(6, 4)) 30 | 31 | # Plot the diagonal 50% line 32 | plt.plot([0, 1], [0, 1], 'k--') 33 | 34 | # Plot the FPR and TPR achieved by our model 35 | plt.plot(fpr, tpr) 36 | plt.xlabel('False Positive Rate') 37 | plt.ylabel('True Positive Rate') 38 | plt.title('ROC Curve') 39 | plt.savefig(fn) 40 | 41 | return fn 42 | 43 | def evaluate( 44 | test_x_data_s3_path, 45 | test_y_data_s3_path, 46 | model_s3_path, 47 | output_s3_prefix, 48 | tracking_server_arn, 49 | experiment_name=None, 50 | pipeline_run_id=None, 51 | run_id=None, 52 | ): 53 | try: 54 | suffix = strftime('%d-%H-%M-%S', gmtime()) 55 | mlflow.set_tracking_uri(tracking_server_arn) 56 | experiment = mlflow.set_experiment(experiment_name=experiment_name if experiment_name else f"{evaluate.__name__ }-{suffix}") 57 | pipeline_run = mlflow.start_run(run_id=pipeline_run_id) if pipeline_run_id else None 58 | run = mlflow.start_run(run_id=run_id) if run_id else mlflow.start_run(run_name=f"evaluate-{suffix}", nested=True) 59 | 60 | # Read test data 61 | X_test = xgb.DMatrix(pd.read_csv(test_x_data_s3_path, header=None).values) 62 | y_test = pd.read_csv(test_y_data_s3_path, header=None).to_numpy() 63 | 64 | # Run predictions 65 | probability = load_model(model_s3_path).predict(X_test) 66 | 67 | # Evaluate predictions 68 | fpr, tpr, thresholds = roc_curve(y_test, probability) 69 | auc_score = auc(fpr, tpr) 70 | eval_result = {"evaluation_result": { 71 | "classification_metrics": { 72 | "auc_score": { 73 | "value": auc_score, 74 | }, 75 | }, 76 | }} 77 | 78 | mlflow.log_metric("auc_score", auc_score) 79 | mlflow.log_artifact(plot_roc_curve(fpr, tpr)) 80 | 81 | prediction_baseline_s3_path = f"{output_s3_prefix}/prediction_baseline/prediction_baseline.csv" 82 | 83 | # Save prediction baseline file - we need it later for the model quality monitoring 84 | pd.DataFrame({"prediction":np.array(np.round(probability), dtype=int), 85 | "probability":probability, 86 | "label":y_test.squeeze()} 87 | ).to_csv(prediction_baseline_s3_path, index=False, header=True) 88 | 89 | return { 90 | **eval_result, 91 | "prediction_baseline_data":prediction_baseline_s3_path, 92 | "experiment_name":experiment.name, 93 | "pipeline_run_id":pipeline_run.info.run_id if pipeline_run else '' 94 | } 95 | 96 | except Exception as e: 97 | print(f"Exception in processing script: {e}") 98 | raise e 99 | finally: 100 | mlflow.end_run() -------------------------------------------------------------------------------- /pipeline_steps/extract.py: -------------------------------------------------------------------------------- 1 | import boto3 2 | import pandas as pd 3 | import numpy as np 4 | import mlflow 5 | from mlflow.data.pandas_dataset import PandasDataset 6 | from time import gmtime, strftime 7 | from sagemaker.session import Session 8 | from sagemaker.feature_store.feature_store import FeatureStore 9 | from sagemaker.feature_store.feature_group import FeatureGroup 10 | 11 | def extract_features( 12 | feature_group_name, 13 | query_output_s3_path, 14 | ): 15 | region = boto3.Session().region_name 16 | boto_session = boto3.Session(region_name=region) 17 | 18 | sagemaker_client = boto_session.client(service_name="sagemaker", region_name=region) 19 | featurestore_runtime = boto_session.client(service_name="sagemaker-featurestore-runtime",region_name=region) 20 | 21 | # Create FeatureStore session object 22 | feature_store_session = Session( 23 | boto_session=boto_session, 24 | sagemaker_client=sagemaker_client, 25 | sagemaker_featurestore_runtime_client=featurestore_runtime, 26 | ) 27 | 28 | feature_store = FeatureStore(sagemaker_session=feature_store_session) 29 | dataset_feature_group = FeatureGroup(feature_group_name) 30 | 31 | # Create dataset builder to retrieve the most recent version of each record 32 | builder = feature_store.create_dataset( 33 | base=dataset_feature_group, 34 | # included_feature_names=inlcuded_feature_names, 35 | output_path=query_output_s3_path, 36 | ).with_number_of_recent_records_by_record_identifier(1) 37 | 38 | df_dataset, query = builder.to_dataframe() 39 | 40 | return df_dataset 41 | 42 | def prepare_datasets( 43 | feature_group_name, 44 | output_s3_prefix, 45 | query_output_s3_path, 46 | tracking_server_arn, 47 | experiment_name=None, 48 | pipeline_run_name=None, 49 | run_id=None, 50 | ): 51 | try: 52 | suffix = strftime('%d-%H-%M-%S', gmtime()) 53 | mlflow.set_tracking_uri(tracking_server_arn) 54 | experiment = mlflow.set_experiment(experiment_name=experiment_name if experiment_name else f"{prepare_datasets.__name__ }-{suffix}") 55 | pipeline_run = mlflow.start_run(run_name=pipeline_run_name) if pipeline_run_name else None 56 | run = mlflow.start_run(run_id=run_id) if run_id else mlflow.start_run(run_name=f"feature-extraction-{suffix}", nested=True) 57 | 58 | target_col = "y" 59 | feature_store_col = ['event_time', 'record_id'] 60 | 61 | df_model_data = extract_features( 62 | feature_group_name, 63 | query_output_s3_path, 64 | ).drop(feature_store_col, axis=1) 65 | 66 | print(f"Extracted {len(df_model_data)} rows from the feature group {feature_group_name}") 67 | 68 | # log dataset 69 | input_dataset = mlflow.data.from_pandas(df_model_data, source=output_s3_prefix) 70 | mlflow.log_input(input_dataset, context="featureset") 71 | 72 | # Shuffle and splitting dataset 73 | train_data, validation_data, test_data = np.split( 74 | df_model_data.sample(frac=1, random_state=1729), 75 | [int(0.7 * len(df_model_data)), int(0.9 * len(df_model_data))], 76 | ) 77 | 78 | print(f"Data split > train:{train_data.shape} | validation:{validation_data.shape} | test:{test_data.shape}") 79 | 80 | mlflow.log_params( 81 | { 82 | "full_dataset": df_model_data.shape, 83 | "train": train_data.shape, 84 | "validate": validation_data.shape, 85 | "test": test_data.shape 86 | } 87 | ) 88 | 89 | # Set S3 upload paths 90 | train_data_output_s3_path = f"{output_s3_prefix}/train/train.csv" 91 | validation_data_output_s3_path = f"{output_s3_prefix}/validation/validation.csv" 92 | test_x_data_output_s3_path = f"{output_s3_prefix}/test/test_x.csv" 93 | test_y_data_output_s3_path = f"{output_s3_prefix}/test/test_y.csv" 94 | baseline_data_output_s3_path = f"{output_s3_prefix}/baseline/baseline.csv" 95 | 96 | # Upload datasets to S3 97 | train_data.to_csv(train_data_output_s3_path, index=False, header=False) 98 | validation_data.to_csv(validation_data_output_s3_path, index=False, header=False) 99 | test_data[target_col].to_csv(test_y_data_output_s3_path, index=False, header=False) 100 | test_data.drop([target_col], axis=1).to_csv(test_x_data_output_s3_path, index=False, header=False) 101 | 102 | # Save the baseline dataset for model monitoring 103 | df_model_data.drop([target_col], axis=1).to_csv(baseline_data_output_s3_path, index=False, header=False) 104 | 105 | s3 = boto3.client("s3") 106 | 107 | print(f"Datasets are uploaded to S3: {output_s3_prefix}. Exiting.") 108 | 109 | return { 110 | "train_data":train_data_output_s3_path, 111 | "validation_data":validation_data_output_s3_path, 112 | "test_x_data":test_x_data_output_s3_path, 113 | "test_y_data":test_y_data_output_s3_path, 114 | "baseline_data":baseline_data_output_s3_path, 115 | "experiment_name":experiment.name, 116 | "pipeline_run_id":pipeline_run.info.run_id if pipeline_run else '' 117 | } 118 | except Exception as e: 119 | print(f"Exception in processing script: {e}") 120 | raise e 121 | finally: 122 | mlflow.end_run() 123 | 124 | -------------------------------------------------------------------------------- /pipeline_steps/ingest.py: -------------------------------------------------------------------------------- 1 | import boto3 2 | from sagemaker.feature_store.feature_group import FeatureGroup 3 | import numpy as np 4 | import pandas as pd 5 | from sklearn.preprocessing import MinMaxScaler 6 | from datetime import datetime, timezone, date 7 | from sagemaker.session import Session 8 | 9 | 10 | def process_and_ingest( 11 | input_s3_url, 12 | feature_group_name, 13 | ): 14 | def generate_event_timestamp(): 15 | # naive datetime representing local time 16 | naive_dt = datetime.now() 17 | # take timezone into account 18 | aware_dt = naive_dt.astimezone() 19 | # time in UTC 20 | utc_dt = aware_dt.astimezone(timezone.utc) 21 | # transform to ISO-8601 format 22 | event_time = utc_dt.isoformat(timespec='milliseconds') 23 | event_time = event_time.replace('+00:00', 'Z') 24 | return event_time 25 | 26 | def convert_col_name(c): 27 | return c.replace('.', '_').replace('-', '_').rstrip('_') 28 | 29 | # Download data from S3 30 | df_data = pd.read_csv(input_s3_url, sep=";") 31 | 32 | target_col = "y" 33 | 34 | # Indicator variable to capture when pdays takes a value of 999 35 | df_data["no_previous_contact"] = np.where(df_data["pdays"] == 999, 1, 0) 36 | 37 | # Indicator for individuals not actively employed 38 | df_data["not_working"] = np.where( 39 | np.in1d(df_data["job"], ["student", "retired", "unemployed"]), 1, 0 40 | ) 41 | 42 | # remove unnecessary data 43 | df_model_data = df_data.drop( 44 | ["duration", "emp.var.rate", "cons.price.idx", "cons.conf.idx", "euribor3m", "nr.employed"], 45 | axis=1, 46 | ) 47 | 48 | bins = [18, 30, 40, 50, 60, 70, 90] 49 | labels = ['18-29', '30-39', '40-49', '50-59', '60-69', '70-plus'] 50 | 51 | df_model_data['age_range'] = pd.cut(df_model_data.age, bins, labels=labels, include_lowest=True) 52 | df_model_data = pd.concat([df_model_data, pd.get_dummies(df_model_data['age_range'], prefix='age', dtype=int)], axis=1) 53 | df_model_data.drop('age', axis=1, inplace=True) 54 | df_model_data.drop('age_range', axis=1, inplace=True) 55 | 56 | scaled_features = ['pdays', 'previous', 'campaign'] 57 | df_model_data[scaled_features] = MinMaxScaler().fit_transform(df_model_data[scaled_features]) 58 | 59 | df_model_data = pd.get_dummies(df_model_data, dtype=int) # Convert categorical variables to sets of indicators 60 | 61 | # Replace "y_no" and "y_yes" with a single label column, and bring it to the front: 62 | df_model_data = pd.concat( 63 | [ 64 | df_model_data["y_yes"].rename(target_col), 65 | df_model_data.drop(["y_no", "y_yes"], axis=1), 66 | ], 67 | axis=1, 68 | ) 69 | 70 | df_model_data['event_time'] = generate_event_timestamp() 71 | df_model_data['record_id'] = [f'R{i}' for i in range(len(df_model_data))] 72 | 73 | df_model_data = df_model_data.rename(columns=convert_col_name) 74 | 75 | df_model_data = df_model_data.convert_dtypes(infer_objects=True, convert_boolean=False) 76 | df_model_data['record_id'] = df_model_data['record_id'].astype('string') 77 | df_model_data['event_time'] = df_model_data['event_time'].astype('string') 78 | 79 | # Ingest data into the feature group 80 | dataset_feature_group = FeatureGroup(name=feature_group_name, sagemaker_session=Session()) 81 | 82 | print(f'Ingesting data into feature group: {dataset_feature_group.name} ...') 83 | dataset_feature_group.ingest(data_frame=df_model_data, max_processes=4, wait=True) 84 | print(f'{len(df_model_data)} customer records ingested into feature group: {dataset_feature_group.name}') 85 | 86 | return dataset_feature_group.describe()['FeatureGroupArn'] -------------------------------------------------------------------------------- /pipeline_steps/preprocess.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | import numpy as np 3 | import mlflow 4 | from mlflow.data.pandas_dataset import PandasDataset 5 | from time import gmtime, strftime 6 | from sklearn.preprocessing import MinMaxScaler, LabelEncoder 7 | 8 | def preprocess( 9 | input_data_s3_path, 10 | output_s3_prefix, 11 | tracking_server_arn, 12 | experiment_name=None, 13 | pipeline_run_name=None, 14 | run_id=None, 15 | ): 16 | try: 17 | suffix = strftime('%d-%H-%M-%S', gmtime()) 18 | mlflow.set_tracking_uri(tracking_server_arn) 19 | experiment = mlflow.set_experiment(experiment_name=experiment_name if experiment_name else f"{preprocess.__name__ }-{suffix}") 20 | pipeline_run = mlflow.start_run(run_name=pipeline_run_name) if pipeline_run_name else None 21 | run = mlflow.start_run(run_id=run_id) if run_id else mlflow.start_run(run_name=f"processing-{suffix}", nested=True) 22 | 23 | # Load data 24 | df_data = pd.read_csv(input_data_s3_path, sep=";") 25 | 26 | input_dataset = mlflow.data.from_pandas(df_data, source=input_data_s3_path) 27 | mlflow.log_input(input_dataset, context="raw_input") 28 | 29 | target_col = "y" 30 | 31 | # Indicator variable to capture when pdays takes a value of 999 32 | df_data["no_previous_contact"] = np.where(df_data["pdays"] == 999, 1, 0) 33 | 34 | # Indicator for individuals not actively employed 35 | df_data["not_working"] = np.where( 36 | np.in1d(df_data["job"], ["student", "retired", "unemployed"]), 1, 0 37 | ) 38 | 39 | # remove data not used for the modelling 40 | df_model_data = df_data.drop( 41 | ["duration", "emp.var.rate", "cons.price.idx", "cons.conf.idx", "euribor3m", "nr.employed"], 42 | axis=1, 43 | ) 44 | 45 | bins = [18, 30, 40, 50, 60, 70, 90] 46 | labels = ['18-29', '30-39', '40-49', '50-59', '60-69', '70-plus'] 47 | 48 | df_model_data['age_range'] = pd.cut(df_model_data.age, bins, labels=labels, include_lowest=True) 49 | df_model_data = pd.concat([df_model_data, pd.get_dummies(df_model_data['age_range'], prefix='age', dtype=int)], axis=1) 50 | df_model_data.drop('age', axis=1, inplace=True) 51 | df_model_data.drop('age_range', axis=1, inplace=True) 52 | 53 | # Scale features 54 | scaled_features = ['pdays', 'previous', 'campaign'] 55 | df_model_data[scaled_features] = MinMaxScaler().fit_transform(df_model_data[scaled_features]) 56 | 57 | # Convert categorical variables to sets of indicators 58 | df_model_data = pd.get_dummies(df_model_data, dtype=int) 59 | 60 | # Replace "y_no" and "y_yes" with a single label column, and bring it to the front: 61 | df_model_data = pd.concat( 62 | [ 63 | df_model_data["y_yes"].rename(target_col), 64 | df_model_data.drop(["y_no", "y_yes"], axis=1), 65 | ], 66 | axis=1, 67 | ) 68 | 69 | model_dataset = mlflow.data.from_pandas(df_data) 70 | mlflow.log_input(model_dataset, context="model_dataset") 71 | 72 | # Shuffle and split the dataset 73 | train_data, validation_data, test_data = np.split( 74 | df_model_data.sample(frac=1, random_state=1729), 75 | [int(0.7 * len(df_model_data)), int(0.9 * len(df_model_data))], 76 | ) 77 | 78 | print(f"## Data split > train:{train_data.shape} | validation:{validation_data.shape} | test:{test_data.shape}") 79 | 80 | mlflow.log_params( 81 | { 82 | "full_dataset": df_model_data.shape, 83 | "train": train_data.shape, 84 | "validate": validation_data.shape, 85 | "test": test_data.shape 86 | } 87 | ) 88 | 89 | # Set S3 upload path 90 | train_data_output_s3_path = f"{output_s3_prefix}/train/train.csv" 91 | validation_data_output_s3_path = f"{output_s3_prefix}/validation/validation.csv" 92 | test_x_data_output_s3_path = f"{output_s3_prefix}/test/test_x.csv" 93 | test_y_data_output_s3_path = f"{output_s3_prefix}/test/test_y.csv" 94 | baseline_data_output_s3_path = f"{output_s3_prefix}/baseline/baseline.csv" 95 | 96 | # Upload datasets to S3 97 | train_data.to_csv(train_data_output_s3_path, index=False, header=False) 98 | validation_data.to_csv(validation_data_output_s3_path, index=False, header=False) 99 | test_data[target_col].to_csv(test_y_data_output_s3_path, index=False, header=False) 100 | test_data.drop([target_col], axis=1).to_csv(test_x_data_output_s3_path, index=False, header=False) 101 | 102 | # We need the baseline dataset for model monitoring 103 | df_model_data.drop([target_col], axis=1).to_csv(baseline_data_output_s3_path, index=False, header=False) 104 | 105 | print("## Data processing complete. Exiting.") 106 | 107 | return { 108 | "train_data":train_data_output_s3_path, 109 | "validation_data":validation_data_output_s3_path, 110 | "test_x_data":test_x_data_output_s3_path, 111 | "test_y_data":test_y_data_output_s3_path, 112 | "baseline_data":baseline_data_output_s3_path, 113 | "experiment_name":experiment.name, 114 | "pipeline_run_id":pipeline_run.info.run_id if pipeline_run else '' 115 | } 116 | 117 | except Exception as e: 118 | print(f"Exception in processing script: {e}") 119 | raise e 120 | finally: 121 | mlflow.end_run() -------------------------------------------------------------------------------- /pipeline_steps/register.py: -------------------------------------------------------------------------------- 1 | import json 2 | import sagemaker 3 | import boto3 4 | import mlflow 5 | from time import gmtime, strftime 6 | from sagemaker.estimator import Estimator 7 | from sagemaker.model_metrics import ( 8 | MetricsSource, 9 | ModelMetrics, 10 | FileSource 11 | ) 12 | 13 | def register( 14 | training_job_name, 15 | model_package_group_name, 16 | model_approval_status, 17 | evaluation_result, 18 | output_s3_prefix, 19 | tracking_server_arn, 20 | model_statistics_s3_path=None, 21 | model_constraints_s3_path=None, 22 | model_data_statistics_s3_path=None, 23 | model_data_constraints_s3_path=None, 24 | experiment_name=None, 25 | pipeline_run_id=None, 26 | run_id=None, 27 | ): 28 | try: 29 | suffix = strftime('%d-%H-%M-%S', gmtime()) 30 | mlflow.set_tracking_uri(tracking_server_arn) 31 | experiment = mlflow.set_experiment(experiment_name=experiment_name if experiment_name else f"{register.__name__ }-{suffix}") 32 | pipeline_run = mlflow.start_run(run_id=pipeline_run_id) if pipeline_run_id else None 33 | run = mlflow.start_run(run_id=run_id) if run_id else mlflow.start_run(run_name=f"register-{suffix}", nested=True) 34 | 35 | evaluation_result_path = f"evaluation.json" 36 | with open(evaluation_result_path, "w") as f: 37 | f.write(json.dumps(evaluation_result)) 38 | 39 | mlflow.log_artifact(local_path=evaluation_result_path) 40 | 41 | estimator = Estimator.attach(training_job_name) 42 | 43 | model_metrics = ModelMetrics( 44 | model_statistics=MetricsSource( 45 | s3_uri=model_statistics_s3_path, 46 | content_type="application/json", 47 | ) if model_statistics_s3_path else None, 48 | model_constraints=MetricsSource( 49 | s3_uri=model_constraints_s3_path, 50 | content_type="application/json", 51 | ) if model_constraints_s3_path else None, 52 | model_data_statistics=MetricsSource( 53 | s3_uri=model_data_statistics_s3_path, 54 | content_type="application/json", 55 | ) if model_data_statistics_s3_path else None, 56 | model_data_constraints=MetricsSource( 57 | s3_uri=model_data_constraints_s3_path, 58 | content_type="application/json", 59 | ) if model_data_constraints_s3_path else None, 60 | ) 61 | 62 | model_package = estimator.register( 63 | content_types=["text/csv"], 64 | response_types=["text/csv"], 65 | inference_instances=["ml.m5.xlarge", "ml.m5.large"], 66 | transform_instances=["ml.m5.xlarge", "ml.m5.large"], 67 | model_package_group_name=model_package_group_name, 68 | approval_status=model_approval_status, 69 | model_metrics=model_metrics, 70 | model_name="from-idea-to-prod-pipeline-model", 71 | domain="MACHINE_LEARNING", 72 | task="CLASSIFICATION", 73 | ) 74 | 75 | mlflow.log_params({ 76 | "model_package_arn":model_package.model_package_arn, 77 | "model_statistics_uri":model_statistics_s3_path if model_statistics_s3_path else '', 78 | "model_constraints_uri":model_constraints_s3_path if model_constraints_s3_path else '', 79 | "data_statistics_uri":model_data_statistics_s3_path if model_data_statistics_s3_path else '', 80 | "data_constraints_uri":model_data_constraints_s3_path if model_data_constraints_s3_path else '', 81 | }) 82 | 83 | return { 84 | "model_package_arn":model_package.model_package_arn, 85 | "model_package_group_name":model_package_group_name, 86 | "pipeline_run_id":pipeline_run.info.run_id if pipeline_run else '' 87 | } 88 | 89 | except Exception as e: 90 | print(f"Exception in processing script: {e}") 91 | raise e 92 | finally: 93 | mlflow.end_run() 94 | 95 | -------------------------------------------------------------------------------- /record_preprocessor.py: -------------------------------------------------------------------------------- 1 | import json 2 | import random 3 | import ast 4 | import sys 5 | import subprocess 6 | import os 7 | 8 | def preprocess_handler(inference_record): 9 | 10 | input_enc_type = inference_record.endpoint_input.encoding 11 | input_data = inference_record.endpoint_input.data 12 | output_data = inference_record.endpoint_output.data.rstrip("\n") 13 | eventmedatadata = inference_record.event_metadata 14 | custom_attribute = json.loads(eventmedatadata.custom_attribute[0]) if eventmedatadata.custom_attribute is not None else None 15 | 16 | if input_enc_type == "CSV": 17 | # don't include output data in the record for data quality monitor 18 | outputs = input_data 19 | return { f'_c{i}' : float(d) if i in [0,1,2] else int(float(d)) for i, d in enumerate(outputs.split(",")) } 20 | else: 21 | raise ValueError(f"encoding type {input_enc_type} is not supported") 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /sagemaker-project-templates-roles.md: -------------------------------------------------------------------------------- 1 | # Amazon SageMaker project template roles 2 | To use the provided SageMaker projects you need to provision specific IAM execution roles as specified in [SageMaker Studio Permissions Required to Use Projects](https://docs.aws.amazon.com/sagemaker/latest/dg/sagemaker-projects-studio-updates.html). 3 | 4 | The following roles are required to use the provided SageMaker project templates: 5 | 6 | - Launch constraint role: `arn:aws:iam:::role/service-role/AmazonSageMakerServiceCatalogProductsLaunchRole` 7 | - Product use role: `arn:aws:iam:::role/service-role/AmazonSageMakerServiceCatalogProductsUseRole` 8 | - CloudFormation use role: `arn:aws:iam:::role/service-role/AmazonSageMakerServiceCatalogProductsCloudformationRole` 9 | - CodeBuild use role: `arn:aws:iam:::role/service-role/AmazonSageMakerServiceCatalogProductsCodeBuildRole` 10 | - CodePipeline use role: `arn:aws:iam:::role/service-role/AmazonSageMakerServiceCatalogProductsCodePipelineRole` 11 | - Events use role: `arn:aws:iam:::role/service-role/AmazonSageMakerServiceCatalogProductsEventsRole` 12 | - API Gateway use role: `arn:aws:iam:::role/service-role/AmazonSageMakerServiceCatalogProductsApiGatewayRole` 13 | - Firehose use role: `arn:aws:iam:::role/service-role/AmazonSageMakerServiceCatalogProductsFirehoseRole` 14 | - Glue use role: `arn:aws:iam:::role/service-role/AmazonSageMakerServiceCatalogProductsGlueRole` 15 | - Lambda use role: `arn:aws:iam:::role/service-role/AmazonSageMakerServiceCatalogProductsLambdaRole` 16 | - SageMaker use role: `arn:aws:iam:::role/service-role/AmazonSageMakerServiceCatalogProductsExecutionRole` 17 | 18 | ## Provision the required roles 19 | There are two options to provision the required roles. 20 | 21 | ### Option 1 - SageMaker console 22 | If you don't have a SageMaker domain in your account, you must create a new one. You must enable all options on the **SageMaker Projects and JumpStart** pane: 23 | 24 | ![](img/enable-sagemaker-projects.png) 25 | 26 | The SageMaker domain creates the required roles automatically. 27 | 28 | If you already have a SageMaker domain in your account, follow [Shut Down and Update SageMaker Studio and Studio Apps](https://docs.aws.amazon.com/sagemaker/latest/dg/studio-tasks-update.html) instructions to update the domain. You must shutdown both JupyterServer and KernelGateway apps. After you shutdown all apps, go to Amazon SageMaker console, choose **Domains** on the left-side pane and select your domain. Go to **Domain settings**, click on **Configure app** on the **App** card. Make sure all options enabled on on the **SageMaker Projects and JumpStart** pane. Click through all **Next** in configuration panes and choose **Submit**. This will update the domain and create all needed project roles automatically. 29 | 30 | ### Option 2 - use CloudFormation template 31 | Deploy the provided CloudFormation template [`cfn-templates/sagemaker-project-templates-roles.yaml`](cfn-templates/sagemaker-project-templates-roles.yaml). To deploy the roles you must have the corresponding permissions to create new IAM roles. 32 | 33 | Run the following command in the command terminal from the project repository directory: 34 | 35 | ```sh 36 | aws cloudformation deploy \ 37 | --template-file cfn-templates/sagemaker-project-templates-roles.yaml \ 38 | --stack-name sagemaker-project-template-roles \ 39 | --capabilities CAPABILITY_IAM CAPABILITY_NAMED_IAM \ 40 | --parameter-overrides \ 41 | CreateCloudFormationRole=YES \ 42 | CreateCodeBuildRole=YES \ 43 | CreateCodePipelineRole=YES \ 44 | CreateEventsRole=YES \ 45 | CreateProductsExecutionRole=YES 46 | ``` -------------------------------------------------------------------------------- /utils/monitoring_utils.py: -------------------------------------------------------------------------------- 1 | import os, sys 2 | from urllib.parse import urlparse 3 | from sagemaker.processing import Processor, ProcessingInput, ProcessingOutput 4 | 5 | def get_model_monitor_container_uri(region): 6 | container_uri_format = '{0}.dkr.ecr.{1}.amazonaws.com/sagemaker-model-monitor-analyzer' 7 | 8 | regions_to_accounts = { 9 | 'eu-north-1': '895015795356', 10 | 'me-south-1': '607024016150', 11 | 'ap-south-1': '126357580389', 12 | 'us-east-2': '680080141114', 13 | 'us-east-2': '777275614652', 14 | 'eu-west-1': '468650794304', 15 | 'eu-central-1': '048819808253', 16 | 'sa-east-1': '539772159869', 17 | 'ap-east-1': '001633400207', 18 | 'us-east-1': '156813124566', 19 | 'ap-northeast-2': '709848358524', 20 | 'eu-west-2': '749857270468', 21 | 'ap-northeast-1': '574779866223', 22 | 'us-west-2': '159807026194', 23 | 'us-west-1': '890145073186', 24 | 'ap-southeast-1': '245545462676', 25 | 'ap-southeast-2': '563025443158', 26 | 'ca-central-1': '536280801234' 27 | } 28 | 29 | container_uri = container_uri_format.format(regions_to_accounts[region], region) 30 | return container_uri 31 | 32 | def get_file_name(url): 33 | a = urlparse(url) 34 | return os.path.basename(a.path) 35 | 36 | def run_model_monitor_job( 37 | region, 38 | instance_type, 39 | role, 40 | data_capture_path, 41 | statistics_path, 42 | constraints_path, 43 | reports_path, 44 | instance_count=1, 45 | preprocessor_path=None, 46 | postprocessor_path=None, 47 | publish_cloudwatch_metrics='Disabled', 48 | wait=True, 49 | logs=True, 50 | ): 51 | 52 | data_capture_sub_path = data_capture_path[data_capture_path.rfind('datacapture') :] 53 | data_capture_sub_path = data_capture_sub_path[data_capture_sub_path.find('/') + 1 :] 54 | processing_output_paths = reports_path + '/' + data_capture_sub_path 55 | 56 | input_1 = ProcessingInput(input_name='input_1', 57 | source=data_capture_path, 58 | destination='/opt/ml/processing/input/endpoint/' + data_capture_sub_path, 59 | s3_data_type='S3Prefix', 60 | s3_input_mode='File') 61 | 62 | baseline = ProcessingInput(input_name='baseline', 63 | source=statistics_path, 64 | destination='/opt/ml/processing/baseline/stats', 65 | s3_data_type='S3Prefix', 66 | s3_input_mode='File') 67 | 68 | constraints = ProcessingInput(input_name='constraints', 69 | source=constraints_path, 70 | destination='/opt/ml/processing/baseline/constraints', 71 | s3_data_type='S3Prefix', 72 | s3_input_mode='File') 73 | 74 | outputs = ProcessingOutput(output_name='result', 75 | source='/opt/ml/processing/output', 76 | destination=processing_output_paths, 77 | s3_upload_mode='Continuous') 78 | 79 | env = {'baseline_constraints': '/opt/ml/processing/baseline/constraints/' + get_file_name(constraints_path), 80 | 'baseline_statistics': '/opt/ml/processing/baseline/stats/' + get_file_name(statistics_path), 81 | 'dataset_format': '{"sagemakerCaptureJson":{"captureIndexNames":["endpointInput","endpointOutput"]}}', 82 | 'dataset_source': '/opt/ml/processing/input/endpoint', 83 | 'output_path': '/opt/ml/processing/output', 84 | 'publish_cloudwatch_metrics': publish_cloudwatch_metrics } 85 | 86 | inputs=[input_1, baseline, constraints] 87 | 88 | if postprocessor_path: 89 | env['post_analytics_processor_script'] = '/opt/ml/processing/code/postprocessing/' + get_file_name(postprocessor_path) 90 | 91 | post_processor_script = ProcessingInput(input_name='post_processor_script', 92 | source=postprocessor_path, 93 | destination='/opt/ml/processing/code/postprocessing', 94 | s3_data_type='S3Prefix', 95 | s3_input_mode='File') 96 | inputs.append(post_processor_script) 97 | 98 | if preprocessor_path: 99 | env['record_preprocessor_script'] = '/opt/ml/processing/code/preprocessing/' + get_file_name(preprocessor_path) 100 | 101 | pre_processor_script = ProcessingInput(input_name='pre_processor_script', 102 | source=preprocessor_path, 103 | destination='/opt/ml/processing/code/preprocessing', 104 | s3_data_type='S3Prefix', 105 | s3_input_mode='File') 106 | 107 | inputs.append(pre_processor_script) 108 | 109 | processor = Processor(image_uri = get_model_monitor_container_uri(region), 110 | instance_count = instance_count, 111 | instance_type = instance_type, 112 | role=role, 113 | env = env) 114 | 115 | return processor.run(inputs=inputs, 116 | outputs=[outputs], 117 | wait=wait, 118 | logs=logs, 119 | ) --------------------------------------------------------------------------------