본문 바로가기

Google Cloud Blog

BigQuery ML(BQML)로 이미지 분류 모델 개발하기

본 글의 원문은 여기에서 확인하실 수 있습니다.


구조화되지 않은 이미지 데이터를 캡처, 저장 및 분류하는 수많은 사용 사례가 있습니다. 예를 들면 실종자를 찾기 위한 소셜 미디어 분석, 도로 교통 추적을 위한 이미지 분석 또는 전자 상거래 추천을 위한 미디어 분석이 있습니다. 대부분의 조직은 오늘날 생성되는 대부분의 데이터가 매우 비정형이고 데이터 유형 및 형식에 걸친 대규모 분석의 경우 엔터프라이즈 애플리케이션에 대한 몇 가지 제한 요소가 있기 때문에 완전한 데이터 기반이 될 수 없습니다. 1) 데이터 스토리지 및 관리, 2) 인프라 관리 및 3) 데이터 과학 리소스의 가용성. BigQuery의 새로운 구조화되지 않은 데이터 분석 기능을 활용하여, 지금 구조화되지 않은 데이터로 저장, 처리, 분석, 모델링, 예측하고 쿼리에서 구조화 데이터와 결합할 수 있습니다. 무엇보다도 코드 없는 SQL로 이 모든 작업을 수행할 수 있습니다.

이 블로그에서는 BigQuery에서 요가 포즈의 이미지를 저장하고 분석하는 사용 사례에 대해 논의한 다음 BigQuery ML로 분류 모델을 구현하여 SQL 구문만 사용하여 포즈에 레이블을 지정합니다.

 

BigQuery 및 BQML

BigQuery는 운영 오버헤드 없이 바이트에서 페타바이트로 확장할 수 있는 서버리스 멀티 클라우드 데이터 웨어하우스입니다. 따라서 ML 교육 데이터를 저장하는 데 적합합니다. 또한 내장된 BQML(BigQuery Machine Learning) 및 분석 기능을 통해 SQL 쿼리만 사용하여 코드 없이 예측을 생성할 수 있습니다. 또한 통합 쿼리를 사용하여 외부 소스의 데이터에 액세스할 수 있으므로 복잡한 ETL 파이프라인이 필요하지 않습니다. BigQuery가 제공하는 모든 것에 대한 자세한 내용은 빅쿼리 페이지에서 확인할 수 있습니다.

지금까지 우리는 BigQuery를 사용자가 정형 및 반정형 데이터를 분석하는 데 도움이 되는 완전 관리형 클라우드 데이터 웨어하우스로 알고 있습니다. 하지만,

  1. BigQuery는 구조화되지 않은 데이터에 대한 모든 분석 및 ML을 수행하도록 확장되었습니다.
  2. SQL 쿼리를 사용하여 추가 코드를 작성하지 않고도 이미지, 비디오, 오디오 등에 대한 통찰력 있는 분석, 분석 및 ML을 대규모로 수행할 수 있습니다.
  3. 정형 데이터와 비정형 데이터가 모두 하나의 테이블에 함께 존재하는 것처럼 결합할 수 있습니다.

다음 섹션에서 다루는 Yoga Pose Classification 사용 사례에서 이에 대해 논의할 것입니다.

BigQuery ML을 사용한 이미지 데이터 분류

"구조화된" 쿼리와 관련된 이미지 데이터에 대한 최초의 액세스를 통해 이제 BigQuery ML을 사용하는 기계 학습 분류 모델을 사용하여 결과를 예측할 수 있습니다. 이해하기 쉽게 관련 단계를 5단계로 설명합니다.

1. 데이터 세트 및 BigLake 연결 생성

5가지 요가 포즈의 이미지 감지 사용 사례의 경우 공개적으로 사용 가능한 데이터 세트를 사용했으며 데이터 세트, git에서 액세스할 수 있습니다. 우리가 식별하는 요가 포즈는 다운독, 여신, 판자, 나무, 전사2로 제한됩니다.

BigQuery Dataset 생성을 시작하기 전에 Google Cloud 프로젝트를 선택하거나 생성하고 프로젝트에서 결제가 사용 설정되어 있는지 확인하세요. BigQuery API 및 BigQuery 연결 API를 사용 설정합니다.

a. 아래 단계를 사용하여 "yoga_set" 데이터 세트를 만듭니다.

b. BigLake 연결을 사용하면 세분화된 BigQuery 액세스 제어 및 보안을 유지하면서 외부 데이터 소스를 연결할 수 있습니다. 지금은 이미지 데이터용 Cloud Storage입니다. 이 연결을 사용하여 Cloud Storage에서 개체를 읽습니다. BigLake 연결을 생성하려면 아래 단계를 따르십시오.

BigQuery 페이지의 탐색기 창에서 데이터 추가를 클릭합니다.

외부 데이터 소스에 대한 연결을 클릭하고 BigLake 및 원격 기능 옵션을 선택합니다.

연결 이름을 제공하고 연결을 만듭니다. 이 프로세스에서 생성된 서비스 계정 ID를 기록해 두십시오.

2. Cloud Storage 버킷 생성 및 권한 부여

Cloud Storage 버킷을 사용하여 모델을 만들려는 요가 포즈의 이미지 파일을 포함할 것입니다.

a. Cloud Storage Buckets 페이지로 이동하여 CREATE를 클릭합니다.

b. 버킷 생성 페이지에서 버킷 정보를 입력하고 계속 진행합니다. 위 단계에서 설명한 데이터 세트 및 연결과 동일한 리전에 있는지 확인하고 생성합니다.

c. 버킷이 생성되면 이미지를 저장하고(콘솔 또는 Cloud Shell 명령을 통해 또는 프로그래밍 방식으로) 이미지에 액세스하기 위해 연결 서비스 계정(이전에 저장한)에 필요한 권한을 부여합니다.

> export sa="yourServiceAccountId@email.address"
> gsutil iam ch serviceAccount:$sa:objectViewer "gs://<<bucket>>"

3. 객체 테이블 생성

우리가 만든 연결을 사용하여 버킷의 구조화되지 않은 데이터에 액세스하려면 BigQuery에서 외부 개체 테이블을 만듭니다. BigQuery 편집기에서 아래 CREATE SQL을 실행합니다.

CREATE OR REPLACE EXTERNAL TABLE `<<dataset>>.<<table_name>>` 

WITH CONNECTION `us.<<connection-name>>` 

OPTIONS(

object_metadata="SIMPLE", uris=["gs://<<bucket>>/<<folder>>/*.jpg"]);

외부 테이블은 아래와 같이 생성됩니다.

새로 생성된 테이블에서 포즈를 빠르게 쿼리해 보겠습니다.

SELECT data , uri

FROM `yoga_set.yoga_poses` 

WHERE REGEXP_CONTAINS(uri, 'gs://yoga_images/Downdog')

Limit 1;

아래 스크린샷에서 볼 수 있듯이 비정형 이미지를 정형 데이터처럼 생성하고 조작할 수 있습니다.

이제 위의 쿼리 결과를 작은 Python snippet으로 내보내 결과를 시각화해 보겠습니다.

외부 테이블을 만들고 SQL 쿼리만 사용하여 Cloud Storage에서 이미지에 액세스했으므로 분류 모델을 만드는 다음 섹션으로 넘어가겠습니다.

4. 모델 생성 및 Cloud Storage에 업로드

이 구현을 위해 사전 훈련된 ResNet 50 모델을 사용하여 방금 생성한 개체 테이블에서 추론을 실행합니다. ResNet 50 모델은 이미지 파일을 분석하고 이미지가 해당 클래스(로짓)에 속할 가능성을 나타내는 벡터 배치를 출력합니다.

이 단계로 이동하기 전에 필요한 모든 권한이 있는지 확인하십시오. 그런 다음 아래 단계를 따르십시오.

a. 이 위치에서 모델을 다운로드하고 로컬에 저장합니다.
b. 이것은 saved_model.pb 및 변수 폴더로 압축을 풀어야 합니다.
c. 이전 섹션에서 생성한 버킷에 이 두 파일(파일 및 폴더)을 업로드합니다.

이 단계가 완료되면 모델 관련 파일이 위 이미지에 표시된 이미지와 동일한 버킷에 있어야 합니다.

5. 모델을 BQML에 로드하고 추론합니다!

이 단계에서는 앞에서 만든 외부 테이블과 동일한 BigQuery 데이터 세트에 모델을 로드하고 Cloud Storage에 저장한 이미지에 적용합니다.

a. BigQuery 편집기에서 다음 SQL 문을 실행합니다.

CREATE MODEL `<<Dataset>>.<<Model_Name>>`

OPTIONS(

model_type = 'TENSORFLOW',

model_path = 'gs://<<Bucket>>/*');

실행이 완료되면 BigQuery의 데이터세트 섹션에 나열된 모델을 볼 수 있습니다.

b. 모델을 검사하여 입력 및 출력 필드를 확인합니다. 데이터 세트를 확장하고 방금 생성한 "yoga_poses_resnet" 모델을 클릭합니다. 스키마 탭을 클릭합니다.

레이블 섹션에서 출력 필드를 나타내는 "activation_49" 필드를 볼 수 있습니다. 기능 섹션에서 모델에 입력될 것으로 예상되는 필드를 나타내는 "input_1"을 볼 수 있습니다. "테스트" 데이터에 대해 전달하는 필드로 추론 쿼리(또는 예측 쿼리)에서 "input_1"을 참조합니다.

c. 당신의 요가 자세를 추론해보세요!

방금 만든 모델을 사용하여 테스트 이미지 데이터를 분류해 보겠습니다. 외부 테이블을 만들 때 Cloud Storage 버킷에서 식별된 일부 테스트 이미지(요가 포즈)가 있는지 확인하세요. 방금 만든 BQML 모델을 사용하여 추론을 수행하기 위해 BigQuery에서 해당 테스트 이미지를 선택적으로 쿼리할 것입니다. 아래 쿼리를 사용하여 테스트를 트리거합니다.

SELECT * 

FROM ML.PREDICT(

MODEL yoga_set.yoga_poses_resnet,

(SELECT uri, ML.DECODE_IMAGE(data) AS input_1

FROM yoga_set.yoga_poses where REGEXP_CONTAINS(uri,

'gs://yoga_images/Downdog/00000097.jpg')));

위의 쿼리에서 외부 테이블의 특정 URI 값(00000097.jpg)을 포함하는 것으로 식별된 하나의 테스트 이미지를 선택합니다. 또한 SELECT 부분은 ML.PREDICT 함수가 작동하도록 ML.DECODE_IMAGE 구조를 "input_1" 필드로 사용합니다.

실행이 완료되면 아래와 같이 결과가 표시됩니다.

이제 ResNet 모델을 깊이 있게 알고 있는 사람들은 분류를 이해하는 데 도움이 될 것입니다. 그러나 저와 같은 사람들을 위해 분류를 시각적으로 이해하기 위해 작은 snippet을 코딩해 보겠습니다.

d. 결과 병합

위 출력을 시각화하는 한 가지 방법은 BigQuery SQL의 UNNEST 구문을 사용하여 activation_49 필드 값을 flattening하는 것입니다. 이전 단계의 결과를 flattening하려면 아래 쿼리를 참조하세요. 결과 클래스에 텍스트 레이블을 추가로 지정하려는 경우 쿼리에서 자리 표시자 <<LABEL_LOGIC>> 대신 logic을 도입할 수 있습니다(사용 시 주석 해제).

with predictions as (

SELECT

Uri, data, SPLIT(uri, "/")[OFFSET(ARRAY_LENGTH(SPLIT(uri, "/")) - 1)] as img,   

i as label_i,

<<LABEL_LOGIC>> label,

Score

FROM ML.PREDICT(

MODEL yoga_set.yoga_poses_resnet, 

(SELECT data, uri, ML.DECODE_IMAGE(data) AS input_1 

FROM yoga_set.yoga_poses  

WHERE 

REGEXP_CONTAINS(uri,'gs://yoga_images/Goddess/00000007.jpg'))), 

UNNEST(activation_49) as score WITH OFFSET i)

SELECT * FROM predictions  

ORDER BY score DESC

LIMIT  5;

클래스 레이블 지정 logic이 없으면 쿼리에 대한 출력은 다음과 같습니다.

모델을 좀 더 살펴보고 데이터 및 모델 출력에 가장 적합한 logic을 적용할 수 있습니다.

e. 추론 시각화

마지막으로 분류 결과를 시각화하는 빠른 Python snippet입니다! 위 쿼리 결과를 CSV 파일로 내보내고 Python 코드에서 참조합니다.

위의 이미지 출력은 BQML을 사용한 분류를 위해 ML.PREDICT 쿼리에 전달한 테스트 입력과 정확히 동일한 Yoga Pose "Downward Dog"를 나타냅니다!

BigQuery로 정형 및 비정형 통합

마지막으로 이 구현에서 제가 가장 좋아하는 부분은 구조화된 관계형 테이블의 필드를 이 구조화되지 않은 이미지 데이터와 통합하는 것입니다. 포즈와 건강 관련 데이터를 보관하기 위해 외부 테이블과 동일한 데이터세트에 구조화된 BigQuery 테이블을 만들었습니다.

위의 이미지는 "yoga_health"라는 구조화된 데이터 테이블의 스키마를 나타내며 필드는 pose, focus, health_benefit 및 breath입니다. 아래 쿼리는 정형 데이터와 비정형 데이터를 결합합니다.

SELECT SPLIT(uri, "/")[OFFSET(ARRAY_LENGTH(SPLIT(uri, "/")) - 2)] as pose,

a.health_benefit, breath, focus, data 

FROM `abis-345004.yoga_set.yoga_health` a, yoga_set.yoga_poses b 

WHERE a.pose = SPLIT(uri, "/")[OFFSET(ARRAY_LENGTH(SPLIT(uri, "/")) - 2)];

결과는 다음과 같습니다.

메모: 이 블로그에서 다룬 모든 쿼리는 BigQuery Magic 명령을 사용하여 Python Notebook에서 직접 실행할 수 있습니다.

Try it out

우리는 BigQuery에 구조화되지 않은 데이터를 성공적으로 저장하고 쿼리했으며, BQML을 사용하여 분류 모델을 만들고 모델로 테스트 요가 포즈를 예측했습니다. 이를 구현하려면 Google Cloud 프로젝트를 시작하고 Codelab을 실행해보세요.