{
"cells": [
{
"cell_type": "markdown",
"id": "89e1fb16",
"metadata": {},
"source": [
"\n",
"## Bring Your Own Algorithm to SageMaker\n",
"### Architecture of this notebook \n",
"\n",
"\n",
"
\n",
"\n",
"\n",
"### 1. Training\n",
"a. [Bring Your Own Container](#byoc)\n",
"\n",
"b. [Training locally](#local_train)\n",
"\n",
"c. [Trigger remote training job](#remote_train)\n",
"\n",
"d. [Test locally](#local_test)\n",
"\n",
"### 2. Deploy EndPoint\n",
"[Deploy model to SageMaker Endpoint](#deploy_endpoint)\n",
"\n",
"### 3. Build Lambda Function\n",
"a. [Construct lambda function](#build_lambda_function)\n",
"\n",
"b. [Test lambda](#lambda_test)\n",
"\n",
"### 4. Configure API Gateway\n",
"\n",
"a. [Construct and setting api gateway](#api-gateway)\n",
"\n",
"b. [Configure for passing binary media to Lambda Function](#binary-content)\n",
"\n",
"c. [test api gateway](#test-api)\n"
]
},
{
"cell_type": "markdown",
"id": "16465ef9",
"metadata": {},
"source": [
"### BYOC (Bring Your Own Container) for Example Audio Classification Algorithm\n",
"\n"
]
},
{
"cell_type": "markdown",
"id": "fb3ba248",
"metadata": {},
"source": [
"* prepare necessry variables\n",
"using `boto3` to get region and account_id for later usage - ECR uri construction "
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "59e0ca34",
"metadata": {},
"outputs": [],
"source": [
"import boto3 \n",
"\n",
"session = boto3.session.Session()\n",
"region = session.region_name\n",
"client = boto3.client(\"sts\")\n",
"account_id = client.get_caller_identity()[\"Account\"]\n",
"algorithm_name = \"vgg16-audio\""
]
},
{
"cell_type": "markdown",
"id": "d7c8d54f",
"metadata": {},
"source": [
"#### 3 elements to build bring your own container \n",
"* `build_and_push.sh` is the script communicating with ECR \n",
"* `Dockerfile` defines the training and serving environment \n",
"* `code/train` and `code/serve` defines entry point of our container "
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "25666268",
"metadata": {
"scrolled": true
},
"outputs": [],
"source": [
"!./build_and_push.sh"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "a25fdd51",
"metadata": {},
"outputs": [],
"source": [
"!cat Dockerfile"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "c73d2b73",
"metadata": {},
"outputs": [],
"source": [
"!cat build_and_push.sh"
]
},
{
"cell_type": "markdown",
"id": "b0409012",
"metadata": {},
"source": [
"* construct image uri by account_id, region and algorithm_name"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "b74e5c16",
"metadata": {},
"outputs": [],
"source": [
"image_uri=f\"{account_id}.dkr.ecr.{region}.amazonaws.com/{algorithm_name}\"\n",
"image_uri"
]
},
{
"cell_type": "markdown",
"id": "7ca14500",
"metadata": {},
"source": [
"* prepare necessary variables/object for training "
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "9da9a16b",
"metadata": {},
"outputs": [],
"source": [
"import sagemaker \n",
"session = sagemaker.session.Session()\n",
"bucket = session.default_bucket()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "2bfb9fc3",
"metadata": {},
"outputs": [],
"source": [
"from sagemaker import get_execution_role\n",
"\n",
"role = get_execution_role()\n",
"print(role)\n",
"\n",
"s3_path = f\"s3://{bucket}/data/competition\"\n",
"s3_path"
]
},
{
"cell_type": "markdown",
"id": "d9c8cfa9",
"metadata": {},
"source": [
"### Dataset Description - \n",
"\n",
"Dataset used in this workshop can be obtained from [Dog Bark Sound AI competition](https://tbrain.trendmicro.com.tw/Competitions/Details/15) hold by the world leading pet camera brand [Tomofun](https://en.wikipedia.org/wiki/Tomofun). The url below will be invalid after workshop. "
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "0b982b91",
"metadata": {},
"outputs": [],
"source": [
"# s3://tomofun-audio-classification-yianc\n",
"# data/data.zip\n",
"!wget -O data.zip https://tinyurl.com/ydzvotsd\n",
"!unzip data.zip \n",
"!aws s3 cp --recursive ./input/data/competition/ $s3_path"
]
},
{
"cell_type": "markdown",
"id": "3c6eb82c",
"metadata": {},
"source": [
"### Train model in a docker container with terminal interface \n",
""
]
},
{
"cell_type": "markdown",
"id": "46d54159",
"metadata": {},
"source": [
"* start container in interactive mode\n",
"```\n",
"IMAGE_ID=$(sudo docker images --filter=reference=vgg16-audio --format \"{{.ID}}\")\n",
"nvidia-docker run -it -v $PWD:/opt/ml --entrypoint '' $IMAGE_ID bash \n",
"```\n",
"* train model based on README.md\n",
"```\n",
"python train.py --csv_path=/opt/ml/input/data/competition/meta_train.csv --data_dir=/opt/ml/input/data/competition/train --epochs=50 --val_split 0.1\n",
"```"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "61859c2c",
"metadata": {},
"outputs": [],
"source": [
"from datetime import datetime\n",
"now = datetime.now()\n",
"timestamp = datetime.timestamp(now)\n",
"job_name = \"audio-{}\".format(str(int(timestamp))) \n",
"job_name"
]
},
{
"cell_type": "markdown",
"id": "d4ba9776",
"metadata": {},
"source": [
"### Start SageMaker Training Job\n",
"\n",
"* sagemaker training jobs can run either locally or remotely "
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "f5c92feb",
"metadata": {},
"outputs": [],
"source": [
"mode = 'remote'\n",
"if mode == 'local':\n",
" csess = sagemaker.local.LocalSession()\n",
"else: \n",
" csess = session\n",
"\n",
"print(csess)\n",
"estimator = sagemaker.estimator.Estimator( \n",
" role=role,\n",
" image_uri=image_uri,\n",
" instance_count=1,\n",
"# instance_type='local_gpu',\n",
" instance_type='ml.p3.8xlarge',\n",
" sagemaker_session=csess,\n",
" volume_size=100, \n",
" debugger_hook_config=False\n",
" )"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "b2ad6d30",
"metadata": {},
"outputs": [],
"source": [
"estimator.fit(inputs={\"competition\":s3_path}, job_name=job_name)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "5d10001b",
"metadata": {},
"outputs": [],
"source": [
"estimator.model_data"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "2fe806c1",
"metadata": {},
"outputs": [],
"source": [
"model_s3_path = estimator.model_data\n",
"\n",
"!aws s3 cp $model_s3_path . \n",
"!tar -xvf model.tar.gz\n",
"!mkdir -p model \n",
"!mv final_model.pkl model/"
]
},
{
"cell_type": "markdown",
"id": "31fdc1f1",
"metadata": {},
"source": [
"### Test Model Locally \n",
"\n",
"\n",
"* start container in interactive mode\n",
"```\n",
"IMAGE_ID=$(sudo docker images --filter=reference=vgg16-audio --format \"{{.ID}}\")\n",
"nvidia-docker run -it -v $PWD:/opt/ml --entrypoint '' $IMAGE_ID bash \n",
"```\n",
"* test model based on README.md\n",
"```\n",
"python test.py --test_csv /opt/ml/input/data/competition/meta_train.csv --data_dir /opt/ml/input/data/competition/train --model_name VGGish --model_path /opt/ml/model --saved_root results/test --saved_name test_result\n",
"```"
]
},
{
"cell_type": "markdown",
"id": "324979a4",
"metadata": {},
"source": [
"### Deploy SageMaker Endpoint \n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ee7dce3a",
"metadata": {},
"outputs": [],
"source": [
"predictor = estimator.deploy(instance_type='ml.p2.xlarge', initial_instance_count=1, serializer=sagemaker.serializers.IdentitySerializer())\n",
"# predictor = estimator.deploy(instance_type='local_gpu', initial_instance_count=1, serializer=sagemaker.serializers.IdentitySerializer())"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "694d5673",
"metadata": {},
"outputs": [],
"source": [
"endpoint_name = predictor.endpoint_name"
]
},
{
"cell_type": "markdown",
"id": "4ebf4cd3",
"metadata": {},
"source": [
"### You can deploy by using model file directly \n",
"\n",
"The Source code is as below. we can use model locally trained to deploy a sagemaker endpoint "
]
},
{
"cell_type": "markdown",
"id": "3fb6b174",
"metadata": {},
"source": [
"#### get example model file from s3 \n",
"```\n",
"source_model_data_url = 'https://tinyurl.com/yh7tw3hj'\n",
"!wget -O model.tar.gz $source_model_data_url\n",
"\n",
"MODEL_PATH = f's3://{bucket}/model'\n",
"model_data_s3_uri = f'{MODEL_PATH}/model.tar.gz'\n",
"!aws s3 cp model.tar.gz $model_data_s3_uri\n",
"```\n"
]
},
{
"cell_type": "markdown",
"id": "f5d35f98",
"metadata": {},
"source": [
"#### build endpoint from the model file \n",
"```\n",
"import time \n",
"\n",
"mode = 'remote'\n",
"\n",
"if mode == 'local':\n",
" csess = sagemaker.local.LocalSession()\n",
"else:\n",
" csess = session\n",
"\n",
"model = sagemaker.model.Model(image_uri, \n",
" model_data = model_data_s3_uri,\n",
" role = role,\n",
" predictor_cls = sagemaker.predictor.Predictor,\n",
" sagemaker_session = csess)\n",
"\n",
"now = datetime.now()\n",
"timestamp = datetime.timestamp(now)\n",
"new_endpoint_name = \"audio-{}\".format(str(int(timestamp))) \n",
"object_detector = model.deploy(initial_instance_count = 1,\n",
" instance_type = 'ml.p2.xlarge',\n",
"# instance_type = 'local_gpu',\n",
" endpoint_name = new_endpoint_name,\n",
" serializer = sagemaker.serializers.IdentitySerializer())\n",
"```"
]
},
{
"cell_type": "markdown",
"id": "4ea4712f",
"metadata": {},
"source": [
"### You can also update endpoint based on following example code \n",
"\n",
"```\n",
"new_detector = sagemaker.predictor.Predictor(endpoint_name = endpoint_name) \n",
"new_detector.update_endpoint(model_name=model.name, initial_instance_count = 1,\n",
" instance_type = 'ml.p2.xlarge')\n",
"```"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "800266b9",
"metadata": {},
"outputs": [],
"source": [
"import json \n",
"file_name = \"./input/data/competition/train/train_00002.wav\"\n",
"with open(file_name, 'rb') as image:\n",
" f = image.read()\n",
" b = bytearray(f)\n",
"results = predictor.predict(b)\n",
"detections = json.loads(results)\n",
"print(detections) "
]
},
{
"cell_type": "markdown",
"id": "99277225",
"metadata": {},
"source": [
"### Create Lambda Function \n",
""
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "18eb9018",
"metadata": {},
"outputs": [],
"source": [
"import time \n",
"iam = boto3.client(\"iam\")\n",
"\n",
"role_name = \"AmazonSageMaker-LambdaExecutionRole\"\n",
"assume_role_policy_document = {\n",
" \"Version\": \"2012-10-17\",\n",
" \"Statement\": [\n",
" {\n",
" \"Effect\": \"Allow\",\n",
" \"Principal\": {\n",
" \"Service\": [\"sagemaker.amazonaws.com\", \"lambda.amazonaws.com\"]\n",
" },\n",
" \"Action\": \"sts:AssumeRole\"\n",
" }\n",
" ]\n",
"}\n",
"\n",
"create_role_response = iam.create_role(\n",
" RoleName = role_name,\n",
" AssumeRolePolicyDocument = json.dumps(assume_role_policy_document)\n",
")\n",
"\n",
"\n",
"# Now add S3 support\n",
"iam.attach_role_policy(\n",
" PolicyArn='arn:aws:iam::aws:policy/AmazonS3FullAccess',\n",
" RoleName=role_name\n",
")\n",
"\n",
"iam.attach_role_policy(\n",
" PolicyArn='arn:aws:iam::aws:policy/AmazonSQSFullAccess',\n",
" RoleName=role_name\n",
")\n",
"\n",
"iam.attach_role_policy(\n",
" PolicyArn='arn:aws:iam::aws:policy/AmazonSageMakerFullAccess',\n",
" RoleName=role_name\n",
")\n",
"time.sleep(60) # wait for a minute to allow IAM role policy attachment to propagate\n",
"\n",
"lambda_role_arn = create_role_response[\"Role\"][\"Arn\"]\n",
"print(lambda_role_arn)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "6176ccc0",
"metadata": {},
"outputs": [],
"source": [
"%%bash -s \"$bucket\" \n",
"cd invoke_endpoint \n",
"zip -r invoke_endpoint.zip .\n",
"aws s3 cp invoke_endpoint.zip s3://$1/lambda/"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "67438c92",
"metadata": {},
"outputs": [],
"source": [
"import os\n",
"cwd = os.getcwd()\n",
"!aws lambda create-function --function-name invoke_endpoint --zip-file fileb://$cwd/invoke_endpoint/invoke_endpoint.zip --handler lambda_function.lambda_handler --runtime python3.7 --role $lambda_role_arn"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "e796c8d7",
"metadata": {},
"outputs": [],
"source": [
"endpoint_name = predictor.endpoint_name\n",
"bucket_key = \"audio-demo\"\n",
"variables = f\"ENDPOINT_NAME={endpoint_name}\"\n",
"env = \"Variables={\"+variables+\"}\"\n",
"\n",
"!aws lambda update-function-configuration --function-name invoke_endpoint --environment \"$env\"\n"
]
},
{
"cell_type": "markdown",
"id": "917f4344",
"metadata": {},
"source": [
"### Test Material \n",
"\n",
"```\n",
"{\n",
" \"content\": \"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\"\n",
"}\n",
"```"
]
},
{
"cell_type": "markdown",
"id": "7ad204bd",
"metadata": {},
"source": [
"### Configure API Gateway \n",
"\n",
"* Finally, we need an API to have the service accessible\n",
"* This API accepts image POST to it and pass the image to ```invoke_image_object_detection```\n",
"\n",
"```curl -X POST -H 'content-type: application/octet-stream' --data-binary @$f $OD_API | jq .``` \n",
"\n",
"* we can create it by console also by aws cli "
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "3633b5a5",
"metadata": {},
"outputs": [],
"source": [
"!aws lambda add-permission \\\n",
" --function-name invoke_endpoint \\\n",
" --action lambda:InvokeFunction \\\n",
" --statement-id apigateway \\\n",
" --principal apigateway.amazonaws.com \n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "248453d7",
"metadata": {},
"outputs": [],
"source": [
"!sed \"s//$account_id/g\" latestswagger2-template.json > latestswagger2-tmp.json \n",
"!sed \"s//$region/g\" latestswagger2-tmp.json > latestswagger2.json "
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "e41a793c",
"metadata": {},
"outputs": [],
"source": [
"api_info = !aws apigateway import-rest-api \\\n",
" --fail-on-warnings \\\n",
" --body 'file:////home/ec2-user/SageMaker/incremental-training-mlops/01-byoc/latestswagger2.json' "
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "9fe10210",
"metadata": {},
"outputs": [],
"source": [
"api_info"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "efd65142",
"metadata": {},
"outputs": [],
"source": [
"api_obj = json.loads(''.join(api_info))\n",
"api_id = api_obj['id']\n",
"api_id"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "1172b911",
"metadata": {},
"outputs": [],
"source": [
"!aws apigateway create-deployment --rest-api-id $api_id --stage-name dev"
]
},
{
"cell_type": "markdown",
"id": "a9b544d7",
"metadata": {},
"source": [
"### Manually Setup API-Gateway in Console\n",
"\n"
]
},
{
"cell_type": "markdown",
"id": "15e0d063",
"metadata": {},
"source": [
"#### Create Restful API \n",
"
"
]
},
{
"cell_type": "markdown",
"id": "811cd55d",
"metadata": {},
"source": [
"#### Create resource and methods \n",
"* click the drop down manual and name your resource \n",
"
\n",
"\n",
"* focus on the resource just created, click the drop down manual and select create method, then select backend lambda function \n",
"
\n",
"
\n"
]
},
{
"cell_type": "markdown",
"id": "b3c37d2b",
"metadata": {},
"source": [
"### Configurations for passing the binary content to backend\n",
"* Add binary media type in ```Settings``` of this API \n",
"* Configure which attribute to extract and fill it in event in Lambda integration"
]
},
{
"cell_type": "markdown",
"id": "b0165600",
"metadata": {},
"source": [
"
\n",
"
\n",
"
"
]
},
{
"cell_type": "markdown",
"id": "134039cc",
"metadata": {},
"source": [
"### Test API Gateway \n",
""
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "d35f9bd3",
"metadata": {},
"outputs": [],
"source": [
"api_endpoint = \"https://{}.execute-api.{}.amazonaws.com/dev/classify\".format(api_id, region)\n",
"\n",
"!curl -X POST -H 'content-type: application/octet-stream' --data-binary @./input/data/competition/train/train_00002.wav $api_endpoint\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "c7b02625",
"metadata": {},
"outputs": [],
"source": [
"%store endpoint_name \n",
"%store lambda_role_arn\n",
"%store model_s3_path "
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "574e474b",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "conda_pytorch_latest_p36",
"language": "python",
"name": "conda_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": 5
}