From 01dbfb67a51210341e1671516bd807464a787ab2 Mon Sep 17 00:00:00 2001 From: Ryan Dana <106407392+rdamazon@users.noreply.github.com> Date: Fri, 23 Jun 2023 13:56:22 -0700 Subject: [PATCH] Remediate fixed notebooks (#4286) * Prune use_cases * remediating pytorch_smdataparallel_maskrcnn_demo.ipynb * Remediate --- ...ature-Attribution-Drift-for-Endpoint.ipynb | 102 +- ...pytorch_smdataparallel_maskrcnn_demo.ipynb | 390 ------ use-cases/computer_vision/README.md | 18 - use-cases/computer_vision/deploy_model.py | 55 - .../inference_specification.py | 78 -- .../metastases-detection-pipeline.ipynb | 784 ----------- .../metastases-detection.ipynb | 1035 --------------- use-cases/computer_vision/split_data.py | 61 - use-cases/index.rst | 8 - .../1_dataprep_dw_job_predmaint.ipynb | 682 ---------- .../2_dataprep_predmaint.ipynb | 597 --------- .../3_train_tune_predict_predmaint.ipynb | 1171 ----------------- 12 files changed, 4 insertions(+), 4977 deletions(-) delete mode 100644 training/distributed_training/pytorch/data_parallel/maskrcnn/pytorch_smdataparallel_maskrcnn_demo.ipynb delete mode 100644 use-cases/computer_vision/README.md delete mode 100644 use-cases/computer_vision/deploy_model.py delete mode 100644 use-cases/computer_vision/inference_specification.py delete mode 100644 use-cases/computer_vision/metastases-detection-pipeline.ipynb delete mode 100644 use-cases/computer_vision/metastases-detection.ipynb delete mode 100644 use-cases/computer_vision/split_data.py delete mode 100644 use-cases/predictive_maintenance/1_dataprep_dw_job_predmaint.ipynb delete mode 100644 use-cases/predictive_maintenance/2_dataprep_predmaint.ipynb delete mode 100644 use-cases/predictive_maintenance/3_train_tune_predict_predmaint.ipynb diff --git a/sagemaker_model_monitor/fairness_and_explainability_jsonlines/SageMaker-Monitoring-Feature-Attribution-Drift-for-Endpoint.ipynb b/sagemaker_model_monitor/fairness_and_explainability_jsonlines/SageMaker-Monitoring-Feature-Attribution-Drift-for-Endpoint.ipynb index e506159a7d..6f4ad2ca44 100644 --- a/sagemaker_model_monitor/fairness_and_explainability_jsonlines/SageMaker-Monitoring-Feature-Attribution-Drift-for-Endpoint.ipynb +++ b/sagemaker_model_monitor/fairness_and_explainability_jsonlines/SageMaker-Monitoring-Feature-Attribution-Drift-for-Endpoint.ipynb @@ -2,14 +2,12 @@ "cells": [ { "cell_type": "markdown", - "id": "5a524a4c-5a39-4b6b-abb1-1c8e1b2de84c", "metadata": {}, "source": [ "# Amazon SageMaker Clarify Model Explainability Monitor - JSON Lines Format" ] }, { - "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ @@ -24,7 +22,6 @@ }, { "cell_type": "markdown", - "id": "4eaae7a8-2ab1-4f7c-8cb2-6b23606c58c1", "metadata": {}, "source": [ "## Runtime\n", @@ -34,7 +31,6 @@ }, { "cell_type": "markdown", - "id": "5e939eb9-9189-48fe-ab44-ddc6f942f8e3", "metadata": {}, "source": [ "## Contents\n", @@ -64,7 +60,6 @@ }, { "cell_type": "markdown", - "id": "a0a2c6a4-a249-40bf-adbc-8bd00fb06cfe", "metadata": { "tags": [] }, @@ -74,7 +69,6 @@ }, { "cell_type": "markdown", - "id": "1879bacd-fedd-434a-8094-40cd48f5f140", "metadata": {}, "source": [ "[Amazon SageMaker Model Monitor](https://docs.aws.amazon.com/sagemaker/latest/dg/model-monitor.html) continuously monitors the quality of Amazon SageMaker machine learning models in production. It enables developers to set alerts for when there are deviations in the model quality. Early and pro-active detection of these deviations enables corrective actions, such as retraining models, auditing upstream systems, or fixing data quality issues without having to monitor models manually or build additional tooling. \n", @@ -93,7 +87,6 @@ }, { "cell_type": "markdown", - "id": "a4eed2c2-4e67-49cd-8b16-01d10c0acdb0", "metadata": {}, "source": [ "## General Setup" @@ -101,7 +94,6 @@ }, { "cell_type": "markdown", - "id": "56e754c8-d82a-49a3-9967-d7a487a42549", "metadata": {}, "source": [ "The notebook uses the [SageMaker Python SDK](https://github.com/aws/sagemaker-python-sdk). The following cell upgrades the SDK and its dependencies. Then you may need to restart the kernel and rerun the notebook to pick up the up-to-date APIs, if the notebook is executed in the SageMaker Studio." @@ -110,7 +102,6 @@ { "cell_type": "code", "execution_count": null, - "id": "e815029f-6166-40f6-a5dd-da2358f8b7fa", "metadata": {}, "outputs": [], "source": [ @@ -121,7 +112,6 @@ }, { "cell_type": "markdown", - "id": "43f20cf6-1672-45ab-966b-5db2d51aad53", "metadata": {}, "source": [ "### Imports\n", @@ -132,7 +122,6 @@ { "cell_type": "code", "execution_count": 2, - "id": "21f01570-2eee-46ef-b044-8b65569c26b7", "metadata": {}, "outputs": [], "source": [ @@ -149,7 +138,6 @@ }, { "cell_type": "markdown", - "id": "5baa9278-a1c9-427c-a9d9-5ddab19bcd49", "metadata": {}, "source": [ "### Handful of configuration\n", @@ -164,7 +152,6 @@ { "cell_type": "code", "execution_count": 3, - "id": "74b11f7c-e9cd-4321-8de5-27ca6dd85d01", "metadata": {}, "outputs": [ { @@ -211,7 +198,6 @@ }, { "cell_type": "markdown", - "id": "d7da5265-858f-4478-978b-ad592464b61d", "metadata": {}, "source": [ "### Model file and data files\n", @@ -236,7 +222,6 @@ { "cell_type": "code", "execution_count": 4, - "id": "f75d26c9-0f0b-422d-97cb-b74efd5eacd6", "metadata": {}, "outputs": [], "source": [ @@ -245,7 +230,6 @@ }, { "cell_type": "markdown", - "id": "dc4d1d6a-c75c-4563-9699-33de88469093", "metadata": {}, "source": [ "This example includes two dataset files, both in the JSON Lines format. The data also originates from [the SageMaker Clarify offline processing example notebook](https://github.com/aws/amazon-sagemaker-examples/blob/main/sagemaker-clarify/fairness_and_explainability/fairness_and_explainability_jsonlines_format.ipynb)." @@ -254,7 +238,6 @@ { "cell_type": "code", "execution_count": 5, - "id": "f1eaa4fe-622f-4745-a3cc-52d40db8ce9f", "metadata": {}, "outputs": [], "source": [ @@ -265,7 +248,6 @@ }, { "cell_type": "markdown", - "id": "5ca1001e-0b91-4133-8bce-6710aaa33270", "metadata": {}, "source": [ "The train dataset has the features and the ground truth label (pointed to by the key \"label\")," @@ -274,7 +256,6 @@ { "cell_type": "code", "execution_count": 6, - "id": "06c22c10-7ba8-417a-a0dc-1e152a0a3287", "metadata": {}, "outputs": [ { @@ -295,7 +276,6 @@ }, { "cell_type": "markdown", - "id": "ddebb1fd-d480-4700-8dd8-3143205331a6", "metadata": {}, "source": [ "The test dataset only has features." @@ -304,7 +284,6 @@ { "cell_type": "code", "execution_count": 7, - "id": "9f78d463-f1ff-4483-8cf3-562bccb98a2b", "metadata": {}, "outputs": [ { @@ -325,7 +304,6 @@ }, { "cell_type": "markdown", - "id": "a7b89b8d-5036-4bd9-8aa5-f5d638617aba", "metadata": {}, "source": [ "Here are the headers of the train dataset. \"Target\" is the header of the ground truth label, and the others are the feature headers. They will be used to beautify the analysis report." @@ -334,7 +312,6 @@ { "cell_type": "code", "execution_count": 8, - "id": "2a843093-0548-48dd-9f82-e80af07c357e", "metadata": {}, "outputs": [], "source": [ @@ -360,7 +337,6 @@ }, { "cell_type": "markdown", - "id": "2441fc17-0299-4b11-afe7-efdb167263ad", "metadata": {}, "source": [ "To verify that the execution role for this notebook has the necessary permissions to proceed, put a simple test object into the S3 bucket specified above. If this command fails, update the role to have `s3:PutObject` permission on the bucket and try again." @@ -369,7 +345,6 @@ { "cell_type": "code", "execution_count": 9, - "id": "dfe69a8c-9bf6-47c4-bb59-a775fd3b6934", "metadata": {}, "outputs": [ { @@ -391,7 +366,6 @@ }, { "cell_type": "markdown", - "id": "7a099ef6-8d09-478d-854c-989758bad1c5", "metadata": {}, "source": [ "Then upload the files to S3 so that they can be used by SageMaker." @@ -400,7 +374,6 @@ { "cell_type": "code", "execution_count": 10, - "id": "0f0fe183-4c83-4d22-bce5-65eba6a351e2", "metadata": {}, "outputs": [ { @@ -437,7 +410,6 @@ }, { "cell_type": "markdown", - "id": "2d11cc57-8ab4-422e-9492-4126f34ef4c5", "metadata": {}, "source": [ "## Real-time Inference Endpoint\n", @@ -447,7 +419,6 @@ }, { "cell_type": "markdown", - "id": "3d295bc3-3a82-4f22-9768-29572c0ae4f3", "metadata": { "tags": [] }, @@ -462,7 +433,6 @@ { "cell_type": "code", "execution_count": 11, - "id": "d0c565e0-051a-4f6c-bcb6-3dca8f4ec592", "metadata": {}, "outputs": [ { @@ -502,7 +472,6 @@ }, { "cell_type": "markdown", - "id": "c86306f2-8f15-4d39-9cbb-2f6c0e7ee978", "metadata": {}, "source": [ "**NOTE**: The following cell takes about 10 minutes to deploy the model." @@ -511,7 +480,6 @@ { "cell_type": "code", "execution_count": 12, - "id": "77330b34-0640-4b00-b3bb-4a8ea6e9a223", "metadata": {}, "outputs": [ { @@ -535,7 +503,6 @@ }, { "cell_type": "markdown", - "id": "14bf8504-bca2-4948-867a-cab4ca349bd9", "metadata": {}, "source": [ "### Invoke the endpoint\n", @@ -546,7 +513,6 @@ { "cell_type": "code", "execution_count": 13, - "id": "44a908e5-c16f-41dc-b718-323ab5ed4268", "metadata": {}, "outputs": [], "source": [ @@ -556,7 +522,6 @@ }, { "cell_type": "markdown", - "id": "2ccc2ed6-355a-4cdb-a44e-1463c0d9ef9f", "metadata": {}, "source": [ "#### Example: Single record" @@ -564,7 +529,6 @@ }, { "cell_type": "markdown", - "id": "ea0e8368-37b1-41d2-b0da-0f22fee2b87e", "metadata": {}, "source": [ "Request payload:" @@ -573,7 +537,6 @@ { "cell_type": "code", "execution_count": 14, - "id": "52fbb63a-e1d8-414e-968a-20822305f23c", "metadata": {}, "outputs": [ { @@ -591,7 +554,6 @@ }, { "cell_type": "markdown", - "id": "f880886a-38cc-44c1-acc4-f3876956e2a8", "metadata": {}, "source": [ "Response payload:" @@ -600,7 +562,6 @@ { "cell_type": "code", "execution_count": 15, - "id": "87531e43-c9d1-4d9b-8019-19bec1a832eb", "metadata": {}, "outputs": [ { @@ -627,7 +588,6 @@ }, { "cell_type": "markdown", - "id": "22fe887e-ec0d-4b2a-9c32-28d93c2e25be", "metadata": {}, "source": [ "#### Example: Two records" @@ -635,7 +595,6 @@ }, { "cell_type": "markdown", - "id": "6094ad1c-55dd-40d1-b31f-8d47f21814c3", "metadata": {}, "source": [ "Request payload:" @@ -644,7 +603,6 @@ { "cell_type": "code", "execution_count": 16, - "id": "2cd41694-9e20-461f-ae85-5f792a521753", "metadata": {}, "outputs": [ { @@ -665,7 +623,6 @@ }, { "cell_type": "markdown", - "id": "3ab91982-67b4-4293-86cb-bb61be2f67aa", "metadata": {}, "source": [ "Response payload:" @@ -674,7 +631,6 @@ { "cell_type": "code", "execution_count": 17, - "id": "fece49e7-38b9-4b33-91ca-f23fcd06dcbb", "metadata": {}, "outputs": [ { @@ -701,7 +657,6 @@ }, { "cell_type": "markdown", - "id": "243eac0c-a697-42b6-a56f-c0279cc7cd57", "metadata": {}, "source": [ "### View captured data\n", @@ -716,7 +671,6 @@ { "cell_type": "code", "execution_count": 18, - "id": "18c649dd-40ef-4260-b499-0f3c371f970f", "metadata": {}, "outputs": [ { @@ -749,7 +703,6 @@ }, { "cell_type": "markdown", - "id": "0b4b01fd-4df2-42ff-935e-8843f1bc568f", "metadata": {}, "source": [ "Next, view the content of a single capture file." @@ -758,7 +711,6 @@ { "cell_type": "code", "execution_count": 19, - "id": "e4ad7021-4bcc-4fe1-880e-11a872941ff1", "metadata": {}, "outputs": [ { @@ -781,7 +733,6 @@ }, { "cell_type": "markdown", - "id": "6e09cffd-111a-43a1-8429-2fa3fbce9d2e", "metadata": {}, "source": [ "Finally, the contents of a single line is present below in formatted JSON to observe a little better.\n", @@ -793,7 +744,6 @@ { "cell_type": "code", "execution_count": 20, - "id": "14611944-0ae1-4f9f-ab6e-4b5c74ee7f3f", "metadata": {}, "outputs": [ { @@ -830,7 +780,6 @@ }, { "cell_type": "markdown", - "id": "4b473f92-7142-4f79-8a27-86672682a5b2", "metadata": {}, "source": [ "### Start generating some artificial traffic\n", @@ -842,7 +791,6 @@ { "cell_type": "code", "execution_count": 21, - "id": "0af95cc5-9e1d-46fd-b373-16015c87be58", "metadata": {}, "outputs": [], "source": [ @@ -863,7 +811,6 @@ { "cell_type": "code", "execution_count": 22, - "id": "00e832f7-8cc7-4044-b2aa-f22c93d2078d", "metadata": {}, "outputs": [], "source": [ @@ -889,7 +836,6 @@ }, { "cell_type": "markdown", - "id": "f8d87f96-1ab6-4ad9-bd0d-f21b18ebcded", "metadata": {}, "source": [ "## Model Explainability Monitor\n", @@ -900,7 +846,6 @@ { "cell_type": "code", "execution_count": 23, - "id": "273af941-56ff-4a08-a1e1-023e2d4ec090", "metadata": {}, "outputs": [], "source": [ @@ -913,7 +858,6 @@ }, { "cell_type": "markdown", - "id": "c47a6f66-bdd8-4815-b3ed-286035f6e4ce", "metadata": {}, "source": [ "### Baselining job\n", @@ -925,7 +869,6 @@ }, { "cell_type": "markdown", - "id": "b7bd931a-bacc-480b-8d2d-c363abe9943f", "metadata": {}, "source": [ "#### Configurations\n", @@ -935,7 +878,6 @@ }, { "cell_type": "markdown", - "id": "6398d447-0ccf-4c79-a29d-8d6a54e1c034", "metadata": {}, "source": [ "`DataConfig` stores information about the dataset to be analyzed. For example, the dataset file and its format (like JSON Lines), where to store the analysis results. Some special things to note about this configuration for the JSON Lines dataset,\n", @@ -952,7 +894,6 @@ { "cell_type": "code", "execution_count": 24, - "id": "fd146e26-a54c-4a31-acc9-5a406ddf8680", "metadata": {}, "outputs": [], "source": [ @@ -970,7 +911,6 @@ }, { "cell_type": "markdown", - "id": "93c9c98b-67a5-45e0-8aa5-a488e25a6de8", "metadata": {}, "source": [ "`ModelConfig` is configuration related to model to be used for inferencing. In order to compute SHAP values, the SageMaker Clarify explainer generates synthetic dataset and then get its predictions for the SageMaker model. To accomplish this, the processing job will use the model to create an ephemeral endpoint (also known as \"shadow endpoint\"). The processing job will delete the shadow endpoint after the computations are completed. One special thing to note about this configuration for the JSON Lines model input and output,\n", @@ -981,7 +921,6 @@ { "cell_type": "code", "execution_count": 25, - "id": "3a49acc6-c6a9-46fa-aed7-e93e67fae373", "metadata": {}, "outputs": [], "source": [ @@ -998,7 +937,6 @@ }, { "cell_type": "markdown", - "id": "506b583a-f643-45dc-bdd3-ae29120734fa", "metadata": {}, "source": [ "Currently, the SageMaker Clarify explainer offers a scalable and efficient implementation of SHAP, so the explainability config is `SHAPConfig`, including\n", @@ -1016,7 +954,6 @@ { "cell_type": "code", "execution_count": 26, - "id": "0ead08ae-1867-41b9-8c0e-6202760c4175", "metadata": {}, "outputs": [ { @@ -1047,7 +984,6 @@ }, { "cell_type": "markdown", - "id": "3c9417f1-b2b2-4c23-81ba-256ff4616c5c", "metadata": {}, "source": [ "#### Kick off baselining job\n", @@ -1058,7 +994,6 @@ { "cell_type": "code", "execution_count": 27, - "id": "9c27e74b-31f6-435a-a0d4-bef52a4cdcdb", "metadata": {}, "outputs": [ { @@ -1094,7 +1029,6 @@ }, { "cell_type": "markdown", - "id": "9cf396d3-c7ab-4041-8820-64c5ebd15d46", "metadata": {}, "source": [ "**NOTE**: The following cell waits until the baselining job is completed (in about 10 minutes). It then inspects the suggested constraints. This step can be skipped, because the monitor to be scheduled will automatically pick up baselining job name and wait for it before monitoring execution." @@ -1103,7 +1037,6 @@ { "cell_type": "code", "execution_count": 28, - "id": "ad0ece68-f130-4b66-b8ab-36d2916502c8", "metadata": {}, "outputs": [ { @@ -1156,7 +1089,6 @@ }, { "cell_type": "markdown", - "id": "5545f7e0-8256-4b33-8385-741c23b9acc6", "metadata": {}, "source": [ "### Monitoring Schedule\n", @@ -1166,7 +1098,6 @@ }, { "cell_type": "markdown", - "id": "b99f1d50-d9ce-42c6-84da-a710bfb7b47a", "metadata": {}, "source": [ "If a baselining job has been submitted, then the monitor object will automatically pick up the analysis configuration from the baselining job. But if the baselining step is skipped, or if the capture dataset has different nature than the training dataset, then analysis configuration has to be provided.\n", @@ -1183,7 +1114,6 @@ { "cell_type": "code", "execution_count": 29, - "id": "8d160d3e-0482-4c4b-a171-e62eddb38b87", "metadata": {}, "outputs": [], "source": [ @@ -1193,7 +1123,6 @@ { "cell_type": "code", "execution_count": 30, - "id": "1c7a1355-2997-46f2-ae02-cb00063e3661", "metadata": {}, "outputs": [ { @@ -1231,7 +1160,6 @@ }, { "cell_type": "markdown", - "id": "bf22401a-4662-4063-b47f-5be6becf3c3b", "metadata": {}, "source": [ "#### Wait for the first execution\n", @@ -1244,7 +1172,6 @@ { "cell_type": "code", "execution_count": 31, - "id": "ae00eb31-bbc7-4cf9-9fae-b323b4d380b2", "metadata": {}, "outputs": [], "source": [ @@ -1274,7 +1201,6 @@ }, { "cell_type": "markdown", - "id": "16fabf1c-8458-4186-9fb2-7bfa2462b705", "metadata": {}, "source": [ "**NOTE**: The following cell waits until the first monitoring execution is started. As explained above, the wait could take more than 60 minutes." @@ -1283,7 +1209,6 @@ { "cell_type": "code", "execution_count": 32, - "id": "b512df1e-57cf-4ba3-9262-0c325c4a600e", "metadata": {}, "outputs": [ { @@ -1304,7 +1229,6 @@ }, { "cell_type": "markdown", - "id": "210955ae-1709-423f-98c0-ca93476eebde", "metadata": {}, "source": [ "In real world, a monitoring schedule is supposed to be active all the time. But in this example, it can be stopped to avoid incurring extra charges. A stopped schedule will not trigger further executions, but the ongoing execution will continue. And if needed, the schedule can be restarted by `start_monitoring_schedule()`." @@ -1313,7 +1237,6 @@ { "cell_type": "code", "execution_count": 33, - "id": "a6980d31-c96d-4850-a7fb-c8583eeac54e", "metadata": {}, "outputs": [ { @@ -1331,7 +1254,6 @@ }, { "cell_type": "markdown", - "id": "117a4a1d-4410-4f60-b859-762f18f7370b", "metadata": {}, "source": [ "#### Wait for the execution to finish\n", @@ -1347,7 +1269,6 @@ { "cell_type": "code", "execution_count": 34, - "id": "2b07426d-f805-4527-9863-1d3d664734fa", "metadata": {}, "outputs": [], "source": [ @@ -1375,7 +1296,6 @@ }, { "cell_type": "markdown", - "id": "01434010-3c04-4ef5-acd2-21a3a0035fc8", "metadata": {}, "source": [ "**NOTE**: The following cell takes about 10 minutes." @@ -1384,7 +1304,6 @@ { "cell_type": "code", "execution_count": 35, - "id": "25e36f00-f488-4a16-867f-92c53d819782", "metadata": {}, "outputs": [ { @@ -1402,7 +1321,6 @@ }, { "cell_type": "markdown", - "id": "27ecf876-5999-4c2a-adcd-0a8537f082e6", "metadata": {}, "source": [ "#### Inspect execution results\n", @@ -1416,7 +1334,6 @@ { "cell_type": "code", "execution_count": 36, - "id": "3c767cbd-78c5-433d-a850-e230cb5a55dd", "metadata": {}, "outputs": [ { @@ -1461,7 +1378,6 @@ }, { "cell_type": "markdown", - "id": "602a2ef3-4d6c-4d93-974e-77a679fc4757", "metadata": {}, "source": [ "If there are any violations compared to the baseline, they are listed here. See [Feature Attribution Drift Violations](https://docs.aws.amazon.com/sagemaker/latest/dg/clarify-model-monitor-model-attribution-drift-violations.html) for the schema of the file, and how violations are detected." @@ -1470,7 +1386,6 @@ { "cell_type": "code", "execution_count": 37, - "id": "a7174d2e-9ee4-437f-be9a-c9d984318b76", "metadata": {}, "outputs": [], "source": [ @@ -1481,7 +1396,6 @@ }, { "cell_type": "markdown", - "id": "1b2e3d97-27cc-4325-814d-04219d25ab76", "metadata": {}, "source": [ "By default, the analysis results are also published to CloudWatch, see [CloudWatch Metrics for Feature Attribution Drift Analysis](https://docs.aws.amazon.com/sagemaker/latest/dg/clarify-feature-attribute-drift-cw.html)." @@ -1489,7 +1403,6 @@ }, { "cell_type": "markdown", - "id": "f6388287-b810-4522-bcc1-928228982388", "metadata": {}, "source": [ "## Cleanup\n", @@ -1499,7 +1412,6 @@ }, { "cell_type": "markdown", - "id": "554e8db8-4918-420c-9b4d-5c7263a402e7", "metadata": {}, "source": [ "First stop the worker thread," @@ -1508,7 +1420,6 @@ { "cell_type": "code", "execution_count": 38, - "id": "f813097c-00cc-4ee4-91cc-d03b72915c67", "metadata": {}, "outputs": [], "source": [ @@ -1517,7 +1428,6 @@ }, { "cell_type": "markdown", - "id": "80f971c4-c1ae-4766-ab44-a30d361df523", "metadata": {}, "source": [ "Then stop all monitors scheduled for the endpoint" @@ -1526,7 +1436,6 @@ { "cell_type": "code", "execution_count": 39, - "id": "e4b99289-3924-4d40-9860-75ccea76646b", "metadata": {}, "outputs": [ { @@ -1550,7 +1459,6 @@ }, { "cell_type": "markdown", - "id": "f2442401-06c9-481a-a04c-e339d618af54", "metadata": {}, "source": [ "Finally, delete the endpoint" @@ -1559,7 +1467,6 @@ { "cell_type": "code", "execution_count": 40, - "id": "d6dd0678-66d3-493d-bee4-7e2a9dab901e", "metadata": {}, "outputs": [], "source": [ @@ -1568,7 +1475,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ @@ -1611,9 +1517,9 @@ "metadata": { "instance_type": "ml.t3.medium", "kernelspec": { - "display_name": "Python 3 (Data Science)", + "display_name": "Python 3 (Data Science 3.0)", "language": "python", - "name": "python3__SAGEMAKER_INTERNAL__arn:aws:sagemaker:us-west-2:236514542706:image/datascience-1.0" + "name": "python3__SAGEMAKER_INTERNAL__arn:aws:sagemaker:us-west-2:236514542706:image/sagemaker-data-science-310-v1" }, "language_info": { "codemirror_mode": { @@ -1625,11 +1531,11 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.7.10" + "version": "3.10.6" }, "toc-autonumbering": false, "toc-showmarkdowntxt": false }, "nbformat": 4, "nbformat_minor": 5 -} \ No newline at end of file +} diff --git a/training/distributed_training/pytorch/data_parallel/maskrcnn/pytorch_smdataparallel_maskrcnn_demo.ipynb b/training/distributed_training/pytorch/data_parallel/maskrcnn/pytorch_smdataparallel_maskrcnn_demo.ipynb deleted file mode 100644 index 30a8f0a20f..0000000000 --- a/training/distributed_training/pytorch/data_parallel/maskrcnn/pytorch_smdataparallel_maskrcnn_demo.ipynb +++ /dev/null @@ -1,390 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Distributed data parallel `MaskRCNN` training with PyTorch and SageMaker distributed\n" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "---\n", - "\n", - "This notebook's CI test result for us-west-2 is as follows. CI test results in other regions can be found at the end of the notebook. \n", - "\n", - "![This us-west-2 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/us-west-2/training|distributed_training|pytorch|data_parallel|maskrcnn|pytorch_smdataparallel_maskrcnn_demo.ipynb)\n", - "\n", - "---" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "[Amazon SageMaker's distributed library](https://docs.aws.amazon.com/sagemaker/latest/dg/distributed-training.html) can be used to train deep learning models faster and cheaper. The [data parallel](https://docs.aws.amazon.com/sagemaker/latest/dg/data-parallel.html) feature in this library (`smdistributed.dataparallel`) is a distributed data parallel training framework for PyTorch, TensorFlow, and MXNet.\n", - "\n", - "This notebook demonstrates how to use `smdistributed.dataparallel` with PyTorch(version 1.10.2) on [Amazon SageMaker](https://aws.amazon.com/sagemaker/) to train a `MaskRCNN` model on [COCO 2017 dataset](https://cocodataset.org/#home) using [Amazon FSx for Lustre file-system](https://aws.amazon.com/fsx/lustre/) as data source.\n", - "\n", - "The outline of steps is as follows:\n", - "\n", - "1. Stage COCO 2017 dataset on [Amazon S3](https://aws.amazon.com/s3/)\n", - "2. Create Amazon FSx Lustre file-system and import data into the file-system from S3\n", - "3. Build Docker training image and push it to [Amazon ECR](https://aws.amazon.com/ecr/)\n", - "4. Configure data input channels for SageMaker\n", - "5. Configure hyper-prarameters\n", - "6. Define training metrics\n", - "7. Define training job, set distribution strategy to `SMDataParallel` and start training\n", - "\n", - "**NOTE:** With large training dataset, we recommend using [Amazon FSx](https://aws.amazon.com/fsx/) as the input file system for the SageMaker training job. FSx file input to SageMaker significantly cuts down training start up time on SageMaker because it avoids downloading the training data each time you start the training job (as done with S3 input for SageMaker training job) and provides good data read throughput.\n", - "\n", - "\n", - "**NOTE:** This example requires SageMaker Python SDK v2.X" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Amazon SageMaker Initialization\n", - "\n", - "Initialize the notebook instance. Get the AWS Region and a SageMaker execution role.\n", - "\n", - "### SageMaker role\n", - "\n", - "The following code cell defines `role` which is the IAM role ARN used to create and run SageMaker training and hosting jobs. This is the same IAM role used to create this SageMaker Notebook instance. \n", - "\n", - "`role` must have permission to create a SageMaker training job and host a model. For granular policies you can use to grant these permissions, see [Amazon SageMaker Roles](https://docs.aws.amazon.com/sagemaker/latest/dg/sagemaker-roles.html). If you do not require fine-tuned permissions for this demo, you can use the IAM managed policy `AmazonSageMakerFullAccess` to complete this demo. \n", - "\n", - "As described above, since we will be using FSx, please make sure to attach `FSx Access` permission to this IAM role." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "%%time\n", - "! python3 -m pip install --upgrade sagemaker\n", - "import sagemaker\n", - "from sagemaker import get_execution_role\n", - "from sagemaker.estimator import Estimator\n", - "import boto3\n", - "\n", - "sagemaker_session = sagemaker.Session()\n", - "bucket = sagemaker_session.default_bucket()\n", - "\n", - "role = (\n", - " get_execution_role()\n", - ") # provide a pre-existing role ARN as an alternative to creating a new role\n", - "role_name = role.split([\"/\"][-1])\n", - "print(f\"SageMaker Execution Role:{role}\")\n", - "print(f\"The name of the Execution role: {role_name[-1]}\")\n", - "\n", - "client = boto3.client(\"sts\")\n", - "account = client.get_caller_identity()[\"Account\"]\n", - "print(f\"AWS account:{account}\")\n", - "\n", - "session = boto3.session.Session()\n", - "region = session.region_name\n", - "print(f\"AWS region:{region}\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "To verify that the role above has required permissions:\n", - "\n", - "1. Go to the IAM console: https://console.aws.amazon.com/iam/home.\n", - "2. Select **Roles**.\n", - "3. Enter the role name in the search box to search for that role. \n", - "4. Select the role.\n", - "5. Use the **Permissions** tab to verify this role has required permissions attached." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Prepare SageMaker Training Images\n", - "\n", - "1. SageMaker by default use the latest [Amazon Deep Learning Container Images (DLC)](https://github.com/aws/deep-learning-containers/blob/master/available_images.md) PyTorch training image. In this step, we use it as a base image and install additional dependencies required for training `MaskRCNN` model.\n", - "2. In the GitHub repository https://github.com/HerringForks/DeepLearningExamples.git we have made a `smdistributed.dataparallel` PyTorch `MaskRCNN` training script available for your use. We will be installing the same on the training image.\n", - "\n", - "### Build and Push Docker Image to ECR\n", - "\n", - "Run the below command build the docker image and push it to ECR." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "image = \"\" # Example: mask-rcnn-smdataparallel-sagemaker\n", - "tag = \"\" # Example: pt1.8" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "!pygmentize ./Dockerfile" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "!pygmentize ./build_and_push.sh" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "dlc_account_id = 763104351884 # By default, set the account ID used for most regions" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "! aws ecr get-login-password --region {region} | docker login --username AWS --password-stdin {dlc_account_id}.dkr.ecr.{region}.amazonaws.com\n", - "! chmod +x build_and_push.sh; bash build_and_push.sh {dlc_account_id} {region} {image} {tag}" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Preparing FSx Input for SageMaker\n", - "\n", - "1. Download and prepare your training dataset on S3.\n", - "2. Follow the steps listed here to create a FSx linked with your S3 bucket with training data - https://docs.aws.amazon.com/fsx/latest/LustreGuide/create-fs-linked-data-repo.html. Make sure to add an endpoint to your VPC allowing S3 access.\n", - "3. Follow the steps listed here to configure your SageMaker training job to use FSx https://aws.amazon.com/blogs/machine-learning/speed-up-training-on-amazon-sagemaker-using-amazon-efs-or-amazon-fsx-for-lustre-file-systems/\n", - "\n", - "### Important Caveats\n", - "\n", - "1. You need to use the same `subnet` and `vpc` and `security group` used with FSx when launching the SageMaker notebook instance. The same configurations will be used by your SageMaker training job.\n", - "2. Make sure you set appropriate inbound/output rules in the `security group`. Specially, opening up these ports is necessary for SageMaker to access the FSx file system in the training job. https://docs.aws.amazon.com/fsx/latest/LustreGuide/limit-access-security-groups.html\n", - "3. Make sure `SageMaker IAM Role` used to launch this SageMaker training job has access to `AmazonFSx`.\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## SageMaker PyTorch Estimator function options\n", - "\n", - "In the following code block, you can update the estimator function to use a different instance type, instance count, and distribution strategy. You're also passing in the training script you reviewed in the previous cell.\n", - "\n", - "**Instance types**\n", - "\n", - "`SMDataParallel` supports model training on SageMaker with the following instance types only. For best performance, it is recommended you use an instance type that supports Amazon Elastic Fabric Adapter (ml.p3dn.24xlarge and ml.p4d.24xlarge).\n", - "\n", - "1. ml.p3.16xlarge\n", - "1. ml.p3dn.24xlarge [Recommended]\n", - "1. ml.p4d.24xlarge [Recommended]\n", - "\n", - "**Instance count**\n", - "\n", - "To get the best performance and the most out of `SMDataParallel`, you should use at least 2 instances, but you can also use 1 for testing this example.\n", - "\n", - "**Distribution strategy**\n", - "\n", - "Note that to use DDP mode, you update the `distribution` strategy, and set it to use `smdistributed dataparallel`. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import os\n", - "from sagemaker.pytorch import PyTorch" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "instance_type = \"ml.p4d.24xlarge\" # Other supported instance type: ml.p3.16xlarge, ml.p4d.24xlarge\n", - "instance_count = 2 # You can use 2, 4, 8 etc.\n", - "docker_image = f\"{account}.dkr.ecr.{region}.amazonaws.com/{image}:{tag}\" # YOUR_ECR_IMAGE_BUILT_WITH_ABOVE_DOCKER_FILE\n", - "region = \"\" # Example: us-west-2\n", - "username = \"AWS\"\n", - "subnets = [\"\"] # Should be same as Subnet used for FSx. Example: subnet-0f9XXXX\n", - "security_group_ids = [\n", - " \"\"\n", - "] # Should be same as Security group used for FSx. sg-03ZZZZZZ\n", - "job_name = \"pytorch-smdataparallel-mrcnn-fsx\" # This job name is used as prefix to the sagemaker training job. Makes it easy for your look for your training job in SageMaker Training job console.\n", - "file_system_id = \"\" # FSx file system ID with your training dataset. Example: 'fs-0bYYYYYY'\n", - "config_file = (\n", - " \"e2e_mask_rcnn_R_50_FPN_1x_16GPU_4bs.yaml\" # file that specifies the model config options\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "In the hyperparameter's dictionary, add the following:\n", - "1. To use AMP (FP16), add `\"fp16\": \"\"` to set True. In the training script, there's already an option `action=\"store_true\"` that automatically sets the empty inputs to `True`.\n", - "2. To properly set the training data path for the SageMaker training environment, add `\"data-dir\": \"/opt/ml/input/data/train\"`." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "hyperparameters = {\n", - " \"config-file\": config_file,\n", - " \"skip-test\": \"\",\n", - " \"seed\": 987,\n", - " \"fp16\": \"\",\n", - " \"max_steps\": 1000,\n", - " \"data-dir\": \"/opt/ml/input/data/train\",\n", - "}" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "estimator = PyTorch(\n", - " entry_point=\"train_pytorch_smdataparallel_maskrcnn.py\",\n", - " role=role,\n", - " image_uri=docker_image,\n", - " source_dir=\".\",\n", - " instance_count=instance_count,\n", - " instance_type=instance_type,\n", - " framework_version=\"1.10.2\",\n", - " py_version=\"py38\",\n", - " sagemaker_session=sagemaker_session,\n", - " hyperparameters=hyperparameters,\n", - " subnets=subnets,\n", - " security_group_ids=security_group_ids,\n", - " debugger_hook_config=False,\n", - " # Training using SMDataParallel Distributed Training Framework\n", - " distribution={\"smdistributed\": {\"dataparallel\": {\"enabled\": True}}},\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Configure FSx Input for your SageMaker Training job\n", - "\n", - "from sagemaker.inputs import FileSystemInput\n", - "\n", - "file_system_directory_path = \"YOUR_MOUNT_PATH_FOR_TRAINING_DATA\" # NOTE: '/fsx/' will be the root mount path. Example: '/fsx/mask_rcnn/PyTorch'\n", - "file_system_access_mode = \"ro\"\n", - "file_system_type = \"FSxLustre\"\n", - "train_fs = FileSystemInput(\n", - " file_system_id=file_system_id,\n", - " file_system_type=file_system_type,\n", - " directory_path=file_system_directory_path,\n", - " file_system_access_mode=file_system_access_mode,\n", - ")\n", - "data_channels = {\"train\": train_fs}" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Submit SageMaker training job\n", - "estimator.fit(inputs=data_channels, job_name=job_name)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Notebook CI Test Results\n", - "\n", - "This notebook was tested in multiple regions. The test results are as follows, except for us-west-2 which is shown at the top of the notebook.\n", - "\n", - "![This us-east-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/us-east-1/training|distributed_training|pytorch|data_parallel|maskrcnn|pytorch_smdataparallel_maskrcnn_demo.ipynb)\n", - "\n", - "![This us-east-2 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/us-east-2/training|distributed_training|pytorch|data_parallel|maskrcnn|pytorch_smdataparallel_maskrcnn_demo.ipynb)\n", - "\n", - "![This us-west-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/us-west-1/training|distributed_training|pytorch|data_parallel|maskrcnn|pytorch_smdataparallel_maskrcnn_demo.ipynb)\n", - "\n", - "![This ca-central-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/ca-central-1/training|distributed_training|pytorch|data_parallel|maskrcnn|pytorch_smdataparallel_maskrcnn_demo.ipynb)\n", - "\n", - "![This sa-east-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/sa-east-1/training|distributed_training|pytorch|data_parallel|maskrcnn|pytorch_smdataparallel_maskrcnn_demo.ipynb)\n", - "\n", - "![This eu-west-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/eu-west-1/training|distributed_training|pytorch|data_parallel|maskrcnn|pytorch_smdataparallel_maskrcnn_demo.ipynb)\n", - "\n", - "![This eu-west-2 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/eu-west-2/training|distributed_training|pytorch|data_parallel|maskrcnn|pytorch_smdataparallel_maskrcnn_demo.ipynb)\n", - "\n", - "![This eu-west-3 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/eu-west-3/training|distributed_training|pytorch|data_parallel|maskrcnn|pytorch_smdataparallel_maskrcnn_demo.ipynb)\n", - "\n", - "![This eu-central-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/eu-central-1/training|distributed_training|pytorch|data_parallel|maskrcnn|pytorch_smdataparallel_maskrcnn_demo.ipynb)\n", - "\n", - "![This eu-north-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/eu-north-1/training|distributed_training|pytorch|data_parallel|maskrcnn|pytorch_smdataparallel_maskrcnn_demo.ipynb)\n", - "\n", - "![This ap-southeast-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/ap-southeast-1/training|distributed_training|pytorch|data_parallel|maskrcnn|pytorch_smdataparallel_maskrcnn_demo.ipynb)\n", - "\n", - "![This ap-southeast-2 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/ap-southeast-2/training|distributed_training|pytorch|data_parallel|maskrcnn|pytorch_smdataparallel_maskrcnn_demo.ipynb)\n", - "\n", - "![This ap-northeast-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/ap-northeast-1/training|distributed_training|pytorch|data_parallel|maskrcnn|pytorch_smdataparallel_maskrcnn_demo.ipynb)\n", - "\n", - "![This ap-northeast-2 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/ap-northeast-2/training|distributed_training|pytorch|data_parallel|maskrcnn|pytorch_smdataparallel_maskrcnn_demo.ipynb)\n", - "\n", - "![This ap-south-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/ap-south-1/training|distributed_training|pytorch|data_parallel|maskrcnn|pytorch_smdataparallel_maskrcnn_demo.ipynb)\n" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "conda_amazonei_pytorch_latest_p36", - "language": "python", - "name": "conda_amazonei_pytorch_latest_p36" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.6.13" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} \ No newline at end of file diff --git a/use-cases/computer_vision/README.md b/use-cases/computer_vision/README.md deleted file mode 100644 index 8d2e15656c..0000000000 --- a/use-cases/computer_vision/README.md +++ /dev/null @@ -1,18 +0,0 @@ -# Computer Vision Demo - ----- - -## Contents - -Notebooks are as follows: -1. train -1. lineage -1. deploy-predict -1. pipeline - ----- -## Useful Resources - -* Computer vision demo: https://www.youtube.com/watch?v=Bx8r7GD1EKY&feature=youtu.be -* [Amazon SageMaker Developer Guide](https://docs.aws.amazon.com/sagemaker/latest/dg/whatis.html) -* [Amazon SageMaker Python SDK Documentation](https://sagemaker.readthedocs.io/en/stable/) diff --git a/use-cases/computer_vision/deploy_model.py b/use-cases/computer_vision/deploy_model.py deleted file mode 100644 index 37287dd384..0000000000 --- a/use-cases/computer_vision/deploy_model.py +++ /dev/null @@ -1,55 +0,0 @@ -import argparse -import time - -import boto3 - -# Parse argument variables passed via the DeployModel processing step -parser = argparse.ArgumentParser() -parser.add_argument("--model-name", type=str) -parser.add_argument("--region", type=str) -parser.add_argument("--endpoint-instance-type", type=str) -parser.add_argument("--endpoint-name", type=str) -args = parser.parse_args() - -region = args.region -boto3.setup_default_session(region_name=region) -sagemaker_boto_client = boto3.client("sagemaker") - -# name truncated per sagameker length requirements (63 char max) -endpoint_config_name = f"{args.model_name[:56]}-config" -existing_configs = sagemaker_boto_client.list_endpoint_configs(NameContains=endpoint_config_name)[ - "EndpointConfigs" -] - -if not existing_configs: - create_ep_config_response = sagemaker_boto_client.create_endpoint_config( - EndpointConfigName=endpoint_config_name, - ProductionVariants=[ - { - "InstanceType": args.endpoint_instance_type, - "InitialVariantWeight": 1, - "InitialInstanceCount": 1, - "ModelName": args.model_name, - "VariantName": "AllTraffic", - } - ], - ) - -existing_endpoints = sagemaker_boto_client.list_endpoints(NameContains=args.endpoint_name)[ - "Endpoints" -] - -if not existing_endpoints: - create_endpoint_response = sagemaker_boto_client.create_endpoint( - EndpointName=args.endpoint_name, EndpointConfigName=endpoint_config_name - ) - -endpoint_info = sagemaker_boto_client.describe_endpoint(EndpointName=args.endpoint_name) -endpoint_status = endpoint_info["EndpointStatus"] - -while endpoint_status == "Creating": - endpoint_info = sagemaker_boto_client.describe_endpoint(EndpointName=args.endpoint_name) - endpoint_status = endpoint_info["EndpointStatus"] - print("Endpoint status:", endpoint_status) - if endpoint_status == "Creating": - time.sleep(60) diff --git a/use-cases/computer_vision/inference_specification.py b/use-cases/computer_vision/inference_specification.py deleted file mode 100644 index 4191f58c77..0000000000 --- a/use-cases/computer_vision/inference_specification.py +++ /dev/null @@ -1,78 +0,0 @@ -import json - - -class InferenceSpecification: - - template = """ -{ - "InferenceSpecification": { - "Containers" : [{"Image": "IMAGE_REPLACE_ME"}], - "SupportedTransformInstanceTypes": INSTANCES_REPLACE_ME, - "SupportedRealtimeInferenceInstanceTypes": INSTANCES_REPLACE_ME, - "SupportedContentTypes": CONTENT_TYPES_REPLACE_ME, - "SupportedResponseMIMETypes": RESPONSE_MIME_TYPES_REPLACE_ME - } -} -""" - - def get_inference_specification_dict( - self, ecr_image, supports_gpu, supported_content_types=None, supported_mime_types=None - ): - return json.loads( - self.get_inference_specification_json( - ecr_image, supports_gpu, supported_content_types, supported_mime_types - ) - ) - - def get_inference_specification_json( - self, ecr_image, supports_gpu, supported_content_types=None, supported_mime_types=None - ): - if supported_mime_types is None: - supported_mime_types = [] - if supported_content_types is None: - supported_content_types = [] - return ( - self.template.replace("IMAGE_REPLACE_ME", ecr_image) - .replace("INSTANCES_REPLACE_ME", self.get_supported_instances(supports_gpu)) - .replace("CONTENT_TYPES_REPLACE_ME", json.dumps(supported_content_types)) - .replace("RESPONSE_MIME_TYPES_REPLACE_ME", json.dumps(supported_mime_types)) - ) - - def get_supported_instances(self, supports_gpu): - cpu_list = [ - "ml.m4.xlarge", - "ml.m4.2xlarge", - "ml.m4.4xlarge", - "ml.m4.10xlarge", - "ml.m4.16xlarge", - "ml.m5.large", - "ml.m5.xlarge", - "ml.m5.2xlarge", - "ml.m5.4xlarge", - "ml.m5.12xlarge", - "ml.m5.24xlarge", - "ml.c4.xlarge", - "ml.c4.2xlarge", - "ml.c4.4xlarge", - "ml.c4.8xlarge", - "ml.c5.xlarge", - "ml.c5.2xlarge", - "ml.c5.4xlarge", - "ml.c5.9xlarge", - "ml.c5.18xlarge", - ] - gpu_list = [ - "ml.p2.xlarge", - "ml.p2.8xlarge", - "ml.p2.16xlarge", - "ml.p3.2xlarge", - "ml.p3.8xlarge", - "ml.p3.16xlarge", - ] - - list_to_return = cpu_list - - if supports_gpu: - list_to_return = cpu_list + gpu_list - - return json.dumps(list_to_return) diff --git a/use-cases/computer_vision/metastases-detection-pipeline.ipynb b/use-cases/computer_vision/metastases-detection-pipeline.ipynb deleted file mode 100644 index 87ca9fce4c..0000000000 --- a/use-cases/computer_vision/metastases-detection-pipeline.ipynb +++ /dev/null @@ -1,784 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Computer Vision for Medical Imaging - Pipeline Mode\n" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "---\n", - "\n", - "This notebook's CI test result for us-west-2 is as follows. CI test results in other regions can be found at the end of the notebook. \n", - "\n", - "![This us-west-2 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/us-west-2/use-cases|computer_vision|metastases-detection-pipeline.ipynb)\n", - "\n", - "---" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "This notebook showcases techniques and services offer by SageMaker to build a model which predicts if an image of cells contains cancer. This notebook describes how to automate the ML workflow using SageMaker Pipelines." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Dataset\n", - "The dataset for this demo comes from the [Camelyon16 Challenge](https://camelyon16.grand-challenge.org/) made available under the CC0 licencse. The raw data provided by the challenge has been processed into 96x96 pixel tiles by [Bas Veeling](https://github.com/basveeling/pcam) and also made available under the CC0 license. For detailed information on each dataset please see the papers below:\n", - "* Ehteshami Bejnordi et al. Diagnostic Assessment of Deep Learning Algorithms for Detection of Lymph Node Metastases in Women With Breast Cancer. JAMA: The Journal of the American Medical Association, 318(22), 2199\u20132210. [doi:jama.2017.14585](https://doi.org/10.1001/jama.2017.14585)\n", - "* B. S. Veeling, J. Linmans, J. Winkens, T. Cohen, M. Welling. \"Rotation Equivariant CNNs for Digital Pathology\". [arXiv:1806.03962](http://arxiv.org/abs/1806.03962)\n", - "\n", - "The tiled dataset from Bas Veeling is over 6GB of data. In order to easily run this demo, the dataset has been pruned to the first 14,000 images of the tiled dataset and comes included in the repo with this notebook for convenience." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Update Sagemaker SDK and Boto3\n", - "\n", - "
\n", - "NOTE You may get an error from pip's dependency resolver; you can ignore this error.\n", - "
" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "! pip install --upgrade sagemaker boto3" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Import Libraries" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import pip\n", - "\n", - "\n", - "def import_or_install(package):\n", - " try:\n", - " __import__(package)\n", - " except ImportError:\n", - " ! pip install $package\n", - "\n", - "\n", - "required_packages = [\"sagemaker\", \"boto3\", \"h5py\", \"tqdm\", \"matplotlib\", \"opencv-python\"]\n", - "\n", - "for package in required_packages:\n", - " import_or_install(package)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import boto3\n", - "import sagemaker\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "import cv2\n", - "import os\n", - "import zipfile\n", - "import h5py\n", - "import mxnet as mx\n", - "from datetime import datetime\n", - "from tqdm import tqdm\n", - "\n", - "from sagemaker.workflow.pipeline import Pipeline\n", - "from sagemaker.workflow.steps import CreateModelStep\n", - "from sagemaker.sklearn.processing import SKLearnProcessor\n", - "from sagemaker.workflow.step_collections import RegisterModel\n", - "from sagemaker.workflow.steps import ProcessingStep, TrainingStep\n", - "from sagemaker.workflow.parameters import ParameterInteger, ParameterFloat, ParameterString" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Configure Boto3 Clients and Sessions" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "region = \"us-west-2\" # Change region as needed\n", - "boto3.setup_default_session(region_name=region)\n", - "boto_session = boto3.Session(region_name=region)\n", - "\n", - "s3_client = boto3.client(\"s3\", region_name=region)\n", - "\n", - "sagemaker_boto_client = boto_session.client(\"sagemaker\")\n", - "sagemaker_session = sagemaker.session.Session(\n", - " boto_session=boto_session, sagemaker_client=sagemaker_boto_client\n", - ")\n", - "sagemaker_role = sagemaker.get_execution_role()\n", - "\n", - "bucket = sagemaker.Session().default_bucket()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Load Dataset" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# check if directory exists\n", - "if not os.path.isdir(\"data\"):\n", - " os.mkdir(\"data\")\n", - "\n", - "# download zip file from public s3 bucket\n", - "!wget -P data https://sagemaker-sample-files.s3.amazonaws.com/datasets/image/pcam/medical_images.zip" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "with zipfile.ZipFile(\"data/medical_images.zip\") as zf:\n", - " zf.extractall()\n", - "with open(\"data/camelyon16_tiles.h5\", \"rb\") as hf:\n", - " f = h5py.File(hf, \"r\")\n", - "\n", - " X = f[\"x\"][()]\n", - " y = f[\"y\"][()]\n", - "\n", - "print(\"Shape of X:\", X.shape)\n", - "print(\"Shape of y:\", y.shape)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# write to session s3 bucket\n", - "s3_client.upload_file(\"data/medical_images.zip\", bucket, f\"data/medical_images.zip\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# delete local copy\n", - "import os\n", - "\n", - "if os.path.exists(\"data/medical_images.zip\"):\n", - " os.remove(\"data/medical_images.zip\")\n", - "else:\n", - " print(\"The file does not exist\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## View Sample Images from Dataset" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def preview_images(X, y, n, cols):\n", - " sample_images = X[:n]\n", - " sample_labels = y[:n]\n", - "\n", - " rows = int(np.ceil(n / cols))\n", - " fig, axs = plt.subplots(rows, cols, figsize=(11.5, 7))\n", - "\n", - " for i, ax in enumerate(axs.flatten()):\n", - " image = sample_images[i]\n", - " label = sample_labels[i]\n", - " ax.imshow(image)\n", - " ax.axis(\"off\")\n", - " ax.set_title(f\"Label: {label}\")\n", - "\n", - " plt.tight_layout()\n", - "\n", - "\n", - "preview_images(X, y, 15, 5)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Shuffle and Split Dataset" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from sklearn.model_selection import train_test_split\n", - "\n", - "X_numpy = X[:]\n", - "y_numpy = y[:]\n", - "\n", - "X_train, X_test, y_train, y_test = train_test_split(\n", - " X_numpy, y_numpy, test_size=1000, random_state=0\n", - ")\n", - "X_train, X_val, y_train, y_val = train_test_split(X_train, y_train, test_size=2000, random_state=1)\n", - "\n", - "print(X_train.shape)\n", - "print(X_val.shape)\n", - "print(X_test.shape)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Convert Splits to RecordIO Format" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def write_to_recordio(X: np.ndarray, y: np.ndarray, prefix: str):\n", - " record = mx.recordio.MXIndexedRecordIO(idx_path=f\"{prefix}.idx\", uri=f\"{prefix}.rec\", flag=\"w\")\n", - " for idx, arr in enumerate(tqdm(X)):\n", - " header = mx.recordio.IRHeader(0, y[idx], idx, 0)\n", - " s = mx.recordio.pack_img(\n", - " header,\n", - " arr,\n", - " quality=95,\n", - " img_fmt=\".jpg\",\n", - " )\n", - " record.write_idx(idx, s)\n", - " record.close()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "write_to_recordio(X_train, y_train, prefix=\"data/train\")\n", - "write_to_recordio(X_val, y_val, prefix=\"data/val\")\n", - "write_to_recordio(X_test, y_test, prefix=\"data/test\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Upload Data Splits to S3" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "prefix = \"cv-metastasis\"\n", - "\n", - "try:\n", - " s3_client.create_bucket(\n", - " Bucket=bucket, ACL=\"private\", CreateBucketConfiguration={\"LocationConstraint\": region}\n", - " )\n", - " print(f\"Created S3 bucket: {bucket}\")\n", - "\n", - "except Exception as e:\n", - " if e.response[\"Error\"][\"Code\"] == \"BucketAlreadyOwnedByYou\":\n", - " print(f\"Using existing bucket: {bucket}\")\n", - " else:\n", - " raise (e)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "s3_client.upload_file(\"data/train.rec\", bucket, f\"{prefix}/data/train/train.rec\")\n", - "s3_client.upload_file(\"data/val.rec\", bucket, f\"{prefix}/data/val/val.rec\")\n", - "s3_client.upload_file(\"data/test.rec\", bucket, f\"{prefix}/data/test/test.rec\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Configure the Estimator" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "training_image = sagemaker.image_uris.retrieve(\"image-classification\", region)\n", - "num_training_samples = X_train.shape[0]\n", - "num_classes = len(np.unique(y_train))\n", - "\n", - "hyperparameters = {\n", - " \"num_layers\": 18,\n", - " \"use_pretrained_model\": 1,\n", - " \"augmentation_type\": \"crop_color_transform\",\n", - " \"image_shape\": \"3,96,96\",\n", - " \"num_classes\": num_classes,\n", - " \"num_training_samples\": num_training_samples,\n", - " \"mini_batch_size\": 64,\n", - " \"epochs\": 5,\n", - " \"learning_rate\": 0.01,\n", - " \"precision_dtype\": \"float32\",\n", - "}\n", - "\n", - "estimator_config = {\n", - " \"hyperparameters\": hyperparameters,\n", - " \"image_uri\": training_image,\n", - " \"role\": sagemaker.get_execution_role(),\n", - " \"instance_count\": 1,\n", - " \"instance_type\": \"ml.p3.2xlarge\",\n", - " \"volume_size\": 100,\n", - " \"max_run\": 360000,\n", - " \"output_path\": f\"s3://{bucket}/{prefix}/training_jobs\",\n", - "}\n", - "\n", - "image_classifier = sagemaker.estimator.Estimator(**estimator_config)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Pipeline" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Step 1: Create RecordIO Splits" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "base_uri = f\"s3://{bucket}/{prefix}/data\"\n", - "input_data_uri = sagemaker.s3.S3Uploader.upload(\n", - " local_path=\"data/camelyon16_tiles.h5\", desired_s3_uri=base_uri\n", - ")\n", - "\n", - "input_data = ParameterString(name=\"InputData\", default_value=input_data_uri)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "s3_client.upload_file(Filename=\"split_data.py\", Bucket=bucket, Key=f\"{prefix}/code/split_data.py\")\n", - "split_data_script_uri = f\"s3://{bucket}/{prefix}/code/split_data.py\"\n", - "split_data_instance_type = \"ml.t3.large\"\n", - "\n", - "sklearn_processor = SKLearnProcessor(\n", - " framework_version=\"1.0-1\",\n", - " instance_type=split_data_instance_type,\n", - " instance_count=1,\n", - " base_job_name=\"image-classication-split-data\",\n", - " role=sagemaker_role,\n", - ")\n", - "\n", - "split_data_step = ProcessingStep(\n", - " name=\"SplitData\",\n", - " processor=sklearn_processor,\n", - " inputs=[\n", - " sagemaker.processing.ProcessingInput(\n", - " source=input_data, destination=\"/opt/ml/processing/input\"\n", - " ),\n", - " ],\n", - " outputs=[\n", - " sagemaker.processing.ProcessingOutput(\n", - " output_name=\"train_data\", source=\"/opt/ml/processing/output/data/train\"\n", - " ),\n", - " sagemaker.processing.ProcessingOutput(\n", - " output_name=\"val_data\", source=\"/opt/ml/processing/output/data/val\"\n", - " ),\n", - " sagemaker.processing.ProcessingOutput(\n", - " output_name=\"test_data\", source=\"/opt/ml/processing/output/data/test\"\n", - " ),\n", - " ],\n", - " code=split_data_script_uri,\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Step 2: Train Model" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "train_step_inputs = {\n", - " \"train\": sagemaker.inputs.TrainingInput(\n", - " s3_data=split_data_step.properties.ProcessingOutputConfig.Outputs[\n", - " \"train_data\"\n", - " ].S3Output.S3Uri,\n", - " content_type=\"application/x-recordio\",\n", - " s3_data_type=\"S3Prefix\",\n", - " input_mode=\"Pipe\",\n", - " ),\n", - " \"validation\": sagemaker.inputs.TrainingInput(\n", - " s3_data=split_data_step.properties.ProcessingOutputConfig.Outputs[\n", - " \"val_data\"\n", - " ].S3Output.S3Uri,\n", - " content_type=\"application/x-recordio\",\n", - " s3_data_type=\"S3Prefix\",\n", - " input_mode=\"Pipe\",\n", - " ),\n", - "}\n", - "\n", - "train_step = TrainingStep(name=\"TrainModel\", estimator=image_classifier, inputs=train_step_inputs)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Step 3: Register Model" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "mpg_name = \"cv-metastasis-{}\".format(datetime.now().strftime(\"%Y-%m-%d-%H-%M-%S\"))\n", - "\n", - "model_approval_status = ParameterString(\n", - " name=\"ModelApprovalStatus\", default_value=\"PendingManualApproval\"\n", - ")\n", - "\n", - "register_step = RegisterModel(\n", - " name=\"RegisterModel\",\n", - " estimator=image_classifier,\n", - " model_data=train_step.properties.ModelArtifacts.S3ModelArtifacts,\n", - " content_types=[\"image/jpeg\"],\n", - " response_types=[\"text/csv\"],\n", - " inference_instances=[\"ml.t2.medium\", \"ml.m5.xlarge\"],\n", - " transform_instances=[\"ml.m5.xlarge\"],\n", - " model_package_group_name=mpg_name,\n", - " approval_status=model_approval_status,\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Step 4: Create Model" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "model = sagemaker.model.Model(\n", - " name=f\"{mpg_name}-pipline\",\n", - " image_uri=training_image,\n", - " model_data=train_step.properties.ModelArtifacts.S3ModelArtifacts,\n", - " sagemaker_session=sagemaker_session,\n", - " role=sagemaker_role,\n", - ")\n", - "\n", - "inputs = sagemaker.inputs.CreateModelInput(instance_type=\"ml.m4.xlarge\")\n", - "\n", - "create_model_step = CreateModelStep(name=\"ModelPreDeployment\", model=model, inputs=inputs)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Step 5: Deploy Model" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "s3_client.upload_file(\n", - " Filename=\"deploy_model.py\", Bucket=bucket, Key=f\"{prefix}/code/deploy_model.py\"\n", - ")\n", - "deploy_model_script_uri = f\"s3://{bucket}/{prefix}/code/deploy_model.py\"\n", - "deploy_instance_type = \"ml.m4.xlarge\"\n", - "\n", - "deploy_model_processor = SKLearnProcessor(\n", - " framework_version=\"1.0-1\",\n", - " role=sagemaker_role,\n", - " instance_type=\"ml.t3.medium\",\n", - " instance_count=1,\n", - " base_job_name=f\"{prefix}-deploy-model\",\n", - " sagemaker_session=sagemaker_session,\n", - ")\n", - "\n", - "deploy_step = ProcessingStep(\n", - " name=\"DeployModel\",\n", - " processor=deploy_model_processor,\n", - " job_arguments=[\n", - " \"--model-name\",\n", - " create_model_step.properties.ModelName,\n", - " \"--region\",\n", - " region,\n", - " \"--endpoint-instance-type\",\n", - " deploy_instance_type,\n", - " \"--endpoint-name\",\n", - " \"cv-model-pipeline\",\n", - " ],\n", - " code=deploy_model_script_uri,\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Create Pipeline" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "pipeline_name = \"{}-pipeline-{}\".format(prefix, datetime.now().strftime(\"%Y-%m-%d-%H-%M-%S\"))\n", - "\n", - "pipeline = Pipeline(\n", - " name=pipeline_name,\n", - " parameters=[input_data, model_approval_status],\n", - " steps=[split_data_step, train_step, register_step, create_model_step, deploy_step],\n", - ")\n", - "\n", - "pipeline.upsert(role_arn=sagemaker_role)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "parameters = {\"ModelApprovalStatus\": \"Approved\"}\n", - "\n", - "start_response = pipeline.start(parameters=parameters)\n", - "start_response.wait(max_attempts=100)\n", - "start_response.describe()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Lineage\n", - "\n", - "Review the lineage of the artifacts generated by the pipeline." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import time\n", - "from sagemaker.lineage.visualizer import LineageTableVisualizer\n", - "from pprint import pprint\n", - "\n", - "\n", - "viz = LineageTableVisualizer(sagemaker_session)\n", - "for execution_step in reversed(start_response.list_steps()):\n", - " pprint(execution_step)\n", - " display(viz.show(pipeline_execution_step=execution_step))\n", - " time.sleep(5)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Clean up resources" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def delete_model_package_group(sm_client, package_group_name):\n", - " try:\n", - " model_versions = sm_client.list_model_packages(ModelPackageGroupName=package_group_name)\n", - "\n", - " except Exception as e:\n", - " print(\"{} \\n\".format(e))\n", - " return\n", - "\n", - " for model_version in model_versions[\"ModelPackageSummaryList\"]:\n", - " try:\n", - " sm_client.delete_model_package(ModelPackageName=model_version[\"ModelPackageArn\"])\n", - " except Exception as e:\n", - " print(\"{} \\n\".format(e))\n", - " time.sleep(0.5) # Ensure requests aren't throttled\n", - "\n", - " try:\n", - " sm_client.delete_model_package_group(ModelPackageGroupName=package_group_name)\n", - " print(\"{} model package group deleted\".format(package_group_name))\n", - " except Exception as e:\n", - " print(\"{} \\n\".format(e))\n", - " return\n", - "\n", - "\n", - "def delete_sagemaker_pipeline(sm_client, pipeline_name):\n", - " try:\n", - " sm_client.delete_pipeline(\n", - " PipelineName=pipeline_name,\n", - " )\n", - " print(\"{} pipeline deleted\".format(pipeline_name))\n", - " except Exception as e:\n", - " print(\"{} \\n\".format(e))\n", - " return" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "client = sagemaker.Session().sagemaker_client\n", - "delete_model_package_group(client, mpg_name)\n", - "delete_sagemaker_pipeline(client, pipeline_name)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Notebook CI Test Results\n", - "\n", - "This notebook was tested in multiple regions. The test results are as follows, except for us-west-2 which is shown at the top of the notebook.\n", - "\n", - "![This us-east-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/us-east-1/use-cases|computer_vision|metastases-detection-pipeline.ipynb)\n", - "\n", - "![This us-east-2 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/us-east-2/use-cases|computer_vision|metastases-detection-pipeline.ipynb)\n", - "\n", - "![This us-west-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/us-west-1/use-cases|computer_vision|metastases-detection-pipeline.ipynb)\n", - "\n", - "![This ca-central-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/ca-central-1/use-cases|computer_vision|metastases-detection-pipeline.ipynb)\n", - "\n", - "![This sa-east-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/sa-east-1/use-cases|computer_vision|metastases-detection-pipeline.ipynb)\n", - "\n", - "![This eu-west-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/eu-west-1/use-cases|computer_vision|metastases-detection-pipeline.ipynb)\n", - "\n", - "![This eu-west-2 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/eu-west-2/use-cases|computer_vision|metastases-detection-pipeline.ipynb)\n", - "\n", - "![This eu-west-3 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/eu-west-3/use-cases|computer_vision|metastases-detection-pipeline.ipynb)\n", - "\n", - "![This eu-central-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/eu-central-1/use-cases|computer_vision|metastases-detection-pipeline.ipynb)\n", - "\n", - "![This eu-north-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/eu-north-1/use-cases|computer_vision|metastases-detection-pipeline.ipynb)\n", - "\n", - "![This ap-southeast-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/ap-southeast-1/use-cases|computer_vision|metastases-detection-pipeline.ipynb)\n", - "\n", - "![This ap-southeast-2 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/ap-southeast-2/use-cases|computer_vision|metastases-detection-pipeline.ipynb)\n", - "\n", - "![This ap-northeast-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/ap-northeast-1/use-cases|computer_vision|metastases-detection-pipeline.ipynb)\n", - "\n", - "![This ap-northeast-2 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/ap-northeast-2/use-cases|computer_vision|metastases-detection-pipeline.ipynb)\n", - "\n", - "![This ap-south-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/ap-south-1/use-cases|computer_vision|metastases-detection-pipeline.ipynb)\n" - ] - } - ], - "metadata": { - "instance_type": "ml.t3.medium", - "kernelspec": { - "display_name": "conda_mxnet_p36", - "language": "python", - "name": "conda_mxnet_p36" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.6.13" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} \ No newline at end of file diff --git a/use-cases/computer_vision/metastases-detection.ipynb b/use-cases/computer_vision/metastases-detection.ipynb deleted file mode 100644 index 7b203f9fe5..0000000000 --- a/use-cases/computer_vision/metastases-detection.ipynb +++ /dev/null @@ -1,1035 +0,0 @@ -{ - "cells": [ - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Computer Vision for Medical Imaging\n" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "---\n", - "\n", - "This notebook's CI test result for us-west-2 is as follows. CI test results in other regions can be found at the end of the notebook. \n", - "\n", - "![This us-west-2 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/us-west-2/use-cases|computer_vision|metastases-detection.ipynb)\n", - "\n", - "---" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "This notebook showcases techniques and services offer by SageMaker to build a model which predicts if an image of cells contains cancer. This notebook shows how to build a model using hyperparameter tuning." - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Dataset\n", - "The dataset for this demo comes from the [Camelyon16 Challenge](https://camelyon16.grand-challenge.org/) made available under the CC0 licencse. The raw data provided by the challenge has been processed into 96x96 pixel tiles by [Bas Veeling](https://github.com/basveeling/pcam) and also made available under the CC0 license. For detailed information on each dataset please see the papers below:\n", - "* Ehteshami Bejnordi et al. Diagnostic Assessment of Deep Learning Algorithms for Detection of Lymph Node Metastases in Women With Breast Cancer. JAMA: The Journal of the American Medical Association, 318(22), 2199–2210. [doi:jama.2017.14585](https://doi.org/10.1001/jama.2017.14585)\n", - "* B. S. Veeling, J. Linmans, J. Winkens, T. Cohen, M. Welling. \"Rotation Equivariant CNNs for Digital Pathology\". [arXiv:1806.03962](http://arxiv.org/abs/1806.03962)\n", - "\n", - "The tiled dataset from Bas Veeling is over 6GB of data. In order to easily run this demo, the dataset has been pruned to the first 14,000 images of the tiled dataset and comes included in the repo with this notebook for convenience." - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Update Sagemaker SDK and Boto3\n", - "\n", - "
\n", - "NOTE You may get an error from pip's dependency resolver; you can ignore this error.\n", - "
" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import pip\n", - "\n", - "\n", - "def import_or_install(package):\n", - " try:\n", - " __import__(package)\n", - " except ImportError:\n", - " ! pip install $package\n", - "\n", - "\n", - "required_packages = [\"sagemaker\", \"boto3\", \"h5py\", \"tqdm\", \"matplotlib\", \"opencv-python\"]\n", - "\n", - "for package in required_packages:\n", - " import_or_install(package)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Import Libraries" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import io\n", - "import os\n", - "import h5py\n", - "import zipfile\n", - "import boto3\n", - "import sagemaker\n", - "import mxnet as mx\n", - "import numpy as np\n", - "from tqdm import tqdm\n", - "import matplotlib.pyplot as plt\n", - "import cv2\n", - "from datetime import datetime\n", - "\n", - "from inference_specification import InferenceSpecification" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Configure Boto3 Clients and Sessions" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "region = \"us-west-2\" # Change region as needed\n", - "boto3.setup_default_session(region_name=region)\n", - "boto_session = boto3.Session(region_name=region)\n", - "\n", - "s3_client = boto3.client(\"s3\", region_name=region)\n", - "\n", - "sagemaker_boto_client = boto_session.client(\"sagemaker\")\n", - "sagemaker_session = sagemaker.session.Session(\n", - " boto_session=boto_session, sagemaker_client=sagemaker_boto_client\n", - ")\n", - "sagemaker_role = sagemaker.get_execution_role()\n", - "\n", - "bucket = sagemaker.Session().default_bucket()" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Part 1: Prepare Dataset\n", - "### Load Dataset" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# check if directory exists\n", - "if not os.path.isdir(\"data\"):\n", - " os.mkdir(\"data\")\n", - "\n", - "# download zip file from public s3 bucket\n", - "s3_client.download_file(\n", - " f\"sagemaker-example-files-prod-{region}\",\n", - " \"datasets/image/pcam/medical_images.zip\",\n", - " \"data/medical_images.zip\",\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "with zipfile.ZipFile(\"data/medical_images.zip\") as zf:\n", - " zf.extractall()\n", - "with open(\"data/camelyon16_tiles.h5\", \"rb\") as hf:\n", - " f = h5py.File(hf, \"r\")\n", - "\n", - " X = f[\"x\"][()]\n", - " y = f[\"y\"][()]\n", - "\n", - "print(\"Shape of X:\", X.shape)\n", - "print(\"Shape of y:\", y.shape)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# write to session s3 bucket\n", - "s3_client.upload_file(\"data/medical_images.zip\", bucket, f\"data/medical_images.zip\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# delete local copy\n", - "import os\n", - "\n", - "if os.path.exists(\"data/medical_images.zip\"):\n", - " os.remove(\"data/medical_images.zip\")\n", - "else:\n", - " print(\"The file does not exist\")" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### View Sample Images from Dataset" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def preview_images(X, y, n, cols):\n", - " sample_images = X[:n]\n", - " sample_labels = y[:n]\n", - "\n", - " rows = int(np.ceil(n / cols))\n", - " fig, axs = plt.subplots(rows, cols, figsize=(11.5, 7))\n", - "\n", - " for i, ax in enumerate(axs.flatten()):\n", - " image = sample_images[i]\n", - " label = sample_labels[i]\n", - " ax.imshow(image)\n", - " ax.axis(\"off\")\n", - " ax.set_title(f\"Label: {label}\")\n", - "\n", - " plt.tight_layout()\n", - "\n", - "\n", - "preview_images(X, y, 15, 5)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Shuffle and Split Dataset" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from sklearn.model_selection import train_test_split\n", - "\n", - "X_numpy = X[:]\n", - "y_numpy = y[:]\n", - "\n", - "X_train, X_test, y_train, y_test = train_test_split(\n", - " X_numpy, y_numpy, test_size=1000, random_state=0\n", - ")\n", - "X_train, X_val, y_train, y_val = train_test_split(X_train, y_train, test_size=2000, random_state=1)\n", - "\n", - "print(X_train.shape)\n", - "print(X_val.shape)\n", - "print(X_test.shape)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Convert Splits to RecordIO Format" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def write_to_recordio(X: np.ndarray, y: np.ndarray, prefix: str):\n", - " record = mx.recordio.MXIndexedRecordIO(idx_path=f\"{prefix}.idx\", uri=f\"{prefix}.rec\", flag=\"w\")\n", - " for idx, arr in enumerate(tqdm(X)):\n", - " header = mx.recordio.IRHeader(0, y[idx], idx, 0)\n", - " s = mx.recordio.pack_img(\n", - " header,\n", - " arr,\n", - " quality=95,\n", - " img_fmt=\".jpg\",\n", - " )\n", - " record.write_idx(idx, s)\n", - " record.close()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "write_to_recordio(X_train, y_train, prefix=\"data/train\")\n", - "write_to_recordio(X_val, y_val, prefix=\"data/val\")\n", - "write_to_recordio(X_test, y_test, prefix=\"data/test\")" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Upload Data Splits to S3" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "prefix = \"cv-metastasis-{}\".format(datetime.now().strftime(\"%Y-%m-%d-%H-%M-%S\"))\n", - "\n", - "try:\n", - " s3_client.create_bucket(\n", - " Bucket=bucket, ACL=\"private\", CreateBucketConfiguration={\"LocationConstraint\": region}\n", - " )\n", - " print(f\"Created S3 bucket: {bucket}\")\n", - "\n", - "except Exception as e:\n", - " if e.response[\"Error\"][\"Code\"] == \"BucketAlreadyOwnedByYou\":\n", - " print(f\"Using existing bucket: {bucket}\")\n", - " else:\n", - " raise (e)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "s3_client.upload_file(\"data/train.rec\", bucket, f\"{prefix}/data/train/train.rec\")\n", - "s3_client.upload_file(\"data/val.rec\", bucket, f\"{prefix}/data/val/val.rec\")\n", - "s3_client.upload_file(\"data/test.rec\", bucket, f\"{prefix}/data/test/test.rec\")" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Part 2: Training the Model\n", - "### Configure the Estimator" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "training_image = sagemaker.image_uris.retrieve(\"image-classification\", region)\n", - "num_training_samples = X_train.shape[0]\n", - "num_classes = len(np.unique(y_train))\n", - "\n", - "hyperparameters = {\n", - " \"num_layers\": 18,\n", - " \"use_pretrained_model\": 1,\n", - " \"augmentation_type\": \"crop_color_transform\",\n", - " \"image_shape\": \"3,96,96\",\n", - " \"num_classes\": num_classes,\n", - " \"num_training_samples\": num_training_samples,\n", - " \"mini_batch_size\": 64,\n", - " \"epochs\": 5,\n", - " \"learning_rate\": 0.01,\n", - " \"precision_dtype\": \"float32\",\n", - "}\n", - "\n", - "estimator_config = {\n", - " \"hyperparameters\": hyperparameters,\n", - " \"image_uri\": training_image,\n", - " \"role\": sagemaker.get_execution_role(),\n", - " \"instance_count\": 1,\n", - " \"instance_type\": \"ml.p3.2xlarge\",\n", - " \"volume_size\": 100,\n", - " \"max_run\": 360000,\n", - " \"output_path\": f\"s3://{bucket}/{prefix}/training_jobs\",\n", - "}\n", - "\n", - "image_classifier = sagemaker.estimator.Estimator(**estimator_config)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Configure the Hyperparameter Tuner\n", - "\n", - "Although we would prefer to tune for recall, the current HyperparameterTuner implementation for Image Classification only supports validation accuracy." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "hyperparameter_ranges = {\n", - " \"mini_batch_size\": sagemaker.parameter.CategoricalParameter([16, 32, 64]),\n", - " \"learning_rate\": sagemaker.parameter.CategoricalParameter([0.001, 0.01]),\n", - "}\n", - "\n", - "hyperparameter_tuner = sagemaker.tuner.HyperparameterTuner(\n", - " estimator=image_classifier,\n", - " objective_metric_name=\"validation:accuracy\",\n", - " hyperparameter_ranges=hyperparameter_ranges,\n", - " max_jobs=6,\n", - " max_parallel_jobs=2,\n", - " base_tuning_job_name=prefix,\n", - ")" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Define the Data Channels" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "train_input = sagemaker.inputs.TrainingInput(\n", - " s3_data=f\"s3://{bucket}/{prefix}/data/train\",\n", - " content_type=\"application/x-recordio\",\n", - " s3_data_type=\"S3Prefix\",\n", - " input_mode=\"Pipe\",\n", - ")\n", - "\n", - "val_input = sagemaker.inputs.TrainingInput(\n", - " s3_data=f\"s3://{bucket}/{prefix}/data/val\",\n", - " content_type=\"application/x-recordio\",\n", - " s3_data_type=\"S3Prefix\",\n", - " input_mode=\"Pipe\",\n", - ")\n", - "\n", - "data_channels = {\"train\": train_input, \"validation\": val_input}" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Run Hyperparameter Tuning Jobs" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "if \"tuning_job_name\" not in locals():\n", - " hyperparameter_tuner.fit(inputs=data_channels)\n", - " tuning_job_name = hyperparameter_tuner.describe().get(\"HyperParameterTuningJobName\")\n", - "else:\n", - " print(f\"Using previous tuning job: {tuning_job_name}\")" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Examine Results\n", - "\n", - "
\n", - "NOTE: If your kernel has restarted after running the hyperparameter tuning job, everyting you need has been persisted to SageMaker. You can continue on without having to run the tuning job again.\n", - "
" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "results = sagemaker.analytics.HyperparameterTuningJobAnalytics(tuning_job_name)\n", - "results_df = results.dataframe()\n", - "results_df" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "best_training_job_summary = results.description()[\"BestTrainingJob\"]\n", - "best_training_job_name = best_training_job_summary[\"TrainingJobName\"]\n", - "\n", - "%store best_training_job_name" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Part 3: Retrieving and Saving the Model in SageMaker Lineage and SageMaker Model Registry\n", - "### Examine Lineage\n", - "Though you already know the training job details from running the cells above, if we were just given the model uri, we could use SageMaker Lineage to retrieve the training job details which produced the model." - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Data Lineage and Metrics for Best Model" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from sagemaker.lineage import context, artifact, association, action" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Training data artifact" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "results = sagemaker.analytics.HyperparameterTuningJobAnalytics(tuning_job_name)\n", - "results_df = results.dataframe()\n", - "best_training_job_summary = results.description()[\"BestTrainingJob\"]\n", - "best_training_job_details = sagemaker_boto_client.describe_training_job(\n", - " TrainingJobName=best_training_job_name\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "data_artifact_list = []\n", - "for data_input in best_training_job_details[\"InputDataConfig\"]:\n", - " channel = data_input[\"ChannelName\"]\n", - " data_s3_uri = data_input[\"DataSource\"][\"S3DataSource\"][\"S3Uri\"]\n", - "\n", - " matching_artifacts = list(\n", - " artifact.Artifact.list(source_uri=data_s3_uri, sagemaker_session=sagemaker_session)\n", - " )\n", - "\n", - " if matching_artifacts:\n", - " data_artifact = matching_artifacts[0]\n", - " print(f\"Using existing artifact: {data_artifact.artifact_arn}\")\n", - " else:\n", - " data_artifact = artifact.Artifact.create(\n", - " artifact_name=channel,\n", - " source_uri=data_s3_uri,\n", - " artifact_type=\"DataSet\",\n", - " sagemaker_session=sagemaker_session,\n", - " )\n", - " print(f\"Create artifact {data_artifact.artifact_arn}: SUCCESSFUL\")\n", - " data_artifact_list.append(data_artifact)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Model artifact" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "trained_model_s3_uri = best_training_job_details[\"ModelArtifacts\"][\"S3ModelArtifacts\"]\n", - "\n", - "matching_artifacts = list(\n", - " artifact.Artifact.list(source_uri=trained_model_s3_uri, sagemaker_session=sagemaker_session)\n", - ")\n", - "\n", - "if matching_artifacts:\n", - " model_artifact = matching_artifacts[0]\n", - " print(f\"Using existing artifact: {model_artifact.artifact_arn}\")\n", - "else:\n", - " model_artifact = artifact.Artifact.create(\n", - " artifact_name=\"TrainedModel\",\n", - " source_uri=trained_model_s3_uri,\n", - " artifact_type=\"Model\",\n", - " sagemaker_session=sagemaker_session,\n", - " )\n", - " print(f\"Create artifact {model_artifact.artifact_arn}: SUCCESSFUL\")" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Set artifact associations" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "trial_component = sagemaker_boto_client.describe_trial_component(\n", - " TrialComponentName=best_training_job_summary[\"TrainingJobName\"] + \"-aws-training-job\"\n", - ")\n", - "trial_component_arn = trial_component[\"TrialComponentArn\"]" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Store artifacts" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "artifact_list = data_artifact_list + [model_artifact]\n", - "\n", - "for artif in artifact_list:\n", - " if artif.artifact_type == \"DataSet\":\n", - " assoc = \"ContributedTo\"\n", - " else:\n", - " assoc = \"Produced\"\n", - " try:\n", - " association.Association.create(\n", - " source_arn=artif.artifact_arn,\n", - " destination_arn=trial_component_arn,\n", - " association_type=assoc,\n", - " sagemaker_session=sagemaker_session,\n", - " )\n", - " print(f\"Association with {artif.artifact_type}: SUCCESSFUL\")\n", - " except:\n", - " print(f\"Association already exists with {artif.artifact_type}\")" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Model Registry\n", - "You can also save your model in the model registry, which you can use to check and retrieve your model in the future" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "mpg_name = prefix\n", - "\n", - "model_packages = sagemaker_boto_client.list_model_packages(ModelPackageGroupName=mpg_name)[\n", - " \"ModelPackageSummaryList\"\n", - "]\n", - "\n", - "if model_packages:\n", - " print(f\"Using existing Model Package Group: {mpg_name}\")\n", - "else:\n", - " mpg_input_dict = {\n", - " \"ModelPackageGroupName\": mpg_name,\n", - " \"ModelPackageGroupDescription\": \"Cancer metastasis detection\",\n", - " }\n", - "\n", - " mpg_response = sagemaker_boto_client.create_model_package_group(**mpg_input_dict)\n", - " print(f\"Create Model Package Group {mpg_name}: SUCCESSFUL\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "scrolled": true - }, - "outputs": [], - "source": [ - "training_jobs = results_df[\"TrainingJobName\"]\n", - "\n", - "for job_name in training_jobs:\n", - " job_data = sagemaker_boto_client.describe_training_job(TrainingJobName=job_name)\n", - " model_uri = job_data.get(\"ModelArtifacts\", {}).get(\"S3ModelArtifacts\")\n", - " training_image = job_data[\"AlgorithmSpecification\"][\"TrainingImage\"]\n", - "\n", - " mp_inference_spec = InferenceSpecification().get_inference_specification_dict(\n", - " ecr_image=training_image,\n", - " supports_gpu=False,\n", - " supported_content_types=[\"text/csv\"],\n", - " supported_mime_types=[\"text/csv\"],\n", - " )\n", - "\n", - " mp_inference_spec[\"InferenceSpecification\"][\"Containers\"][0][\"ModelDataUrl\"] = model_uri\n", - " mp_input_dict = {\n", - " \"ModelPackageGroupName\": mpg_name,\n", - " \"ModelPackageDescription\": \"SageMaker Image Classifier\",\n", - " \"ModelApprovalStatus\": \"PendingManualApproval\",\n", - " }\n", - "\n", - " mp_input_dict.update(mp_inference_spec)\n", - " mp_response = sagemaker_boto_client.create_model_package(**mp_input_dict)\n", - "\n", - "model_packages = sagemaker_boto_client.list_model_packages(\n", - " ModelPackageGroupName=mpg_name, MaxResults=6\n", - ")[\"ModelPackageSummaryList\"]\n", - "model_packages" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Part 4: Deploying the Model\n", - "### Create Model from Existing Training Job Name for Deployment\n", - "\n", - "We can use the name of the best training job from our hyperparameter tuning experiment and create its corresponding model." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "model_name = \"metastasis-detection-{}\".format(datetime.now().strftime(\"%Y-%m-%d-%H-%M-%S\"))\n", - "model_matches = sagemaker_boto_client.list_models(NameContains=model_name)[\"Models\"]\n", - "training_image = sagemaker.image_uris.retrieve(\"image-classification\", region)\n", - "\n", - "if not model_matches:\n", - " print(f\"Creating model {model_name}\")\n", - " sagemaker_session.create_model_from_job(\n", - " name=model_name,\n", - " training_job_name=best_training_job_summary[\"TrainingJobName\"],\n", - " role=sagemaker_role,\n", - " image_uri=training_image,\n", - " )\n", - "else:\n", - " print(f\"Model {model_name} already exists.\")" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Deploy Model using Data from Model Registry\n", - "\n", - "As we saved data about model in the Model Resgistry, we can look up details about the model and use them to deploy the model." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "training_jobs = results_df[\"TrainingJobName\"]\n", - "best_model_index = np.where(training_jobs.values == best_training_job_summary[\"TrainingJobName\"])[\n", - " 0\n", - "][0]\n", - "best_model_info = sagemaker_boto_client.describe_model_package(\n", - " ModelPackageName=model_packages[best_model_index][\"ModelPackageArn\"]\n", - ")\n", - "best_model_container = best_model_info.get(\"InferenceSpecification\").get(\"Containers\")[0]\n", - "deploy_instance_type = best_model_info.get(\"InferenceSpecification\").get(\n", - " \"SupportedRealtimeInferenceInstanceTypes\"\n", - ")[0]\n", - "\n", - "best_model = sagemaker.Model(\n", - " image_uri=best_model_container.get(\"Image\"),\n", - " model_data=best_model_container.get(\"ModelDataUrl\"),\n", - " role=sagemaker.get_execution_role(),\n", - " name=mpg_name,\n", - ")\n", - "\n", - "best_model.deploy(\n", - " initial_instance_count=1, instance_type=deploy_instance_type, endpoint_name=mpg_name\n", - ")" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Inference\n", - "Finally, the we can now validate the model for use. You can obtain the endpoint from the client library using the result from previous operations, and generate classifications from the trained model using that endpoint." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from sklearn.model_selection import train_test_split\n", - "\n", - "with h5py.File(\"data/camelyon16_tiles.h5\", \"r\") as hf:\n", - " X = hf[\"x\"][()]\n", - " y = hf[\"y\"][()]\n", - "\n", - "X_numpy = X[:]\n", - "y_numpy = y[:]\n", - "\n", - "X_train, X_test, y_train, y_test = train_test_split(\n", - " X_numpy, y_numpy, test_size=1000, random_state=0\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# view test image\n", - "image = X_test[0]\n", - "label = y_test[0]\n", - "plt.imshow(image)\n", - "plt.axis(\"off\")\n", - "plt.title(f\"Label: {label}\");" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from PIL import Image\n", - "\n", - "img = Image.fromarray(X_test[0])\n", - "file_name = \"data/test_image.jpg\"\n", - "img.save(file_name)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import json\n", - "\n", - "runtime = boto3.Session().client(service_name=\"runtime.sagemaker\")\n", - "with open(file_name, \"rb\") as f:\n", - " payload = f.read()\n", - " payload = bytearray(payload)\n", - "\n", - "response = runtime.invoke_endpoint(\n", - " EndpointName=mpg_name, ContentType=\"application/x-image\", Body=payload\n", - ")\n", - "\n", - "result = response[\"Body\"].read()\n", - "\n", - "# result will be in json format and convert it to ndarray\n", - "result = json.loads(result)\n", - "print(result)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# the result will output the probabilities for all classes\n", - "# find the class with maximum probability and print the class index\n", - "index = np.argmax(result)\n", - "index" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "predictions = []\n", - "for i in range(len(X_test)):\n", - " img = Image.fromarray(X_test[i])\n", - " file_name = f\"/tmp/test_image.jpg\"\n", - " img.save(file_name)\n", - "\n", - " with open(file_name, \"rb\") as f:\n", - " payload = f.read()\n", - " payload = bytearray(payload)\n", - "\n", - " response = runtime.invoke_endpoint(\n", - " EndpointName=mpg_name, ContentType=\"application/x-image\", Body=payload\n", - " )\n", - "\n", - " result = response[\"Body\"].read()\n", - " result = json.loads(result)\n", - " index = np.argmax(result)\n", - " predictions.append(index)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from sklearn.metrics import precision_recall_fscore_support\n", - "\n", - "precision, recall, f1, _ = precision_recall_fscore_support(y_test, predictions)\n", - "print(f\"Precision = {precision[1]}\")\n", - "print(f\"Recall = {recall[1]}\")\n", - "print(f\"F1-Score = {f1[1]}\")" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Part 5: Clean up resources" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "best_model.sagemaker_session.delete_endpoint(mpg_name)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Notebook CI Test Results\n", - "\n", - "This notebook was tested in multiple regions. The test results are as follows, except for us-west-2 which is shown at the top of the notebook.\n", - "\n", - "![This us-east-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/us-east-1/use-cases|computer_vision|metastases-detection.ipynb)\n", - "\n", - "![This us-east-2 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/us-east-2/use-cases|computer_vision|metastases-detection.ipynb)\n", - "\n", - "![This us-west-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/us-west-1/use-cases|computer_vision|metastases-detection.ipynb)\n", - "\n", - "![This ca-central-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/ca-central-1/use-cases|computer_vision|metastases-detection.ipynb)\n", - "\n", - "![This sa-east-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/sa-east-1/use-cases|computer_vision|metastases-detection.ipynb)\n", - "\n", - "![This eu-west-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/eu-west-1/use-cases|computer_vision|metastases-detection.ipynb)\n", - "\n", - "![This eu-west-2 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/eu-west-2/use-cases|computer_vision|metastases-detection.ipynb)\n", - "\n", - "![This eu-west-3 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/eu-west-3/use-cases|computer_vision|metastases-detection.ipynb)\n", - "\n", - "![This eu-central-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/eu-central-1/use-cases|computer_vision|metastases-detection.ipynb)\n", - "\n", - "![This eu-north-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/eu-north-1/use-cases|computer_vision|metastases-detection.ipynb)\n", - "\n", - "![This ap-southeast-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/ap-southeast-1/use-cases|computer_vision|metastases-detection.ipynb)\n", - "\n", - "![This ap-southeast-2 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/ap-southeast-2/use-cases|computer_vision|metastases-detection.ipynb)\n", - "\n", - "![This ap-northeast-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/ap-northeast-1/use-cases|computer_vision|metastases-detection.ipynb)\n", - "\n", - "![This ap-northeast-2 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/ap-northeast-2/use-cases|computer_vision|metastases-detection.ipynb)\n", - "\n", - "![This ap-south-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/ap-south-1/use-cases|computer_vision|metastases-detection.ipynb)\n" - ] - } - ], - "metadata": { - "instance_type": "ml.t3.medium", - "kernelspec": { - "display_name": "Python 3 (MXNet 1.9 Python 3.8 CPU Optimized)", - "language": "python", - "name": "python3__SAGEMAKER_INTERNAL__arn:aws:sagemaker:us-west-2:236514542706:image/mxnet-1.9-cpu-py38-ubuntu20.04-sagemaker-v1.0" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.10" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/use-cases/computer_vision/split_data.py b/use-cases/computer_vision/split_data.py deleted file mode 100644 index bd2069eaf8..0000000000 --- a/use-cases/computer_vision/split_data.py +++ /dev/null @@ -1,61 +0,0 @@ -import subprocess -import sys - -subprocess.check_call([sys.executable, "-m", "pip", "install", "h5py"]) -subprocess.check_call([sys.executable, "-m", "pip", "install", "mxnet"]) -subprocess.check_call([sys.executable, "-m", "pip", "install", "opencv-python-headless"]) - -import os -import pathlib - -import cv2 -import h5py -import mxnet as mx -import numpy as np -from sklearn.model_selection import train_test_split - - -def write_to_recordio(X: np.ndarray, y: np.ndarray, prefix: str): - record = mx.recordio.MXIndexedRecordIO(idx_path=f"{prefix}.idx", uri=f"{prefix}.rec", flag="w") - for idx, arr in enumerate(X): - header = mx.recordio.IRHeader(0, y[idx], idx, 0) - s = mx.recordio.pack_img( - header, - arr, - quality=95, - img_fmt=".jpg", - ) - record.write_idx(idx, s) - record.close() - - -if __name__ == "__main__": - - # input_path = pathlib.Path('/opt/ml/processing/input') - # input_file = list(input_path.glob('*.h5'))[0] - - input_file = "/opt/ml/processing/input/camelyon16_tiles.h5" - f = h5py.File(input_file, "r") - X = f["x"] - y = f["y"] - - X_numpy = X[:] - y_numpy = y[:] - - X_train, X_test, y_train, y_test = train_test_split( - X_numpy, y_numpy, test_size=1000, random_state=0 - ) - X_train, X_val, y_train, y_val = train_test_split( - X_train, y_train, test_size=2000, random_state=1 - ) - - output_dir = "/opt/ml/processing/output/data" - - write_to_recordio(X_train, y_train, prefix=f"{output_dir}/train/train") - write_to_recordio(X_val, y_val, prefix=f"{output_dir}/val/val") - write_to_recordio(X_test, y_test, prefix=f"{output_dir}/test/test") - - # we do not need the idx files so we remove them to prevent them from becoming part of the output - os.remove(f"{output_dir}/train/train.idx") - os.remove(f"{output_dir}/val/val.idx") - os.remove(f"{output_dir}/test/test.idx") diff --git a/use-cases/index.rst b/use-cases/index.rst index ad5fdd4066..2ad21ffb38 100644 --- a/use-cases/index.rst +++ b/use-cases/index.rst @@ -29,14 +29,6 @@ E-Commerce Personalization retail_recommend/retail_recommend_pipeline -Computer Vision for Medical Imaging ------------------------------------ - -.. toctree:: - :maxdepth: 1 - - computer_vision/metastases-detection - computer_vision/metastases-detection-pipeline Pipelines with NLP for Product Rating Prediction diff --git a/use-cases/predictive_maintenance/1_dataprep_dw_job_predmaint.ipynb b/use-cases/predictive_maintenance/1_dataprep_dw_job_predmaint.ipynb deleted file mode 100644 index 2cf8c0dd43..0000000000 --- a/use-cases/predictive_maintenance/1_dataprep_dw_job_predmaint.ipynb +++ /dev/null @@ -1,682 +0,0 @@ -{ - "cells": [ - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Fleet Predictive Maintenance: Part 1. Data Preparation with SageMaker Data Wrangler\n" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "---\n", - "\n", - "This notebook's CI test result for us-west-2 is as follows. CI test results in other regions can be found at the end of the notebook. \n", - "\n", - "![This us-west-2 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/us-west-2/use-cases|predictive_maintenance|1_dataprep_dw_job_predmaint.ipynb)\n", - "\n", - "---" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "*Using SageMaker Studio to Predict Fault Classification*\n" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Background\n", - "\n", - "This notebook is part of a sequence of notebooks whose purpose is to demonstrate a Predictive Maintenance (PrM) solution for automobile fleet maintenance via Amazon SageMaker Studio so that business users have a quick path towards a PrM POC. In this notebook, we will be focusing on preprocessing engine sensor data. It is the first notebook in a series of notebooks. You can choose to run this notebook by itself or in sequence with the other notebooks listed below. Please see the [README.md](README.md) for more information about this use case implement of this sequence of notebooks. " - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "1. [Data Prep: Processing Job from Data Wrangler Output](./1_dataprep_dw_job_predmaint.ipynb) (current notebook)\n", - "1. [Data Prep: Featurization](./2_dataprep_predmaint.ipynb)\n", - "1. [Train, Tune and Predict using Batch Transform](./3_train_tune_predict_predmaint.ipynb)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Important Notes: \n", - "\n", - "* Due to cost consideration, the goal of this example is to show you how to use some of SageMaker Studio's features, not necessarily to achieve the best result. \n", - "* We use the built-in classification algorithm in this example, and a Python 3 (Data Science) Kernel is required.\n", - "* The nature of predictive maintenace solutions, requires a domain knowledge expert of the system or machinery. With this in mind, we will make assumptions here for certain elements of this solution with the acknowldgement that these assumptions should be informed by a domain expert and a main business stakeholder" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "----\n", - "## SageMaker Data Wrangler Job Notebook\n", - "\n", - "This notebook uses the Data Wrangler .flow file to submit a SageMaker Data Wrangler Job\n", - "with the following steps:\n", - "\n", - "* Push Data Wrangler .flow file to S3\n", - "* Parse the .flow file inputs, and create the argument dictionary to submit to a boto client\n", - "* Submit the ProcessingJob arguments and wait for Job completion\n", - "\n", - "Optionally, the notebook also gives an example of starting a SageMaker XGBoost TrainingJob using\n", - "the newly processed data." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Upgrade SageMaker to the latest version\n", - "! pip install --upgrade sagemaker" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import json\n", - "import os\n", - "import time\n", - "import uuid\n", - "\n", - "import boto3\n", - "import sagemaker" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Parameters\n", - "\n", - "The following lists configurable parameters that are used throughout this notebook." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# S3 bucket for saving processing job outputs\n", - "# Feel free to specify a different bucket here if you wish.\n", - "sess = sagemaker.Session()\n", - "bucket = sess.default_bucket()\n", - "prefix = \"data_wrangler_flows\"\n", - "flow_id = f\"{time.strftime('%d-%H-%M-%S', time.gmtime())}-{str(uuid.uuid4())[:8]}\"\n", - "flow_name = f\"flow-{flow_id}\"\n", - "flow_uri = f\"s3://{bucket}/{prefix}/{flow_name}.flow\"\n", - "\n", - "flow_file_name = \"dw_flow/prm.flow\"\n", - "\n", - "iam_role = sagemaker.get_execution_role()\n", - "\n", - "# Processing Job Resources Configurations\n", - "# Data wrangler processing job only supports 1 instance.\n", - "instance_count = 1\n", - "instance_type = \"ml.m5.4xlarge\"\n", - "\n", - "# Processing Job Path URI Information. This is the where the output data from SageMaker Data Wrangler will be stored.\n", - "output_prefix = f\"export-{flow_name}/output\"\n", - "output_path = f\"s3://{bucket}/{output_prefix}\"\n", - "# Output name is auto-generated from the select node's ID + output name from the flow file, which specifies how the data will be transformed.\n", - "output_name = \"ff586e7b-a02d-472b-91d4-da3dd05d7a30.default\"\n", - "\n", - "processing_job_name = f\"data-wrangler-flow-processing-{flow_id}\"\n", - "\n", - "processing_dir = \"/opt/ml/processing\"\n", - "\n", - "# Modify the variable below to specify the content type to be used for writing each output\n", - "# Currently supported options are 'CSV' or 'PARQUET', and default to 'CSV'\n", - "output_content_type = \"CSV\"\n", - "\n", - "# URL to use for sagemaker client.\n", - "# If this is None, boto will automatically construct the appropriate URL to use\n", - "# when communicating with sagemaker.\n", - "sagemaker_endpoint_url = None" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "__For this demo, the following cell has been added to the generated code from the Data Wrangler export. The changes are needed to update the S3 bucket in the .flow file to match your S3 location as well as make sure we have the right container URI depending on your region.__" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from demo_helpers import update_dw_s3uri\n", - "\n", - "# update the flow file to change the s3 location to our bucket\n", - "update_dw_s3uri(flow_file_name)\n", - "\n", - "# get the Data Wrangler container associated with our region\n", - "region = boto3.Session().region_name\n", - "container_uri = sagemaker.image_uris.retrieve(\n", - " \"data-wrangler\", sagemaker.Session().boto_region_name, version=\"1.x\"\n", - ")\n", - "\n", - "dw_output_path_prm = output_path\n", - "print(\n", - " f\"Storing dw_output_path_prm = {dw_output_path_prm} for use in next notebook 2_fleet_predmaint.ipynb\"\n", - ")\n", - "%store dw_output_path_prm" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Push Flow to S3\n", - "\n", - "Use the following cell to upload the Data Wrangler .flow file to Amazon S3 so that\n", - "it can be used as an input to the processing job." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Load .flow file\n", - "with open(flow_file_name) as f:\n", - " flow = json.load(f)\n", - "\n", - "# Upload to S3\n", - "s3_client = boto3.client(\"s3\")\n", - "s3_client.upload_file(flow_file_name, bucket, f\"{prefix}/{flow_name}.flow\")\n", - "\n", - "print(f\"Data Wrangler Flow notebook uploaded to {flow_uri}\")" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Create Processing Job arguments\n", - "\n", - "This notebook submits a Processing Job using the Sagmaker Python SDK. Below, utility methods are \n", - "defined for creating Processing Job Inputs for the following sources: S3, Athena, and Redshift." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from sagemaker.processing import ProcessingInput, ProcessingOutput\n", - "from sagemaker.dataset_definition.inputs import (\n", - " AthenaDatasetDefinition,\n", - " DatasetDefinition,\n", - " RedshiftDatasetDefinition,\n", - ")\n", - "\n", - "\n", - "def create_flow_notebook_processing_input(base_dir, flow_s3_uri):\n", - " return ProcessingInput(\n", - " source=flow_s3_uri,\n", - " destination=f\"{base_dir}/flow\",\n", - " input_name=\"flow\",\n", - " s3_data_type=\"S3Prefix\",\n", - " s3_input_mode=\"File\",\n", - " s3_data_distribution_type=\"FullyReplicated\",\n", - " )\n", - "\n", - "\n", - "def create_s3_processing_input(s3_dataset_definition, name, base_dir):\n", - " return ProcessingInput(\n", - " source=s3_dataset_definition[\"s3ExecutionContext\"][\"s3Uri\"],\n", - " destination=f\"{base_dir}/{name}\",\n", - " input_name=name,\n", - " s3_data_type=\"S3Prefix\",\n", - " s3_input_mode=\"File\",\n", - " s3_data_distribution_type=\"FullyReplicated\",\n", - " )\n", - "\n", - "\n", - "def create_athena_processing_input(athena_dataset_defintion, name, base_dir):\n", - " return ProcessingInput(\n", - " input_name=name,\n", - " dataset_definition=DatasetDefinition(\n", - " local_path=f\"{base_dir}/{name}\",\n", - " athena_dataset_definition=AthenaDatasetDefinition(\n", - " catalog=athena_dataset_defintion[\"catalogName\"],\n", - " database=athena_dataset_defintion[\"databaseName\"],\n", - " query_string=athena_dataset_defintion[\"queryString\"],\n", - " output_s3_uri=athena_dataset_defintion[\"s3OutputLocation\"] + f\"{name}/\",\n", - " output_format=athena_dataset_defintion[\"outputFormat\"].upper(),\n", - " ),\n", - " ),\n", - " )\n", - "\n", - "\n", - "def create_redshift_processing_input(redshift_dataset_defintion, name, base_dir):\n", - " return ProcessingInput(\n", - " input_name=name,\n", - " dataset_definition=DatasetDefinition(\n", - " local_path=f\"{base_dir}/{name}\",\n", - " redshift_dataset_definition=RedshiftDatasetDefinition(\n", - " cluster_id=redshift_dataset_defintion[\"clusterIdentifier\"],\n", - " database=redshift_dataset_defintion[\"database\"],\n", - " db_user=redshift_dataset_defintion[\"dbUser\"],\n", - " query_string=redshift_dataset_defintion[\"queryString\"],\n", - " cluster_role_arn=redshift_dataset_defintion[\"unloadIamRole\"],\n", - " output_s3_uri=redshift_dataset_defintion[\"s3OutputLocation\"] + f\"{name}/\",\n", - " output_format=redshift_dataset_defintion[\"outputFormat\"].upper(),\n", - " ),\n", - " ),\n", - " )\n", - "\n", - "\n", - "def create_processing_inputs(processing_dir, flow, flow_uri):\n", - " \"\"\"Helper function for creating processing inputs\n", - " :param flow: loaded data wrangler flow notebook\n", - " :param flow_uri: S3 URI of the data wrangler flow notebook\n", - " \"\"\"\n", - " processing_inputs = []\n", - " flow_processing_input = create_flow_notebook_processing_input(processing_dir, flow_uri)\n", - " processing_inputs.append(flow_processing_input)\n", - "\n", - " for node in flow[\"nodes\"]:\n", - " if \"dataset_definition\" in node[\"parameters\"]:\n", - " data_def = node[\"parameters\"][\"dataset_definition\"]\n", - " name = data_def[\"name\"]\n", - " source_type = data_def[\"datasetSourceType\"]\n", - "\n", - " if source_type == \"S3\":\n", - " processing_inputs.append(create_s3_processing_input(data_def, name, processing_dir))\n", - " elif source_type == \"Athena\":\n", - " processing_inputs.append(\n", - " create_athena_processing_input(data_def, name, processing_dir)\n", - " )\n", - " elif source_type == \"Redshift\":\n", - " processing_inputs.append(\n", - " create_redshift_processing_input(data_def, name, processing_dir)\n", - " )\n", - " else:\n", - " raise ValueError(f\"{source_type} is not supported for Data Wrangler Processing.\")\n", - "\n", - " return processing_inputs\n", - "\n", - "\n", - "def create_processing_output(output_name, output_path, processing_dir):\n", - " return ProcessingOutput(\n", - " output_name=output_name,\n", - " source=os.path.join(processing_dir, \"output\"),\n", - " destination=output_path,\n", - " s3_upload_mode=\"EndOfJob\",\n", - " )\n", - "\n", - "\n", - "def create_container_arguments(output_name, output_content_type):\n", - " output_config = {output_name: {\"content_type\": output_content_type}}\n", - " return [f\"--output-config '{json.dumps(output_config)}'\"]" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Start ProcessingJob\n", - "\n", - "Now, the Processing Job is submitted using the Processor from the Sagemaker SDK.\n", - "Logs are turned off, but can be turned on for debugging purposes." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "%%time\n", - "from sagemaker.processing import Processor\n", - "\n", - "processor = Processor(\n", - " role=iam_role,\n", - " image_uri=container_uri,\n", - " instance_count=instance_count,\n", - " instance_type=instance_type,\n", - " sagemaker_session=sess,\n", - ")\n", - "\n", - "processor.run(\n", - " inputs=create_processing_inputs(processing_dir, flow, flow_uri),\n", - " outputs=[create_processing_output(output_name, output_path, processing_dir)],\n", - " arguments=create_container_arguments(output_name, output_content_type),\n", - " wait=True,\n", - " logs=False,\n", - " job_name=processing_job_name,\n", - ")" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Data Cleaning with Data Wrangler\n", - "\n", - "#### Load, preparation, EDA and Preprocessing \n", - "\n", - "[contents](#2_Contents)\n", - "\n", - "For the initial data preparation and exploration, we will utilize SageMaker's new feature, Data Wrangler, to load data and do some data transformations. In the Data Wrangler GUI, we will perform the following steps. Note that because this data is generated, the data is relatively clean and there are few data cleaning steps needed. After completing these steps, you can uncomment and run the code below to inspect your cleaned data.\n", - "1. Load fleet sensor logs data from S3\n", - "1. Load fleet details data from S3\n", - "1. Change column data types \n", - "1. Change coulmn headers \n", - "1. Check for Null/NA values (impute or drop)\n", - "1. Join sensor and details data\n", - "1. One-Hot Encode categorical features\n", - "1. Do preliminar analysis using built-in feature\n", - "1. Export recipe as SageMaker Data Wrangler job\n", - "1. Upload final cleaned data set to S3\n", - "\n", - "\n", - "\n", - "For our purposes, we will download the final cleaned data set from S3 into our SageMaker Studio instance, but for more information on how to load and preprocess tabular data follow this link: [Tabular Preprocessing Blog]().\n", - "For additional information on preprocessing for PrM, please refer to this blog, [On the relevance of preprocessing in predictive\n", - "maintenance for dynamic systems](https://bird.bcamath.org/bitstream/handle/20.500.11824/892/CernudaPREDICT2018S16.pdf?sequence=1&isAllowed=y)." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# fleet = wr.s3.read_csv(path=dw_output_path_prm, dataset=True)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# # add in additional features and change data types\n", - "# fleet[\"datetime\"] = pd.to_datetime(fleet[\"datetime\"], format=\"%Y-%m-%d %H:%M:%S\")\n", - "# fleet[\"cycle\"] = fleet.groupby(\"vehicle_id\")[\"datetime\"].rank(\"dense\")\n", - "# fleet[\"make\"] = fleet[\"make\"].astype(\"category\")\n", - "# fleet[\"model\"] = fleet[\"model\"].astype(\"category\")\n", - "# fleet[\"vehicle_class\"] = fleet[\"vehicle_class\"].astype(\"category\")\n", - "# fleet[\"engine_type\"] = fleet[\"engine_type\"].astype(\"category\")\n", - "# fleet[\"engine_age\"] = fleet[\"datetime\"].dt.year - fleet[\"year\"]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# fleet = fleet[\n", - "# [\n", - "# \"target\",\n", - "# \"vehicle_id\",\n", - "# \"datetime\",\n", - "# \"make\",\n", - "# \"model\",\n", - "# \"year\",\n", - "# \"vehicle_class\",\n", - "# \"engine_type\",\n", - "# \"make_code_Make A\",\n", - "# \"make_code_Make B\",\n", - "# \"make_code_Make E\",\n", - "# \"make_code_Make C\",\n", - "# \"make_code_Make D\",\n", - "# \"model_code_Model E1\",\n", - "# \"model_code_Model A4\",\n", - "# \"model_code_Model B1\",\n", - "# \"model_code_Model B2\",\n", - "# \"model_code_Model A2\",\n", - "# \"model_code_Model A3\",\n", - "# \"model_code_Model B3\",\n", - "# \"model_code_Model C2\",\n", - "# \"model_code_Model A1\",\n", - "# \"model_code_Model A5\",\n", - "# \"model_code_Model A6\",\n", - "# \"model_code_Model C1\",\n", - "# \"model_code_Model D1\",\n", - "# \"model_code_Model E2\",\n", - "# \"vehicle_class_code_Truck-Tractor\",\n", - "# \"vehicle_class_code_Truck\",\n", - "# \"vehicle_class_code_Bus\",\n", - "# \"vehicle_class_code_Transport\",\n", - "# \"engine_type_code_Engine E\",\n", - "# \"engine_type_code_Engine C\",\n", - "# \"engine_type_code_Engine B\",\n", - "# \"engine_type_code_Engine F\",\n", - "# \"engine_type_code_Engine H\",\n", - "# \"engine_type_code_Engine D\",\n", - "# \"engine_type_code_Engine A\",\n", - "# \"engine_type_code_Engine G\",\n", - "# \"voltage\",\n", - "# \"current\",\n", - "# \"resistance\",\n", - "# \"cycle\",\n", - "# \"engine_age\",\n", - "# ]\n", - "# ]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# fleet.sort_values(by=[\"vehicle_id\", \"datetime\"], inplace=True)\n", - "# fleet.to_csv(\"fleet_data.csv\", index=False)\n", - "# fleet.shape" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "If you followed the above steps correctly, you data should match that of the existing [fleet_data.csv](fleet_data.csv). It would also fit the following key observations:\n", - "\n", - "- There are 90 vehicles in the fleet\n", - "- Data has 9000 observations and 44 columns.\n", - "- Vehicle can be identified useing the 'vehicle_id' column.\n", - "- The label column, called 'Target', is an indicator of failure ('0' = No Failure; '1' = Failure).\n", - "- There are 4 numeric features available for prediction and 4 categorical features. We will expand upon these later in the Feature Engineering section of this notebook. " - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Kick off SageMaker Training Job (Optional)\n", - "\n", - "Data Wrangler is a SageMaker tool for processing data to be used for Machine Learning. Now that\n", - "the data has been processed, users will want to train a model using the data. The following shows\n", - "an example of doing so using a popular algorithm XGBoost.\n", - "\n", - "It is important to note that the following XGBoost objective ['binary', 'regression',\n", - "'multiclass'], hyperparameters, or content_type may not be suitable for the output data, and will\n", - "require changes to train a proper model. Furthermore, for CSV training, the algorithm assumes that\n", - "the target variable is in the first column. For more information on SageMaker XGBoost, please see [XGBoost Algorithm](https://docs.aws.amazon.com/sagemaker/latest/dg/xgboost.html).\n", - "\n", - "### Find Training Data path\n", - "\n", - "The below demonstrates how to recursively search the output directory to find the data location." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "s3_client = boto3.client(\"s3\")\n", - "list_response = s3_client.list_objects_v2(Bucket=bucket, Prefix=output_prefix)\n", - "\n", - "training_path = None\n", - "\n", - "for content in list_response[\"Contents\"]:\n", - " if \"_SUCCESS\" not in content[\"Key\"]:\n", - " training_path = content[\"Key\"]\n", - "\n", - "print(training_path)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Next, the Training Job hyperparameters are set. For more information on XGBoost Hyperparameters,\n", - "see [XGBoost Parameters](https://xgboost.readthedocs.io/en/latest/parameter.html)." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "region = boto3.Session().region_name\n", - "container = sagemaker.image_uris.retrieve(\"xgboost\", region, \"1.2-1\")\n", - "hyperparameters = {\n", - " \"max_depth\": \"5\",\n", - " \"objective\": \"reg:squarederror\",\n", - " \"num_round\": \"10\",\n", - "}\n", - "train_content_type = (\n", - " \"application/x-parquet\" if output_content_type.upper() == \"PARQUET\" else \"text/csv\"\n", - ")\n", - "train_input = sagemaker.inputs.TrainingInput(\n", - " s3_data=f\"s3://{bucket}/{training_path}\",\n", - " content_type=train_content_type,\n", - ")" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The TrainingJob configurations are set using the SageMaker Python SDK Estimator, and which is fit\n", - "using the training data from the ProcessingJob that was run earlier." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "estimator = sagemaker.estimator.Estimator(\n", - " container,\n", - " iam_role,\n", - " hyperparameters=hyperparameters,\n", - " instance_count=1,\n", - " instance_type=\"ml.m5.2xlarge\",\n", - ")\n", - "estimator.fit({\"train\": train_input})" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Notebook CI Test Results\n", - "\n", - "This notebook was tested in multiple regions. The test results are as follows, except for us-west-2 which is shown at the top of the notebook.\n", - "\n", - "![This us-east-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/us-east-1/use-cases|predictive_maintenance|1_dataprep_dw_job_predmaint.ipynb)\n", - "\n", - "![This us-east-2 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/us-east-2/use-cases|predictive_maintenance|1_dataprep_dw_job_predmaint.ipynb)\n", - "\n", - "![This us-west-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/us-west-1/use-cases|predictive_maintenance|1_dataprep_dw_job_predmaint.ipynb)\n", - "\n", - "![This ca-central-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/ca-central-1/use-cases|predictive_maintenance|1_dataprep_dw_job_predmaint.ipynb)\n", - "\n", - "![This sa-east-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/sa-east-1/use-cases|predictive_maintenance|1_dataprep_dw_job_predmaint.ipynb)\n", - "\n", - "![This eu-west-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/eu-west-1/use-cases|predictive_maintenance|1_dataprep_dw_job_predmaint.ipynb)\n", - "\n", - "![This eu-west-2 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/eu-west-2/use-cases|predictive_maintenance|1_dataprep_dw_job_predmaint.ipynb)\n", - "\n", - "![This eu-west-3 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/eu-west-3/use-cases|predictive_maintenance|1_dataprep_dw_job_predmaint.ipynb)\n", - "\n", - "![This eu-central-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/eu-central-1/use-cases|predictive_maintenance|1_dataprep_dw_job_predmaint.ipynb)\n", - "\n", - "![This eu-north-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/eu-north-1/use-cases|predictive_maintenance|1_dataprep_dw_job_predmaint.ipynb)\n", - "\n", - "![This ap-southeast-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/ap-southeast-1/use-cases|predictive_maintenance|1_dataprep_dw_job_predmaint.ipynb)\n", - "\n", - "![This ap-southeast-2 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/ap-southeast-2/use-cases|predictive_maintenance|1_dataprep_dw_job_predmaint.ipynb)\n", - "\n", - "![This ap-northeast-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/ap-northeast-1/use-cases|predictive_maintenance|1_dataprep_dw_job_predmaint.ipynb)\n", - "\n", - "![This ap-northeast-2 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/ap-northeast-2/use-cases|predictive_maintenance|1_dataprep_dw_job_predmaint.ipynb)\n", - "\n", - "![This ap-south-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/ap-south-1/use-cases|predictive_maintenance|1_dataprep_dw_job_predmaint.ipynb)\n" - ] - } - ], - "metadata": { - "instance_type": "ml.t3.medium", - "kernelspec": { - "display_name": "Python 3 (Data Science 3.0)", - "language": "python", - "name": "python3__SAGEMAKER_INTERNAL__arn:aws:sagemaker:us-east-1:081325390199:image/sagemaker-data-science-310-v1" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.10.6" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/use-cases/predictive_maintenance/2_dataprep_predmaint.ipynb b/use-cases/predictive_maintenance/2_dataprep_predmaint.ipynb deleted file mode 100644 index abca3a663d..0000000000 --- a/use-cases/predictive_maintenance/2_dataprep_predmaint.ipynb +++ /dev/null @@ -1,597 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Fleet Predictive Maintenance: Part 2. Feature Engineering and Exploratory Data Visualization\n" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "---\n", - "\n", - "This notebook's CI test result for us-west-2 is as follows. CI test results in other regions can be found at the end of the notebook. \n", - "\n", - "![This us-west-2 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/us-west-2/use-cases|predictive_maintenance|2_dataprep_predmaint.ipynb)\n", - "\n", - "---" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "*Using SageMaker Studio to Predict Fault Classification*" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Background\n", - "\n", - "This notebook is part of a sequence of notebooks whose purpose is to demonstrate a Predictive Maintenance (PrM) solution for automobile fleet maintenance via Amazon SageMaker Studio so that business users have a quick path towards a PrM POC. In this notebook, we will be focusing on feature engineering. It is the second notebook in a series of notebooks. You can choose to run this notebook by itself or in sequence with the other notebooks listed below. Please see the [README.md](README.md) for more information about this use case implement of this sequence of notebooks. " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "1. [Data Prep: Processing Job from SageMaker Data Wrangler Output](./1_dataprep_dw_job_predmaint.ipynb)\n", - "1. [Data Prep: Featurization](./2_dataprep_predmaint.ipynb) (current notebook)\n", - "1. [Train, Tune and Predict using Batch Transform](./3_train_tune_predict_predmaint.ipynb)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Important Notes: \n", - "\n", - "* Due to cost consideration, the goal of this example is to show you how to use some of SageMaker Studio's features, not necessarily to achieve the best result. \n", - "* We use the built-in classification algorithm in this example, and a Python 3 (Data Science) Kernel is required.\n", - "* The nature of predictive maintenace solutions, requires a domain knowledge expert of the system or machinery. With this in mind, we will make assumptions here for certain elements of this solution with the acknowldgement that these assumptions should be informed by a domain expert and a main business stakeholder" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "---\n", - " \n", - "\n", - "## Contents\n", - "\n", - "1. [Setup](#Setup)\n", - "1. [Feature Engineering](#Feature-Engineering)\n", - "1. [Visualization of the Data Distributions](#Visualization-of-the-Data-Distributions)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "---\n", - "## Setup\n", - "\n", - "Let's start by:\n", - "\n", - "* Installing and importing any dependencies\n", - "* Instantiating SageMaker session\n", - "* Specifying the S3 bucket and prefix that you want to use for your training and model data. This should be within the same region as SageMaker training\n", - "* Defining the IAM role used to give training access to your data\n", - " " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Install any missing dependencies\n", - "!pip install -qU 'sagemaker-experiments==0.1.24' 'sagemaker>=2.16.1' 'boto3' 'awswrangler'" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import os\n", - "import json\n", - "import sys\n", - "import collections\n", - "import glob\n", - "import numpy as np\n", - "import pandas as pd\n", - "import matplotlib.pyplot as plt\n", - "import seaborn as sns\n", - "\n", - "# SageMaker dependencies\n", - "import boto3\n", - "import sagemaker\n", - "from sagemaker import get_execution_role\n", - "from sagemaker.image_uris import retrieve\n", - "import awswrangler as wr\n", - "\n", - "# This instantiates a SageMaker session that we will be operating in.\n", - "smclient = boto3.Session().client(\"sagemaker\")\n", - "region = boto3.Session().region_name\n", - "\n", - "# This object represents the IAM role that we are assigned.\n", - "role = sagemaker.get_execution_role()\n", - "\n", - "sess = sagemaker.Session()\n", - "bucket = sess.default_bucket()\n", - "\n", - "# prefix is the path within the bucket where SageMaker stores the output from training jobs.\n", - "prefix_prm = \"predmaint\" # place to upload training files within the bucket" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "---\n", - "## Feature Engineering \n", - "\n", - "For PrM, feature selection, generation and engineering is extremely important and very depended on domain expertise and understanding of the systems involved. For our solution, we will focus on the some simple features such as:\n", - "* lag features \n", - "* rolling average\n", - "* rolling standard deviation \n", - "* age of the engines \n", - "* categorical labels\n", - "\n", - "These features serve as a small example of the potential features that could be created. Other features to consider are changes in the sensor values within a window, change from the initial value or number over a defined threshold. For additional guidance on Feature Engineering, visit the [SageMaker Tabular Feature Engineering guide](). " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "First, we load up our cleaned dataset, which can be produced by following the steps in the notebook [Data Prep: Processing Job from SageMaker Data Wrangler Output](./1_dataprep_dw_job_predmaint.ipynb) (the first section in this notebook series). See the [Background](#Background) section at the beginning of the notebook for more information." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "fleet = pd.read_csv(\"fleet_data.csv\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "%matplotlib inline\n", - "fig, axs = plt.subplots(3, 1, figsize=(20, 15))\n", - "plot_fleet = fleet.loc[fleet[\"vehicle_id\"] == 1]\n", - "\n", - "sns.set_style(\"darkgrid\")\n", - "axs[0].plot(plot_fleet[\"datetime\"], plot_fleet[\"voltage\"])\n", - "axs[1].plot(plot_fleet[\"datetime\"], plot_fleet[\"current\"])\n", - "axs[2].plot(plot_fleet[\"datetime\"], plot_fleet[\"resistance\"])\n", - "\n", - "axs[0].set_ylabel(\"voltage\")\n", - "axs[1].set_ylabel(\"current\")\n", - "axs[2].set_ylabel(\"resistance\");" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "fig, axs = plt.subplots(3, 1, figsize=(20, 15))\n", - "plot_fleet = fleet.loc[fleet[\"vehicle_id\"] == 2]\n", - "\n", - "sns.set_style(\"darkgrid\")\n", - "axs[0].plot(plot_fleet[\"datetime\"], plot_fleet[\"voltage\"])\n", - "axs[1].plot(plot_fleet[\"datetime\"], plot_fleet[\"current\"])\n", - "axs[2].plot(plot_fleet[\"datetime\"], plot_fleet[\"resistance\"])\n", - "\n", - "axs[0].set_ylabel(\"voltage\")\n", - "axs[1].set_ylabel(\"current\")\n", - "axs[2].set_ylabel(\"resistance\");" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# let's look at the proportion of failures to non-failure\n", - "print(fleet[\"target\"].value_counts())\n", - "print(\n", - " \"\\nPercent of failures in the dataset: \"\n", - " + str(fleet[\"target\"].value_counts()[1] / len(fleet[\"target\"]))\n", - ")\n", - "print(\n", - " \"Number of vehicles with 1+ failures: \"\n", - " + str(fleet[fleet[\"target\"] == 1][\"vehicle_id\"].drop_duplicates().count())\n", - " + \"\\n\"\n", - ")\n", - "\n", - "# view the percentage distribution of target column\n", - "print(fleet[\"target\"].value_counts() / np.float(len(fleet)))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We can see that percentage of observations of the class label 0 (no failure) and 1 (failure) is 80.42% and 19.58% respectively. So, this is a class imbalanced problem. For PrM, class imbalance is oftentimes a problem as failues happen less frequently and businesses do not want to allow for more failures than is necessary. There are a variety of techniques for dealing with class imbalances in data such as [SMOTE](https://imbalanced-learn.readthedocs.io/en/stable/generated/imblearn.over_sampling.SMOTE.html). For this use case, we will leverage SageMaker's Estimator built-in hyperparameters to I will deal with imbalance. We discuss more in a later section." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "p = fleet.groupby([\"vehicle_id\"])[\"target\"].sum().rename(\"percentage of failures\")\n", - "fail_percent = pd.DataFrame(p / 100)\n", - "print(fail_percent.sort_values(\"percentage of failures\", ascending=False).head(20))\n", - "# fail_percent.plot(kind='box')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# check for missing values\n", - "print(fleet.isnull().sum())\n", - "\n", - "# check sensor readings for zeros\n", - "fleet[fleet.loc[:, \"voltage\":\"resistance\"].values == 0]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# # optional: load in the fleet dataset from above\n", - "# fleet = pd.read_csv('fleet_data.csv')\n", - "fleet.datetime = pd.to_datetime(fleet.datetime)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# add lag features for voltage, current and resistance\n", - "# we will only look as 2 lags\n", - "for i in range(1, 2):\n", - " fleet[\"voltage_lag_\" + str(i)] = (\n", - " fleet.groupby(\"vehicle_id\")[\"voltage\"].shift(i).fillna(method=\"bfill\", limit=7)\n", - " )\n", - " fleet[\"current_lag_\" + str(i)] = (\n", - " fleet.groupby(\"vehicle_id\")[\"current\"].shift(i).fillna(method=\"bfill\", limit=7)\n", - " )\n", - " fleet[\"resistance_lag_\" + str(i)] = (\n", - " fleet.groupby(\"vehicle_id\")[\"resistance\"].shift(i).fillna(method=\"bfill\", limit=7)\n", - " )" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# create rolling stats for voltage, current and resistance group by vehicle_id\n", - "stats = pd.DataFrame()\n", - "grouped = fleet.groupby(\"vehicle_id\")\n", - "\n", - "# windows set to 4\n", - "# you could also add in additional rolling window lengths based on the machinery and domain knowledge\n", - "mean = [\n", - " (col + \"_\" + \"rolling_mean_\" + str(win), grouped[col].rolling(window=win).mean())\n", - " for win in [4]\n", - " for col in [\"voltage\", \"current\", \"resistance\"]\n", - "]\n", - "std = [\n", - " (col + \"_\" + \"rolling_std_\" + str(win), grouped[col].rolling(window=win).std())\n", - " for win in [4]\n", - " for col in [\"voltage\", \"current\", \"resistance\"]\n", - "]\n", - "df_mean = pd.DataFrame.from_dict(collections.OrderedDict(mean))\n", - "df_std = pd.DataFrame.from_dict(collections.OrderedDict(std))\n", - "stats = (\n", - " pd.concat([df_mean, df_std], axis=1)\n", - " .reset_index()\n", - " .set_index(\"level_1\")\n", - " .fillna(method=\"bfill\", limit=7)\n", - ") # fill backward\n", - "stats.head(5)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "fleet_lagged = pd.concat([fleet, stats.drop(columns=[\"vehicle_id\"])], axis=1)\n", - "fleet_lagged.head(2)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# let's look at the descriptive statistics that summarize the central tendency, dispersion and shape of a dataset’s distribution\n", - "round(fleet_lagged.describe(), 2).T" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "---\n", - "## Visualization of the Data Distributions" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# plot a single engine's histograms\n", - "# we will lood at vehicle_id 2 as it has 1+ failures\n", - "def plot_engine_hists(sensor_data):\n", - " cols = sensor_data.columns\n", - " n_cols = min(len(cols), 4)\n", - " n_rows = int(np.ceil(len(cols) / n_cols))\n", - "\n", - " fig, axes = plt.subplots(n_rows, n_cols, figsize=(15, 15))\n", - " plt.tight_layout()\n", - " axes = axes.flatten()\n", - " for col, ax in zip(cols, axes):\n", - " sns.distplot(sensor_data[[col]], ax=ax, label=col)\n", - " ax.set_xlabel(col)\n", - " ax.set_ylabel(\"p\")\n", - "\n", - "\n", - "plot_engine_hists(fleet_lagged[fleet_lagged[\"vehicle_id\"] == 2].loc[:, \"voltage\":])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "You should get a diagram that looks like the diagram below.\n", - "\n", - "![](engine_histogram_output.png)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# remove features used for one-hot encoding the categorical features including make, model, engine_type and vehicle_class\n", - "features = fleet_lagged.drop(columns=[\"make\", \"model\", \"year\", \"vehicle_class\", \"engine_type\"])\n", - "features.to_csv(\"features.csv\", index=False)\n", - "features_created_prm = True\n", - "%store features_created_prm" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "features = pd.read_csv(\"features.csv\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Although we have kept the EDA and feature engineering limited here, there is much more that could be done. Additional analysis could be done to understand if the relationships between the make and model and/or the engine type and failure rates. Also, much more analysis could be done based on discussions with domain experts and their in-depth understandings of the systems based on experience. " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### Now let's split our data into train, test and validation" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "For PrM, we will want to split the data based on a time-dependent record splitting strategy since the data is time series sensor readings. We will make the splits by choosing a points in time based on the desired size of the training, test and validations sets. To prevent any records in the training set from sharing time windows with the records in the test set, we remove any records at the boundary." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# we will devote 80% to training, and we will save 10% for test and ~10% for validation (less the dropped records to avoid data leakage)\n", - "train_size = int(len(features) * 0.80)\n", - "val_size = int(len(features) * 0.10)\n", - "\n", - "# order by datetime in order to split on time\n", - "ordered = features.sort_values(\"datetime\")\n", - "\n", - "# make train, test and validation splits\n", - "train, test, val = (\n", - " ordered[0:train_size],\n", - " ordered[train_size : train_size + val_size],\n", - " ordered.tail(val_size),\n", - ")\n", - "train.sort_values([\"vehicle_id\", \"datetime\"], inplace=True)\n", - "\n", - "# make sure there is no data leakage between train, test and validation\n", - "test = test.loc[test[\"datetime\"] > train[\"datetime\"].max()]\n", - "val = val.loc[val[\"datetime\"] > test[\"datetime\"].max()]\n", - "\n", - "print(\"First train datetime: \", train[\"datetime\"].min())\n", - "print(\"Last train datetime: \", train[\"datetime\"].max(), \"\\n\")\n", - "print(\"First test datetime: \", test[\"datetime\"].min())\n", - "print(\"Last test datetime: \", test[\"datetime\"].max(), \"\\n\")\n", - "print(\"First validation datetime: \", val[\"datetime\"].min())\n", - "print(\"Last validation datetime: \", val[\"datetime\"].max())" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "train = train.drop([\"datetime\", \"vehicle_id\"], axis=1)\n", - "\n", - "test = test.sort_values([\"vehicle_id\", \"datetime\"])\n", - "test = test.drop([\"datetime\", \"vehicle_id\"], axis=1)\n", - "\n", - "val = val.sort_values([\"vehicle_id\", \"datetime\"])\n", - "val = val.drop([\"datetime\", \"vehicle_id\"], axis=1)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "print(\"Total Observations: \", len(ordered))\n", - "print(\"Number of observations in the training data:\", len(train))\n", - "print(\"Number of observations in the test data:\", len(test))\n", - "print(\"Number of observations in the validation data:\", len(val))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### Converting data to the appropriate format for Estimator\n", - "\n", - "Amazon SageMaker implementation of Linear Learner takes either csv format or recordIO-wrapped protobuf. We will start by scaling the features and saving the data files to csv format. Then, we will save the data to file. If you are using your own data, and it is too large to fit in memory, protobuf might be a better option than csv. For more information on data formats for training, please refer to [Common Data Formats for Training](https://docs.aws.amazon.com/sagemaker/latest/dg/cdf-training.html)." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# scale all features for train, test and validation\n", - "from sklearn import preprocessing\n", - "\n", - "scaler = preprocessing.MinMaxScaler(feature_range=(0.0, 1.0))\n", - "train = pd.DataFrame(scaler.fit_transform(train))\n", - "test = pd.DataFrame(scaler.transform(test))\n", - "val = pd.DataFrame(scaler.transform(val))\n", - "\n", - "train.to_csv(\"train.csv\", header=False, index=False)\n", - "test.to_csv(\"test.csv\", header=False, index=False)\n", - "test.loc[:, 1:].to_csv(\"test_x.csv\", header=False, index=False)\n", - "val.to_csv(\"validation.csv\", header=False, index=False)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "---\n", - "## Next Notebook : Train\n", - "\n", - "### SageMaker Estimator and Experiments\n", - "\n", - "Once you have selected some models that you would like to try out, SageMaker Experiments can be a great tool to track and compare all of the models before selecting the best model to deploy. We will set up an experiment using SageMaker experiments to track all the model training iterations for the Linear Learner Estimator we will try. You can read more about [SageMaker Experiments](https://docs.aws.amazon.com/sagemaker/latest/dg/experiments.html) to learn about experiment features, tracking and comparing outputs. " - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Notebook CI Test Results\n", - "\n", - "This notebook was tested in multiple regions. The test results are as follows, except for us-west-2 which is shown at the top of the notebook.\n", - "\n", - "![This us-east-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/us-east-1/use-cases|predictive_maintenance|2_dataprep_predmaint.ipynb)\n", - "\n", - "![This us-east-2 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/us-east-2/use-cases|predictive_maintenance|2_dataprep_predmaint.ipynb)\n", - "\n", - "![This us-west-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/us-west-1/use-cases|predictive_maintenance|2_dataprep_predmaint.ipynb)\n", - "\n", - "![This ca-central-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/ca-central-1/use-cases|predictive_maintenance|2_dataprep_predmaint.ipynb)\n", - "\n", - "![This sa-east-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/sa-east-1/use-cases|predictive_maintenance|2_dataprep_predmaint.ipynb)\n", - "\n", - "![This eu-west-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/eu-west-1/use-cases|predictive_maintenance|2_dataprep_predmaint.ipynb)\n", - "\n", - "![This eu-west-2 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/eu-west-2/use-cases|predictive_maintenance|2_dataprep_predmaint.ipynb)\n", - "\n", - "![This eu-west-3 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/eu-west-3/use-cases|predictive_maintenance|2_dataprep_predmaint.ipynb)\n", - "\n", - "![This eu-central-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/eu-central-1/use-cases|predictive_maintenance|2_dataprep_predmaint.ipynb)\n", - "\n", - "![This eu-north-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/eu-north-1/use-cases|predictive_maintenance|2_dataprep_predmaint.ipynb)\n", - "\n", - "![This ap-southeast-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/ap-southeast-1/use-cases|predictive_maintenance|2_dataprep_predmaint.ipynb)\n", - "\n", - "![This ap-southeast-2 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/ap-southeast-2/use-cases|predictive_maintenance|2_dataprep_predmaint.ipynb)\n", - "\n", - "![This ap-northeast-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/ap-northeast-1/use-cases|predictive_maintenance|2_dataprep_predmaint.ipynb)\n", - "\n", - "![This ap-northeast-2 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/ap-northeast-2/use-cases|predictive_maintenance|2_dataprep_predmaint.ipynb)\n", - "\n", - "![This ap-south-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/ap-south-1/use-cases|predictive_maintenance|2_dataprep_predmaint.ipynb)\n" - ] - } - ], - "metadata": { - "instance_type": "ml.t3.medium", - "kernelspec": { - "display_name": "Python 3 (Data Science 3.0)", - "language": "python", - "name": "python3__SAGEMAKER_INTERNAL__arn:aws:sagemaker:us-east-1:081325390199:image/sagemaker-data-science-310-v1" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.10.6" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/use-cases/predictive_maintenance/3_train_tune_predict_predmaint.ipynb b/use-cases/predictive_maintenance/3_train_tune_predict_predmaint.ipynb deleted file mode 100644 index 6b439207ce..0000000000 --- a/use-cases/predictive_maintenance/3_train_tune_predict_predmaint.ipynb +++ /dev/null @@ -1,1171 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Fleet Predictive Maintenance: Part 3. Training, Hyperparameter Tuning, and Prediction\n" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "---\n", - "\n", - "This notebook's CI test result for us-west-2 is as follows. CI test results in other regions can be found at the end of the notebook. \n", - "\n", - "![This us-west-2 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/us-west-2/use-cases|predictive_maintenance|3_train_tune_predict_predmaint.ipynb)\n", - "\n", - "---" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "*Using SageMaker Studio to Predict Fault Classification*" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Background\n", - "\n", - "This notebook is part of a sequence of notebooks whose purpose is to demonstrate a Predictive Maintenance (PrM) solution for automobile fleet maintenance via Amazon SageMaker Studio so that business users have a quick path towards a PrM POC. In this notebook, we will be focusing on training, tuning, and deploying a model. It is the third notebook in a series of notebooks. You can choose to run this notebook by itself or in sequence with the other notebooks listed below. Please see the [README.md](README.md) for more information about this use case implement of this sequence of notebooks. " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "1. [Data Prep: Processing Job from SageMaker Data Wrangler Output](./1_dataprep_dw_job_predmaint.ipynb)\n", - "1. [Data Prep: Featurization](./2_dataprep_predmaint.ipynb)\n", - "1. [Train, Tune and Predict using Batch Transform](./3_train_tune_predict_predmaint.ipynb) (current notebook)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Important Notes: \n", - "\n", - "* Due to cost consideration, the goal of this example is to show you how to use some of SageMaker Studio's features, not necessarily to achieve the best result. \n", - "* We use the built-in classification algorithm in this example, and a Python 3 (Data Science) Kernel is required.\n", - "* The nature of predictive maintenace solutions, requires a domain knowledge expert of the system or machinery. With this in mind, we will make assumptions here for certain elements of this solution with the acknowldgement that these assumptions should be informed by a domain expert and a main business stakeholder\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "---\n", - "## Setup\n", - "\n", - "Let's start by:\n", - "\n", - "* Installing and importing any dependencies\n", - "* Instantiating SageMaker session\n", - "* Specifying the S3 bucket and prefix that you want to use for your training and model data. This should be within the same region as SageMaker training\n", - "* Defining the IAM role used to give training access to your data\n", - " " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Install any missing dependencies\n", - "!pip install -qU 'sagemaker-experiments==0.1.24' 'sagemaker>=2.16.1' 'boto3' 'awswrangler'" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import os\n", - "import json\n", - "import sys\n", - "import collections\n", - "import glob\n", - "import numpy as np\n", - "import pandas as pd\n", - "import matplotlib.pyplot as plt\n", - "import seaborn as sns\n", - "\n", - "# SageMaker dependencies\n", - "import boto3\n", - "import sagemaker\n", - "from sagemaker import get_execution_role\n", - "from sagemaker.image_uris import retrieve\n", - "import awswrangler as wr\n", - "\n", - "# This instantiates a SageMaker session that we will be operating in.\n", - "smclient = boto3.Session().client(\"sagemaker\")\n", - "region = boto3.Session().region_name\n", - "\n", - "# This object represents the IAM role that we are assigned.\n", - "role = sagemaker.get_execution_role()\n", - "\n", - "sess = sagemaker.Session()\n", - "bucket = sess.default_bucket()\n", - "\n", - "# prefix is the path within the bucket where SageMaker stores the output from training jobs.\n", - "prefix_prm = \"predmaint\" # place to upload training files within the bucket" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Before training, we must first upload our data in S3. To see how the existing train, test, and validation datasets were generated, take a look at [Data Prep: Processing Job from SageMaker Data Wrangler Output](./1_dataprep_dw_job_predmaint.ipynb) (which is the first part of this notebook series) followed by [Data Prep: Featurization](./2_dataprep_predmaint.ipynb) (which is the second part of this notebook series). See the [Background](#Background) section at the beginning of the notebook for more information." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# helper function for converting data to csv(necessary for Linear Learner) and upload to S3\n", - "def upload_file_to_bucket(bucket, prefix, file_path):\n", - " file_dir, file_name = os.path.split(file_path)\n", - " df = pd.read_csv(file_path)\n", - " boto3.resource(\"s3\").meta.client.upload_file(\n", - " Filename=file_path, Bucket=bucket, Key=(prefix + \"/\" + file_name)\n", - " )\n", - " print(f\"uploaded {prefix} data location: s3://{bucket}/{prefix}/{file_name}\")\n", - " path_to_data = f\"s3://{bucket}/{prefix}/{file_name}\"\n", - " return path_to_data" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# convert and upload to S3\n", - "path_to_train_data_prm = upload_file_to_bucket(bucket, \"train\", \"train.csv\")\n", - "path_to_test_data_prm = upload_file_to_bucket(bucket, \"test\", \"test.csv\")\n", - "path_to_test_x_data_prm = upload_file_to_bucket(bucket, \"test\", \"test_x.csv\")\n", - "path_to_valid_data_prm = upload_file_to_bucket(bucket, \"validation\", \"validation.csv\")\n", - "\n", - "# let's also setup an output S3 location for the model artifact that will be output as the result of training with the algorithm.\n", - "output_location = f\"s3://{bucket}/output\"\n", - "print(\"training artifacts will be uploaded to: {}\".format(output_location))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from sagemaker.inputs import TrainingInput\n", - "\n", - "train_channel = TrainingInput(path_to_train_data_prm, content_type=\"text/csv\")\n", - "test_channel = TrainingInput(path_to_test_data_prm, content_type=\"text/csv\")\n", - "test_x_channel = TrainingInput(path_to_test_x_data_prm, content_type=\"text/csv\")\n", - "valid_channel = TrainingInput(path_to_valid_data_prm, content_type=\"text/csv\")\n", - "\n", - "data_channels = {\"train\": train_channel, \"validation\": valid_channel}" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The data is stored in S3 and is ready for use in the estimators." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "---\n", - "## Train\n", - "\n", - "### SageMaker Estimator and Experiments\n", - "\n", - "Once you have selected some models that you would like to try out, SageMaker Experiments can be a great tool to track and compare all of the models before selecting the best model to deploy. We will set up an experiment using SageMaker experiments to track all the model training iterations for the Linear Learner Estimator we will try. You can read more about [SageMaker Experiments](https://docs.aws.amazon.com/sagemaker/latest/dg/experiments.html) to learn about experiment features, tracking and comparing outputs. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# setup\n", - "# import dependencies\n", - "from sagemaker.analytics import ExperimentAnalytics\n", - "from smexperiments.experiment import Experiment\n", - "from smexperiments.trial import Trial\n", - "from smexperiments.trial_component import TrialComponent\n", - "from smexperiments.tracker import Tracker\n", - "from time import strftime" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "if \"create_date\" not in locals():\n", - " create_date = strftime(\"%Y-%m-%d-%H-%M-%S\")\n", - " %store create_date\n", - "\n", - " # location within S3 for outputs\n", - " exp_prefix = f\"sagemaker-experiments/linear-learner-{create_date}\"\n", - " %store exp_prefix" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "If you used the storemagic previously, you can pick up from here using the `create_date` variable." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# create the experiment\n", - "experiment_name = f\"ll-failure-classification-{create_date}\"\n", - "\n", - "try:\n", - " my_experiment = Experiment.load(experiment_name=experiment_name)\n", - " print(f\"Experiment loaded {experiment_name}: SUCCESS\")\n", - "except Exception as e:\n", - " if \"ResourceNotFound\" in str(e):\n", - " my_experiment = Experiment.create(\n", - " experiment_name=experiment_name,\n", - " description=\"Classification PrM Experiment\",\n", - " tags=[{\"Key\": \"my-experiments\", \"Value\": \"exp\"}],\n", - " sagemaker_boto_client=smclient,\n", - " )\n", - " print(f\"Experiment creation {experiment_name}: SUCCESS\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Note: The tags parameter is optional. You can search for the tag using Studio, the SageMaker console, and the SDK. Tags can also be applied to trials and trial components. For information on how to search tags using Studio, see [Search by Tag](https://docs.aws.amazon.com/sagemaker/latest/dg/experiments-search-studio.html#experiments-search-studio-tags)." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "with Tracker.create(display_name=\"training\", sagemaker_boto_client=smclient) as tracker:\n", - " tracker.log_input(name=\"prm-dataset\", media_type=\"s3/uri\", value=path_to_train_data_prm)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now we can begin to specify our linear model from the Amazon SageMaker Linear Learner Estimator. For this binary classification problem, we have the option of selecting between logistic regression or hinge loss (Support Vector Machines). Here are additional resources to learn more about the [Input/Output Interface for the Linear Learner Algorithm](https://docs.aws.amazon.com/sagemaker/latest/dg/linear-learner.html#ll-input_output) and the [Linear Learner Hyperparameters](https://docs.aws.amazon.com/sagemaker/latest/dg/ll_hyperparameters.html). One piece to note is that Amazon SageMaker's Linear Learner actually fits many models in parallel, each with slightly different hyperparameters, and then returns the one with the best fit. This functionality is automatically enabled. There are a number of additional parameters available for the Linear Learner Estimator, so we will start be using the default features as well as:\n", - "\n", - "- `loss` which controls how we penalize mistakes in our model estimates. For this case, we will start with logistic and move to using hinge loss if necessary for model improvement.\n", - "- `predictor_type` is set to 'binary_classifier' since we are trying to predict whether a failure occurs or it doesn't.\n", - "- `mini_batch_size` is set to 99. This value can be tuned for relatively minor improvements in fit and speed, but selecting a reasonable value relative to the dataset is appropriate in most cases.\n", - "- `wd` or `l1` which control regularization. Regularization can prevent model overfitting by preventing our estimates from becoming too finely tuned to the training data, which can actually hurt generalizability. In this case, we'll leave these parameters as their default \"auto\" though." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We will start by first building a logistic regression Linear Learner Estimator, setting the hyperparameters and configuring the SageMaker Experiment with the trial created above. We will then evaluate the results of the experiment. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "scrolled": true - }, - "outputs": [], - "source": [ - "# set output path\n", - "lr_output_path = f\"s3://{bucket}/{exp_prefix}/output/lr_default\"\n", - "\n", - "# with SageMaker v2.0, Image URI function get_image_uri has been replaced with sagemaker.image_uris.retrieve()\n", - "container = sagemaker.image_uris.retrieve(\n", - " framework=\"linear-learner\", region=region, version=\"1\", image_scope=\"training\"\n", - ")\n", - "\n", - "# create the trail component and the first experiment for linear learner\n", - "training_trail_component = tracker.trial_component\n", - "trial_name_1 = trial_name = f\"linear-learner-lr-training-job-{create_date}\"\n", - "\n", - "# create the trial if it doesn't exist\n", - "try:\n", - " my_trial = Trial.load(trial_name=trial_name_1)\n", - " print(f\"Loaded existing trial: {trial_name_1}\")\n", - "except Exception as e:\n", - " if \"ResourceNotFound\" in str(e):\n", - " my_trial = Trial.create(experiment_name=experiment_name, trial_name=trial_name_1)\n", - " print(f\"Create trial {my_trial.trial_name}: SUCCESSFUL \\n\")\n", - "\n", - " print(f\"Creating logistic regression estimator. \\n\")\n", - " lr = sagemaker.estimator.Estimator(\n", - " container,\n", - " role,\n", - " instance_count=1,\n", - " instance_type=\"ml.c4.xlarge\",\n", - " output_path=lr_output_path,\n", - " sagemaker_session=sess,\n", - " enable_sagemaker_metrics=True,\n", - " )\n", - "\n", - " lr.set_hyperparameters(\n", - " predictor_type=\"binary_classifier\",\n", - " loss=\"logistic\", # default for auto is logistic regression\n", - " epochs=20, # high number of epochs as early stopping feature will stop training\n", - " mini_batch_size=99,\n", - " )\n", - "\n", - " lr.fit(\n", - " inputs=data_channels,\n", - " experiment_config={\n", - " \"ExperimentName\": my_experiment.experiment_name,\n", - " \"TrialName\": my_trial.trial_name,\n", - " \"TrialComponentDisplayName\": \"ll-lr-training-job\",\n", - " },\n", - " logs=True,\n", - " )" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We will now train a Linear Learner model with hinge loss, i.e. Support Vector Machines, and use the default hyperparmeters listed below. We will add this trial to the experiment for later comparison. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "scrolled": true - }, - "outputs": [], - "source": [ - "svm_output_path = f\"s3://{bucket}/{exp_prefix}/output/svm_default\"\n", - "trial_name_2 = f\"linear-learner-svm-{create_date}\"\n", - "\n", - "# create the trial if it doesn't exist\n", - "try:\n", - " my_trial = Trial.load(trial_name=trial_name_2)\n", - " print(f\"Loaded existing trial: {trial_name_2}\")\n", - "except Exception as e:\n", - " if \"ResourceNotFound\" in str(e):\n", - " my_trial = Trial.create(experiment_name=experiment_name, trial_name=trial_name_2)\n", - " print(f\"Create trial {my_trial.trial_name}: SUCCESSFUL\")\n", - "\n", - " svm = sagemaker.estimator.Estimator(\n", - " container,\n", - " role,\n", - " instance_count=1,\n", - " instance_type=\"ml.c4.xlarge\",\n", - " output_path=svm_output_path,\n", - " sagemaker_session=sess,\n", - " enable_sagemaker_metrics=True,\n", - " )\n", - " svm.set_hyperparameters(\n", - " predictor_type=\"binary_classifier\", loss=\"hinge_loss\", epochs=20, mini_batch_size=99\n", - " )\n", - "\n", - " svm.fit(\n", - " inputs=data_channels,\n", - " experiment_config={\n", - " \"ExperimentName\": my_experiment.experiment_name,\n", - " \"TrialName\": my_trial.trial_name,\n", - " \"TrialComponentDisplayName\": \"ll-svm-training-job\",\n", - " },\n", - " logs=True,\n", - " )" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Next, we will add in a selection for the hyperparameter `binary_classifier_model_selection_criteria` which allows us to define which metric we would like our model to optimize for (auto threshold tuning). We can choose between percision, recall, F1 and accuracy among other metric choices. \n", - "\n", - "It's important to note here that for PrM, we must carefully select our evaluation metric based on domain knowlege. For example, recall increases the chance of catching all failures even false ones. Whereas, precision decreases the chance of catching false failures along with real failures. It is not hard to see that these metrics do not always incorporate the business needs, especially the dollar costs and benefits associated with machinery failures. \n", - "\n", - "With this in mind, we will select F1 as the evaluation metric as it is generally a good evaluation metric for imbalanced classification proglems. If you would like to learn more about selecting a custom cost sensitive evaluation metric for your business use case, you can review the article listen in the *Additional Resources* section below. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "scrolled": true - }, - "outputs": [], - "source": [ - "svm_output_path = f\"s3://{bucket}/{exp_prefix}/output/svm_threshold\"\n", - "trial_name_3 = f\"linear-learner-svm-thresh-{create_date}\"\n", - "\n", - "# create the trial if it doesn't exist\n", - "try:\n", - " my_trial = Trial.load(trial_name=trial_name_3)\n", - " print(f\"Loaded existing trial: {trial_name_3}\")\n", - "except Exception as e:\n", - " if \"ResourceNotFound\" in str(e):\n", - " my_trial = Trial.create(experiment_name=experiment_name, trial_name=trial_name_3)\n", - " print(f\"Create trial {my_trial.trial_name}: SUCCESSFUL\")\n", - "\n", - " svm_thresh = sagemaker.estimator.Estimator(\n", - " container,\n", - " role,\n", - " instance_count=1,\n", - " instance_type=\"ml.c4.xlarge\",\n", - " output_path=svm_output_path,\n", - " sagemaker_session=sess,\n", - " )\n", - "\n", - " svm_thresh.set_hyperparameters(\n", - " predictor_type=\"binary_classifier\",\n", - " loss=\"hinge_loss\",\n", - " binary_classifier_model_selection_criteria=\"f_beta\",\n", - " epochs=20,\n", - " mini_batch_size=99,\n", - " )\n", - "\n", - " # linear.fit({'train': path_to_train_data_prm})\n", - " svm_thresh.fit(\n", - " inputs=data_channels,\n", - " experiment_config={\n", - " \"ExperimentName\": my_experiment.experiment_name,\n", - " \"TrialName\": my_trial.trial_name,\n", - " \"TrialComponentDisplayName\": \"ll-svm-thresh-training-job\",\n", - " },\n", - " logs=True,\n", - " )" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Let's try dealing with class imbalances to try to improve precision and recall\n", - "\n", - "We will set the hyperparameter `positive_example_weight_mult` to *balanced* in order to use weighting by class to address the class imbalance issue. Since we have only 19% failures compared to non-failures, we can leverage this built-in hyperparameter to try to improve model performance. Here is more documentation about [Linear Learner Hyperparameters](https://docs.aws.amazon.com/sagemaker/latest/dg/ll_hyperparameters.html)." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "scrolled": true - }, - "outputs": [], - "source": [ - "# Training a binary classifier with hinge loss and balanced class weights\n", - "\n", - "# set output path\n", - "svm_output_path = f\"s3://{bucket}/{exp_prefix}/output/svm_balanced\"\n", - "trial_name_4 = f\"linear-learner-svm-balanced-{create_date}\"\n", - "\n", - "# create the trial if it doesn't exist\n", - "try:\n", - " my_trial = Trial.load(trial_name=trial_name_4)\n", - " print(f\"Loaded existing trial: {trial_name_4}\")\n", - "except Exception as e:\n", - " if \"ResourceNotFound\" in str(e):\n", - " my_trial = Trial.create(experiment_name=experiment_name, trial_name=trial_name_4)\n", - " print(f\"Create trial {my_trial.trial_name}: SUCCESSFUL\")\n", - "\n", - " # specify algorithm containers and instantiate an Estimator with hyperparams\n", - " svm_balanced = sagemaker.estimator.Estimator(\n", - " container,\n", - " role,\n", - " instance_count=1,\n", - " instance_type=\"ml.c4.xlarge\",\n", - " output_path=svm_output_path,\n", - " sagemaker_session=sess,\n", - " enable_sagemaker_metrics=True,\n", - " )\n", - "\n", - " svm_balanced.set_hyperparameters(\n", - " predictor_type=\"binary_classifier\",\n", - " loss=\"hinge_loss\",\n", - " positive_example_weight_mult=\"balanced\", # this is for dealing with class imbalances\n", - " epochs=20,\n", - " mini_batch_size=99,\n", - " )\n", - " # fit model to data\n", - " svm_balanced.fit(\n", - " inputs=data_channels,\n", - " experiment_config={\n", - " \"ExperimentName\": my_experiment.experiment_name,\n", - " \"TrialName\": my_trial.trial_name,\n", - " \"TrialComponentDisplayName\": \"ll-svm-bal-training-job\",\n", - " },\n", - " logs=True,\n", - " )" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# first we can look at all the trials together to evaluate the performance\n", - "trial_component_analytics = ExperimentAnalytics(experiment_name=my_experiment.experiment_name)\n", - "analytic_table = trial_component_analytics.dataframe()\n", - "analytic_table = analytic_table[\n", - " [\n", - " \"TrialComponentName\",\n", - " \"DisplayName\",\n", - " \"positive_example_weight_mult\",\n", - " \"validation:recall - Avg\",\n", - " \"validation:binary_classification_accuracy - Avg\",\n", - " \"validation:roc_auc_score - Avg\",\n", - " \"train:objective_loss - Avg\",\n", - " \"validation:objective_loss:final - Avg\",\n", - " \"validation:objective_loss - Avg\",\n", - " \"validation:binary_f_beta - Avg\",\n", - " \"validation:precision - Avg\",\n", - " \"Trials\",\n", - " \"Experiments\",\n", - " ]\n", - "]\n", - "\n", - "analytic_table.sort_values(\n", - " [\"validation:binary_classification_accuracy - Avg\", \"validation:binary_f_beta - Avg\"],\n", - " ascending=False,\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Observations:\n", - "\n", - "* Balancing class weights improved precision, but decreased recall significantly \n", - "* Accuracy for all the models is relatively consistent at around 84%\n", - "* Across all the metrics, SVM with auto hyperparameters performed the best cumulatively\n", - "\n", - "We will move forward with with the auto SMV model, labeled as `svm-default`" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# # option to deploy a predictor here and make predictions against this endpoint\n", - "\n", - "# # initialize the deserializer and serializer\n", - "# serializer = sagemaker.serializers.CSVSerializer()\n", - "# deserializer = sagemaker.deserializers.JSONDeserializer()\n", - "\n", - "# svm_predictor = svm.deploy(initial_instance_count=1,\n", - "# instance_type='local'\n", - "# instance_type='ml.m4.xlarge',\n", - "# serializer=serializer,\n", - "# deserializer=deserializer,\n", - "# endpoint_name='svm',\n", - "# model_name='svm')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Hyperparamter Tuning \n", - "\n", - "### Next, we set up the hyperparmeter tuning job using SageMaker Automatic Tuning\n", - "\n", - "*Note, with the settings below, the hyperparameter tuning job can take about 30 minutes to complete.*\n", - "\n", - "Hyperparameters can dramtically affect the performance of trained models. Thus, we need to pick the right values to achieve the best model result. Since model results are also affected by the data set as well, it is important to select the best hyperparmateters by searching for them using an algorithmic approach that can be automated and perform efficiently.\n", - "\n", - "Using Automatic Tuning, we will specify a range, or a list of possible values in the case of categorical hyperparameters, for each of the hyperparameter that we plan to tune. SageMaker hyperparameter tuning will automatically launch multiple training jobs with different hyperparameter settings, evaluate results of those training jobs based on a predefined \"objective metric\", and select the hyperparameter settings for future attempts based on previous results. For each hyperparameter tuning job, we will give it a budget (max number of training jobs) and it will complete once that many training jobs have been executed.\n", - "\n", - "In this example, we are using SageMaker Python SDK to set up and manage the hyperparameter tuning job. We first configure the training jobs the hyperparameter tuning job will launch by initiating an estimator, which includes the following configuration:\n", - "\n", - "* hyperparameters that SageMaker Automatic Model Tuning will tune: `learning_rate` \n", - "* the maximum number of training jobs it will run to optimize the objective metric: 5\n", - "* the number of parallel training jobs that will run in the tuning job: 2\n", - "* the objective metric that Automatic Model Tuning will use: validation:accuracy\n", - "\n", - "We will also demonstrates how to associate trial components created by a hyperparameter tuning job with an experiment management trial.\n", - "\n", - "Read the following link more information on how to [Tune a Linear Learner Model](https://docs.aws.amazon.com/sagemaker/latest/dg/linear-learner-tuning.html) and about [How Hyperparameter Tuning Works](https://docs.aws.amazon.com/sagemaker/latest/dg/automatic-model-tuning-how-it-works.html)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from sagemaker.tuner import HyperparameterTuner, ContinuousParameter\n", - "from botocore.exceptions import ClientError" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# custom job name\n", - "prm_tuning_job_name = f\"ll-svm-tuning-job\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# set output path\n", - "svm_output_path = f\"s3://{bucket}/{exp_prefix}/output/tuning/svm_default\"\n", - "\n", - "# create the tuning job if it doesn't exist\n", - "try:\n", - " svm_tune = sagemaker.estimator.Estimator(\n", - " container,\n", - " role,\n", - " instance_count=1,\n", - " instance_type=\"ml.c4.xlarge\",\n", - " output_path=svm_output_path,\n", - " sagemaker_session=sess,\n", - " )\n", - "\n", - " svm_tune.set_hyperparameters(\n", - " predictor_type=\"binary_classifier\", loss=\"hinge_loss\", epochs=20, mini_batch_size=99\n", - " )\n", - "\n", - " hyperparameter_ranges = {\n", - " \"learning_rate\": ContinuousParameter(0.01, 0.5, scaling_type=\"Logarithmic\")\n", - " }\n", - "\n", - " # configure HyperparameterTuner\n", - " my_tuner = HyperparameterTuner(\n", - " estimator=svm_tune, # previously-configured Estimator object\n", - " objective_metric_name=\"validation:binary_classification_accuracy\",\n", - " hyperparameter_ranges=hyperparameter_ranges,\n", - " max_jobs=5,\n", - " max_parallel_jobs=2,\n", - " strategy=\"Random\",\n", - " base_tuning_job_name=prm_tuning_job_name,\n", - " )\n", - "\n", - " # start hyperparameter tuning job\n", - " my_tuner.fit(inputs=data_channels, include_cls_metadata=False)\n", - " print(f\"Create tuning job {prm_tuning_job_name}: SUCCESSFUL\")\n", - "except ClientError as e:\n", - " if \"ResourceInUse\" in str(e):\n", - " my_tuner = HyperparameterTuner.attach(prm_tuning_job_name)\n", - " print(f\"Attach tuning job {prm_tuning_job_name}: SUCCESSFUL\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# check status\n", - "boto3.client(\"sagemaker\").describe_hyper_parameter_tuning_job(\n", - " HyperParameterTuningJobName=my_tuner.latest_tuning_job.job_name\n", - ")[\"HyperParameterTuningJobStatus\"]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "tune_analytics = sagemaker.HyperparameterTuningJobAnalytics(\n", - " my_tuner.latest_tuning_job.job_name\n", - ").dataframe()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# get the most recently created tuning jobs\n", - "list_tuning_jobs_response = smclient.list_hyper_parameter_tuning_jobs(\n", - " SortBy=\"CreationTime\", SortOrder=\"Descending\"\n", - ")\n", - "\n", - "# inspect output\n", - "print(f'Found {len(list_tuning_jobs_response[\"HyperParameterTuningJobSummaries\"])} tuning jobs.')\n", - "tuning_jobs = list_tuning_jobs_response[\"HyperParameterTuningJobSummaries\"]\n", - "most_recently_created_tuning_job = tuning_jobs[0]\n", - "tuning_job_name = most_recently_created_tuning_job[\"HyperParameterTuningJobName\"]\n", - "experiment_name = my_experiment.experiment_name\n", - "tune_trial_name = tuning_job_name + \"-trial\"\n", - "%store tune_trial_name\n", - "\n", - "print(f\"Associate all training jobs created by {tuning_job_name} with trial {tune_trial_name}\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# create the trial if it doesn't exist\n", - "try:\n", - " tune_trial = Trial.load(trial_name=tune_trial_name)\n", - " print(f\"Loaded existing trial: {tune_trial_name}\")\n", - "except Exception as e:\n", - " if \"ResourceNotFound\" in str(e):\n", - " tune_trial = Trial.create(experiment_name=experiment_name, trial_name=tune_trial_name)\n", - " print(f\"Create trial {tune_trial.trial_name}: SUCCESSFUL\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from sagemaker import HyperparameterTuningJobAnalytics, Session\n", - "from smexperiments.search_expression import Filter, Operator, SearchExpression\n", - "from smexperiments.trial import Trial\n", - "from smexperiments.trial_component import TrialComponent\n", - "\n", - "# get the training jobs associated with the tuning job\n", - "tuning_analytics = HyperparameterTuningJobAnalytics(tuning_job_name, sess)\n", - "\n", - "training_job_summaries = tuning_analytics.training_job_summaries()\n", - "training_job_arns = list(map(lambda x: x[\"TrainingJobArn\"], training_job_summaries))\n", - "print(\n", - " f\"Found {len(training_job_arns)} training jobs for hyperparameter tuning job {tuning_job_name}.\"\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import time\n", - "from datetime import datetime, timezone\n", - "\n", - "# get the trial components derived from the training jobs\n", - "creation_time = most_recently_created_tuning_job[\"CreationTime\"]\n", - "creation_time = creation_time.astimezone(timezone.utc)\n", - "creation_time = creation_time.strftime(\"%Y-%m-%dT%H:%M:%SZ\")\n", - "\n", - "created_after_filter = Filter(\n", - " name=\"CreationTime\",\n", - " operator=Operator.GREATER_THAN_OR_EQUAL,\n", - " value=str(creation_time),\n", - ")\n", - "\n", - "# the training job names contain the tuning job name (and the training job name is in the source arn)\n", - "source_arn_filter = Filter(\n", - " name=\"Source.SourceArn\", operator=Operator.CONTAINS, value=tuning_job_name\n", - ")\n", - "source_type_filter = Filter(\n", - " name=\"Source.SourceType\", operator=Operator.EQUALS, value=\"SageMakerTrainingJob\"\n", - ")\n", - "\n", - "search_expression = SearchExpression(\n", - " filters=[created_after_filter, source_arn_filter, source_type_filter]\n", - ")\n", - "\n", - "# search iterates over every page of results by default\n", - "trial_component_search_results = list(\n", - " TrialComponent.search(search_expression=search_expression, sagemaker_boto_client=smclient)\n", - ")\n", - "print(f\"Found {len(trial_component_search_results)} trial components.\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# associate the trial components with the trial\n", - "for tc in trial_component_search_results:\n", - " print(\n", - " f\"Associating trial component {tc.trial_component_name} with trial {tune_trial.trial_name}.\"\n", - " )\n", - " tune_trial.add_trial_component(tc.trial_component_name)\n", - " # sleep to avoid throttling\n", - " time.sleep(0.5)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# here is the output of all of the hyperparameter tuning trial runs\n", - "tuning_analytics.dataframe()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "---\n", - "## Predict\n", - "\n", - "### Deploy Model with Batch Transform and Get Inferences for the Test Dataset\n", - "\n", - "Let's predict on our test dataset to understand how accurate our model is. We will create batch inferences and use a helper function to evaludate the results. \n", - "\n", - "Use batch transform when you:\n", - "- Want to get inferences for an entire dataset and index them to serve inferences in real time\n", - "- Don't need a persistent endpoint that applications (for example, web or mobile apps) can call to get inferences\n", - "- Don't need the subsecond latency that SageMaker hosted endpoints provide\n", - "\n", - "Here is additional information about how to [Use Batch Transform](https://docs.aws.amazon.com/sagemaker/latest/dg/batch-transform.html). " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The following code creates a `sagemaker.transformer.Transformer` object from the model that was trained in the sections above. Then it calls that object's transform method to create a transform job. When you create the `sagemaker.transformer.Transformer` object, you specify the number and type of ML instances to use to perform the batch transform job, and the location in Amazon S3 where you want to store the inferences.For more information, see [SageMaker Transformer](https://sagemaker.readthedocs.io/en/stable/transformer.html)." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Select the best model, deploy and get batch predictions" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "scrolled": true - }, - "outputs": [], - "source": [ - "# get best model\n", - "best_model = my_tuner.best_estimator()\n", - "\n", - "# the location of the test dataset\n", - "batch_input = path_to_test_x_data_prm\n", - "\n", - "# the location to store the results of the batch transform job\n", - "batch_output = f\"s3://{bucket}/transform/batch-inference\"\n", - "\n", - "# create transformer for best model\n", - "transformer = best_model.transformer(\n", - " instance_count=1,\n", - " instance_type=\"ml.m4.xlarge\",\n", - " output_path=batch_output,\n", - " accept=\"application/json\",\n", - ")\n", - "\n", - "# get batch inferences\n", - "transformer.transform(data=batch_input, content_type=\"text/csv\", split_type=\"Line\")\n", - "\n", - "transformer.wait()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Great, now that our Batch Transform job is complete, we can download the predictions and evaluate the results. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "!aws s3 cp --recursive $transformer.output_path ./" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We see that the endpoint returned JSON which contains `predictions`, including the `score` and `predicted_label`. In this case, `score` will be a continuous value between [0, 1] representing the probability there will be a failure in the window. `predicted_label` will take a value of either `0` or `1` where `1` denotes that we predict a failure within the next designated time window, while `0` denotes that we are predicting that there is not a failure within the next time window. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def evaluate_model(batch_file_path, test_labels, model_name, metrics=True):\n", - " \"\"\"\n", - " Download batch predictions and iterate through results. Evaluate model results by comparing to actuals from test data.\n", - " Return binary classification metrics.\n", - " \"\"\"\n", - "\n", - " # open batch prediction file and parse json to exctract predicted label\n", - " with open(batch_file_path, \"r\") as f:\n", - " for line in f:\n", - " result = json.loads(line)\n", - " predictions = pd.Series(\n", - " [\n", - " result[\"predictions\"][i][\"predicted_label\"]\n", - " for i in range(len(result[\"predictions\"]))\n", - " ]\n", - " )\n", - "\n", - " # calculate true positives, false positives, true negatives, false negatives\n", - " tp = np.logical_and(test_labels, predictions).sum()\n", - " fp = np.logical_and(1 - test_labels, predictions).sum()\n", - " tn = np.logical_and(1 - test_labels, 1 - predictions).sum()\n", - " fn = np.logical_and(test_labels, 1 - predictions).sum()\n", - "\n", - " # calculate binary classification metrics\n", - " recall = tp / (tp + fn)\n", - " precision = tp / (tp + fp)\n", - " accuracy = (tp + tn) / (tp + fp + tn + fn)\n", - " f1 = 2 * precision * recall / (precision + recall)\n", - "\n", - " if metrics:\n", - " print(pd.crosstab(test_labels, predictions, rownames=[\"actuals\"], colnames=[\"predictions\"]))\n", - " print(f\"Accuracy: {accuracy}\")\n", - " print(f\"F1: {f1}\")\n", - " print(f\"Recall: {recall}\")\n", - " print(f\"Precision: {precision}\")\n", - "\n", - " return {\n", - " \"TP\": tp,\n", - " \"FP\": fp,\n", - " \"FN\": fn,\n", - " \"TN\": tn,\n", - " \"Precision\": precision,\n", - " \"Recall\": recall,\n", - " \"Accuracy\": accuracy,\n", - " \"F1\": f1,\n", - " \"Model\": model_name,\n", - " }" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# call evaluation function and inspect results\n", - "test = pd.read_csv(\"test.csv\", header=None)\n", - "test_y = test[0]\n", - "evaluate_model(\"test_x.csv.out\", test_y, \"PrM-Classification-SVM\", metrics=True)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Clean Up (Optional)\n", - "\n", - "Once we're done don't forget to clean up the endpoint and experiments to prevent unnecessary billing." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def delete_endpoint(predictor):\n", - " try:\n", - " predictor.delete_model()\n", - " predictor.delete_endpoint()\n", - " print(\"Deleted {}\".format(predictor.endpoint))\n", - " except:\n", - " print(\"Already deleted: {}\".format(predictor.endpoint))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# you can run this cell if you deployed your estimator instead of doing Batch Transform\n", - "# delete_endpoint(svm_predictor)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "(Optional) In order to delete the experiments created, you can `delete_all` or use the `cleanup_boto3` helper function to delete individual experiments by passing the experiment name to the function. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# run this to delete the experiment and all its related trials and trial components\n", - "# my_experiment.delete_all(action='--force')\n", - "sm = boto3.Session().client(\"sagemaker\")\n", - "\n", - "\n", - "def cleanup_boto3(experiment_name):\n", - " trials = sm.list_trials(ExperimentName=experiment_name)[\"TrialSummaries\"]\n", - " print(\"TrialNames:\")\n", - " for trial in trials:\n", - " trial_name = trial[\"TrialName\"]\n", - " print(f\"\\n{trial_name}\")\n", - "\n", - " components_in_trial = sm.list_trial_components(TrialName=trial_name)\n", - " print(\"\\tTrialComponentNames:\")\n", - " for component in components_in_trial[\"TrialComponentSummaries\"]:\n", - " component_name = component[\"TrialComponentName\"]\n", - " print(f\"\\t{component_name}\")\n", - " sm.disassociate_trial_component(TrialComponentName=component_name, TrialName=trial_name)\n", - " try:\n", - " # comment out to keep trial components\n", - " sm.delete_trial_component(TrialComponentName=component_name)\n", - " except:\n", - " # component is associated with another trial\n", - " continue\n", - " # to prevent throttling\n", - " time.sleep(0.5)\n", - " sm.delete_trial(TrialName=trial_name)\n", - " sm.delete_experiment(ExperimentName=experiment_name)\n", - " print(f\"\\nExperiment {experiment_name} deleted\")\n", - "\n", - "\n", - "# Call cleanup_boto3\n", - "\n", - "# Use experiment name not display name\n", - "experiment_name = my_experiment.experiment_name\n", - "# cleanup_boto3(experiment_name)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "jupyter": { - "outputs_hidden": true - } - }, - "source": [ - "---\n", - "## Extensions\n", - "\n", - "* Our linear model does a relatively good job of predicting if a failure will occur in the next window of time and has an overall accuracy of close to 84%, but we can re-run the model with different values of the hyperparameters, loss functions etc and see if we get improved prediction\n", - " * Re-running the model with further tweaks to these hyperparameters may provide more accurate out-of-sample predictions\n", - "* We also did not do much feature engineering\n", - " * We can create additional features by considering cross-product/intreaction of multiple features, squaring or raising higher powers of the features to induce non-linear effects, etc. \n", - " * If we expand the features using non-linear terms and interactions, we can then tweak the regulaization parameter to optimize the expanded model and hence generate improved forecasts\n", - "* As a further extension, we can experiment with many tree-based models such as XGBoost, Random Forest, or gradient boosting to address the class imbalance as these models are less sensitive to class imbalances \n", - "* Once the model performance has met the business's desired output, it can be deployed at the edge using [AWS IoT Greengrass](https://aws.amazon.com/greengrass/)\n", - " * Here is an additional example of [Predictive Maintenance Deployed at the Edge](https://github.com/aws-samples/amazon-sagemaker-predictive-maintenance-deployed-at-edge) using SageMaker and Greengrass for guidance \n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Additonal Resources\n", - "\n", - "- [A Survey of Predictive Maintenance: Systems, Purposes and Approaches](https://arxiv.org/pdf/1912.07383.pdf)\n", - "-[Cost-Sensitive Learning for Predictive Maintenance](https://arxiv.org/pdf/1809.10979.pdf)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Notebook CI Test Results\n", - "\n", - "This notebook was tested in multiple regions. The test results are as follows, except for us-west-2 which is shown at the top of the notebook.\n", - "\n", - "![This us-east-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/us-east-1/use-cases|predictive_maintenance|3_train_tune_predict_predmaint.ipynb)\n", - "\n", - "![This us-east-2 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/us-east-2/use-cases|predictive_maintenance|3_train_tune_predict_predmaint.ipynb)\n", - "\n", - "![This us-west-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/us-west-1/use-cases|predictive_maintenance|3_train_tune_predict_predmaint.ipynb)\n", - "\n", - "![This ca-central-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/ca-central-1/use-cases|predictive_maintenance|3_train_tune_predict_predmaint.ipynb)\n", - "\n", - "![This sa-east-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/sa-east-1/use-cases|predictive_maintenance|3_train_tune_predict_predmaint.ipynb)\n", - "\n", - "![This eu-west-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/eu-west-1/use-cases|predictive_maintenance|3_train_tune_predict_predmaint.ipynb)\n", - "\n", - "![This eu-west-2 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/eu-west-2/use-cases|predictive_maintenance|3_train_tune_predict_predmaint.ipynb)\n", - "\n", - "![This eu-west-3 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/eu-west-3/use-cases|predictive_maintenance|3_train_tune_predict_predmaint.ipynb)\n", - "\n", - "![This eu-central-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/eu-central-1/use-cases|predictive_maintenance|3_train_tune_predict_predmaint.ipynb)\n", - "\n", - "![This eu-north-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/eu-north-1/use-cases|predictive_maintenance|3_train_tune_predict_predmaint.ipynb)\n", - "\n", - "![This ap-southeast-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/ap-southeast-1/use-cases|predictive_maintenance|3_train_tune_predict_predmaint.ipynb)\n", - "\n", - "![This ap-southeast-2 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/ap-southeast-2/use-cases|predictive_maintenance|3_train_tune_predict_predmaint.ipynb)\n", - "\n", - "![This ap-northeast-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/ap-northeast-1/use-cases|predictive_maintenance|3_train_tune_predict_predmaint.ipynb)\n", - "\n", - "![This ap-northeast-2 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/ap-northeast-2/use-cases|predictive_maintenance|3_train_tune_predict_predmaint.ipynb)\n", - "\n", - "![This ap-south-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/ap-south-1/use-cases|predictive_maintenance|3_train_tune_predict_predmaint.ipynb)\n" - ] - } - ], - "metadata": { - "instance_type": "ml.t3.medium", - "kernelspec": { - "display_name": "Python 3 (Data Science 2.0)", - "language": "python", - "name": "python3__SAGEMAKER_INTERNAL__arn:aws:sagemaker:us-west-2:236514542706:image/sagemaker-data-science-38" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.13" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -}