{ "cells": [ { "attachments": {}, "cell_type": "markdown", "metadata": { "tags": [] }, "source": [ "# SageMaker Pipelines with Amazon SageMaker Geospatial Capabilities\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/sagemaker-geospatial|geospatial-pipeline|geospatial-pipelines.ipynb)\n", "\n", "---" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": { "tags": [] }, "source": [ "\n", "This notebook demonstrates how to create a SageMaker Pipeline to automate geospatial data processing workflows.\n", "\n", "Amazon SageMaker Pipelines is a tool for building machine learning pipelines that take advantage of direct SageMaker integration. In this notebook, we will combine Amazon SageMaker geospatial capabilities with Amazon SageMaker Pipelines to create a reproducible and automated workflow which executes a chain of Earth Observation Jobs.\n", "\n", "![Pipeline Architecture](images/pipeline_architecture.png)\n", "\n", "----" ] }, { "cell_type": "markdown", "metadata": { "jp-MarkdownHeadingCollapsed": true, "tags": [] }, "source": [ "## Prerequisites\n", "\n", "### General setup\n", "\n", "This notebook runs with Kernel Geospatial 1.0. Note that the following policies need to be attached to the execution role that you used to run this notebook:\n", "\n", "- AmazonSageMakerFullAccess\n", "- AmazonSageMakerGeospatialFullAccess\n", "\n", "You can see the policies attached to the role in the IAM console under the permissions tab. If required, add the roles using the 'Add Permissions' button.\n", "\n", "### Interactions with AWS Lambda, Amazon S3, and Amazon SQS\n", "\n", "To allow deployment of the Lambda function and use the SageMaker geospatial services from within the notebook, the notebook's execution role needs to allow to assume the role. This can be done by adding the following trust policy using the 'Trust relationships' tab:\n", "\n", "```\n", "{\n", " \"Version\": \"2012-10-17\",\n", " \"Statement\": [\n", " {\n", " \"Effect\": \"Allow\",\n", " \"Principal\": {\n", " \"Service\": [\n", " \"sagemaker.amazonaws.com\",\n", " \"sagemaker-geospatial.amazonaws.com\",\n", " \"lambda.amazonaws.com\",\n", " \"s3.amazonaws.com\"\n", " ]\n", " },\n", " \"Action\": \"sts:AssumeRole\"\n", " }\n", " ]\n", "}\n", "```\n", "\n", "Additionaly the notebook's AWS IAM role needs to have the proper permissions for interacting with AWS Lambda, Amazon S3, and Amazon SQS as required.\n", "\n", "For demo purposes, the following inline policy can be added. Please note that this policy should be scoped down to improve security for any production deployment, following the least privilege principle:\n", "\n", "```\n", "{\n", " \"Version\": \"2012-10-17\",\n", " \"Statement\": [\n", " {\n", " \"Effect\": \"Allow\",\n", " \"Action\": [\n", " \"s3:GetObject\",\n", " \"s3:PutObject\",\n", " \"s3:DeleteObject\",\n", " \"s3:ListBucket\"\n", " ],\n", " \"Resource\": [\n", " \"arn:aws:s3:::*\"\n", " ]\n", " },\n", " {\n", " \"Effect\": \"Allow\",\n", " \"Action\": [\n", " \"sqs:SendMessage\",\n", " \"sqs:ReceiveMessage\",\n", " \"sqs:DeleteMessage\",\n", " \"sqs:GetQueueAttributes\",\n", " \"sqs:GetQueueUrl\",\n", " \"sqs:CreateQueue\"\n", " ],\n", " \"Resource\": [\n", " \"*\"\n", " ]\n", " },\n", " {\n", " \"Effect\": \"Allow\",\n", " \"Action\": [\n", " \"lambda:*\",\n", " \"logs:CreateLogGroup\",\n", " \"logs:CreateLogStream\",\n", " \"logs:PutLogEvents\"\n", " ],\n", " \"Resource\": [\n", " \"*\"\n", " ]\n", " },\n", " {\n", " \"Effect\": \"Allow\",\n", " \"Action\": [\n", " \"iam:GetRole\",\n", " \"iam:PassRole\",\n", " \"sts:GetCallerIdentity\"\n", " ],\n", " \"Resource\": \"*\"\n", " }\n", " ]\n", "}\n", "\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "-----\n", "## Import SageMaker geospatial capabilities SDK" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [] }, "outputs": [], "source": [ "import boto3\n", "import sagemaker\n", "import json\n", "from datetime import datetime\n", "\n", "session = boto3.Session()\n", "execution_role = sagemaker.get_execution_role()\n", "sagemaker_session = sagemaker.Session()\n", "region = \"us-west-2\"\n", "bucket = sagemaker_session.default_bucket() # Alternatively you can use your custom bucket here.\n", "bucket_prefix = \"eoj-pipeline-example\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "--------\n", "## Setup Infrastructure\n", "\n", "The following steps will setup the necessary infrastructure to execute a [SageMaker Pipeline](https://docs.aws.amazon.com/sagemaker/latest/dg/pipelines-sdk.html) using geospatial capabilities. Earth Observation Jobs (EOJs) are executed asynchronous and the pipeline needs to be able to check the status via callbacks.\n", "\n", "For this, we'll setup a Lambda function and a SQS queue which are both later used in the pipeline.\n", "\n", "This infrastructure needs to be created only once and can then be referenced in multiple pipelines." ] }, { "cell_type": "markdown", "metadata": { "tags": [] }, "source": [ "### Create Lambda layer\n", "\n", "Before we create the Lambda function, we'll create a [Lambda layer](https://docs.aws.amazon.com/lambda/latest/dg/configuration-layers.html) which contains a recent boto3 version which is necessary to use the sagemaker-geospatial API.\n", "\n", "The following steps are packaging the layer code, uploading the code package to S3 and creating the actual Lambda layer." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [] }, "outputs": [], "source": [ "import argparse\n", "import os\n", "import subprocess\n", "import sys\n", "import tempfile\n", "import venv\n", "import zipfile\n", "\n", "\n", "def zipdir(path, zip_fhandle):\n", " for root, dirs, files in os.walk(path):\n", " for file in files:\n", " zip_fhandle.write(\n", " os.path.join(root, file),\n", " os.path.relpath(os.path.join(root, file), os.path.join(path, \"..\")),\n", " )\n", "\n", "\n", "requirements = [\"boto3==1.26.100\"]\n", "\n", "output_file = \"assets/boto_layer.zip\"\n", "\n", "tmp_dir = tempfile.TemporaryDirectory()\n", "tmp_dir_path = tmp_dir.name\n", "\n", "lambda_dir = os.path.join(tmp_dir_path, \"python\")\n", "os.mkdir(lambda_dir)\n", "\n", "work_dir = os.getcwd()\n", "os.chdir(tmp_dir_path)\n", "\n", "venv_dir = os.path.join(tmp_dir_path, \"venv/\")\n", "pip_bin = os.path.join(venv_dir, \"bin/pip\")\n", "\n", "venv.create(venv_dir, with_pip=True)\n", "\n", "for r in requirements:\n", " subprocess.run([pip_bin, \"install\", \"--quiet\", \"--disable-pip-version-check\", r], check=True)\n", "\n", "os.rename(os.path.join(venv_dir, \"lib\"), os.path.join(lambda_dir, \"lib\"))\n", "# rename directory to Lambda runtime target version to enable implicit module import\n", "os.rename(\n", " os.path.join(lambda_dir, \"lib\", \"python3.10\"), os.path.join(lambda_dir, \"lib\", \"python3.9\")\n", ")\n", "\n", "with zipfile.ZipFile(os.path.join(work_dir, output_file), \"w\") as zf:\n", " zipdir(os.path.basename(lambda_dir), zf)\n", "\n", "os.chdir(work_dir)\n", "tmp_dir.cleanup()" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [] }, "outputs": [], "source": [ "layer_archive_object_key = f\"{bucket_prefix}/infra/boto_layer.zip\"\n", "output_file = \"assets/boto_layer.zip\"\n", "\n", "s3_client = boto3.client(\"s3\")\n", "response = s3_client.upload_file(output_file, bucket, layer_archive_object_key)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [] }, "outputs": [], "source": [ "lambda_client = boto3.client(\"lambda\")\n", "\n", "response = lambda_client.publish_layer_version(\n", " LayerName=\"boto3-1_26_100-layer\",\n", " Content={\n", " \"S3Bucket\": bucket,\n", " \"S3Key\": layer_archive_object_key,\n", " },\n", " CompatibleRuntimes=[\"python3.9\"],\n", ")\n", "\n", "layer_arn = response[\"LayerVersionArn\"]\n", "print(f\"Created Lambda layer with ARN: {layer_arn}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Create Lambda function\n", "\n", "After the layer has been created, we will create the actual Lambda function. The code for Lambda function is located at [assets/eoj_pipeline_lambda.py](assets/eoj_pipeline_lambda.py).\n", "\n", "The Lambda function will provide functionality to start EOJs and also check their status. It will be used in combination with an Amazon SQS queue.\n", "\n", "The following cell will create the Lambda function `geospatial-eoj-pipeline-lambda`." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [] }, "outputs": [], "source": [ "import zipfile\n", "\n", "with zipfile.ZipFile(\"./assets/eoj_pipeline_lambda.py.zip\", \"w\") as zf:\n", " zf.write(\"./assets/eoj_pipeline_lambda.py\", \"eoj_pipeline_lambda.py\")\n", "\n", "with open(\"./assets/eoj_pipeline_lambda.py.zip\", \"rb\") as f:\n", " zipped_code = f.read()\n", "\n", "lambda_client = boto3.client(\"lambda\")\n", "\n", "# set this to True to delete the lambda function named `geospatial-eoj-pipeline-lambda` before deploying the lambda function\n", "# if set to True, this allows the execution of this cell multiple times\n", "delete_before_create = False\n", "\n", "if delete_before_create:\n", " try:\n", " lambda_client.delete_function(FunctionName=\"geospatial-eoj-pipeline-lambda\")\n", " # ignore if the function does not exist\n", " except lambda_client.exceptions.ResourceNotFoundException:\n", " pass\n", "\n", "\n", "response = lambda_client.create_function(\n", " FunctionName=\"geospatial-eoj-pipeline-lambda\",\n", " Runtime=\"python3.9\",\n", " Role=execution_role,\n", " Handler=\"eoj_pipeline_lambda.lambda_handler\",\n", " Code=dict(ZipFile=zipped_code),\n", " Layers=[layer_arn],\n", " Timeout=60,\n", " Environment={\"Variables\": {\"LOGGING_LEVEL\": \"INFO\"}},\n", ")\n", "\n", "function_arn = response[\"FunctionArn\"]\n", "print(f\"Created Lambda function with ARN: {function_arn}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Create SQS queue\n", "\n", "After creating the Lambda function to invoke EOJs, we will create an Amazon SQS queue for asynchronous callbacks.\n", "\n", "As Earth Observation Jobs (EOJs) are executed in an asynchronous fashion, the SQS queue is needed to check the EOJ status within the pipeline asynchronously.\n", "\n", "The following cell will create an Amazon SQS queue which will be later used in the pipeline." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [] }, "outputs": [], "source": [ "# Create SQS queue for handling async processes and callback\n", "sqs_client = boto3.client(\"sqs\", region_name=region)\n", "\n", "sqs_client.create_queue(\n", " QueueName=f\"geospatial-eoj-pipeline-queue\",\n", " Attributes={\n", " \"VisibilityTimeout\": \"300\",\n", " \"DelaySeconds\": \"5\",\n", " \"ReceiveMessageWaitTimeSeconds\": \"5\",\n", " },\n", ")\n", "queue_url = sqs_client.get_queue_url(QueueName=f\"geospatial-eoj-pipeline-queue\")[\"QueueUrl\"]\n", "queue_arn = sqs_client.get_queue_attributes(QueueUrl=queue_url, AttributeNames=[\"QueueArn\"])[\n", " \"Attributes\"\n", "][\"QueueArn\"]\n", "\n", "print(\"Created queue: {}\".format(json.dumps({\"url\": queue_url, \"arn\": queue_arn}, indent=4)))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now we need to associate the SQS queue as an input trigger for our Lambda function, in this way whenever the Callback Step pushes a message to the queue it would run our Lambda function for checking the status of the EOJ. We do this by creating an Event Source Mapping between the Lambda function and the SQS queue." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [] }, "outputs": [], "source": [ "# Link SQS queue with the geospatial-check-lambda function...\n", "event_source_mapping = lambda_client.create_event_source_mapping(\n", " EventSourceArn=queue_arn, FunctionName=\"geospatial-eoj-pipeline-lambda\", Enabled=True\n", ")\n", "print(f'Mapping Lambda function and SQS queue through UUID: {event_source_mapping[\"UUID\"]}')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "----\n", "## Pipeline Creation\n", "\n", "After the necessary infrastructure has been deployed, we can build the pipeline.\n", "\n", "We will define the parameters which are used to configure our pipeline dynamically whenever we execute the pipeline.\n", "\n", "The code below allows the creation of a desired amount of EOJ steps within the pipeline. In this example, we will create 3 EOJ steps and one additional export step. By adapting the parameter `eoj_step_count`, the amount of EOJ steps can be changed." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [] }, "outputs": [], "source": [ "from sagemaker.workflow.parameters import ParameterString\n", "\n", "parameter_execution_role = ParameterString(\n", " name=\"parameter_execution_role\", default_value=execution_role\n", ")\n", "parameter_region = ParameterString(name=\"parameter_region\", default_value=region)\n", "parameter_queue_url = ParameterString(name=\"parameter_queue_url\", default_value=queue_url)\n", "parameter_eoj_input_config = ParameterString(name=\"parameter_eoj_input_config\", default_value=\"\")\n", "\n", "# this argument defines how many EOJ steps should be created for the pipeline\n", "eoj_step_count = 3\n", "parameters_step_eoj_config = []\n", "for step_n in range(1, eoj_step_count + 1):\n", " parameters_step_eoj_config.append(\n", " ParameterString(name=f\"parameter_step_{step_n}_eoj_config\", default_value=\"\")\n", " )\n", "\n", "parameter_eoj_export_config = ParameterString(name=\"parameter_eoj_export_config\", default_value=\"\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Next, we will create as many EOJ steps, as provided in `eoj_step_count`. Each iteration will create a LambdaStep and a CallbackStep which depends on the former." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [] }, "outputs": [], "source": [ "import time\n", "from sagemaker.workflow.lambda_step import LambdaStep, LambdaOutput, LambdaOutputTypeEnum\n", "from sagemaker.workflow.callback_step import CallbackStep, CallbackOutput, CallbackOutputTypeEnum\n", "from sagemaker.lambda_helper import Lambda\n", "\n", "pipeline_steps = []\n", "previous_lambda_step = None\n", "for step_n in range(1, eoj_step_count + 1):\n", " if previous_lambda_step is None:\n", " eoj_input_config = parameter_eoj_input_config\n", " step_dependencies = []\n", " else:\n", " eoj_input_config = previous_lambda_step.properties.Outputs[\"eoj_arn\"]\n", " step_dependencies = [pipeline_steps[-1].name]\n", "\n", " current_lambda_step = LambdaStep(\n", " name=f\"eoj-processing-step-{step_n}\",\n", " depends_on=step_dependencies,\n", " lambda_func=Lambda(function_arn=function_arn),\n", " inputs={\n", " \"role\": parameter_execution_role,\n", " \"region\": parameter_region,\n", " \"eoj_input_config\": eoj_input_config,\n", " \"eoj_config\": parameters_step_eoj_config[step_n - 1],\n", " \"eoj_name\": f\"eoj-pipeline-step-{step_n}\",\n", " },\n", " outputs=[\n", " LambdaOutput(output_name=\"statusCode\", output_type=LambdaOutputTypeEnum.String),\n", " LambdaOutput(output_name=\"eoj_arn\", output_type=LambdaOutputTypeEnum.String),\n", " ],\n", " )\n", "\n", " callback_step = CallbackStep(\n", " name=f\"eoj-callback-step-{step_n}\",\n", " depends_on=[current_lambda_step.name],\n", " sqs_queue_url=parameter_queue_url,\n", " inputs={\n", " \"role\": parameter_execution_role,\n", " \"region\": parameter_region,\n", " \"eoj_arn\": current_lambda_step.properties.Outputs[\"eoj_arn\"],\n", " },\n", " outputs=[\n", " CallbackOutput(output_name=\"eoj_status\", output_type=CallbackOutputTypeEnum.String),\n", " ],\n", " )\n", "\n", " previous_lambda_step = current_lambda_step\n", "\n", " pipeline_steps.append(current_lambda_step)\n", " pipeline_steps.append(callback_step)" ] }, { "cell_type": "markdown", "metadata": { "tags": [] }, "source": [ "Then, we will create additional steps which enable the export of the EOJ." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [] }, "outputs": [], "source": [ "last_lambda_step = pipeline_steps[-2]\n", "last_callback_step = pipeline_steps[-1]\n", "\n", "export_lambda_step = LambdaStep(\n", " name=\"export-eoj-step\",\n", " depends_on=[last_callback_step.name],\n", " lambda_func=Lambda(function_arn=function_arn),\n", " inputs={\n", " \"eoj_arn\": last_lambda_step.properties.Outputs[\"eoj_arn\"],\n", " \"role\": parameter_execution_role,\n", " \"region\": parameter_region,\n", " \"eoj_export_config\": parameter_eoj_export_config,\n", " },\n", " outputs=[\n", " LambdaOutput(output_name=\"statusCode\", output_type=LambdaOutputTypeEnum.String),\n", " LambdaOutput(output_name=\"eoj_arn\", output_type=LambdaOutputTypeEnum.String),\n", " ],\n", ")\n", "\n", "export_callback_step = CallbackStep(\n", " name=\"export-eoj-callback\",\n", " depends_on=[export_lambda_step.name],\n", " sqs_queue_url=parameter_queue_url,\n", " inputs={\n", " \"role\": parameter_execution_role,\n", " \"region\": parameter_region,\n", " \"eoj_arn\": export_lambda_step.properties.Outputs[\"eoj_arn\"],\n", " },\n", " outputs=[\n", " CallbackOutput(output_name=\"statusJob\", output_type=CallbackOutputTypeEnum.String),\n", " ],\n", ")\n", "\n", "pipeline_steps.append(export_lambda_step)\n", "pipeline_steps.append(export_callback_step)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Finally, we can define our pipeline based on the steps and parameters created before." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [] }, "outputs": [], "source": [ "from sagemaker.workflow.pipeline import Pipeline\n", "\n", "pipeline_name = \"GeospatialEarthObservationPipeline\"\n", "\n", "pipeline_parameters = [\n", " parameter_execution_role,\n", " parameter_region,\n", " parameter_queue_url,\n", " parameter_eoj_input_config,\n", " parameter_eoj_export_config,\n", "] + parameters_step_eoj_config\n", "\n", "pipeline = Pipeline(\n", " name=pipeline_name,\n", " parameters=pipeline_parameters,\n", " steps=pipeline_steps,\n", ")" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "scrolled": true, "tags": [] }, "outputs": [], "source": [ "# uncomment to see the created pipeline definition as JSON in the notebook\n", "# definition = json.loads(pipeline.definition())\n", "# definition" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [] }, "outputs": [], "source": [ "pipeline.upsert(role_arn=execution_role)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "After the pipeline has been created, you are able to inspect the created pipeline.\n", "\n", "For this, you can navigate to the SageMaker Studio Resources tab in the left menu and click on `Pipelines`.\n", "\n", "You should be able to see the \"GeospatialEarthObservationPipeline\" in the list. You can click on it and then navigate to the `Graph` tab to see a visual representation of the created pipeline." ] }, { "cell_type": "markdown", "metadata": { "tags": [] }, "source": [ "![SageMaker Pipeline](images/sagemaker_eo_pipeline.png)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "--------\n", "## Pipeline execution\n", "\n", "The following cell is defining the configuration for the pipeline and finally runs a pipeline execution.\n", "\n", "If you adapted the `eoj_step_count` in the previous cells, you must ensure that `eoj_configs` contain as many EOJ configurations as you have steps." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [] }, "outputs": [], "source": [ "aoi_coordinates = [\n", " [10.046694766538735, 49.62389264555313],\n", " [10.046694766538735, 49.4502039714734],\n", " [10.34697773264952, 49.4502039714734],\n", " [10.34697773264952, 49.62389264555313],\n", " [10.046694766538735, 49.62389264555313],\n", "]\n", "\n", "eoj_input_config = {\n", " \"RasterDataCollectionQuery\": {\n", " \"RasterDataCollectionArn\": \"arn:aws:sagemaker-geospatial:us-west-2:378778860802:raster-data-collection/public/nmqj48dcu3g7ayw8\", # Sentinel-2 data\n", " \"AreaOfInterest\": {\n", " \"AreaOfInterestGeometry\": {\"PolygonGeometry\": {\"Coordinates\": [aoi_coordinates]}}\n", " },\n", " \"TimeRangeFilter\": {\n", " \"StartTime\": \"2022-05-01T00:00:00Z\",\n", " \"EndTime\": \"2022-07-31T23:59:59Z\",\n", " },\n", " \"PropertyFilters\": {\n", " \"Properties\": [{\"Property\": {\"EoCloudCover\": {\"LowerBound\": 0, \"UpperBound\": 2}}}]\n", " },\n", " }\n", "}\n", "\n", "eoj_config_step_1 = {\n", " \"CloudRemovalConfig\": {\n", " \"AlgorithmName\": \"INTERPOLATION\",\n", " \"InterpolationValue\": \"-9999\",\n", " \"TargetBands\": [\"red\", \"nir\"],\n", " }\n", "}\n", "\n", "eoj_config_step_2 = {\n", " \"BandMathConfig\": {\n", " \"CustomIndices\": {\n", " \"Operations\": [\n", " {\n", " \"Name\": \"ndvi\",\n", " \"Equation\": \"(nir - red) / (nir + red)\",\n", " \"OutputType\": \"FLOAT32\",\n", " },\n", " ]\n", " },\n", " }\n", "}\n", "\n", "eoj_config_step_3 = {\n", " \"TemporalStatisticsConfig\": {\n", " \"GroupBy\": \"YEARLY\",\n", " \"Statistics\": [\"MEAN\"],\n", " \"TargetBands\": [\"ndvi\"],\n", " },\n", "}\n", "\n", "eoj_configs = [eoj_config_step_1, eoj_config_step_2, eoj_config_step_3]\n", "\n", "if len(eoj_configs) != eoj_step_count:\n", " raise Exception(\n", " \"The number of provided EOJ configs must be the same as the configured EOJ pipeline steps\"\n", " )\n", "\n", "eoj_export_config = {\"S3Data\": {\"S3Uri\": f\"s3://{bucket}/{bucket_prefix}/export/\"}}\n", "\n", "pipeline_execution_parameters = {\n", " \"parameter_execution_role\": execution_role,\n", " \"parameter_region\": region,\n", " \"parameter_queue_url\": queue_url,\n", " \"parameter_eoj_input_config\": eoj_input_config,\n", " \"parameter_eoj_export_config\": eoj_export_config,\n", "}\n", "\n", "for step_n in range(1, eoj_step_count + 1):\n", " pipeline_execution_parameters[f\"parameter_step_{step_n}_eoj_config\"] = eoj_configs[step_n - 1]\n", "\n", "execution = pipeline.start(parameters=pipeline_execution_parameters)" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "After the pipeline execution has been started, you can see it as well in the Pipelines UI.\n", "\n", "Navigate back to the \"GeospatialEarthObservationPipeline\" in the Pipelines UI and you can see the execution in the `Executions` tab. You can double-click it to see the details of this execution.\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "![SageMaker Pipeline Execution](images/sagemaker_eo_pipeline_execution.png)" ] }, { "cell_type": "markdown", "metadata": { "tags": [] }, "source": [ "### Alternative way to execute the created Pipeline\n", "\n", "The Pipeline exection example in the previous cell needs an initialized `Pipeline` object to run a pipeline execution. If you want to execute the pipeline from within other notebooks, this can be done in the following way." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import boto3\n", "import json\n", "\n", "eoj_step_count = 3\n", "\n", "# define your pipeline configuration as in the example above\n", "aoi_coordinates = [\n", " [10.046694766538735, 49.62389264555313],\n", " [10.046694766538735, 49.4502039714734],\n", " [10.34697773264952, 49.4502039714734],\n", " [10.34697773264952, 49.62389264555313],\n", " [10.046694766538735, 49.62389264555313],\n", "]\n", "\n", "eoj_input_config = {\n", " \"RasterDataCollectionQuery\": {\n", " \"RasterDataCollectionArn\": \"arn:aws:sagemaker-geospatial:us-west-2:378778860802:raster-data-collection/public/nmqj48dcu3g7ayw8\", # Sentinel-2 data\n", " \"AreaOfInterest\": {\n", " \"AreaOfInterestGeometry\": {\"PolygonGeometry\": {\"Coordinates\": [aoi_coordinates]}}\n", " },\n", " \"TimeRangeFilter\": {\n", " \"StartTime\": \"2022-05-01T00:00:00Z\",\n", " \"EndTime\": \"2022-07-31T23:59:59Z\",\n", " },\n", " \"PropertyFilters\": {\n", " \"Properties\": [{\"Property\": {\"EoCloudCover\": {\"LowerBound\": 0, \"UpperBound\": 2}}}]\n", " },\n", " }\n", "}\n", "\n", "eoj_config_step_1 = {\n", " \"CloudRemovalConfig\": {\n", " \"AlgorithmName\": \"INTERPOLATION\",\n", " \"InterpolationValue\": \"-9999\",\n", " \"TargetBands\": [\"red\", \"nir\"],\n", " }\n", "}\n", "\n", "eoj_config_step_2 = {\n", " \"BandMathConfig\": {\n", " \"CustomIndices\": {\n", " \"Operations\": [\n", " {\n", " \"Name\": \"ndvi\",\n", " \"Equation\": \"(nir - red) / (nir + red)\",\n", " \"OutputType\": \"FLOAT32\",\n", " },\n", " ]\n", " },\n", " }\n", "}\n", "\n", "eoj_config_step_3 = {\n", " \"TemporalStatisticsConfig\": {\n", " \"GroupBy\": \"YEARLY\",\n", " \"Statistics\": [\"MEAN\"],\n", " \"TargetBands\": [\"ndvi\"],\n", " },\n", "}\n", "\n", "eoj_configs = [eoj_config_step_1, eoj_config_step_2, eoj_config_step_3]\n", "\n", "if len(eoj_configs) != eoj_step_count:\n", " raise Exception(\n", " \"The number of provided EOJ configs must be the same as the configured EOJ pipeline steps\"\n", " )\n", "\n", "eoj_export_config = {\"S3Data\": {\"S3Uri\": f\"s3://{bucket}/{bucket_prefix}/export/\"}}\n", "\n", "pipeline_execution_parameters = {\n", " \"parameter_execution_role\": execution_role,\n", " \"parameter_region\": region,\n", " \"parameter_queue_url\": queue_url,\n", " \"parameter_eoj_input_config\": eoj_input_config,\n", " \"parameter_eoj_export_config\": eoj_export_config,\n", "}\n", "\n", "for step_n in range(1, eoj_step_count + 1):\n", " pipeline_execution_parameters[f\"parameter_step_{step_n}_eoj_config\"] = eoj_configs[step_n - 1]\n", "\n", "# transform the parameter dictionary into a list format\n", "pipeline_execution_parameters_list = []\n", "for key, value in pipeline_execution_parameters.items():\n", " if type(value) is dict:\n", " value = json.dumps(value)\n", " pipeline_execution_parameters_list.append({\"Name\": key, \"Value\": value})\n", "\n", "# use the sagemaker client to start the pipeline execution with the PipelineName referencing the previously created pipeline\n", "session = boto3.Session()\n", "sagemaker_client = session.client(service_name=\"sagemaker\")\n", "sagemaker_client.start_pipeline_execution(\n", " PipelineName=\"GeospatialEarthObservationPipeline\",\n", " PipelineParameters=pipeline_execution_parameters_list,\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "-------\n", "\n", "### Clean-up" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "When the created pipeline and underlying infrastructure is no longer needed, uncomment and run the following cells for deleting the previously created resources." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [] }, "outputs": [], "source": [ "# Delete the SQS queue\n", "# sqs_client = boto3.client(\"sqs\", region_name=region)\n", "# sqs_client.delete_queue(\n", "# QueueUrl=sqs_client.get_queue_url(QueueName=f\"geospatial-eoj-pipeline-queue\")[\"QueueUrl\"]\n", "# )" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [] }, "outputs": [], "source": [ "# Delete Lambda function\n", "# lambda_client = boto3.client(\"lambda\", region_name=region)\n", "# lambda_client.delete_function(FunctionName=\"geospatial-eoj-pipeline-lambda\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [] }, "outputs": [], "source": [ "# Delete the SageMaker Pipeline\n", "# sagemaker_client = boto3.client(\"sagemaker\", region_name=region)\n", "# sagemaker_client.delete_pipeline(PipelineName=\"GeospatialEarthObservationPipeline\")" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "## Notebook CI Test Results\n", "\n", "This notebook was tested in multiple regions. The test results are as follows, except for us-west-2 which is shown at the top of the notebook.\n", "\n", "![This us-east-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/us-east-1/sagemaker-geospatial|geospatial-pipeline|geospatial-pipelines.ipynb)\n", "\n", "![This us-east-2 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/us-east-2/sagemaker-geospatial|geospatial-pipeline|geospatial-pipelines.ipynb)\n", "\n", "![This us-west-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/us-west-1/sagemaker-geospatial|geospatial-pipeline|geospatial-pipelines.ipynb)\n", "\n", "![This ca-central-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/ca-central-1/sagemaker-geospatial|geospatial-pipeline|geospatial-pipelines.ipynb)\n", "\n", "![This sa-east-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/sa-east-1/sagemaker-geospatial|geospatial-pipeline|geospatial-pipelines.ipynb)\n", "\n", "![This eu-west-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/eu-west-1/sagemaker-geospatial|geospatial-pipeline|geospatial-pipelines.ipynb)\n", "\n", "![This eu-west-2 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/eu-west-2/sagemaker-geospatial|geospatial-pipeline|geospatial-pipelines.ipynb)\n", "\n", "![This eu-west-3 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/eu-west-3/sagemaker-geospatial|geospatial-pipeline|geospatial-pipelines.ipynb)\n", "\n", "![This eu-central-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/eu-central-1/sagemaker-geospatial|geospatial-pipeline|geospatial-pipelines.ipynb)\n", "\n", "![This eu-north-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/eu-north-1/sagemaker-geospatial|geospatial-pipeline|geospatial-pipelines.ipynb)\n", "\n", "![This ap-southeast-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/ap-southeast-1/sagemaker-geospatial|geospatial-pipeline|geospatial-pipelines.ipynb)\n", "\n", "![This ap-southeast-2 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/ap-southeast-2/sagemaker-geospatial|geospatial-pipeline|geospatial-pipelines.ipynb)\n", "\n", "![This ap-northeast-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/ap-northeast-1/sagemaker-geospatial|geospatial-pipeline|geospatial-pipelines.ipynb)\n", "\n", "![This ap-northeast-2 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/ap-northeast-2/sagemaker-geospatial|geospatial-pipeline|geospatial-pipelines.ipynb)\n", "\n", "![This ap-south-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/ap-south-1/sagemaker-geospatial|geospatial-pipeline|geospatial-pipelines.ipynb)\n" ] } ], "metadata": { "availableInstances": [ { "_defaultOrder": 0, "_isFastLaunch": true, "category": "General purpose", "gpuNum": 0, "hideHardwareSpecs": false, "memoryGiB": 4, "name": "ml.t3.medium", "vcpuNum": 2 }, { "_defaultOrder": 1, "_isFastLaunch": false, "category": "General purpose", "gpuNum": 0, "hideHardwareSpecs": false, "memoryGiB": 8, "name": "ml.t3.large", "vcpuNum": 2 }, { "_defaultOrder": 2, "_isFastLaunch": false, "category": "General purpose", "gpuNum": 0, "hideHardwareSpecs": false, "memoryGiB": 16, "name": "ml.t3.xlarge", "vcpuNum": 4 }, { "_defaultOrder": 3, "_isFastLaunch": false, "category": "General purpose", "gpuNum": 0, "hideHardwareSpecs": false, "memoryGiB": 32, "name": "ml.t3.2xlarge", "vcpuNum": 8 }, { "_defaultOrder": 4, "_isFastLaunch": true, "category": "General purpose", "gpuNum": 0, "hideHardwareSpecs": false, "memoryGiB": 8, "name": "ml.m5.large", "vcpuNum": 2 }, { "_defaultOrder": 5, "_isFastLaunch": false, "category": "General purpose", "gpuNum": 0, "hideHardwareSpecs": false, "memoryGiB": 16, "name": "ml.m5.xlarge", "vcpuNum": 4 }, { "_defaultOrder": 6, "_isFastLaunch": false, "category": "General purpose", "gpuNum": 0, "hideHardwareSpecs": false, "memoryGiB": 32, "name": "ml.m5.2xlarge", "vcpuNum": 8 }, { "_defaultOrder": 7, "_isFastLaunch": false, "category": "General purpose", "gpuNum": 0, "hideHardwareSpecs": false, "memoryGiB": 64, "name": "ml.m5.4xlarge", "vcpuNum": 16 }, { "_defaultOrder": 8, "_isFastLaunch": false, "category": "General purpose", "gpuNum": 0, "hideHardwareSpecs": false, "memoryGiB": 128, "name": "ml.m5.8xlarge", "vcpuNum": 32 }, { "_defaultOrder": 9, "_isFastLaunch": false, "category": "General purpose", "gpuNum": 0, "hideHardwareSpecs": false, "memoryGiB": 192, "name": "ml.m5.12xlarge", "vcpuNum": 48 }, { "_defaultOrder": 10, "_isFastLaunch": false, "category": "General purpose", "gpuNum": 0, "hideHardwareSpecs": false, "memoryGiB": 256, "name": "ml.m5.16xlarge", "vcpuNum": 64 }, { "_defaultOrder": 11, "_isFastLaunch": false, "category": "General purpose", "gpuNum": 0, "hideHardwareSpecs": false, "memoryGiB": 384, "name": "ml.m5.24xlarge", "vcpuNum": 96 }, { "_defaultOrder": 12, "_isFastLaunch": false, "category": "General purpose", "gpuNum": 0, "hideHardwareSpecs": false, "memoryGiB": 8, "name": "ml.m5d.large", "vcpuNum": 2 }, { "_defaultOrder": 13, "_isFastLaunch": false, "category": "General purpose", "gpuNum": 0, "hideHardwareSpecs": false, "memoryGiB": 16, "name": "ml.m5d.xlarge", "vcpuNum": 4 }, { "_defaultOrder": 14, "_isFastLaunch": false, "category": "General purpose", "gpuNum": 0, "hideHardwareSpecs": false, "memoryGiB": 32, "name": "ml.m5d.2xlarge", "vcpuNum": 8 }, { "_defaultOrder": 15, "_isFastLaunch": false, "category": "General purpose", "gpuNum": 0, "hideHardwareSpecs": false, "memoryGiB": 64, "name": "ml.m5d.4xlarge", "vcpuNum": 16 }, { "_defaultOrder": 16, "_isFastLaunch": false, "category": "General purpose", "gpuNum": 0, "hideHardwareSpecs": false, "memoryGiB": 128, "name": "ml.m5d.8xlarge", "vcpuNum": 32 }, { "_defaultOrder": 17, "_isFastLaunch": false, "category": "General purpose", "gpuNum": 0, "hideHardwareSpecs": false, "memoryGiB": 192, "name": "ml.m5d.12xlarge", "vcpuNum": 48 }, { "_defaultOrder": 18, "_isFastLaunch": false, "category": "General purpose", "gpuNum": 0, "hideHardwareSpecs": false, "memoryGiB": 256, "name": "ml.m5d.16xlarge", "vcpuNum": 64 }, { "_defaultOrder": 19, "_isFastLaunch": false, "category": "General purpose", "gpuNum": 0, "hideHardwareSpecs": false, "memoryGiB": 384, "name": "ml.m5d.24xlarge", "vcpuNum": 96 }, { "_defaultOrder": 20, "_isFastLaunch": false, "category": "General purpose", "gpuNum": 0, "hideHardwareSpecs": true, "memoryGiB": 0, "name": "ml.geospatial.interactive", "supportedImageNames": [ "sagemaker-geospatial-v1-0" ], "vcpuNum": 0 }, { "_defaultOrder": 21, "_isFastLaunch": true, "category": "Compute optimized", "gpuNum": 0, "hideHardwareSpecs": false, "memoryGiB": 4, "name": "ml.c5.large", "vcpuNum": 2 }, { "_defaultOrder": 22, "_isFastLaunch": false, "category": "Compute optimized", "gpuNum": 0, "hideHardwareSpecs": false, "memoryGiB": 8, "name": "ml.c5.xlarge", "vcpuNum": 4 }, { "_defaultOrder": 23, "_isFastLaunch": false, "category": "Compute optimized", "gpuNum": 0, "hideHardwareSpecs": false, "memoryGiB": 16, "name": "ml.c5.2xlarge", "vcpuNum": 8 }, { "_defaultOrder": 24, "_isFastLaunch": false, "category": "Compute optimized", "gpuNum": 0, "hideHardwareSpecs": false, "memoryGiB": 32, "name": "ml.c5.4xlarge", "vcpuNum": 16 }, { "_defaultOrder": 25, "_isFastLaunch": false, "category": "Compute optimized", "gpuNum": 0, "hideHardwareSpecs": false, "memoryGiB": 72, "name": "ml.c5.9xlarge", "vcpuNum": 36 }, { "_defaultOrder": 26, "_isFastLaunch": false, "category": "Compute optimized", "gpuNum": 0, "hideHardwareSpecs": false, "memoryGiB": 96, "name": "ml.c5.12xlarge", "vcpuNum": 48 }, { "_defaultOrder": 27, "_isFastLaunch": false, "category": "Compute optimized", "gpuNum": 0, "hideHardwareSpecs": false, "memoryGiB": 144, "name": "ml.c5.18xlarge", "vcpuNum": 72 }, { "_defaultOrder": 28, "_isFastLaunch": false, "category": "Compute optimized", "gpuNum": 0, "hideHardwareSpecs": false, "memoryGiB": 192, "name": "ml.c5.24xlarge", "vcpuNum": 96 }, { "_defaultOrder": 29, "_isFastLaunch": true, "category": "Accelerated computing", "gpuNum": 1, "hideHardwareSpecs": false, "memoryGiB": 16, "name": "ml.g4dn.xlarge", "vcpuNum": 4 }, { "_defaultOrder": 30, "_isFastLaunch": false, "category": "Accelerated computing", "gpuNum": 1, "hideHardwareSpecs": false, "memoryGiB": 32, "name": "ml.g4dn.2xlarge", "vcpuNum": 8 }, { "_defaultOrder": 31, "_isFastLaunch": false, "category": "Accelerated computing", "gpuNum": 1, "hideHardwareSpecs": false, "memoryGiB": 64, "name": "ml.g4dn.4xlarge", "vcpuNum": 16 }, { "_defaultOrder": 32, "_isFastLaunch": false, "category": "Accelerated computing", "gpuNum": 1, "hideHardwareSpecs": false, "memoryGiB": 128, "name": "ml.g4dn.8xlarge", "vcpuNum": 32 }, { "_defaultOrder": 33, "_isFastLaunch": false, "category": "Accelerated computing", "gpuNum": 4, "hideHardwareSpecs": false, "memoryGiB": 192, "name": "ml.g4dn.12xlarge", "vcpuNum": 48 }, { "_defaultOrder": 34, "_isFastLaunch": false, "category": "Accelerated computing", "gpuNum": 1, "hideHardwareSpecs": false, "memoryGiB": 256, "name": "ml.g4dn.16xlarge", "vcpuNum": 64 }, { "_defaultOrder": 35, "_isFastLaunch": false, "category": "Accelerated computing", "gpuNum": 1, "hideHardwareSpecs": false, "memoryGiB": 61, "name": "ml.p3.2xlarge", "vcpuNum": 8 }, { "_defaultOrder": 36, "_isFastLaunch": false, "category": "Accelerated computing", "gpuNum": 4, "hideHardwareSpecs": false, "memoryGiB": 244, "name": "ml.p3.8xlarge", "vcpuNum": 32 }, { "_defaultOrder": 37, "_isFastLaunch": false, "category": "Accelerated computing", "gpuNum": 8, "hideHardwareSpecs": false, "memoryGiB": 488, "name": "ml.p3.16xlarge", "vcpuNum": 64 }, { "_defaultOrder": 38, "_isFastLaunch": false, "category": "Accelerated computing", "gpuNum": 8, "hideHardwareSpecs": false, "memoryGiB": 768, "name": "ml.p3dn.24xlarge", "vcpuNum": 96 }, { "_defaultOrder": 39, "_isFastLaunch": false, "category": "Memory Optimized", "gpuNum": 0, "hideHardwareSpecs": false, "memoryGiB": 16, "name": "ml.r5.large", "vcpuNum": 2 }, { "_defaultOrder": 40, "_isFastLaunch": false, "category": "Memory Optimized", "gpuNum": 0, "hideHardwareSpecs": false, "memoryGiB": 32, "name": "ml.r5.xlarge", "vcpuNum": 4 }, { "_defaultOrder": 41, "_isFastLaunch": false, "category": "Memory Optimized", "gpuNum": 0, "hideHardwareSpecs": false, "memoryGiB": 64, "name": "ml.r5.2xlarge", "vcpuNum": 8 }, { "_defaultOrder": 42, "_isFastLaunch": false, "category": "Memory Optimized", "gpuNum": 0, "hideHardwareSpecs": false, "memoryGiB": 128, "name": "ml.r5.4xlarge", "vcpuNum": 16 }, { "_defaultOrder": 43, "_isFastLaunch": false, "category": "Memory Optimized", "gpuNum": 0, "hideHardwareSpecs": false, "memoryGiB": 256, "name": "ml.r5.8xlarge", "vcpuNum": 32 }, { "_defaultOrder": 44, "_isFastLaunch": false, "category": "Memory Optimized", "gpuNum": 0, "hideHardwareSpecs": false, "memoryGiB": 384, "name": "ml.r5.12xlarge", "vcpuNum": 48 }, { "_defaultOrder": 45, "_isFastLaunch": false, "category": "Memory Optimized", "gpuNum": 0, "hideHardwareSpecs": false, "memoryGiB": 512, "name": "ml.r5.16xlarge", "vcpuNum": 64 }, { "_defaultOrder": 46, "_isFastLaunch": false, "category": "Memory Optimized", "gpuNum": 0, "hideHardwareSpecs": false, "memoryGiB": 768, "name": "ml.r5.24xlarge", "vcpuNum": 96 }, { "_defaultOrder": 47, "_isFastLaunch": false, "category": "Accelerated computing", "gpuNum": 1, "hideHardwareSpecs": false, "memoryGiB": 16, "name": "ml.g5.xlarge", "vcpuNum": 4 }, { "_defaultOrder": 48, "_isFastLaunch": false, "category": "Accelerated computing", "gpuNum": 1, "hideHardwareSpecs": false, "memoryGiB": 32, "name": "ml.g5.2xlarge", "vcpuNum": 8 }, { "_defaultOrder": 49, "_isFastLaunch": false, "category": "Accelerated computing", "gpuNum": 1, "hideHardwareSpecs": false, "memoryGiB": 64, "name": "ml.g5.4xlarge", "vcpuNum": 16 }, { "_defaultOrder": 50, "_isFastLaunch": false, "category": "Accelerated computing", "gpuNum": 1, "hideHardwareSpecs": false, "memoryGiB": 128, "name": "ml.g5.8xlarge", "vcpuNum": 32 }, { "_defaultOrder": 51, "_isFastLaunch": false, "category": "Accelerated computing", "gpuNum": 1, "hideHardwareSpecs": false, "memoryGiB": 256, "name": "ml.g5.16xlarge", "vcpuNum": 64 }, { "_defaultOrder": 52, "_isFastLaunch": false, "category": "Accelerated computing", "gpuNum": 4, "hideHardwareSpecs": false, "memoryGiB": 192, "name": "ml.g5.12xlarge", "vcpuNum": 48 }, { "_defaultOrder": 53, "_isFastLaunch": false, "category": "Accelerated computing", "gpuNum": 4, "hideHardwareSpecs": false, "memoryGiB": 384, "name": "ml.g5.24xlarge", "vcpuNum": 96 }, { "_defaultOrder": 54, "_isFastLaunch": false, "category": "Accelerated computing", "gpuNum": 8, "hideHardwareSpecs": false, "memoryGiB": 768, "name": "ml.g5.48xlarge", "vcpuNum": 192 } ], "instance_type": "ml.geospatial.interactive", "kernelspec": { "display_name": "Python 3 (Geospatial 1.0)", "language": "python", "name": "python3__SAGEMAKER_INTERNAL__arn:aws:sagemaker:us-west-2:081189585635:image/sagemaker-geospatial-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.10.4" } }, "nbformat": 4, "nbformat_minor": 4 }