Créer une solution d'analyse ML Vision avec Dataflow et l'API Cloud Vision

Last reviewed 2024-04-16 UTC

Dans ce tutoriel, vous allez apprendre à déployer un pipeline Dataflow pour traiter des fichiers image à grande échelle avec Cloud Vision. Dataflow stocke les résultats dans BigQuery afin que vous puissiez vous en servir pour entraîner des modèles prédéfinis BigQuery ML.

Le pipeline Dataflow que vous créez dans ce tutoriel peut gérer des images en grandes quantités. Il n'est limité que par votre quota Vision. Vous pouvez augmenter votre quota Vision en fonction de vos exigences d'évolutivité.

Ce tutoriel est destiné aux ingénieurs de données et aux data scientists. Nous supposons ici que vous disposez de connaissances de base sur la création de pipelines Dataflow à l'aide du SDK Java d'Apache Beam, du SQL standard BigQuery et de scripts shell de base. Nous supposons également que vous maîtrisez Vision.

Objectifs

  • Créer un pipeline d'ingestion de métadonnées d'images avec des notifications Pub/Sub pour Cloud Storage.
  • Déployer un pipeline d'analyse de vision en temps réel avec Dataflow.
  • Utiliser Vision pour analyser des images pour un ensemble de types de fonctionnalités.
  • Analyser et entraîner des données avec BigQuery ML.

Coûts

Dans ce document, vous utilisez les composants facturables suivants de Google Cloud :

Obtenez une estimation des coûts en fonction de votre utilisation prévue à l'aide du simulateur de coût. Les nouveaux utilisateurs de Google Cloud peuvent bénéficier d'un essai gratuit.

Une fois que vous avez terminé les tâches décrites dans ce document, vous pouvez éviter de continuer à payer des frais en supprimant les ressources que vous avez créées. Pour en savoir plus, consultez la section Effectuer un nettoyage.

Avant de commencer

  1. Dans Google Cloud Console, sur la page de sélection du projet, sélectionnez ou créez un projet Google Cloud.

    Accéder au sélecteur de projet

  2. Vérifiez que la facturation est activée pour votre projet Google Cloud.

  3. Dans la console Google Cloud, activez Cloud Shell.

    Activer Cloud Shell

  4. Dans Cloud Shell, activez les API Dataflow, Container Registry et Vision.

    gcloud services enable dataflow.googleapis.com \
    containerregistry.googleapis.com vision.googleapis.com
    
  5. Définissez des variables d'environnement. (Remplacez REGION par l'une des régions Dataflow disponibles. Par exemple :us-central1.)

    export PROJECT=$(gcloud config get-value project)
    export REGION=REGION
    
  6. Clonez le dépôt Git du tutoriel :

    git clone https://github.com/GoogleCloudPlatform/dataflow-vision-analytics.git
    
  7. Accédez au dossier racine du dépôt :

    cd dataflow-vision-analytics
    

Architecture de référence

Le schéma suivant illustre le flux du système que vous créez dans ce tutoriel.

Schéma de workflow montrant le flux d'informations pour l'ingestion, le déclenchement, le traitement et le stockage.

Comme le montre le schéma, le flux est le suivant :

  1. Les clients importent des fichiers image dans un bucket Cloud Storage.

  2. Pour chaque importation de fichier, le système informe automatiquement le client en publiant un message dans Pub/Sub.

  3. Pour chaque nouvelle notification, le pipeline Dataflow effectue les actions suivantes :

    1. Il lit les métadonnées du fichier à partir du message Pub/Sub.
    2. Envoi de chaque segment à l'API Vision pour le traitement des annotations.
    3. Il stocke toutes les annotations dans une table BigQuery pour une analyse plus approfondie.

Créer une notification Pub/Sub pour Cloud Storage

Dans cette section, vous allez créer une notification Pub/Sub pour Cloud Storage. Cette notification publie les métadonnées pour le fichier image importé dans le bucket. En fonction des métadonnées, le pipeline Dataflow commence à traiter la requête.

  1. Dans Cloud Shell, créez un sujet Pub/Sub :

    export GCS_NOTIFICATION_TOPIC="gcs-notification-topic"
    gcloud pubsub topics create ${GCS_NOTIFICATION_TOPIC}
    
  2. Créez un abonnement Pub/Sub pour le sujet :

    export  GCS_NOTIFICATION_SUBSCRIPTION="gcs-notification-subscription"
    gcloud pubsub subscriptions create  ${GCS_NOTIFICATION_SUBSCRIPTION}  --topic=${GCS_NOTIFICATION_TOPIC}
    
  3. Créez un bucket pour stocker les fichiers image d'entrée :

    export IMAGE_BUCKET=${PROJECT}-images
    gsutil mb -c standard -l ${REGION} gs://${IMAGE_BUCKET}
    
  4. Créez une notification Pub/Sub pour le bucket :

    gsutil notification create -t ${GCS_NOTIFICATION_TOPIC} \
      -f json gs://${IMAGE_BUCKET}
    

Une fois les notifications configurées, le système envoie un message Pub/Sub au sujet que vous avez créé. Cette action se produit à chaque fois que vous importez un fichier dans le bucket.

Créer un ensemble de données BigQuery

Dans cette section, vous créez un ensemble de données BigQuery pour stocker les résultats générés par le pipeline Dataflow. Le pipeline crée automatiquement des tables basées sur les types de caractéristiques Vision.

  • Dans Cloud Shell, créez un ensemble de données BigQuery :

    export BIGQUERY_DATASET="vision_analytics"
    bq mk -d --location=US ${BIGQUERY_DATASET}
    

Créer un modèle Flex Dataflow

Dans cette section, vous créez du code de pipeline Apache Beam, puis exécutez le pipeline Dataflow en tant que tâche Dataflow à l'aide d'un modèle Flex Dataflow.

  1. Dans Cloud Shell, créez le code du pipeline Apache Beam :

    gradle build
    
  2. Créez une image Docker pour le modèle Dataflow Flex :

    gcloud auth configure-docker
    gradle jib \
      --image=gcr.io/${PROJECT}/dataflow-vision-analytics:latest
    
  3. Créez un bucket Cloud Storage pour stocker le modèle Dataflow Flex :

    export DATAFLOW_TEMPLATE_BUCKET=${PROJECT}-dataflow-template-config
    gsutil mb -c standard -l ${REGION} \
      gs://${DATAFLOW_TEMPLATE_BUCKET}
    
  4. Importez le fichier de configuration JSON du modèle dans le bucket :

    cat << EOF | gsutil cp - gs://${DATAFLOW_TEMPLATE_BUCKET}/dynamic_template_vision_analytics.json
    {
      "image": "gcr.io/${PROJECT}/dataflow-vision-analytics:latest",
      "sdk_info": {"language": "JAVA"}
    }
    EOF
    

Exécuter le pipeline Dataflow pour un ensemble de fonctionnalités Vision

Les paramètres répertoriés dans le tableau suivant sont spécifiques à ce pipeline Dataflow.

Consultez la documentation Dataflow pour obtenir la liste complète des paramètres d'exécution Dataflow standards.

Paramètre Description

windowInterval

Intervalle de temps (en secondes) pour générer des résultats vers BigQuery et Pub/Sub. La valeur par défaut est 5.

batchSize

Nombre d'images à inclure dans une requête adressée à l'API Vision. La valeur par défaut est 1. Vous définir cette valeur sur un maximum de 16 images.

subscriberId

ID de l'abonnement Pub/Sub qui reçoit les notifications Cloud Storage d'entrée.

keyRange

Paramètre permettant d'améliorer les performances de traitement pour les ensembles de données volumineux. Plus la valeur est haute, plus le parallélisme est élevé entre les nœuds de calcul. La valeur par défaut est 1.

visionApiProjectId

ID de projet à utiliser pour l'API Vision.

datasetName

Référence de l'ensemble de données BigQuery de sortie.

features

Liste des fonctionnalités de traitement d'image.

labelAnnottationTable, landmarkAnnotationTable, logoAnnotationTable, faceAnnotationTable, imagePropertiesTable, cropHintAnnotationTable, errorLogTable

Paramètres de chaîne avec des noms de table pour diverses annotations. Les valeurs par défaut sont fournies pour chaque table.
  1. Dans Cloud Shell, définissez un nom de tâche pour le pipeline Dataflow :

    export JOB_NAME=vision-analytics-pipeline-1
    
  2. Créez un fichier en incluant les paramètres pour le pipeline Dataflow :

    PARAMETERS=params.yaml
    cat << EOF > ${PARAMETERS}
    --parameters:
      autoscalingAlgorithm: THROUGHPUT_BASED
      enableStreamingEngine: "true"
      subscriberId: projects/${PROJECT}/subscriptions/${GCS_NOTIFICATION_SUBSCRIPTION}
      visionApiProjectId: ${PROJECT}
      features: IMAGE_PROPERTIES,LABEL_DETECTION,LANDMARK_DETECTION,LOGO_DETECTION,CROP_HINTS,FACE_DETECTION
      datasetName: ${BIGQUERY_DATASET}
    EOF
    
  3. Exécutez le pipeline Dataflow pour traiter les images pour ces types de fonctionnalités : IMAGE_PROPERTIES, LABEL_DETECTION, LANDMARK_DETECTION, LOGO_DETECTION, CROP_HINTS,FACE_DETECTION.

    gcloud dataflow flex-template run ${JOB_NAME} \
    --project=${PROJECT} \
    --region=${REGION} \
    --template-file-gcs-location=gs://${DATAFLOW_TEMPLATE_BUCKET}/dynamic_template_vision_analytics.json \
    --flags-file ${PARAMETERS}
    

    Cette commande utilise les paramètres répertoriés dans le tableau précédent.

  4. Récupérez l'ID de la tâche Dataflow en cours d'exécution :

    JOB_ID=$(gcloud dataflow jobs list --filter "name:${JOB_NAME}" --format "value(id)" --status active)
    
  5. Affichez l'URL de la page Web de la tâche Dataflow :

    echo "https://console.cloud.google.com/dataflow/jobs/${REGION}/${JOB_ID}"
    
  6. Ouvrez l'URL dans un nouvel onglet de navigateur. Après quelques secondes, le graphique de la tâche Dataflow s'affiche :

    Schéma du workflow pour la tâche Dataflow.

    Le pipeline Dataflow est maintenant en cours d'exécution et attend de recevoir des notifications d'entrée de Pub/Sub.

  7. Dans Cloud Shell, déclenchez le pipeline Dataflow en important quelques fichiers de test dans le bucket d'entrée :

    gsutil cp gs://df-vision-ai-test-data/bali.jpeg gs://${IMAGE_BUCKET}
    gsutil cp gs://df-vision-ai-test-data/faces.jpeg gs://${IMAGE_BUCKET}
    gsutil cp gs://df-vision-ai-test-data/bubble.jpeg gs://${IMAGE_BUCKET}
    gsutil cp gs://df-vision-ai-test-data/setagaya.jpeg gs://${IMAGE_BUCKET}
    gsutil cp gs://df-vision-ai-test-data/st_basils.jpeg gs://${IMAGE_BUCKET}
    
  8. Dans Google Cloud Console, examinez les compteurs personnalisés dans Dataflow (dans le panneau de droite de la tâche Dataflow) et vérifiez qu'ils ont traité les cinq images :

    Liste des images renvoyées par l'importation de fichier.

  9. Dans Cloud Shell, vérifiez que les tables ont été créées automatiquement :

    bq query "select table_name, table_type from \
    ${BIGQUERY_DATASET}.INFORMATION_SCHEMA.TABLES"
    

    Voici le résultat :

    +----------------------+------------+
    |      table_name      | table_type |
    +----------------------+------------+
    | face_annotation      | BASE TABLE |
    | label_annotation     | BASE TABLE |
    | crop_hint_annotation | BASE TABLE |
    | landmark_annotation  | BASE TABLE |
    | image_properties     | BASE TABLE |
    +----------------------+------------+
    
  10. Affichez le schéma de la table landmark_annotation. Sur demande, la fonctionnalité LANDMARK_DETECTION capture les attributs renvoyés par l'appel d'API.

    bq show --schema --format=prettyjson ${BIGQUERY_DATASET}.landmark_annotation
    

    Voici le résultat :

    [
      {
        "mode": "REQUIRED",
        "name": "gcs_uri",
        "type": "STRING"
      },
      {
        "mode": "NULLABLE",
        "name": "mid",
        "type": "STRING"
      },
      {
        "mode": "REQUIRED",
        "name": "description",
        "type": "STRING"
      },
      {
        "mode": "REQUIRED",
        "name": "score",
        "type": "FLOAT"
      },
      {
        "fields": [
          {
            "fields": [
              {
                "mode": "REQUIRED",
                "name": "x",
                "type": "FLOAT"
              },
              {
                "mode": "REQUIRED",
                "name": "y",
                "type": "FLOAT"
              }
            ],
            "mode": "REPEATED",
            "name": "vertices",
            "type": "RECORD"
          }
        ],
        "mode": "NULLABLE",
        "name": "bounding_poly",
        "type": "RECORD"
      },
      {
        "mode": "REPEATED",
        "name": "locations",
        "type": "GEOGRAPHY"
      },
      {
        "mode": "REQUIRED",
        "name": "transaction_timestamp",
        "type": "TIMESTAMP"
      }
    ]
    
  11. Arrêtez le pipeline :

    gcloud dataflow jobs drain ${JOB_ID} \
    --region ${REGION}
    

    Bien qu'il n'y ait plus d'autres notifications Pub/Sub à traiter, le pipeline de streaming que vous avez créé continue de s'exécuter jusqu'à ce que vous saisissiez cette commande.

Analyser un ensemble de données Flickr30K

Dans cette section, vous allez analyser un ensemble de données Flickr30K pour la détection de libellés et de points de repère.

  1. Dans Cloud Shell, définissez un nouveau nom de tâche :

    export JOB_NAME=vision-analytics-pipeline-2
    
  2. Modifiez les paramètres du pipeline Dataflow afin qu'ils soient optimisés pour un grand ensemble de données. Les valeurs batchSize et keyRange sont augmentées pour permettre un débit supérieur. Dataflow adaptera le nombre de nœuds de calcul en fonction des besoins :

    cat <<EOF > ${PARAMETERS}
    --parameters:
      autoscalingAlgorithm: THROUGHPUT_BASED
      enableStreamingEngine: "true"
      subscriberId: projects/${PROJECT}/subscriptions/${GCS_NOTIFICATION_SUBSCRIPTION}
      visionApiProjectId: ${PROJECT}
      features: LABEL_DETECTION,LANDMARK_DETECTION
      datasetName: ${BIGQUERY_DATASET}
      batchSize: "16"
      windowInterval: "5"
      keyRange: "2"
    EOF
    
  3. Exécutez le pipeline :

    gcloud dataflow flex-template run ${JOB_NAME} \
    --project=${PROJECT} \
    --region=${REGION} \
    --template-file-gcs-location=gs://${DATAFLOW_TEMPLATE_BUCKET}/dynamic_template_vision_analytics.json \
    --flags-file ${PARAMETERS}
    
  4. Importez l'ensemble de données dans un bucket d'entrée :

    gsutil -m  cp gs://df-vision-ai-test-data/*  gs://${IMAGE_BUCKET}
    
  5. Récupérez l'ID de la tâche Dataflow en cours d'exécution :

    JOB_ID=$(gcloud dataflow jobs list --filter "name:${JOB_NAME}" --region ${REGION} --format "value(id)" --status active)
    
  6. Affichez l'URL de la page Web de la tâche Dataflow :

    echo "https://console.cloud.google.com/dataflow/jobs/${REGION}/${JOB_ID}"
    
  7. Ouvrez l'URL dans un nouvel onglet de navigateur.

  8. Dans Google Cloud Console, validez les compteurs personnalisés dans Dataflow pour vous assurer que tous les fichiers sont traités. Tous les fichiers sont généralement traités en moins de 30 minutes.

  9. Filtrez par compteurs personnalisés sous Traiter les annotations.

    Voici le résultat :

    Liste des compteurs renvoyés après le filtrage par compteurs personnalisés. Affiche le nom du compteur, la valeur et l'étape.

    La métrique processedFiles (31 935) correspond au nombre total d'images importées dans le bucket (nombre total de fichiers : 31 936). Cependant, la métrique numberOfRequests (1 997) est inférieure au nombre de fichiers ayant été traités dans le pipeline. Cette différence est due au fait que le pipeline regroupe jusqu'à 16 fichiers par requête, comme indiqué dans les valeurs des métriques batchSizeDistribution_*.

  10. Arrêtez le pipeline :

    JOB_ID=$(gcloud dataflow jobs list --filter "name:${JOB_NAME}"
    --region ${REGION}
    --format "value(id)"
    --status active) \
    gcloud dataflow jobs drain ${JOB_ID} \
    --region ${REGION}
    
  11. Dans la console Google Cloud, accédez à la page Éditeur de requête de BigQuery.

    Accéder à l'éditeur de requête

  12. Trouvez le libellé le plus probable pour chaque fichier :

    SELECT
      SPLIT(gcs_uri,'/')[OFFSET(3)] file,
      description,
      score
    FROM (
      SELECT
        gcs_uri,
        description,
        score,
        ROW_NUMBER() OVER (PARTITION BY gcs_uri ORDER BY score DESC )
    AS row_num
      FROM
         `vision_analytics.label_annotation`)
    WHERE
      row_num = 1
    ORDER BY
      gcs_uri DESC
    

    Voici le résultat : Vous pouvez voir dans la réponse que le point de repère est la description la plus probable pour le fichier st_basils.jpeg.

    Liste des noms, descriptions et scores de fichier image.

  13. Trouvez les 10 meilleurs libellés et leur score maximal :

    SELECT
      description,
      COUNT(*) AS found,
      MAX(score) AS max_score
    FROM
      `vision_analytics.label_annotation`
    GROUP BY
      description
    ORDER BY
      found DESC
    LIMIT 10
    

    La sortie ressemble à ceci :

    Liste des 10 principaux libellés trouvés. Elle inclut la description, le nombre d'occurrences et un score maximal.

  14. Trouvez les 10 points de repère les plus populaires :

    SELECT
      description,
      COUNT(*) AS count,
      MAX(score) AS max_score
    FROM
      `vision_analytics.landmark_annotation`
    WHERE
      LENGTH(description)>0
    GROUP BY
      description
    ORDER BY
      count DESC
    LIMIT 10
    

    Voici le résultat : Vous pouvez voir dans la réponse que Times Square est la destination la plus populaire.

    Liste des 10 principaux points de repère renvoyés par la requête. Inclut la description, le nombre et le score maximal.

  15. Trouvez n'importe quelle image comportant une cascade :

    SELECT
      SPLIT(gcs_uri,'/')[OFFSET(3)] file,
      description,
      score
    FROM
      `vision_analytics.landmark_annotation`
    WHERE
      LOWER(description) LIKE '%fall%'
    ORDER BY score DESC
    

    Voici le résultat : Il ne contient que des images de cascades.

    Liste des cascades. Inclut le nom du fichier, sa description et son score.

  16. Trouvez une image d'un monument emblématique dans un rayon de 3 kilomètres du Colisée à Rome (la fonction ST_GEOPOINT utilise la longitude et la latitude du Colisée) :

    WITH
      landmarksWithDistances AS (
      SELECT
        gcs_uri,
        description,
        location,
        ST_DISTANCE(location,
          ST_GEOGPOINT(12.492231,
            41.890222)) distance_in_meters,
      FROM
        `vision_analytics.landmark_annotation` landmarks
      CROSS JOIN
        UNNEST(landmarks.locations) AS location )
    SELECT
      SPLIT(gcs_uri,"/")[OFFSET(3)] file,
      description,
        ROUND(distance_in_meters) distance_in_meters,
      location,
      CONCAT("https://storage.cloud.google.com/", SUBSTR(gcs_uri, 6)) AS image_url
    FROM
      landmarksWithDistances
    WHERE
      distance_in_meters < 3000
    ORDER BY
      distance_in_meters
    LIMIT
      100
    

    Voici le résultat : Vous pouvez voir que plusieurs destinations populaires apparaissent dans ces images :

    Liste de toutes les images dans un rayon de 3 km du Colisée à Rome. Inclut le nom du fichier, sa description, la distance en mètres du Colisée et l'emplacement.

    La même image peut contenir plusieurs emplacements du même point de repère. Cette fonctionnalité est décrite dans la documentation de l'API Vision. Étant donné qu'un emplacement peut indiquer le lieu de la scène dans l'image, plusieurs éléments LocationInfo peuvent être présents. Un autre emplacement peut indiquer le lieu où l'image a été prise. Des informations concernant la localisation sont généralement disponibles pour les points de repère.

    Vous pouvez visualiser les données dans BigQuery Geo Viz en collant la requête précédente. Lorsque vous sélectionnez un point sur la carte, les détails associés s'affichent. L'attribut Image_url contient le lien vers le fichier image, que vous pouvez ouvrir dans un navigateur.

    Carte des lieux et distance depuis le Colisée.

Nettoyer

Pour éviter que les ressources utilisées lors de ce tutoriel soient facturées sur votre compte Google Cloud, supprimez le projet contenant les ressources, ou conservez le projet et supprimez les ressources individuelles.

Supprimer le projet Google Cloud

Le moyen le plus simple d'éviter la facturation consiste à supprimer le projet Google Cloud que vous avez créé pour le tutoriel.

  1. Dans la console Google Cloud, accédez à la page Gérer les ressources.

    Accéder à la page Gérer les ressources

  2. Dans la liste des projets, sélectionnez le projet que vous souhaitez supprimer, puis cliquez sur Supprimer.
  3. Dans la boîte de dialogue, saisissez l'ID du projet, puis cliquez sur Arrêter pour supprimer le projet.

Étapes suivantes