Développement d'applications AWS Panorama - AWS Panorama

Les traductions sont fournies par des outils de traduction automatique. En cas de conflit entre le contenu d'une traduction et celui de la version originale en anglais, la version anglaise prévaudra.

Développement d'applications AWS Panorama

Vous pouvez utiliser l'exemple d'application pour en savoir plus sur la structure d'application AWS Panorama et comme point de départ pour votre propre application.

Le schéma suivant illustre les principaux composants de l'application exécutée sur une appliance AWS Panorama. Le code de l'application utilise le kit SDK de l'application AWS Panorama pour obtenir des images et interagir avec le modèle, auquel il n'a pas d'accès direct. L'application envoie la vidéo vers un écran connecté mais n'envoie pas de données d'image en dehors de votre réseau local.

Exemple d'architecture d'application AWS Panorama

Dans cet exemple, l'application utilise le kit SDK d'application AWS Panorama pour obtenir des images vidéo d'une caméra, prétraiter les données vidéo et envoyer les données à un modèle de vision artificielle qui détecte les objets. L'application affiche le résultat sur un écran HDMI connecté à l'appareil.

Le manifeste d'application

Le manifeste de l'application est un fichier nommégraph.jsondans legraphsfolder. Le manifeste définit les composants de l'application, à savoir les packages, les nœuds et les bords.

Les packages sont des fichiers de code, de configuration et binaires pour le code d'application, les modèles, les caméras et les affichages. L'exemple d'application utilise 4 packages :

Exemple graphs/aws-panorama-sample/graph.json— Packages
"packages": [ { "name": "123456789012::SAMPLE_CODE", "version": "1.0" }, { "name": "123456789012::SQUEEZENET_PYTORCH_V1", "version": "1.0" }, { "name": "panorama::abstract_rtsp_media_source", "version": "1.0" }, { "name": "panorama::hdmi_data_sink", "version": "1.0" } ],

Les deux premiers packages sont définis dans l'application, dans lepackagesannuaire. Ils contiennent le code et le modèle spécifiques à cette application. Les deux autres packages sont des packages génériques de caméra et d'affichage fournis par le service AWS Panorama. Leabstract_rtsp_media_sourceest un espace réservé pour une caméra que vous remplacez lors du déploiement. Lehdmi_data_sinkreprésente le connecteur de sortie HDMI de l'appareil.

Les nœuds sont des interfaces vers des packages, ainsi que des paramètres autres que des packages qui peuvent avoir des valeurs par défaut que vous remplacez au moment du déploiement. Les packages de code et de modèle définissent les interfaces danspackage.jsondes fichiers qui spécifient des entrées et des sorties, qui peuvent être des flux vidéo ou un type de données de base tel qu'un flottant, un booléen ou une chaîne.

Par exemple, les recettescode_nodenœud fait référence à une interface duSAMPLE_CODEpackage.

"nodes": [ { "name": "code_node", "interface": "123456789012::SAMPLE_CODE.interface", "overridable": false, "launch": "onAppStart" },

Cette interface est définie dans le fichier de configuration de package,package.json. L'interface indique que le package est une logique métier et qu'il prend un flux vidéo nommévideo_inet un nombre à virgule flottante nomméthresholden tant qu'entrées. L'interface indique également que le code nécessite un tampon de flux vidéo nommévideo_outpour sortir une vidéo sur un écran

Exemple packages/123456789012-SAMPLE_CODE-1.0/package.json
{ "nodePackage": { "envelopeVersion": "2021-01-01", "name": "SAMPLE_CODE", "version": "1.0", "description": "Computer vision application code.", "assets": [], "interfaces": [ { "name": "interface", "category": "business_logic", "asset": "code_asset", "inputs": [ { "name": "video_in", "type": "media" }, { "name": "threshold", "type": "float32" } ], "outputs": [ { "description": "Video stream output", "name": "video_out", "type": "media" } ] } ] } }

De retour dans le manifeste de l'application, lecamera_nodenode représente un flux vidéo provenant d'une caméra. Il inclut un décorateur qui apparaît dans la console lorsque vous déployez l'application, vous invitant à choisir un flux de caméra.

Exemple graphs/aws-panorama-sample/graph.json— Nœud caméra
{ "name": "camera_node", "interface": "panorama::abstract_rtsp_media_source.rtsp_v1_interface", "overridable": true, "launch": "onAppStart", "decorator": { "title": "Camera", "description": "Choose a camera stream." } },

Un nœud de paramètre,threshold_param, définit le paramètre de seuil de confiance utilisé par le code d'application. Elle a une valeur par défaut de 60 et peut être remplacée pendant le déploiement.

Exemple graphs/aws-panorama-sample/graph.json— Nœud paramètre
{ "name": "threshold_param", "interface": "float32", "value": 60.0, "overridable": true, "decorator": { "title": "Confidence threshold", "description": "The minimum confidence for a classification to be recorded." } }

La dernière section du manifeste de candidature,edges, établit des connexions entre les nœuds. Le flux vidéo de la caméra et le paramètre de seuil se connectent à l'entrée du nœud de code, et la sortie vidéo du nœud de code se connecte à l'écran.

Exemple graphs/aws-panorama-sample/graph.json— Bords
"edges": [ { "producer": "camera_node.video_out", "consumer": "code_node.video_in" }, { "producer": "code_node.video_out", "consumer": "output_node.video_in" }, { "producer": "threshold_param", "consumer": "code_node.threshold" } ]

Create avec l'exemple d'application

Vous pouvez utiliser l'exemple d'application comme point de départ pour votre propre application.

Le nom de chaque package doit être unique dans votre compte. Si vous et un autre utilisateur de votre compte utilisez tous deux un nom de package générique tel quecodeoumodel, il se peut que vous obteniez la mauvaise version du package lors du déploiement. Remplacez le nom du package de code par un nom qui représente votre application.

Pour renommer le package de code
  1. Renommez le dossier du package :packages/123456789012-SAMPLE_CODE-1.0/.

  2. Mettez à jour le nom du package dans les emplacements suivants.

    • Le manifeste d'applicationgraphs/aws-panorama-sample/graph.json

    • Configuration de packagepackages/123456789012-SAMPLE_CODE-1.0/package.json

    • Script de build3-build-container.sh

Pour mettre à jour le code de l'application
  1. Modifiez le code de l'application danspackages/123456789012-SAMPLE_CODE-1.0/src/application.py.

  2. Pour générer le conteneur, exécutez3-build-container.sh.

    aws-panorama-sample$ ./3-build-container.sh TMPDIR=$(pwd) docker build -t code_asset packages/123456789012-SAMPLE_CODE-1.0 Sending build context to Docker daemon 61.44kB Step 1/2 : FROM public.ecr.aws/panorama/panorama-application ---> 9b197f256b48 Step 2/2 : COPY src /panorama ---> 55c35755e9d2 Successfully built 55c35755e9d2 Successfully tagged code_asset:latest docker export --output=code_asset.tar $(docker create code_asset:latest) gzip -9 code_asset.tar Updating an existing asset with the same name { "name": "code_asset", "implementations": [ { "type": "container", "assetUri": "98aaxmpl1c1ef64cde5ac13bd3be5394e5d17064beccee963b4095d83083c343.tar.gz", "descriptorUri": "1872xmpl129481ed053c52e66d6af8b030f9eb69b1168a29012f01c7034d7a8f.json" } ] } Container asset for the package has been succesfully built at ~/aws-panorama-sample-dev/assets/98aaxmpl1c1ef64cde5ac13bd3be5394e5d17064beccee963b4095d83083c343.tar.gz

    L'interface de ligne de commande supprime automatiquement l'ancien actif de conteneur duassetsdossier et met à jour la configuration du package.

  3. Pour charger les packages, exécutez4-package-application.py.

  4. Ouvrez la console AWS PanoramaPage Applications déployées.

  5. Choisissez une application.

  6. Choisissez Remplacer.

  7. Procédez comme suit pour déployer l'application. Si nécessaire, vous pouvez modifier le manifeste de l'application, les flux de caméra ou les paramètres.

Changer le modèle de vision par ordinateur

L'exemple d'application inclut un modèle de vision par ordinateur. Pour utiliser votre propre modèle, modifiez la configuration du nœud du modèle et utilisez l'interface de ligne de commande de l'application AWS Panorama pour l'importer en tant que ressource.

L'exemple suivant utilise un SSD MXNet ResNet50 modèles que vous pouvez télécharger à partir de ce guide GitHub repo :ssd_512_resnet50_v1_voc.tar.gz

Pour modifier le modèle de l'exemple d'application
  1. Renommez le dossier du package en fonction de votre modèle. Par exemple, pourpackages/123456789012-SSD_512_RESNET50_V1_VOC-1.0/.

  2. Mettez à jour le nom du package dans les emplacements suivants.

    • Le manifeste d'applicationgraphs/aws-panorama-sample/graph.json

    • Configuration de packagepackages/123456789012-SSD_512_RESNET50_V1_VOC-1.0/package.json

  3. Dans le fichier de configuration du package (package.json). Remplacez leassetsvaleur dans un tableau vide.

    { "nodePackage": { "envelopeVersion": "2021-01-01", "name": "SSD_512_RESNET50_V1_VOC", "version": "1.0", "description": "Compact classification model", "assets": [],
  4. Ouvrez le fichier descripteur de package (descriptor.json). Mettre à jour leframeworketshapevaleurs correspondant à votre modèle.

    { "mlModelDescriptor": { "envelopeVersion": "2021-01-01", "framework": "MXNET", "inputs": [ { "name": "data", "shape": [ 1, 3, 512, 512 ] } ] } }

    La valeur pourforme,1,3,512,512, indique le nombre d'images que le modèle prend en entrée (1), le nombre de canaux dans chaque image (3 : rouge, vert et bleu) et les dimensions de l'image (512 x 512). Les valeurs et l'ordre du tableau varient selon les modèles.

  5. Importez le modèle avec l'interface de ligne de commande d'application AWS Panorama. L'interface de ligne de commande de l'application AWS Panorama copie les fichiers de modèle et de descripteur dans leassetsavec des noms uniques, et met à jour la configuration du package.

    aws-panorama-sample$ panorama-cli add-raw-model --model-asset-name model-asset \ --model-local-path ssd_512_resnet50_v1_voc.tar.gz \ --descriptor-path packages/123456789012-SSD_512_RESNET50_V1_VOC-1.0/descriptor.json \ --packages-path packages/123456789012-SSD_512_RESNET50_V1_VOC-1.0 { "name": "model-asset", "implementations": [ { "type": "model", "assetUri": "b1a1589afe449b346ff47375c284a1998c3e1522b418a7be8910414911784ce1.tar.gz", "descriptorUri": "a6a9508953f393f182f05f8beaa86b83325f4a535a5928580273e7fe26f79e78.json" } ] }
  6. Pour télécharger le modèle, exécutezpanorama-cli package-application.

    $ panorama-cli package-application Uploading package SAMPLE_CODE Patch Version 1844d5a59150d33f6054b04bac527a1771fd2365e05f990ccd8444a5ab775809 already registered, ignoring upload Uploading package SSD_512_RESNET50_V1_VOC Patch version for the package 244a63c74d01e082ad012ebf21e67eef5d81ce0de4d6ad1ae2b69d0bc498c8fd upload: assets/b1a1589afe449b346ff47375c284a1998c3e1522b418a7be8910414911784ce1.tar.gz to s3://arn:aws:s3:us-west-2:454554846382:accesspoint/panorama-123456789012-wc66m5eishf4si4sz5jefhx 63a/123456789012/nodePackages/SSD_512_RESNET50_V1_VOC/binaries/b1a1589afe449b346ff47375c284a1998c3e1522b418a7be8910414911784ce1.tar.gz upload: assets/a6a9508953f393f182f05f8beaa86b83325f4a535a5928580273e7fe26f79e78.json to s3://arn:aws:s3:us-west-2:454554846382:accesspoint/panorama-123456789012-wc66m5eishf4si4sz5jefhx63 a/123456789012/nodePackages/SSD_512_RESNET50_V1_VOC/binaries/a6a9508953f393f182f05f8beaa86b83325f4a535a5928580273e7fe26f79e78.json { "ETag": "\"2381dabba34f4bc0100c478e67e9ab5e\"", "ServerSideEncryption": "AES256", "VersionId": "KbY5fpESdpYamjWZ0YyGqHo3.LQQWUC2" } Registered SSD_512_RESNET50_V1_VOC with patch version 244a63c74d01e082ad012ebf21e67eef5d81ce0de4d6ad1ae2b69d0bc498c8fd Uploading package SQUEEZENET_PYTORCH_V1 Patch Version 568138c430e0345061bb36f05a04a1458ac834cd6f93bf18fdacdffb62685530 already registered, ignoring upload
  7. Mettez à jour le code d'application. La plupart du code peut être réutilisé. Le code spécifique à la réponse du modèle se trouve dans leprocess_resultsMéthode.

    def process_results(self, inference_results, stream): """Processes output tensors from a computer vision model and annotates a video frame.""" for class_tuple in inference_results: indexes = self.topk(class_tuple[0]) for j in range(2): label = 'Class [%s], with probability %.3f.'% (self.classes[indexes[j]], class_tuple[0][indexes[j]]) stream.add_label(label, 0.1, 0.25 + 0.1*j)

    En fonction de votre modèle, vous devrez peut-être également mettre à jourpreprocessMéthode.

Traitement des images

Avant d'envoyer une image au modèle, l'application la prépare pour l'inférence en la redimensionnant et en normalisant les données de couleur. Le modèle utilisé par l'application nécessite une image de 224 x 224 pixels avec trois canaux de couleur, pour correspondre au nombre d'entrées de sa première couche. L'application ajuste chaque valeur de couleur en la convertissant en un nombre compris entre 0 et 1, en soustrayant la valeur moyenne de cette couleur et en la divisant par l'écart type. Enfin, il combine les canaux de couleur et les convertit en NumPy tableau que le modèle peut traiter.

Exemple application.py— Prétraitement
def preprocess(self, img, width): resized = cv2.resize(img, (width, width)) mean = [0.485, 0.456, 0.406] std = [0.229, 0.224, 0.225] img = resized.astype(np.float32) / 255. img_a = img[:, :, 0] img_b = img[:, :, 1] img_c = img[:, :, 2] # Normalize data in each channel img_a = (img_a - mean[0]) / std[0] img_b = (img_b - mean[1]) / std[1] img_c = (img_c - mean[2]) / std[2] # Put the channels back together x1 = [[[], [], []]] x1[0][0] = img_a x1[0][1] = img_b x1[0][2] = img_c return np.asarray(x1)

Ce processus donne les valeurs du modèle dans une plage prévisible centrée autour de 0. Il correspond au prétraitement appliqué aux images du jeu de données d'entraînement, qui est une approche standard mais qui peut varier selon le modèle.

Chargement de métriques avec le kit SDK pour Python

L'exemple d'application utilise le SDK pour Python pour télécharger des métriques vers Amazon. CloudWatch.

Exemple application.py— SDK pour Python
def process_streams(self): """Processes one frame of video from one or more video streams.""" ... logger.info('epoch length: {:.3f} s ({:.3f} FPS)'.format(epoch_time, epoch_fps)) logger.info('avg inference time: {:.3f} ms'.format(avg_inference_time)) logger.info('max inference time: {:.3f} ms'.format(max_inference_time)) logger.info('avg frame processing time: {:.3f} ms'.format(avg_frame_processing_time)) logger.info('max frame processing time: {:.3f} ms'.format(max_frame_processing_time)) self.inference_time_ms = 0 self.inference_time_max = 0 self.frame_time_ms = 0 self.frame_time_max = 0 self.epoch_start = time.time() self.put_metric_data('AverageInferenceTime', avg_inference_time) self.put_metric_data('AverageFrameProcessingTime', avg_frame_processing_time) def put_metric_data(self, metric_name, metric_value): """Sends a performance metric to CloudWatch.""" namespace = 'AWSPanoramaApplication' dimension_name = 'Application Name' dimension_value = 'aws-panorama-sample' try: metric = self.cloudwatch.Metric(namespace, metric_name) metric.put_data( Namespace=namespace, MetricData=[{ 'MetricName': metric_name, 'Value': metric_value, 'Unit': 'Milliseconds', 'Dimensions': [ { 'Name': dimension_name, 'Value': dimension_value }, { 'Name': 'Device ID', 'Value': self.device_id } ] }] ) logger.info("Put data for metric %s.%s", namespace, metric_name) except ClientError: logger.warning("Couldn't put data for metric %s.%s", namespace, metric_name) except AttributeError: logger.warning("CloudWatch client is not available.")

Il obtient l'autorisation d'un rôle d'exécution que vous attribuez au cours du déploiement. Le rôle est défini dans leaws-panorama-sample.yml AWS CloudFormationmodèle.

Exemple aws-panorama-sample.yml
Resources: runtimeRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Principal: Service: - panorama.amazonaws.com Action: - sts:AssumeRole Policies: - PolicyName: cloudwatch-putmetrics PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: 'cloudwatch:PutMetricData' Resource: '*' Path: /service-role/

L'exemple d'application installe le SDK pour Python et d'autres dépendances avec pip. Lorsque vous créez le conteneur d'applications, leDockerfileexécute des commandes pour installer des bibliothèques en plus de ce qui est fourni avec l'image de base.

Exemple Dockerfile
FROM public.ecr.aws/panorama/panorama-application WORKDIR /panorama COPY . . RUN pip install --no-cache-dir --upgrade pip && \ pip install --no-cache-dir -r requirements.txt

Pour utiliser le pluginAWSSDK dans le code de votre application, modifiez d'abord le modèle pour ajouter des autorisations pour toutes les actions d'API utilisées par l'application. Mettre à jour leAWS CloudFormationempiler en exécutant1-create-role.shchaque fois que vous apportez une modification. Déployez ensuite les modifications apportées au code de votre application.

Pour les actions qui modifient ou utilisent des ressources existantes, il est recommandé de minimiser la portée de cette stratégie en spécifiant un nom ou un modèle pour la cible.Resourcedans une déclaration séparée. Pour plus d'informations sur les actions et les ressources prises en charge par chaque service, consultezActions, ressources et clés de conditiondans le Service Authorization Reférence

Étapes suivantes

Pour obtenir des instructions sur l'utilisation de l'interface de ligne de commande d'application AWS Panorama pour créer des applications et créer des packages à partir de zéro, consultez le README de l'interface

Pour obtenir d'autres exemples de code et un utilitaire de test que vous pouvez utiliser pour valider le code de votre application avant le déploiement, visitez le référentiel d'exemples AWS Panorama.