Dataflow 및 Cloud Vision API를 사용한 ML 비전 분석 솔루션 빌드

Last reviewed 2024-04-16 UTC

이 튜토리얼에서는 Cloud Vision으로 대규모 이미지 파일을 처리하기 위해 Dataflow 파이프라인을 배포하는 방법을 설명합니다. Dataflow는 BigQuery ML 기본 제공 모델을 학습시키는 데 결과를 사용할 수 있도록 결과를 BigQuery에 저장합니다.

튜토리얼에서 만드는 Dataflow 파이프라인은 대규모 이미지를 처리할 수 있습니다. Vision 할당량으로만 제한됩니다. 확장 요구사항에 따라 Vision 할당량을 늘릴 수 있습니다.

이 튜토리얼은 데이터 엔지니어와 데이터 과학자를 대상으로 하며, Apache Beam의 자바 SDK, BigQuery 표준 SQL, 기본 셸 스크립팅을 사용한 Dataflow 파이프라인 빌드에 대한 기본 지식이 있다고 가정합니다. 또한 Vision에 익숙하다고 가정합니다.

목표

  • Cloud Storage용 Pub/Sub 알림으로 이미지 메타데이터 수집 파이프라인을 만듭니다.
  • Dataflow를 사용하여 실시간 비전 분석 파이프라인을 배포합니다.
  • Vision을 사용하여 기능 유형 집합에 대해 이미지를 분석합니다.
  • BigQuery ML을 사용하여 데이터를 분석하고 학습시킵니다.

비용

이 문서에서는 비용이 청구될 수 있는 다음과 같은 Google Cloud 구성요소를 사용합니다.

프로젝트 사용량을 기준으로 예상 비용을 산출하려면 가격 계산기를 사용하세요. Google Cloud를 처음 사용하는 사용자는 무료 체험판을 사용할 수 있습니다.

이 문서에 설명된 태스크를 완료했으면 만든 리소스를 삭제하여 청구가 계속되는 것을 방지할 수 있습니다. 자세한 내용은 삭제를 참조하세요.

시작하기 전에

  1. Google Cloud Console의 프로젝트 선택기 페이지에서 Google Cloud 프로젝트를 선택하거나 만듭니다.

    프로젝트 선택기로 이동

  2. Google Cloud 프로젝트에 결제가 사용 설정되어 있는지 확인합니다.

  3. Google Cloud 콘솔에서 Cloud Shell을 활성화합니다.

    Cloud Shell 활성화

  4. Cloud Shell에서 Dataflow, Container Registry, Vision API를 사용 설정합니다.

    gcloud services enable dataflow.googleapis.com \
    containerregistry.googleapis.com vision.googleapis.com
    
  5. 몇 가지 환경 변수를 설정합니다. (REGION사용 가능한 Dataflow 리전 중 하나로 대체. 예: us-central1).

    export PROJECT=$(gcloud config get-value project)
    export REGION=REGION
    
  6. 튜토리얼의 Git 저장소를 클론합니다.

    git clone https://github.com/GoogleCloudPlatform/dataflow-vision-analytics.git
    
  7. 저장소의 루트 폴더로 이동합니다.

    cd dataflow-vision-analytics
    

참조 아키텍처

다음 다이어그램은 이 튜토리얼에서 빌드한 시스템의 흐름을 보여줍니다.

수집/트리거, 프로세스, 저장에 대한 정보 흐름을 보여주는 워크플로 다이어그램

다이어그램에서 표시된 것처럼 흐름은 다음과 같습니다.

  1. 클라이언트가 이미지 파일을 Cloud Storage 버킷에 업로드합니다.

  2. 파일이 업로드될 때마다 시스템에서 자동으로 메시지를 Pub/Sub에 게시하여 클라이언트에 알립니다.

  3. Dataflow 파이프라인에서는 새 알림마다 다음을 수행합니다.

    1. Pub/Sub 메시지에서 파일 메타데이터를 읽습니다.
    2. 주석 처리를 위해 각 세그먼트를 Vision API로 보냅니다.
    3. 추가 분석을 위해 모든 주석을 BigQuery 테이블에 저장합니다.

Cloud Storage용 Pub/Sub 알림 만들기

이 섹션에서는 Cloud Storage용 Pub/Sub 알림을 만듭니다. 이 알림은 버킷에 업로드된 이미지 파일의 메타데이터를 게시합니다. 메타데이터를 기준으로 Dataflow 파이프라인은 요청 처리를 시작합니다.

  1. Cloud Shell에서 Pub/Sub 주제를 만듭니다.

    export GCS_NOTIFICATION_TOPIC="gcs-notification-topic"
    gcloud pubsub topics create ${GCS_NOTIFICATION_TOPIC}
    
  2. 주제의 Pub/Sub 구독을 만듭니다.

    export  GCS_NOTIFICATION_SUBSCRIPTION="gcs-notification-subscription"
    gcloud pubsub subscriptions create  ${GCS_NOTIFICATION_SUBSCRIPTION}  --topic=${GCS_NOTIFICATION_TOPIC}
    
  3. 입력 이미지 파일을 저장할 버킷을 만듭니다.

    export IMAGE_BUCKET=${PROJECT}-images
    gsutil mb -c standard -l ${REGION} gs://${IMAGE_BUCKET}
    
  4. 버킷용 Pub/Sub 알림을 만듭니다.

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

알림을 구성했으므로 시스템에서 사용자가 만든 주제로 Pub/Sub 메시지를 보냅니다. 이 작업은 버킷에 파일을 업로드할 때마다 수행됩니다.

BigQuery 데이터 세트 만들기

이 섹션에서는 BigQuery 데이터 세트를 만들어 Dataflow 파이프라인의 결과 출력을 저장합니다. 파이프라인은 비전 기능 유형에 따라 테이블을 자동으로 만듭니다.

  • Cloud Shell에서 BigQuery 데이터 세트를 만듭니다.

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

Dataflow Flex 템플릿 만들기

이 섹션에서는 Apache Beam 파이프라인 코드를 만든 후 Dataflow Flex 템플릿을 사용하여 Dataflow 파이프라인을 Dataflow 작업으로 실행합니다.

  1. Cloud Shell에서 Apache Beam 파이프라인 코드를 빌드합니다.

    gradle build
    
  2. Dataflow Flex 템플릿용 Docker 이미지를 만듭니다.

    gcloud auth configure-docker
    gradle jib \
      --image=gcr.io/${PROJECT}/dataflow-vision-analytics:latest
    
  3. Dataflow Flex 템플릿을 저장할 Cloud Storage 버킷을 만듭니다.

    export DATAFLOW_TEMPLATE_BUCKET=${PROJECT}-dataflow-template-config
    gsutil mb -c standard -l ${REGION} \
      gs://${DATAFLOW_TEMPLATE_BUCKET}
    
  4. 템플릿의 JSON 구성 파일을 버킷에 업로드합니다.

    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
    

Vision 기능 집합을 위한 Dataflow 파이프라인 실행

다음 표에 나열된 매개변수는 이 Dataflow 파이프라인에 해당됩니다.

표준 Dataflow 실행 매개변수의 전체 목록은 Dataflow 문서를 참조하세요.

매개변수 설명

windowInterval

결과를 BigQuery와 Pub/Sub로 출력하는 시간 간격(초)입니다. 기본값은 5입니다.

batchSize

Vision API에 대한 요청에 포함할 이미지 수입니다. 기본값은 1입니다. 최대 16으로 늘릴 수 있습니다.

subscriberId

입력 Cloud Storage 알림을 수신하는 Pub/Sub 구독의 ID입니다.

keyRange

대규모 데이터 세트의 처리 성능을 개선할 수 있는 매개변수입니다. 값이 클수록 작업자 간에 동시 로드가 증가합니다. 기본값은 1입니다.

visionApiProjectId

Vision API에 사용할 프로젝트 ID입니다.

datasetName

출력 BigQuery 데이터 세트의 참조입니다.

features

이미지 처리 기능의 목록입니다.

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

다양한 주석을 위한 테이블 이름이 있는 문자열 매개변수 각 테이블에 기본값이 제공됩니다.
  1. Cloud Shell에서 Dataflow 파이프라인의 작업 이름을 정의합니다.

    export JOB_NAME=vision-analytics-pipeline-1
    
  2. 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. Dataflow 파이프라인을 실행하여 다음 기능 유형에 대해 이미지를 처리합니다. 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}
    

    이 명령어는 위 표에 나열된 매개변수를 사용합니다.

  4. 실행 중인 Dataflow 작업의 ID를 검색합니다.

    JOB_ID=$(gcloud dataflow jobs list --filter "name:${JOB_NAME}" --format "value(id)" --status active)
    
  5. Dataflow 작업의 웹 페이지 URL을 표시합니다.

    echo "https://console.cloud.google.com/dataflow/jobs/${REGION}/${JOB_ID}"
    
  6. 새 브라우저 탭에서 표시된 URL을 엽니다. 몇 초 후 Dataflow 작업의 그래프가 표시됩니다.

    Dataflow 작업의 워크플로 다이어그램

    이제 Dataflow 파이프라인이 실행되며 Pub/Sub에서 입력 알림 수신을 기다리는 중입니다.

  7. Cloud Shell에서 일부 테스트 파일을 입력 버킷에 업로드하여 Dataflow 파이프라인을 트리거합니다.

    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. Google Cloud Console에서 Dataflow(Dataflow 작업의 오른쪽 패널)의 커스텀 카운터를 검토하고 5개의 이미지를 모두 처리했는지 확인합니다.

    파일 업로드에서 반환된 이미지 목록입니다.

  9. Cloud Shell에서 테이블이 자동으로 생성되었는지 확인합니다.

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

    출력은 다음과 같습니다.

    +----------------------+------------+
    |      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. landmark_annotation 테이블의 스키마를 봅니다. 요청된 경우 LANDMARK_DETECTION 기능은 API 호출에서 반환된 속성을 캡처합니다.

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

    출력은 다음과 같습니다.

    [
      {
        "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. 파이프라인을 중지합니다.

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

    더 이상 처리할 Pub/Sub 알림이 없지만 사용자가 생성한 스트리밍 파이프라인은 이 명령어를 입력할 때까지 계속 실행됩니다.

Flickr30K 데이터 세트 분석

이 섹션에서는 flickr30K 데이터 세트를 분석하여 라벨 및 랜드마크 인식을 수행합니다.

  1. Cloud Shell에서 새 작업 이름을 정의합니다.

    export JOB_NAME=vision-analytics-pipeline-2
    
  2. 큰 데이터 세트에 대해 최적화되도록 Dataflow 파이프라인 매개변수를 변경합니다. 높은 처리량을 허용하기 위해 batchSizekeyRange가 늘어납니다. Dataflow는 필요에 따라 작업자 수를 조정합니다.

    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. 파이프라인을 실행합니다.

    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. 데이터 세트를 입력 버킷에 업로드합니다.

    gsutil -m  cp gs://df-vision-ai-test-data/*  gs://${IMAGE_BUCKET}
    
  5. 실행 중인 Dataflow 작업의 ID를 검색합니다.

    JOB_ID=$(gcloud dataflow jobs list --filter "name:${JOB_NAME}" --region ${REGION} --format "value(id)" --status active)
    
  6. Dataflow 작업의 웹 페이지 URL을 표시합니다.

    echo "https://console.cloud.google.com/dataflow/jobs/${REGION}/${JOB_ID}"
    
  7. 새 브라우저 탭에서 표시된 URL을 엽니다.

  8. Google Cloud Console에서 Dataflow의 커스텀 카운터를 검토하여 모든 파일이 처리되었는지 확인합니다. 모든 파일은 일반적으로 30분 이내에 처리됩니다.

  9. 처리 주석에서 커스텀 카운터로 필터링합니다.

    출력은 다음과 같습니다.

    커스텀 카운터로 필터링한 후에 반환된 카운터 목록입니다. 카운터 이름, 값, 단계를 보여줍니다.

    processedFiles 측정항목(31,935)은 버킷에 업로드된 총 이미지 수와 일치합니다(총 파일 수는 31,936). 하지만 numberOfRequests 측정항목(1,997)은 파이프라인을 통해 진행된 파일 수보다 적습니다. 이러한 차이는 파이프라인이 batchSizeDistribution_* 측정항목의 값에 표시된 대로 요청당 최대 16개의 파일을 일괄 처리하기 때문입니다.

  10. 파이프라인을 종료합니다.

    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. Google Cloud 콘솔에서 BigQuery 쿼리 편집기 페이지로 이동합니다.

    쿼리 편집기로 이동

  12. 각 파일에서 가장 가능성이 높은 라벨을 찾습니다.

    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
    

    출력은 다음과 같습니다. 응답을 통해 Landmark(랜드마크)가 st_basils.jpeg 가장 가능성 높은 파일의 설명임을 알 수 있습니다.

    이미지 파일 이름, 설명, 점수의 목록

  13. 상위 10개의 라벨과 해당 라벨의 최대 점수를 찾습니다.

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

    최종 결과는 다음과 유사합니다.

    발견된 상위 10개 라벨 목록입니다. 여기에는 설명, 발견된 횟수, 최대 점수가 포함됩니다.

  14. 상위 10개의 랜드마크를 찾습니다.

    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
    

    출력은 다음과 같습니다. 응답을 통해 타임즈 스퀘어가 가장 인기 있는 목적지임을 알 수 있습니다.

    쿼리로 반환된 가장 인기 있는 상위 10개 랜드마크의 목록입니다. 설명, 개수, 최대 점수가 포함됩니다.

  15. 폭포가 있는 이미지를 찾습니다.

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

    출력은 다음과 같습니다. 폭포의 이미지만 포함합니다.

    폭포 목록입니다. 파일 이름, 설명, 점수도 포함됩니다.

  16. 로마의 콜로세움에서 3km 이내에 있는 랜드마크의 이미지를 찾습니다(ST_GEOPOINT 함수는 콜로세움의 경도와 위도를 사용).

    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
    

    출력은 다음과 같습니다. 다음 이미지에서는 여러 인기 있는 목적지를 볼 수 있습니다.

    로마의 콜로세움에서 3km 이내의 모든 이미지 목록입니다. 파일 이름, 설명, 콜로세움에서의 거리(미터 단위), 위치가 포함됩니다.

    같은 이미지에 같은 랜드마크의 여러 위치가 포함될 수 있습니다. 이 기능은 Vision API 문서에 설명되어 있습니다. 하나의 위치가 이미지에 나온 현장의 위치를 나타내므로 여러 LocationInfo 요소가 표시될 수 있습니다. 다른 위치는 이미지를 찍은 위치를 나타낼 수 있습니다. 일반적으로 랜드마크의 경우 위치 정보가 표시됩니다.

    이전 쿼리에 붙여넣어 BigQuery Geo Viz의 데이터를 시각화할 수 있습니다. 지도에서 포인트를 선택하면 세부정보가 표시됩니다. Image_url 속성에는 브라우저에서 열 수 있는 이미지 파일의 링크가 포함됩니다.

    위치와 콜로세움에서의 거리가 표시된 지도

삭제

이 가이드에서 사용된 리소스 비용이 Google Cloud 계정에 청구되지 않도록 하려면 리소스가 포함된 프로젝트를 삭제하거나 프로젝트를 유지하고 개별 리소스를 삭제하세요.

Google Cloud 프로젝트 삭제

비용이 청구되지 않도록 하는 가장 쉬운 방법은 튜토리얼에서 만든 Google Cloud 프로젝트를 삭제하는 것입니다.

  1. Google Cloud 콘솔에서 리소스 관리 페이지로 이동합니다.

    리소스 관리로 이동

  2. 프로젝트 목록에서 삭제할 프로젝트를 선택하고 삭제를 클릭합니다.
  3. 대화상자에서 프로젝트 ID를 입력한 후 종료를 클릭하여 프로젝트를 삭제합니다.

다음 단계