[TensorFlow] 대항해시대 온라인 시세 공유 도우미 (2)

이 글에서는 학습된 데이터를 어떻게 저장하고 어떻게 읽어와서 사용할 지에 중점을 두고 설명하겠습니다.

지난 번 글에서 언급한 도시이름, 시세, 화살표의 Learing Model 코드는 이곳에서 확인하실 수 있습니다. 이 코드는 교역품의 러닝 모델과 거의 비슷하기에 뒤에 학습된 모델을 읽어오기 위해 필요한 부분만 설명하겠습니다.

텐서플로우 공식 사이트에는 Save and Restore 항목이 있고, 여기에 보면 tf.saved_model.simple_save 를 이용하면 제일 쉽다고 되어 있습니다. 그래서 저는 이 함수를 사용하기로 결정하였습니다.

처음에는 단순히 아래와 같이 simple_save 코드를 이용하였습니다.

----------
simple_save(session, export_dir)
----------

그리고 저장된 모델은 아래와 같이 로드하였습니다.

----------
def estimate(model_dir, raw_bytes):
    tf.reset_default_graph()
    graph = tf.Graph()
    with graph.as_default():
        with tf.Session(graph=graph) as sess:
            tf.saved_model.loader.load(sess, [tag_constants.SERVING], model_dir, )

            x_data = [[float(x) for x in raw_bytes]]
            logits = tf.argmax(model, 1)

        return sess.run(logits, feed_dict={X: x_data, keep_prob: 1.0})[0]
----------

이러면 에러가 발생합니다. X, keep_prob, model 이라는 것이 무엇인지 모르기 때문이지요.
그렇다고 로드하는 곳에서 다시 X, keep_prob, model 을 정의한다고 이용할 수 있는 것은 아닙니다. 새로 정의하게 되면 저장된 모델과는 다른 별도의 텐서가 생성되니깐요.

아까 말한 가이드 문서를 읽어보면, "Use SavedModel to save and load your model—variables, the graph, and the graph's metadata." 이라는 문구가 있습니다. 이 말이 자동으로 알아서 다 저장한다는 의미는 아니었습니다. 특히 그래프의 Input, Ouput에 해당하는 텐서의 정보를 저장하지 않으면 실제 저장된 모델을 이용하기가 어렵습니다. 그래서 여기에 해당하는 텐서들은  직접 이름을 주고 simple_save 시에 명시해 주어야 합니다.

simple_save 함수에 대해서 조금 더 설명을 하도록 하겠습니다.
SavedModel 에 대한 문서(https://github.com/tensorflow/tensorflow/blob/master/tensorflow/python/saved_model/README.md)를 보면 아래와 같은 내용이 있습니다.

----------
Support for SignatureDefs
    Graphs that are used for inference tasks typically have a set of inputs and outputs. This is called a Signature.
    SavedModel uses SignatureDefs to allow generic support for signatures that may need to be saved with the graphs.
    For commonly used SignatureDefs in the context of TensorFlow Serving, please see documentation here.
----------

그래프와 함께 저장될 signatures를 위해 simple_save 호출 시에 inputs와 outputs에 지정해야 하는 것입니다. 위의 코드에서 보듯이 여기에서 필요한 signatures는 X, keep_prob, model 입니다.

https://github.com/ommokazza/uwo_ps_ml/blob/master/ml/learning_model_towns.py 코드의 일부분입니다. 아래와 같이 텐서에 name 파라메터로 이름을 지정해 주고, simple_save 시에 signature 로 넘겨주었습니다.

----------
...
X = tf.placeholder(tf.float32, [None, len(im.tobytes())], name="X")
...
keep_prob = tf.placeholder(tf.float32, name="keep_prob")
...
model = tf.matmul(L3, W4, name="model")
...
tf.saved_model.simple_save(sess,
                           self.model_dir,
                           inputs={"X" : X, "keep_prob" : keep_prob},
                           outputs={"model" : model})
----------

이렇게 저장된 데이터는 아래와 같은 코드로 텐서를 가져올 수 있습니다.

----------
X = graph.get_tensor_by_name("X:0")
keep_prob = graph.get_tensor_by_name("keep_prob:0")
model = graph.get_tensor_by_name("model:0")
----------
(전체코드: https://github.com/ommokazza/uwo_ps_utils/blob/master/uwo_ps_utils/common.py )

이번 포스트에서는 제가 작업하면서 삽질했던 부분 위주로 설명을 드렸습니다.

제가 작업했던 앱에서는 클라이언트에 저장된 모델과 TensorFlow 라이브러리를 포함해서 exe 파일로 만들었더니 바이너리 용량이 무려 50메가가 넘게 되더군요. 저장된 모델을 서버에 올려서 서버에서 처리할 수 있는 구조로 만들어야 겠지만, 그 작업도 공부삼아 해 볼지는 모르겠습니다.

이전 포스트에서도 언급했지만, 이미지 자체가 정형화된 포맷이라 머신러닝을 사용하지 않는 것이 더 용량이나 실행속도 몇에서 효율적이라고 생각되었거든요. 그래서 제가 개인적으로 작업하던 프로젝트에서는 머신러닝 관련 코드가 다 삭제할 예정입니다.

요즘엔 워낙 한글로 된 머신러닝 관련 자료들이 많아졌는데, 이 포스트들은 얕은 지식으로 쓴 거라... 좀 부끄럽네요.

다음에는 좀 더 내공을 길러서 올 수 있도록 노력을...

댓글

이 블로그의 인기 게시물

[게임개발 스토리] 장르/타입/조합 정보와 몇 가지 팁

[윈도우] 실행 중인 프로그램의 타이틀을 변경하는 유틸리티

Synergy 한글키 패치 공식 버전 적용 및 최종 정리