일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- 네트워크
- git stash
- git 기본명령어
- git init
- CF
- Decision Tree
- enq: FB - contention
- Oracle 논리적 저장 구조
- Collaborative filtering
- 랜덤포레스트
- 리눅스 환경변수
- 배깅
- Oracle ASSM
- BFS
- 통계분석
- eda
- Linux
- 데이터분석
- 추천시스템
- 데이터 분석
- Spark jdbc parallel read
- Spark 튜닝
- 의사결정나무
- 알고리즘
- airflow 정리
- Spark Data Read
- 앙상블
- Python
- SQL
- 오라클 데이터 처리방식
- Today
- Total
[Alex] 데이터 장인의 블로그
[tensorflow] 모든 GPU 사용하여 모델 predict 본문
Tensorflow 모델 트레이닝 방법 중에 모든 gpu를 태워서 '학습(training)' 하는 방법에 대한 내용은 정리가 많이 되어있는 편입니다.
하지만 기존의 만들어진 모델을 각 GPU에 모두 태워서 '예측(predict)' 하는 방법은 거의 정리된 내용이 없어서 제가 겪은 뻘짓과 성공 경험을 정리해두려고 합니다.
분석 환경
AWS GPU instance
Tesla M60 x 4
Memory : 480 G
CPUs : 4 CPU
N of Cores per CPU : 16 cores
목적
- 매일 쌓이는 상품코드에 대한 상품 이미지(url)를 2048 길이로 임베딩하여 저장.
- 많이 등록될 때에는 약 5000개의 상품이 등록되는 경우가 있어, 이를 자동화하여 배치 작업으로 수행할 수 있도록 함.
- 기존의 작업은 Jupyter lab에서 한 커널 당 하나의 GPU를 담당하여 수동으로 임베딩 작업을 거쳤기 때문에 아주 번거롭고 비효율적인 작업.
GPU 할당 방법 예시.
os.environ["CUDA_VISIBLE_DEVICES"] = '3' # 4번째 GPU를 담당하는 Jupyter 커널.
작업을 수행하던 중, 각각 임베딩을 수행하던 커널을 인스턴스화하여 실행하면 어떨까? 생각하였습니다.
Python - 클래스와 인스턴스를 대충 한번 훑어봤던 기억을 더듬으며 아래와 같이 tensorflow, keras 의 xception 임베딩 모델을 GPU를 지정하여 구동할 수 있는 클래스를 만들어봤습니다.
import os
import gc
import pickle
import gzip
import math
from PIL import Image # Pillow, OpenCV, PIL
from io import BytesIO
from socket import timeout
from urllib.request import urlopen
import urllib.parse
import urllib.request
import cx_Oracle
import pandas as pd
import numpy as np
import tensorflow as tf
from tensorflow.python.keras.applications.xception import Xception
from tensorflow.python.keras.layers import GlobalMaxPooling2D
from tensorflow.python.keras.applications.xception import preprocess_input, decode_predictions
class Embed_predictor():
def __init__(self, cuda_divice_num = 1):
os.environ["CUDA_VISIBLE_DEVICES"] = str(cuda_divice_num)
self.vector_shape = (813, 640, 3)
self.model = self.make_embedding_model(self.vector_shape)
def make_embedding_model(self, vector_shape):
base_model = Xception(weights = 'imagenet', # 이미지넷으로 트레이닝 된 모델(Xception)을 불러옴
include_top = False, # 상단의 Fully-connected layer를 포함할 것인지 아닌지 결정
input_shape = vector_shape)
base_model.trainable = False # Feature extraction 파라미터들은 이미지넷으로 학습된 값들을
# 그대로 사용할 것이기 때문에 trainable의 속성을 False로 함
# Add Layer Embedding
xception_model = tf.keras.Sequential([
base_model,
GlobalMaxPooling2D()
])
return xception_model
def load_img_from_url(self, url):
resp = urlopen(url)
im_src = Image.open(BytesIO(resp.read()))
mode = im_src.mode
if mode != 'RGB':
im = im_src.convert('RGB')
else:
im = im_src
img_vector = np.array(im, dtype=np.uint8)
return img_vector, mode
def get_embedding(self, img_name):
img_vector, mode = self.load_img_from_url(img_name)
try:
img_vector = np.expand_dims(img_vector, axis=0)
preprocess_image = preprocess_input(img_vector)
return self.model.predict(preprocess_image).reshape(-1)
except Exception as e:
return np.zeros(2048)
print("e: ", e)
def return_df(self, img_shape_df):
emb_img_list = []
for img_url in img_shape_df['IMAGE']:
img_emb = self.get_embedding(img_url)
emb_img_list.append(img_emb)
lf_img_list = pd.DataFrame(emb_img_list)
img_emb_df = pd.concat([img_shape_df[['PROD_CD', 'IMAGE']], lf_img_list], axis=1)
return img_emb_df
해당 클래스는 인스턴스 생성 시, GPU 번호와 xception 모델을 생성할 수 있도록 하였습니다. 각 인스턴스당 GPU를 파이썬 분산처리 라이브러리 multiprocessing를 활용하여 각각 프로세스 당 하나씩 할당하도록 하였습니다.
Why? - Tensorflow 임베딩 모델 Xception 모델을 만드는 동시에 GPU 메모리를 할당하기 때문에, 각 인스턴스 당 GPU를 지정한 이후에 모델 생성을 수행해야 하였습니다.
[인스턴스 선언(초기화) 시 GPU 할당 및 모델 생성]
def __init__(self, cuda_divice_num = 1):
os.environ["CUDA_VISIBLE_DEVICES"] = str(cuda_divice_num) # GPU 할당
self.vector_shape = (813, 640, 3)
self.model = self.make_embedding_model(self.vector_shape) # xception 모델 생성
해당 클래스를 사용하는 방법은 다음과 같습니다.
테이블 예시.
상품코드 - 이미지 URL
A9030 - https://imageurl.com?A9030
B1203 - https://imageurl.com?B1203
# use multi gpu
from predictor import Embed_predictor
import pandas as pd
import numpy as np
def predict_GPUs(num, df):
predictor = Embed_predictor(num)
return predictor.return_df(df.reset_index())
def paralle_GPUs(df, func, n_cores = 4):
df_split = np.array_split(df, n_cores)
a_args = [0,1,2,3] # GPU list
with Pool(4) as pool:
lst = pool.starmap(func, zip(a_args, df_split))
return lst
# 이미지 url이 포함된 상품테이블 입력
# paralle_GPUs(테이블, 함수, 프로세서 수)
result = paralle_GPUs(img_shape_df, predict_GPUs, 4)
해당 내용은 아래 깃허브에 정리해두었습니다.
https://github.com/Yoon-Alex/multi_GPUs
'ML&DL' 카테고리의 다른 글
[CUDA] GPU, CUDA, CuDNN 버전 확인 (1) | 2021.11.10 |
---|---|
[Linux] tesseract-ocr 설치 및 한글 추출 예시 작업. (0) | 2021.11.07 |