4. 텐서플로 라이트 : 안드로이드 + AND 모델(텐서플로) (1)

앞에서 안드로이드와 연동하는 기초를 꼼꼼하게 챙겼다고 생각했다.
너무 쉽게 생각한 것 아닌가 하는 생각이 들었다.

여기서는 AND 논리 연산을 모델로 꾸며서 안드로이드와 연동한다.
FC 레이어를 사용하는 진짜 딥러닝 모델이기 때문에
이번 예제를 처리할 수 있다면
그 어떤 모델이라도 연동할 수 있다고 생각한다.
그렇지만..
이번에도 나만의 착각일 수 있다.

이번 예제를 통해 공부하려고 했던 것은
모델에 여러 개의 연산이 존재할 때 안드로이드에서 개별적인 호출이 가능한지, 였다.
결론부터 말하자면
할 수는 있지만, 그래야 할 이유가 전혀 없다.

최종적인 출력은 다음과 같다.
얼핏 보면 같아보일 수 있는데.. 각각 해당 버튼을 누른 결과이다.
차이를 주기 위해 상단 제목을 모두 다르게 처리했다.


출력된 실수가 모두 같은 것은
학습이 끝난 모델에 동일한 데이터로 결과를 예측하기 때문이다.
마지막 화면은 시그모이드 연산과 시그모이드를 논리값으로 바꾸는 연산의 결과를 보여준다.

파이썬에서 모델 파일을 2개 만든다.
첫 번째는 출력이 하나일 때 사용하고, 두 번째는 출력이 두 개일 때 사용한다.
이번 코드에서 중요한 것은 입력이 복잡해졌고, 두 번째 출력을 담당하는 logics 연산이다.

import tensorflow as tf
import numpy as np


def make_model(model_path, sess, inputs, outputs):
# inputs와 outputs가 여러 요소를 갖는다면 다중 입출력이 된다.
converter = tf.lite.TFLiteConverter.from_session(sess, inputs, outputs)
flat_data = converter.convert()

with open(model_path, 'wb') as f:
f.write(flat_data)


# and 논리값.
# [0, 0] => [0]
# [1, 1] => [1]
x = [[0, 0], [0, 1], [1, 0], [1, 1]] # np로 변환하지 않아도 됨
y = np.float32([[0], [0], [0], [1]]) # 변환하지 않으면 z와 타입 불일치 에러

# 2와 1을 변수로 대체하면 지저분해지기 때문에 생략
# n_features, n_classes = len(x[0]), len(y[0]) # 2, 1

holder_x = tf.placeholder(tf.float32, shape=[None, 2])

w = tf.Variable(np.random.rand(2, 1), dtype=tf.float32)
b = tf.Variable(np.random.rand(1), dtype=tf.float32)

# (4, 1) = (4, 2) @ (2, 1)
z = tf.matmul(holder_x, w) + b # fully connected 레이어
hx = tf.nn.sigmoid(z) # 활성 함수

# 정수 형변환. 텐서플로 연산이기 떄문에 모델에 포함되고, 안드로이드에서 사용할 수 있다.
# hx는 실수 배열, logics는 정수 배열. 일부러 출력 결과를 다르게 만들었다.
logics = tf.cast(hx >= 0.5, dtype=tf.int32)

loss = tf.nn.sigmoid_cross_entropy_with_logits(labels=y, logits=z)
train = tf.train.GradientDescentOptimizer(0.1).minimize(loss)

with tf.Session() as sess:
sess.run(tf.global_variables_initializer())

for i in range(100):
sess.run(train, {holder_x: x})

# print(sess.run([hx, logics], {holder_x: x}))
# hx : [[0.04933239], [0.22989444], [0.24103162], [0.64626104]],
# logics : [[0], [0], [0], [1]]

# 출력 1개인 모델과 2개인 모델을 별도 생성
make_model('and_model_for_hx_only.tflite', sess, [holder_x], [hx])
make_model('and_model_for_hx_logics.tflite', sess, [holder_x], [hx, logics])


make_model 함수를 만들어서
첫 번째는 [hx], 두 번째는 [hx, logics]를 전달했고 파일 이름을 다르게 처리했다.

이번 글은 여기까지 하고
안드로이드 프로젝트는 다음 글에서 만들어 본다.