Post

Tensorflow 1.13.1 에서 JAVA, C#에 포팅할 모델을 만드는 방법

보통 제가 읽으려고 글을 쓰는데 혹시 부족한게 있다면 댓글이나 메일을 부탁드립니다. 개선하겠습니다.

오늘은 개인적인 일로 Tensorflow를 JAVA, C#에 포팅하기위해 모델을 저장하는 방법을 정리하려 합니다.

사실 사소한건데 맨날 안적어놓으면 또 찾느라 시간 낭비가 되네요 ㅠㅠ

TensorFlow 2.0 version 부터는 설명이 잘 나와 있어서 쉽게 쉽게 할 수 있지만 TensorFlow 1.13.1 version을 예전에 사용하고 지금도 2.0으로 다시 짜기 어려워서 가끔 쓰게 됩니다.


사실 출력이 여러개인 부분을 다루는게 제일 문제도 많기 때문에 출력을 여러개로 하는 모델을 사용합니다.

Model

각 출력이 10개의 클래스를 가지며 출력이 5개인 모델 입니다.

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
def get_model(input_shape, num_len=5, num_classes=10):
    input_tensor = Input(input_shape)
    x = input_tensor

    for i, n_cnn in enumerate([1, 2, 1, 2, 1]):
        with tf.name_scope('layer%d' % (i+1)) as scope:
            for j in range(n_cnn):
                x = Conv2D(32*2**min(i, 3),
                           kernel_size=3,
                           padding='same',
                           kernel_initializer='he_uniform',
                           name='cnn_%d_%d' % (i+1, j+1))(x)
                x = BatchNormalization(name='batch_norm_%d_%d' % (i+1, j+1))(x)
                x = Activation('relu',
                               name='activate_%d_%d' % (i+1, j+1))(x)
            x = MaxPooling2D(2,
                             name='maxpool_%d_%d' % (i+1, j+1))(x)

    x = Flatten()(x)
    output = []

    for i in range(num_len):
        output.append(Dense(num_classes,
                            activation='softmax',
                            name='dense_%d' % i)(x))

    model = Model(inputs=input_tensor, outputs=output)

    return model

학습이나 추론이 중점이 아니고 포팅할때 사용할 모델을 만드는데 초점이 있는 글이기에 학습과 추론은 생략합니다.

JAVA

자바에서는 모델 폴더를 넣어주어야합니다..

1
2
3
4
5
model/
  variables/
    variables.data-00000-of-00001
    variables.index
  saved_model.pb

이건 ~

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
32
33
34
35
36
37
38
39
import os
import numpy as np
import tensorflow as tf
import keras.backend as K
import matplotlib.pyplot as plt
import models

input_shape = (W, H, C)

load_path = "./model.h5"

# model
model = models.get_model(input_shape,
                         num_len=10,
                         num_classes=5)

model.load_weights(load_path)

signature = tf.saved_model.signature_def_utils.predict_signature_def(
        inputs={'image': model.input}, outputs={'0': model.output[0],
                                                '1': model.output[1],
                                                '2': model.output[2],
                                                '3': model.output[3],
                                                '4': model.output[4]})

builder = tf.saved_model.builder.SavedModelBuilder(os.path.join('./freeze_models', load_path))
legacy_init_op = tf.group(tf.tables_initializer(), name='legacy_init_op')

builder.add_meta_graph_and_variables(
        sess=K.get_session(),
        tags=[tf.saved_model.tag_constants.SERVING],
        main_op=tf.local_variables_initializer(),
        legacy_init_op=legacy_init_op,
        signature_def_map={
            tf.saved_model.signature_constants.DEFAULT_SERVING_SIGNATURE_DEF_KEY:
                signature
        })

builder.save()

freeze_models 폴더 안에 모델 이름으로 생성 된 폴더를 JAVA에서 실행시킬때 넣어주면 됩니다.

outputs 부분은 모델에 맞게 바꾸어주셔야 합니다.


TensorFlowShape

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
from keras.optimizers import *
import tensorflow as tf
import keras.backend as K
import models

K.set_learning_phase(0)


def freeze_session(session, keep_var_names=None, output_names=None, clear_devices=True):
    graph = session.graph
    with graph.as_default():
        freeze_var_names = list(set(v.op.name for v in tf.global_variables()).difference(keep_var_names or []))
        output_names = output_names or []
        output_names += [v.op.name for v in tf.global_variables()]
        input_graph_def = graph.as_graph_def()
        if clear_devices:
            for node in input_graph_def.node:
                node.device = ""
        frozen_graph = tf.graph_util.convert_variables_to_constants(
            session, input_graph_def, output_names, freeze_var_names)
        return frozen_graph


def freeze(m, save_name):
    print([out.op.name for out in m.outputs])
    frozen_graph = freeze_session(K.get_session(),
                                  output_names=[out.op.name for out in m.outputs])
    tf.io.write_graph(graph_or_graph_def=frozen_graph,
                  logdir="./frozen_models",
                  name="frozen_graph.pb",
                  as_text=False)

    print("[INFO] Model h5 -> pb")

if __name__ == "__main__":
    # config
    config = tf.ConfigProto()
    config.gpu_options.allow_growth = True
    sess = tf.Session(config=config)
    sess.run(tf.global_variables_initializer())
    K.set_session(sess)

    input_shape = (W, H, C)
    tf.keras.backend.set_learning_phase(0)
    model = models.get_model(input_shape,
                             num_len=10,
                             num_classes=5)

    model.load_weights("./model.h5")
    freeze(model, './frozen_graph.pb')

frozen_models 폴더 안에 생성 된 frozon_graph.pb 파일을 C#에서 실행시킬때 넣어주면 됩니다.

This post is licensed under CC BY 4.0 by the author.