22.01.23 모델 서비스하기

2022. 1. 23. 19:26카테고리 없음

학습된 모델 저장하고 불러오기

tensorflow 모델 구성요소

tensorflow 모델 저장 형식

SavedModel 활용방법

model.save().h5해야 h5는 가능, default는 savedmodel임

Checkpoint 불러오기 save_weights_only는 False가 좋다.

모델 서비스 하기 flask, javascript등 으로 웹에 서비스 가능

Tensorflow.js

flask에서 서비스하기

서버 안정화 처리

실행 가능한 작업 제한

-> 간단한 구현 가능하고, 가벼운 모델이면 서비스 다운을 방지할 수 있으나

-> 사용자가 작업을 예약하는 건 불가능, 대규모 서비스에서는 안됨

다른방법 (작업 큐를 이용한 비동기 처리)

큐 먼저 입력-> 먼저 출력

큐를 이용한 처리 (프로세스 분리)

메인프로세스는 절대 종료되면 안된다. 

작업 큐를 이용한 비동기처리구현

작업 큐와 비동기처리의 장점

실습1 모델저장하기

from elice_utils import EliceUtils

elice_utils = EliceUtils()

import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'

import tensorflow as tf
from tensorflow.keras import layers, models, Sequential
from tensorflow.keras.datasets import mnist
import numpy as np

def load_data():
    (X_train, y_train), (X_test, y_test) = mnist.load_data()
    
    X_train, X_test = X_train / 255.0, X_test / 255.0
    
    X_train = np.expand_dims(X_train, axis=-1)
    X_test = np.expand_dims(X_test, axis=-1)
    
    return X_train, X_test, y_train, y_test

def build_model(input_shape, num_classes=10):
    model = Sequential()
    
    model.add(layers.Conv2D(16, kernel_size=(3, 3), padding="same", activation="relu", input_shape=input_shape))
    model.add(layers.MaxPool2D(2))
    
    model.add(layers.Conv2D(32, kernel_size=(3, 3), padding="same", activation="relu"))
    model.add(layers.MaxPool2D(2))
    
    model.add(layers.Flatten())
    model.add(layers.Dense(num_classes, activation="softmax"))
    
    return model

def main():
    X_train, X_test, y_train, y_test = load_data()
    
    model = build_model(X_train[0].shape)
    
    model.compile(optimizer="adam", loss="sparse_categorical_crossentropy", metrics=["accuracy"])
    model.fit(X_train, y_train, epochs=1, batch_size=64, shuffle=True, verbose=2)
    
    # TODO: H5 형식으로 모델 저장
    model.save('h5_model.h5')
    
    # TODO: SavedModel 형식으로 모델 저장
    model.save('saved_model')

if __name__ == "__main__":
    main()

실습2 모델 불러오기

import os
import tensorflow as tf
import keras
# 모델에 대한 어떠한 정보도 정의하지 않습니다
# 오직 저장된 모델로부터 다양한 정보를 불러와 출력합니다.


print("학습하던 모델을 불러옵니다.")
# TODO: 지시사항을 보고 학습한 SavedModel 형식 모델을 불러오세요 
loaded_model = keras.models.load_model('afterfit')
loaded_model.summary()

# TODO: 지시사항을 보고 5번째 체크 포인트를 불러오세요
loaded_ckpt = keras.models.load_model("./checkpoints/cp-0005.ckpt")
loaded_ckpt.summary()

실습3 checkpoint 이어서 모델 학습하기

import os
import tensorflow as tf
from tensorflow.keras import layers, models, Sequential
from tensorflow.keras.datasets import mnist
import numpy as np

def load_data(): # 학습에 사용할 데이터입니다.

    (X_train, y_train), (X_test, y_test) = mnist.load_data()
    
    X_train, X_test = X_train / 255.0, X_test / 255.0
    
    X_train = np.expand_dims(X_train, axis=-1)
    X_test = np.expand_dims(X_test, axis=-1)
    
    return X_train, X_test, y_train, y_test

def main():
    X_train, X_test, y_train, y_test = load_data() # 빠른 실습을 위해 양이 적은 X_test, y_test 를 학습합니다.
    
    # TODO: 10번째 체크포인트의 경로를 checkpnt_path에 저장하세요
    checkpnt_path = './checkpoints/cp-0010.ckpt' 
    
    # TODO: 불러온 체크포인트를 불러와 model에 저장하세요
    model = models.load_model(checkpnt_path)
    
    # TODO: 10epoch까지 학습된 이 모델을 11번째 epoch부터 이어서 5 epoch 더 학습시키세요
    hist = model.fit( x=X_test, y=y_test, batch_size=64, epochs=15,
        shuffle=True, initial_epoch=10)
        
    return hist, checkpnt_path

if __name__ == "__main__":
    main()

실습4 모델 변환하기

import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'

import tensorflow as tf
from tensorflow.keras import layers, models, Sequential
from tensorflow.keras.datasets import mnist
import numpy as np
import tensorflowjs as tfjs


def load_data():
    (X_train, y_train), (X_test, y_test) = mnist.load_data()
    
    X_train, X_test = X_train / 255.0, X_test / 255.0
    
    X_train = np.expand_dims(X_train, axis=-1)
    X_test = np.expand_dims(X_test, axis=-1)
    
    return X_train, X_test, y_train, y_test

def build_model(input_shape, num_classes=10):
    model = Sequential()
    
    model.add(layers.Conv2D(8, kernel_size=(3, 3), padding="same", activation="relu", input_shape=input_shape))
    model.add(layers.MaxPool2D(2))
    
    model.add(layers.Conv2D(16, kernel_size=(3, 3), padding="same", activation="relu"))
    model.add(layers.MaxPool2D(2))
    
    model.add(layers.Flatten())
    model.add(layers.Dense(num_classes, activation="softmax"))
    
    return model


X_train, X_test, y_train, y_test = load_data()

model = build_model(X_train[0].shape)

model.compile(optimizer="adam", loss="sparse_categorical_crossentropy", metrics=["accuracy"])
model.fit(X_train, y_train, epochs=1, batch_size=64, shuffle=True, verbose=1)    

# TODO: 학습한 모델을 바로 변환 
model.save('JSModel1')

# TODO: 다른 SavedModel 형식의 모델인 "OtherSModel"을 불러오기
loaded_model = models.load_model('OtherSModel')

# TODO: loaded_model을 tensorflow js로 변환
tfjs.converters.save_keras_model(loaded_model, 'JSModel2')

실습5 Flask로 MNIST 서비스하기

from flask import Flask, jsonify, request
import tensorflow as tf
app = Flask(__name__)
import PIL.Image as image

def work(img, model): # 이미지를 입력하면 숫자를 출력하는 함수
    pred = model.predict([img]) # TODO: 모델에 이미지를 넣고 결과를 pred에 저장
    pred = pred[0] # TODO: batch 단위로 나온 결과에서 이미지 하나의 결과를 추출
    idx = tf.math.argmax(pred)  # TODO: 결과중 가장 확률이 높은 index 가져오기
    return idx

@app.route("/", methods=["GET"]) # @app.route를 작성하고, GET Method만 사용합니다.
def predict():    
    imgurl = request.args.get("img")       # img라는 이름으로 url을 받아옴
    result_string="please input image url"
    if imgurl != None:                     # imgurl을 제대로 받은 경우
        imgurl=imgurl.split("?")[0]
        img = image.open("img/"+imgurl)        # 전달받은 url의 이미지 로드  
        img=tf.keras.utils.img_to_array(img)   # 이미지를 행렬로 변환
        img=tf.expand_dims(img, axis=0)        # batch를 위해 한 차원 높게 변환   
        idx = work(img, model)   # 모델을 work 함수를 통해 사용합니다.    
        result_string = "This number is %d"%(idx)   #사용자에게 보여줄 문자열
    return jsonify(result_string)


# Flask 서버를 실행하는 코드입니다.
if __name__ == "__main__":
    model = tf.keras.models.load_model('mymodel') # TODO: 학습된 모델 "mymodel"을 불러오세요.
    app.run(host="0.0.0.0", port=8080) # flask 서비스 시작