{ "cells": [ { "cell_type": "markdown", "id": "cffd59b9", "metadata": {}, "source": [ "# TensorRT YoloV5s Sample Application\n" ] }, { "cell_type": "markdown", "id": "47498764", "metadata": {}, "source": [ "--- \n", "\n", "1. [Prerequisites](#Prerequisites)\n", "1. [Set up](#Set-up)\n", "1. [Import model](#Import-model)\n", "1. [Write and test app code](#Write-and-test-app-code-in-notebook)\n", "1. [Package app](#Package-app)\n", "1. [Deploy app to device](#Deploy-app-to-device)" ] }, { "cell_type": "markdown", "id": "8a2a3ae2", "metadata": { "tags": [] }, "source": [ "# Prerequisites (DO NOT SKIP)" ] }, { "cell_type": "markdown", "id": "9aaddd01", "metadata": {}, "source": [ "1. In a terminal session on this Jupyter notebook server, run `aws configure`. This allows this notebook server to access Panorama resources and deploy applications on your behalf.\n", "\n", "2. This notebook works best in the Test Utility. Please see [here](https://github.com/aws-samples/aws-panorama-samples/blob/main/docs/EnvironmentSetup.md) to set it up \n", "\n", "3. **PLEASE READ THE [README](README.md) INCLUDE WITH THIS BEFORE YOU START USING THIS NOTEBOOK**" ] }, { "cell_type": "markdown", "id": "b1c2f6f8", "metadata": { "tags": [] }, "source": [ "# Set up" ] }, { "cell_type": "markdown", "id": "352b4749", "metadata": {}, "source": [ "Import libraries for use with this notebook environment, you do not need these libraries when you write your application code." ] }, { "cell_type": "code", "execution_count": null, "id": "1183276e", "metadata": {}, "outputs": [], "source": [ "import sys\n", "import os\n", "import time\n", "import json\n", "\n", "import boto3\n", "import sagemaker\n", "\n", "import matplotlib.pyplot as plt\n", "from IPython.core.magic import register_cell_magic\n", "\n", "sys.path.insert( 0, os.path.abspath( \"../common/test_utility\" ) )\n", "import panorama_test_utility\n", "\n", "# instantiate boto3 clients\n", "s3_client = boto3.client('s3')\n", "panorama_client = boto3.client('panorama', region_name = 'us-west-2')\n", "\n", "# configure matplotlib\n", "%matplotlib inline\n", "plt.rcParams[\"figure.figsize\"] = (20,20)\n", "\n", "# register custom magic command\n", "@register_cell_magic\n", "def save_cell(line, cell):\n", " 'Save python code block to a file'\n", " with open(line, 'wt') as fd:\n", " fd.write(cell)" ] }, { "cell_type": "markdown", "id": "00f12da5", "metadata": { "tags": [] }, "source": [ "## Notebook parameters\n", "Global constants that help the notebook create Panorama resources on your behalf." ] }, { "cell_type": "code", "execution_count": null, "id": "1a73ca51", "metadata": {}, "outputs": [], "source": [ "# Device ID, should look like: device-oc66nax4cgzwhyuaeyifrqowue\n", "DEVICE_ID = input( 'DEVICE_ID (format: device-*)' ).strip()" ] }, { "cell_type": "code", "execution_count": null, "id": "82721929", "metadata": { "tags": [] }, "outputs": [], "source": [ "# application name\n", "app_name = 'trtpt_36_2_app'\n", "\n", "## package names and node names\n", "code_package_name = 'trtpt_36_2_app'\n", "camera_node_name = 'abstract_rtsp_media_source'\n", "\n", "# AWS account ID\n", "account_id = boto3.client(\"sts\").get_caller_identity()[\"Account\"]" ] }, { "cell_type": "markdown", "id": "d1034c1e", "metadata": {}, "source": [ "## Set up application\n", "\n", "Every application uses the creator's AWS Account ID as the prefix to uniquely identifies the application resources. Running `panorama-cli import-application` replaces the generic account Id with your account Id." ] }, { "cell_type": "code", "execution_count": null, "id": "96ef4328", "metadata": {}, "outputs": [], "source": [ "!cd ./trtpt_36_2_app && panorama-cli-dev import-application" ] }, { "cell_type": "markdown", "id": "d7266756-2696-4a64-80e7-facfc95aca4e", "metadata": {}, "source": [ "## Download Depedencies and Artifacts (One Time Download)" ] }, { "cell_type": "code", "execution_count": null, "id": "3612d4a7-9dbf-4992-99a6-661c3cb4d93a", "metadata": {}, "outputs": [], "source": [ "panorama_test_utility.download_artifacts_gpu_sample('tensorrt', account_id)" ] }, { "cell_type": "markdown", "id": "db42d5a3-bce4-464c-9fc1-0b4b59949ca0", "metadata": {}, "source": [ "### Build Docker image from Dockerfile" ] }, { "cell_type": "markdown", "id": "5619ef22-fa02-4c8e-a822-68a42d21b4c4", "metadata": {}, "source": [ "Open a terminal, go to ./TRTPT36_opengpu/dependencies/docker and run\n", "\n", "```sudo docker build -t trtpt36:latest . ```" ] }, { "cell_type": "markdown", "id": "4df1a26a-e84b-48f3-a2c6-b289a5a0b4d1", "metadata": { "tags": [] }, "source": [ "## Update camera streams\n", "\n", "In the AWS Panorama console, you can select the camera streams, but programmatically, you need to define the camera stream info for the cameras you are using with the app.\n", "\n", "We used an ```abstract data source``` here, usually this lets you select the pre-created camera source from the console. But programatically, we have to do the following steps\n", "\n", "\n", "- Create Camera\n", "- Create Override json file\n", "- Include the Override json file while are deploying the application" ] }, { "cell_type": "markdown", "id": "c217bb6c-a15f-4ec8-b00b-b91fca369180", "metadata": {}, "source": [ "### Create New Camera\n", "\n", "Because we are using an ```abstract_rtsp_media_source```, we have to create a camera before we can use the ```abstract_rtsp_media_source```\n", "\n", "**NOTE** : Update your RTSP Info in the next cell, Username, Password and RTSP Stream URL" ] }, { "cell_type": "code", "execution_count": null, "id": "e808c80f-6778-4e7c-a906-e02f2a3a4909", "metadata": {}, "outputs": [], "source": [ "CAMERA_NAME = \"test_rtsp_camera_lab2\"\n", "\n", "CAMERA_CREDS = '{\"Username\":\"root\",\"Password\":\"Aws2017!\",\"StreamUrl\": \"rtsp://10.92.202.65/onvif-media/media.amp?profile=profile_1_h264&sessiontimeout=60&streamtype=unicast\"}'" ] }, { "cell_type": "code", "execution_count": null, "id": "53af9488-5e7c-4bb9-ba65-feaf06be8a4e", "metadata": {}, "outputs": [], "source": [ "res = !aws panorama create-node-from-template-job --template-type RTSP_CAMERA_STREAM \\\n", " --output-package-name {CAMERA_NAME} \\\n", " --output-package-version '3.0' \\\n", " --node-name {CAMERA_NAME} \\\n", " --template-parameters '{CAMERA_CREDS}'\n", "\n", "# FIXME : camera node creation fails if it already exists.\n", "# Should either ignore the already-exist error, or delete the node at the end of this notebook\n", "\n", "res = ''.join(res)\n", "print(res)\n", "res_json = json.loads(res)" ] }, { "cell_type": "code", "execution_count": null, "id": "b94dc937-f62a-49a1-ae86-315b9a0c3266", "metadata": {}, "outputs": [], "source": [ "!aws panorama describe-node-from-template-job --job-id {res_json['JobId']}" ] }, { "cell_type": "markdown", "id": "62921b7b-0669-45cb-b0b3-18087fc9be82", "metadata": {}, "source": [ "## Overriding camera node" ] }, { "cell_type": "markdown", "id": "672873ea", "metadata": {}, "source": [ "If you want to override the camera configuration at deployment (for ex. deploy to another site) you can provide a deployment time override. Go to `people_counter_app/deployment_overrides/override_camera.json` file and replace YOUR_AWS_ACCOUNT_ID with your ACCOUNT_ID and YOUR_CAMERA_NAME with your camera name." ] }, { "cell_type": "code", "execution_count": null, "id": "36e9c66f-3f32-4984-b5d8-be69251f022b", "metadata": {}, "outputs": [], "source": [ "# Update Account ID\n", "with open( f\"./{app_name}/deployment_overrides/override_camera.json\", \"r\" ) as fd:\n", " override_json = json.load(fd)\n", "\n", "override_json['nodeGraphOverrides']['packages'][0]['name'] = '{}::{}'.format(account_id, CAMERA_NAME)\n", "override_json['nodeGraphOverrides']['nodes'][0]['name'] = CAMERA_NAME\n", "override_json['nodeGraphOverrides']['nodes'][0]['interface'] = '{}::{}.{}'.format(account_id, CAMERA_NAME, CAMERA_NAME) \n", "override_json['nodeGraphOverrides']['nodeOverrides'][0]['with'][0]['name'] = CAMERA_NAME \n", "\n", "with open( f\"./{app_name}/deployment_overrides/override_camera.json\", \"w\") as fd:\n", " json.dump(override_json, fd)" ] }, { "cell_type": "markdown", "id": "337238ff", "metadata": {}, "source": [ "### Build app with container" ] }, { "cell_type": "code", "execution_count": null, "id": "afc63216", "metadata": {}, "outputs": [], "source": [ "container_asset_name = 'trtpt_36_2_app'" ] }, { "cell_type": "code", "execution_count": null, "id": "25f5b4b1", "metadata": {}, "outputs": [], "source": [ "%%capture captured_output\n", "\n", "# Building container image.This process takes time (5min ~ 10min)\n", "# FIXME : without %%capture, browser tab crashes because of too much output from the command.\n", "\n", "!cd ./trtpt_36_2_app && panorama-cli build \\\n", " --container-asset-name {container_asset_name} \\\n", " --package-path packages/{account_id}-{code_package_name}-1.0" ] }, { "cell_type": "code", "execution_count": null, "id": "81c66f7d-70b6-411c-b86f-5256a47d8516", "metadata": {}, "outputs": [], "source": [ "stdout_lines = captured_output.stdout.splitlines()\n", "stderr_lines = captured_output.stderr.splitlines()\n", "print(\" :\")\n", "print(\" :\")\n", "for line in stdout_lines[-30:] + stderr_lines[-30:]:\n", " print(line)" ] }, { "cell_type": "markdown", "id": "a3775514-e4c1-4cb1-8ebd-41ca8506a62e", "metadata": {}, "source": [ "### Special flags in package.json\n", "\n", "* Step 1 : Before you deploy the application, open TRTPT37_opengpu/trtpt_36_2_app/packages/(account-id)-trtpt_36_2_app-1.0/package.json\n", "* Step 2 : Add the following flags to the package.json\n", "\n", "```\n", "\"requirements\": \n", " [{\n", " \"type\" : \"hardware_access\",\n", " \"inferenceAccelerators\": [ \n", " {\n", " \"deviceType\": \"nvhost_gpu\",\n", " \"sharedResourcePolicy\": {\n", " \"policy\" : \"allow_all\"\n", " }\n", " }\n", " ]\n", " }]\n", "```\n", "\n", "The assets should look something like this\n", "\n", "```\n", "\"assets\": [\n", " {\n", " \"name\": \"trtpt_36_2_app\",\n", " \"implementations\": [\n", " {\n", " \"type\": \"container\",\n", " \"assetUri\": \"9a49a98784f4571adacc417f00942dac7ef2e34686eef21dca9fcb7f4b7ffd70.tar.gz\",\n", " \"descriptorUri\": \"4bab130ec48eea84e072d9fe813b947e9d9610b2924099036b0165026a91d306.json\",\n", " \"requirements\": \n", " [{\n", " \"type\" : \"hardware_access\",\n", " \"inferenceAccelerators\": [ \n", " {\n", " \"deviceType\": \"nvhost_gpu\",\n", " \"sharedResourcePolicy\": {\n", " \"policy\" : \"allow_all\"\n", " }\n", " }\n", " ]\n", " }]\n", " }\n", " ]\n", " }\n", "],\n", "```" ] }, { "cell_type": "markdown", "id": "f017081e", "metadata": {}, "source": [ "### Upload application to Panorama for deploying to devices" ] }, { "cell_type": "code", "execution_count": null, "id": "e8bc1f3b", "metadata": {}, "outputs": [], "source": [ "# This step takes some time, depending on your network environment.\n", "!cd ./trtpt_36_2_app && pwd && panorama-cli-dev setup-panorama-service-cli --region PDX --stage Gamma && panorama-cli-dev package-application" ] }, { "cell_type": "markdown", "id": "4a6794d7", "metadata": {}, "source": [ "### Ready for deploying to a device\n", "\n", "Congrats! Your app is now ready to deploy to a device. Next, you can continue in this notebook to deploy the app programmatically or you can go to the Panorama console and deploying using the AWS Console. The console makes it easier to select camera streams and select the devices you want to deploy to. Programmatic deployment is faster to complete and easier to automate." ] }, { "cell_type": "markdown", "id": "e8e572a8", "metadata": {}, "source": [ "# Deploy app to device" ] }, { "cell_type": "markdown", "id": "b59f04c5", "metadata": {}, "source": [ "Let's make sure the device we are deploying to is available." ] }, { "cell_type": "code", "execution_count": null, "id": "c4cd42dc", "metadata": {}, "outputs": [], "source": [ "response = panorama_client.describe_device(\n", " DeviceId= DEVICE_ID\n", ")\n", "\n", "print('You are deploying to Device: {}'.format(response['Name']))" ] }, { "cell_type": "markdown", "id": "a09b151f", "metadata": {}, "source": [ "## Deploy app\n", "\n", "You are ready to deploy your app. Below, you can see an example of how to use the AWS CLI to deploy the app. Alternatively, you can use the boto3 SDK as you did above for getting the device information." ] }, { "cell_type": "code", "execution_count": null, "id": "8983bd1f-2368-4134-a7dc-1370763beb80", "metadata": {}, "outputs": [], "source": [ "with open(f\"./{app_name}/graphs/{app_name}/graph.json\") as fd:\n", " manifest_payload = \"'%s'\" % json.dumps({\"PayloadData\":json.dumps(json.load(fd))})\n", " \n", "with open(f\"./{app_name}/deployment_overrides/override_camera.json\") as fd:\n", " override_payload = \"'%s'\" % json.dumps({\"PayloadData\":json.dumps(json.load(fd))})" ] }, { "cell_type": "code", "execution_count": null, "id": "5951c872-2b55-49ca-9c0f-800bd64d7b69", "metadata": {}, "outputs": [], "source": [ "role_arn = panorama_test_utility.resolve_sm_role()" ] }, { "cell_type": "code", "execution_count": null, "id": "3887fb98-77ed-49e2-a22e-15836ed99450", "metadata": {}, "outputs": [], "source": [ "res = !aws panorama create-application-instance \\\n", " --name {app_name} \\\n", " --default-runtime-context-device {DEVICE_ID} \\\n", " --manifest-payload {manifest_payload} \\\n", " --manifest-overrides-payload {override_payload}\n", " --runtime-role-arn {role_arn}\n", "\n", "res = ''.join(res)\n", "print(res)\n", "res_json = json.loads(res)" ] }, { "cell_type": "markdown", "id": "ad70b33a", "metadata": {}, "source": [ "# Clean up" ] }, { "cell_type": "code", "execution_count": null, "id": "43b45a9b", "metadata": {}, "outputs": [], "source": [ "panorama_test_utility.remove_application( DEVICE_ID, app_id )" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.6.9" } }, "nbformat": 4, "nbformat_minor": 5 }