Modèle de démonstration : annotation d'images avec crowd-bounding-box - Amazon SageMaker

Modèle de démonstration : annotation d'images avec crowd-bounding-box

Lorsque vous avez choisi d'utiliser un modèle personnalisé comme type de tâche dans la console Amazon SageMaker Ground Truth, vous accédez au Custom labeling task panel (Panneau de tâches d'étiquetage personnalisé). Vous pouvez alors choisir parmi plusieurs modèles de base. Les modèles représentent certaines des tâches les plus courantes et fournissent un échantillon de base à utiliser au fur et à mesure que vous créez votre modèle de tâche. Si vous n'utilisez pas la console, ou si vous souhaitez les utiliser comme voie de recours supplémentaire, veuillez consulter les exemples d'interface utilisateur de tâche pour Amazon SageMaker Ground Truth pour obtenir un référentiel de modèles de démonstration pour divers types de tâches d'étiquetage.

Cette démonstration fonctionne avec le modèle BoundingBox. La démonstration fonctionne également avec les fonctions AWS Lambda nécessaires pour le traitement de vos données avant et après la tâche. Dans le répertoire Github ci-dessus, pour trouver les modèles compatibles avec les fonctions AWS Lambda, recherchez {{ task.input.<property name> }} dans le modèle.

Modèle personnalisé de cadre de délimitation de démarrage.

Voici le modèle de cadre de délimitation de démarrage qui est fourni.

<script src="https://assets.crowd.aws/crowd-html-elements.js"></script> <crowd-form> <crowd-bounding-box name="boundingBox" src="{{ task.input.taskObject | grant_read_access }}" header="{{ task.input.header }}" labels="{{ task.input.labels | to_json | escape }}" > <!-- The <full-instructions> tag is where you will define the full instructions of your task. --> <full-instructions header="Bounding Box Instructions" > <p>Use the bounding box tool to draw boxes around the requested target of interest:</p> <ol> <li>Draw a rectangle using your mouse over each instance of the target.</li> <li>Make sure the box does not cut into the target, leave a 2 - 3 pixel margin</li> <li> When targets are overlapping, draw a box around each object, include all contiguous parts of the target in the box. Do not include parts that are completely overlapped by another object. </li> <li> Do not include parts of the target that cannot be seen, even though you think you can interpolate the whole shape of the target. </li> <li>Avoid shadows, they're not considered as a part of the target.</li> <li>If the target goes off the screen, label up to the edge of the image.</li> </ol> </full-instructions> <!-- The <short-instructions> tag allows you to specify instructions that are displayed in the left hand side of the task interface. It is a best practice to provide good and bad examples in this section for quick reference. --> <short-instructions> Use the bounding box tool to draw boxes around the requested target of interest. </short-instructions> </crowd-bounding-box> </crowd-form>

Les modèles personnalisés utilisent le langage du modèle Liquid et chacun des éléments entre accolades doubles est une variable. La fonction AWS Lambda de pré-annotation doit fournir un objet nommé taskInput et les propriétés de cet objet sont accessibles en tant que {{ task.input.<property name> }} dans votre modèle.

Votre modèle personnalisé de cadre de délimitation de base

Par exemple, supposons que vous avez une large gamme de photos dans laquelle vous connaissez le type d'animal dans une image à partir d'une image préalable de classification de tâche. À présent, vous souhaitez avoir un cadre de délimitation dessiné autour de celle-ci.

L'exemple de base comporte trois variables : taskObject, header et labels.

Chacune d'elles est représentée dans différentes parties du cadre de délimitation.

  • taskObject est une URL HTTP(S) ou un URI S3 pour la photo à annoter. Le code | grant_read_access ajouté est un filtre qui va convertir un URI S3 en URL HTTPS avec un accès de courte durée à cette ressource. Si vous utilisez une URL HTTP(S), il n'est pas nécessaire.

  • header est le texte situé au-dessus de la photo à étiqueter, par exemple « Dessiner un cadre autour de l'oiseau de la photo ».

  • labels est un tableau, représenté sous la forme ['item1', 'item2', ...]. Ce sont des étiquettes que l'employé peut affecter aux différents cadres qu'il dessine. Vous pouvez en avoir une ou plusieurs.

Chacun des noms de variable provient de l'objet JSON dans la réponse de votre fonction de prétraitement Lambda. Les noms ci-dessus sont simplement suggérés. Utilisez les noms de variable qui ont un sens pour vous et facilitent la lecture du code au sein de votre équipe.

Utilisez des variables uniquement lorsque cela est nécessaire

Si un champ ne change pas, vous pouvez supprimer la variable du modèle et la remplacer par du texte. Sinon, vous devez répéter ce texte en tant que valeur dans chaque objet de votre manifeste ou le coder dans votre fonction Lambda de pré-annotation.

Exemple Modèle de cadre de délimitation final personnalisé

Dans un souci de simplification, ce modèle aura une variable, une étiquette et des instructions très basiques. En supposant que votre manifeste dispose d'une propriété « animal » dans chaque objet de données, cette valeur peut être réutilisé dans les deux parties du modèle.

<script src="https://assets.crowd.aws/crowd-html-elements.js"></script> <crowd-form> <crowd-bounding-box name="boundingBox" labels="[ '{{ task.input.animal }}' ]" src="{{ task.input.source-ref | grant_read_access }}" header="Draw a box around the {{ task.input.animal }}." > <full-instructions header="Bounding Box Instructions" > <p>Draw a bounding box around the {{ task.input.animal }} in the image. If there is more than one {{ task.input.animal }} per image, draw a bounding box around the largest one.</p> <p>The box should be tight around the {{ task.input.animal }} with no more than a couple of pixels of buffer around the edges.</p> <p>If the image does not contain a {{ task.input.animal }}, check the <strong> Nothing to label</strong> box. </full-instructions> <short-instructions> <p>Draw a bounding box around the {{ task.input.animal }} in each image. If there is more than one {{ task.input.animal }} per image, draw a bounding box around the largest one.</p> </short-instructions> </crowd-bounding-box> </crowd-form>

Notez la réutilisation de {{ task.input.animal }} tout au long du modèle. Si tous les noms d'animaux de votre manifeste commencent par une lettre majuscule, vous pouvez utiliser {{ task.input.animal | downcase }}, en intégrant l'un des filtres intégrés de Liquid dans les phrases où les minuscules sont nécessaires.

Votre fichier manifeste

Votre fichier manifeste doit fournir les valeurs de variables que vous utilisez dans votre modèle. Vous pouvez modifier un peu les données de votre manifeste dans votre fonction de prétraitement Lambda, mais si vous n'avez pas besoin de le faire, vous réduisez le risque d'erreurs et votre fonction de prétraitement Lambda fonctionnera plus rapidement. Voici un exemple de fichier manifeste pour le modèle.

{"source-ref": "<S3 image URI>", "animal": "horse"} {"source-ref": "<S3 image URI>", "animal" : "bird"} {"source-ref": "<S3 image URI>", "animal" : "dog"} {"source-ref": "<S3 image URI>", "animal" : "cat"}

Votre fonction Lambda de pré-annotation

Dans le cadre de la configuration de la tâche, vous devrez fournir l'ARN d'une fonction AWS Lambda qui peut être appelée pour traiter les entrées du manifeste et les transmettre au moteur de modèles.

Nommage de votre fonction Lambda

La bonne pratique pour nommer votre fonction consiste à utiliser l'une des quatre chaînes dans le cadre du nom de la fonction : SageMaker, Sagemaker, sagemaker, ou LabelingFunction. Cela s'applique aux fonctions de pré-annotation et de post-annotation.

Lorsque vous utilisez la console, si vous avez des fonctions AWS Lambda qui appartiennent à votre compte, une liste déroulante des fonctions répondant aux exigences de nommage s'affiche pour vous permettre d'en choisir une.

Dans cet exemple très basique, vous êtes seulement en passant par les informations du manifeste sans avoir à faire un traitement supplémentaire. Cet exemple de fonction de pré-annotation est écrit pour Python 3.7.

import json def lambda_handler(event, context): return { "taskInput": event['dataObject'] }

L'objet JSON de votre manifeste sera fourni en tant qu'enfant de l'objet event. Les propriétés à l'intérieur de l'objet taskInput seront disponibles en tant que variables de votre modèle, de sorte que la simple définition de la valeur de taskInput pour event['dataObject'] transmettra toutes les valeurs à partir de votre objet de manifeste vers votre modèle, sans avoir à les copier individuellement. Si vous souhaitez envoyer plusieurs valeurs pour le modèle, vous pouvez les ajouter à l'objet taskInput.

Votre fonction Lambda post-annotation

Dans le cadre de la configuration de la tâche, vous devrez fournir l'ARN d'une fonction AWS Lambda qui peut être appelée pour traiter les données de formulaire lorsqu'un employé effectue une tâche. Cela peut être aussi simple ou complexe que vous le souhaitez. Si vous souhaitez consolider les réponses et les noter au fur et à mesure qu'elles arrivent, vous pouvez appliquer les algorithmes de notation et/ou de consolidation de votre choix. Si vous souhaitez stocker les données brutes en vue d'un traitement hors ligne, c'est possible.

Fournissez des autorisations à votre Lambda post-annotation

Les données d'annotation seront stockées dans un fichier désigné par la chaîne s3Uri dans l'objet payload. Pour traiter les annotations au fur et à mesure qu'elles arrivent, même pour une simple fonction de transmission, vous devez attribuer l'accès S3ReadOnly à votre fonction Lambda afin qu'elle puisse lire les fichiers d'annotation.

Dans la page de la console relative à la création de votre fonction Lambda, faites défiler le panneau Execution role (Rôle d'exécution). Sélectionnez Create a new role from one or more templates (Créer un rôle à partir d'un ou de plusieurs modèles). Nommez le rôle. Dans la liste déroulante Policy templates (Modèles de stratégie), choisissez Amazon S3 object read-only permissions (Autorisations en lecture seule d'un objet Amazon S3). Enregistrez la fonction Lambda. Le rôle est enregistré et sélectionné.

L'exemple suivant concerne Python 2.7.

import json import boto3 from urlparse import urlparse def lambda_handler(event, context): consolidated_labels = [] parsed_url = urlparse(event['payload']['s3Uri']); s3 = boto3.client('s3') textFile = s3.get_object(Bucket = parsed_url.netloc, Key = parsed_url.path[1:]) filecont = textFile['Body'].read() annotations = json.loads(filecont); for dataset in annotations: for annotation in dataset['annotations']: new_annotation = json.loads(annotation['annotationData']['content']) label = { 'datasetObjectId': dataset['datasetObjectId'], 'consolidatedAnnotation' : { 'content': { event['labelAttributeName']: { 'workerId': annotation['workerId'], 'boxesInfo': new_annotation, 'imageSource': dataset['dataObject'] } } } } consolidated_labels.append(label) return consolidated_labels

La fonction de post-traitement Lambda reçoit souvent des lots de résultats de tâches dans l'objet d'événement. Ce lot sera l'objet payload sur lequel la fonction Lambda devra itérer. Ce que vous renverrez sera un objet conforme au contrat d'API.

La sortie de votre tâche d'étiquetage

Vous trouverez la sortie de la tâche dans un dossier nommé d'après votre tâche d'étiquetage dans le compartiment S3 cible que vous avez spécifié. Elle figurera dans un sous-dossier nommé manifests.

Pour une tâche de cadre de délimitation, la sortie que vous trouverez dans le manifeste de sortie ressemblera un peu à la démonstration ci-dessous. L'exemple a été nettoyé pour l'impression. La sortie réelle sera une seule ligne par enregistrement.

Exemple Objet JSON dans votre manifeste de sortie

{ "source-ref":"<URL>", "<label attribute name>": { "workerId":"<URL>", "imageSource":"<image URL>", "boxesInfo":"{\"boundingBox\":{\"boundingBoxes\":[{\"height\":878, \"label\":\"bird\", \"left\":208, \"top\":6, \"width\":809}], \"inputImageProperties\":{\"height\":924, \"width\":1280}}}"}, "<label attribute name>-metadata": { "type":"groundTruth/custom", "job_name":"<Labeling job name>", "human-annotated":"yes" }, "animal" : "bird" }

Notez la façon dont l'attribut animal supplémentaire de votre manifeste initial est transmis au manifeste de sortie au même niveau que le source-ref et les données d'étiquetage. Toutes les propriétés de votre manifeste d'entrée, si elles ont été utilisées dans votre modèle ou non, seront transmises au manifeste de sortie.