코딩/알파프로젝트

google AutoML Vision fastapi 연동

cinnamon-lol 2024. 9. 12. 00:42
반응형

  이번 학기 알파프로젝트를 진행하게 되면서 이미지 분석이라는 문제에 마주했다. 프로젝트 내용은 재활용품을 인식해서 적절한 처리 방법을 알려주는 앱으로 쓰레기의 사진을 찍게 되면 해당 사진을 분석해 어떤 물품인지(PP, PE, PS 등등) 판단해야 됬다.

  처음엔 단순히 open ai의 vision을 사용하려 하였으나 우리는 단순히 큰 분류로 분류를 하려는게 아닌 플라스틱 내에서도 PP, PE, PS등을 분류하고 싶어서 더 좋은 모델이 필요했다.

  또한 google 의 Teachable Machine 을 사용해서 우리가 직접 라벨링을 통해서 학습 모델을 만들 수도 있었다. 하지만 학습이 완료된 모델(keras) 를 fastapi에 연동하려 하였으나 tensorflow의 버전문제인지 아니면 python의 설정 문제인지는 모르겠지만 모델 내의 colume을 인식 못하는 문제가 발생하기도 하고, 실제로 학습데이터를 많이 사용하지 못하는 문제가 발생해서 해당 방법도 포기하게 되었다.

google AutoML Vision

  그러던 중 찾은 또 다른 방식이 있는데 바로 GCP(google cloud platform)에서 제공하는 서비스인 AutoML 이다. 

https://cloud.google.com/automl?hl=ko

 

https://cloud.google.com/automl?hl=ko

 

cloud.google.com

  해당 방식이 괜찮다고 느낀 점이 먼저 파인튜닝 모델로 우리는 기존에 좋은 성능으로 만들어져 있던 모델을 간단한 추가 학습만을 통해서 우리에게 필요한 모델로 만들 수 있었다. 또한 우리는 이렇게 학습된 모델들을 클라이언트에서 돌리기 보다는 서버에서 처리하고 그에 대한 응답만 보내 클라이언트의 부담을 줄이고 싶었다. 이를 위해서 해당 모델을 rest api 서버에 쉽게 적용할 수 있어야 되었는데, 이 부분에 대해서는 확신할 수 없었지만 뭔가 되지 않을까?? 라는 생각이 들어서 진행하게 되었다. 또한 AutoML Docs를 통해서 쉽게 가르쳐주었기 때문에 쉽게 작업할 수 있을거 같다는 근자감이 마구마구 생겨나기 시작했다.

 

데이터 수집

데이터는 쉽게 구할 수 있었다. AiHub를 가보니 쉽게 재활용 데이터들을 몇백 기가씩 찾을 수 있었고 이를 활용하기로 했다.

 

AutoML

[나중에 작업하면서 다시 정리]

FastApi

  먼저 마주친 문제들이 몇몇가지 있었다. 먼저 GCP에서 제공해준 기본 코드는 이미지 파일을 서버내에 저장되어 있는 이미지를 가져왔기 때문에 이를 aws의 s3에서 가져올수 있도록 수정해야 됬다. 그리고 gcp와 aws의 인증 문제에 대해서 환경 설정을 하는 과정에서도 애를 많이 먹었다.

virtualenv 및 FastApi 설정

  GCP docs에서 기존에 설치되어 있는 python과 충돌을 방지하려고 가상환경에서 진행하는 것을 권장한다. 

pip install virtualenv
virtualenv <your-env>
source <your-env>/bin/activate
<your-env>/bin/pip install google-cloud-aiplatform

이후 가상환경에서 python 작업을 하면 된다. 가상환경에서 나갈때는 deactivate 를 입력하면 된다.

FastApi 설치와 같은 경우에는 다음 명령어를 사용하면 FastApi와 uvicorn등 실행에 필요한 기본적인 것들을 모두 설치해준다

pip3 install "fastapi[all]"

GCP credential

  먼저 환경 설정부분에서 우리는 GCP의 credential과 AWS S3의 credential 문제를 해결해야 됬는데 이는 쉽게 해결했다. GCP의 경우에는 IAM-서비스 계정 에 들어가게 되면 현재 진행중인 프로젝트들이 나와있다.


그리고 프로젝트-서비스계정-키-새 키 만들기 과정을 통해 JSON형식의 키를 얻게 된다. 이렇게 획득한 키를 서버내에 환경변수로 저장해주게 되면 AutoML실행시 자동으로 해당 환경 변수를 인식에서 인증이 완료 되게 된다.

export GOOGLE_APPLICATION_CREDENTIALS="/Users/username/image-analyze/fair-scout-435211-i5-273fbace65b5.json "

AWS credential

  AWS 인증이 필요한 이유는 먼저 인증이 필요한 이미지를 S3에 저장하고 FastApi에서 해당 S3이미지를 사용할 것이기 때문에 S3에 접근할 수 있는 권한이 있는 유저가 필요하다.

  해당 부분에 대해서는 기존에 사용하고 있던 AWS에서 S3FULLACCESS 권한을 가지고 있는 유저가 있기 때문에 해당 방식을 사용했다. 다음에 기회가 있으면 정리하는걸루,,ㅎㅎ. 이렇게 GCP와 동일하게 해당 key값을 환경변수로 설정하게 되면 AWS 인증도 끝이다.

export AWS_ACCESS_KEY_ID=your_access_key
export AWS_SECRET_ACCESS_KEY=your_secret_key
export AWS_DEFAULT_REGION=your_region

 

S3 접근

  FastApi, 즉 python에서 S3에 접근하기 위해서는 boto3 라는 라이브러리를 사용했다. 해당 라이브러리를 사용하기 위해서 AWS인증이 필요하지만 위에서 인증을 완료했기 때문에 코드만 작성하면 끝난다.

  코드 자체는 매우 간단하다

def read_file_from_s3():
    bucket_name = "busan-image-bucket"
    object_key = "profileImage/5a3e59ed-fb6e-49ab-bdd1-ea7bc55e462e.png"
    s3 = boto3.client('s3')
    response = s3.get_object(Bucket=bucket_name, Key=object_key)
    file_content = response['Body'].read()
    return file_content

  S3의 bucket 이름과 불러오려는 이미지의 리소스 주소를 입력해주면 원하는 이미지를 base64로 인코딩된 데이터로 받게 된다. 나는 먼저 이미지가 제대로 받아와지는지 테스트 하기 위해서 StreamingResponse를 사용해서 받아온 base64데이터를 image로 변환해서 응답하는 간단한 controller 를 만들었고 실제로 잘 동작하는 것을 확인할 수 있었다.

  이제 AutoML의 코드를 FastApi에 가져와서 수정하게 되면 다음과 같은 코드가 나온다.

 

# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# [START aiplatform_predict_image_classification_sample]
import base64

from google.cloud import aiplatform
from google.cloud.aiplatform.gapic.schema import predict


def predict_image_classification_sample(
    project: str,
    endpoint_id: str,
    filename: str,
    location: str = "us-central1",
    api_endpoint: str = "us-central1-aiplatform.googleapis.com",
):
    # The AI Platform services require regional API endpoints.
    client_options = {"api_endpoint": api_endpoint}
    # Initialize client that will be used to create and send requests.
    # This client only needs to be created once, and can be reused for multiple requests.
    client = aiplatform.gapic.PredictionServiceClient(client_options=client_options)
    # with open(filename, "rb") as f:
    #     file_content = f.read()

    # 커스텀한 부분
    file_content = read_file_from_s3()

    # The format of each instance should conform to the deployed model's prediction input schema.
    encoded_content = base64.b64encode(file_content).decode("utf-8")
    instance = predict.instance.ImageClassificationPredictionInstance(
        content=encoded_content,
    ).to_value()
    instances = [instance]
    # See gs://google-cloud-aiplatform/schema/predict/params/image_classification_1.0.0.yaml for the format of the parameters.
    parameters = predict.params.ImageClassificationPredictionParams(
        confidence_threshold=0.5,
        max_predictions=5,
    ).to_value()
    endpoint = client.endpoint_path(
        project=project, location=location, endpoint=endpoint_id
    )
    response = client.predict(
        endpoint=endpoint, instances=instances, parameters=parameters
    )
    print("response")
    print(" deployed_model_id:", response.deployed_model_id)
    # See gs://google-cloud-aiplatform/schema/predict/prediction/image_classification_1.0.0.yaml for the format of the predictions.
    predictions = response.predictions
    for prediction in predictions:
        print(" prediction:", dict(prediction))
    # return predictions


# [END aiplatform_predict_image_classification_sample]

from fastapi.responses import StreamingResponse
from fastapi import FastAPI
import boto3
import io
from io import BytesIO


def read_file_from_s3():
    bucket_name = "bucket_name"
    object_key = "object_key"
    s3 = boto3.client('s3')
    response = s3.get_object(Bucket=bucket_name, Key=object_key)
    file_content = response['Body'].read()
    return file_content


app = FastAPI()

@app.get("/")
def root():
    return {"message": "Hello World"}

@app.get("/image/{imageUrl}")
def imageAnalyze(imageUrl: str):
    return predict_image_classification_sample(
    project="project_id",
    endpoint_id="endpoint_id",
    location="us-central1",
    filename=imageUrl
    )
    # return {"message": imageUrl}

@app.get("/image")
def getImage():
    image_data = read_file_from_s3()
    return StreamingResponse(BytesIO(image_data), media_type="image/png")

결과

임의의 사진 데이터를 사용해보면 PE타입의 쓰레기임을 나타내는 것을 알 수 있다.

 

생각해볼점

  만족하기는 했지만, 생각해볼 점이 좀 많이 있는거 같다. 먼저 아무 사진을 찍더라도 우리가 라벨링한 값중 하나를 응답하기 때문에 쓰레기가 아닌 사진을 찍어도 재활용 라벨이 나오게 된다. 여기서 이제 쓰레기 인지 아닌지 먼저 파악을 해야될거 같은데 해당 방법은 나중에 생각하기로 한다. :)

  또한 분석 시간이 조금 걸린다는 점인데 응답까지 5~10초 정도 걸린다. 이 부분에 대해서 우리가 할 수 있는게 뭐가 있을까? 잘 모르겠다...

  마지막으로 비용이 너무 비싸다. 대충 학습 1시간에 배포 11시간쯤 돌린거 같은데 크레딧를 5만원이나 사용했다. 이대로면 3일이면 크레딧 다쓸거 같은데 ㅠ

반응형

'코딩 > 알파프로젝트' 카테고리의 다른 글

S3 preSigned url  (1) 2024.11.08
minIO S3  (0) 2024.11.07
spring boot, google sheets 자동화  (1) 2024.09.27