텐서플로우 라이트 실행 환경은 목표하는 플랫폼에 따라 다르다. 예를 들어, 임베디드 중 아두이노에서 개발한다면, 이에 대한 라이브러리가 준비되어 있어서, 이를 사용하면 된다.
이제, 각 실행환경에서 사용방법을 확인해 본다.
다음 코드를 CoLab에 입력해 실행해 본다. 최적화하는 부분인 TFLiteConverter 함수 사용만 다르고, 나머지는 일반적인 텐서플로우 코딩과 같다는 것을 알 수 있다.
import logging
logging.getLogger("tensorflow").setLevel(logging.DEBUG)
import tensorflow as tf
from tensorflow import keras
import numpy as np
import pathlib
# MNIST 로딩
mnist = keras.datasets.mnist
(train_images, train_labels), (test_images, test_labels) = mnist.load_data()
# 입력 이미지 정규화
train_images = train_images / 255.0
test_images = test_images / 255.0
# 딥러닝 모델 구조 정의
model = keras.Sequential([
keras.layers.InputLayer(input_shape=(28, 28)),
keras.layers.Reshape(target_shape=(28, 28, 1)),
keras.layers.Conv2D(filters=12, kernel_size=(3, 3), activation=tf.nn.relu),
keras.layers.MaxPooling2D(pool_size=(2, 2)),
keras.layers.Flatten(),
keras.layers.Dense(10)
])
# 필기체 이미지 분류 모델 학습. 1세대만 처리.
model.compile(optimizer='adam',
loss=keras.losses.SparseCategoricalCrossentropy(from_logits=True),
metrics=['accuracy'])
model.fit(
train_images,
train_labels,
epochs=1,
validation_data=(test_images, test_labels)
)
# TFLite버전으로 모델 변환
converter = tf.lite.TFLiteConverter.from_keras_model(model)
tflite_model = converter.convert()
tflite_models_dir = pathlib.Path("/tmp/mnist_tflite_models/") # 폴더 생성
tflite_models_dir.mkdir(exist_ok=True, parents=True)
tflite_model_file = tflite_models_dir/"mnist_model.tflite"
tflite_model_file.write_bytes(tflite_model) # TFLite 파일로 파일 저장
# 최적화 옵션 켜서 모델 저장
converter.optimizations = [tf.lite.Optimize.DEFAULT]
tflite_quant_model = converter.convert()
tflite_model_quant_file = tflite_models_dir/"mnist_model_quant.tflite"
tflite_model_quant_file.write_bytes(tflite_quant_model)
!ls -lh {tflite_models_dir} # CoLab 확인해 보면, 실제 최적화된 모델은 기존 모델의 1/4임
이제 저장된 TFLite 모델을 실행해보자. 아래 코드를 CoLab에 입력해 실행해 본다.
interpreter = tf.lite.Interpreter(model_path=str(tflite_model_file))
interpreter.allocate_tensors() # 최적화 안된 TFLite
interpreter_quant = tf.lite.Interpreter(model_path=str(tflite_model_quant_file))
interpreter_quant.allocate_tensors() # 최적화된 TFLite
test_image = np.expand_dims(test_images[0], axis=0).astype(np.float32) # 첫번째 테스트 이미지
input_index = interpreter.get_input_details()[0]["index"]
output_index = interpreter.get_output_details()[0]["index"]
interpreter.set_tensor(input_index, test_image)
interpreter.invoke() # 모델 실행
predictions = interpreter.get_tensor(output_index) # 예측 결과 얻기
import matplotlib.pylab as plt
plt.imshow(test_images[0])
template = "True:{true}, predicted:{predict}"
_ = plt.title(template.format(true= str(test_labels[0]),
predict=str(np.argmax(predictions[0]))))
plt.grid(False)
TFLite 모델 정확도를 평가해 보자. 아래 코드를 입력해 본다.
# TF Lite 모델 평가용 유틸리티 함수
def evaluate_model(interpreter):
input_index = interpreter.get_input_details()[0]["index"]
output_index = interpreter.get_output_details()[0]["index"]
# 테스트 데이터셋 예측
prediction_digits = []
for test_image in test_images:
# 전처리는 배치로 32비트 실수를 모델 데이터 형식으로 변환하도록 함
test_image = np.expand_dims(test_image, axis=0).astype(np.float32)
interpreter.set_tensor(input_index, test_image)
# 모델 예측 실행
interpreter.invoke()
# 후처리는 가장 높은 정확도 probability 클래스를 찾음
output = interpreter.tensor(output_index)
digit = np.argmax(output()[0])
prediction_digits.append(digit)
# 그라운드 참값과 차이 비교
accurate_count = 0
for index in range(len(prediction_digits)):
if prediction_digits[index] == test_labels[index]:
accurate_count += 1
accuracy = accurate_count * 1.0 / len(prediction_digits)
return accuracy
print(evaluate_model(interpreter))
print(evaluate_model(interpreter_quant))
실제 평가해 보면, 각각 0.9671, 0.9669로 별 차이가 없다.
Javascript 웹 기반 딥러닝 실행
자바스크립트 웹 기반 딥러닝 실행을 위해,
TFJS 라이브러리를 사용한다. 우선, 자바스크립트 node.js 를 이용해 딥러닝 모델을 작성한 후 실행해 본다(참고 -
여기와
TFJS Task API).
우선 터미널에서 아래 명령을 실행한다.
mkdir tfjs
cd tfjs
npm install @tensorflow/tfjs-node
demo.js 코드를 아래와 같이 작성한다.
const tf = require('@tensorflow/tfjs'); // tfjs 임포트
const model = tf.sequential(); // 시퀀스 모델 생성
model.add(tf.layers.dense({units: 100, activation: 'relu', inputShape: [10]}));
model.add(tf.layers.dense({units: 1, activation: 'linear'}));
model.compile({optimizer: 'sgd', loss: 'meanSquaredError'});
const xs = tf.randomNormal ([100, 10]); // 학습 입력 데이터
const ys = tf.randomNormal ([100, 1]); // 결과 라벨 데이터
model.fit (xs, ys,
{epochs : 100,
callbacks : {onEpochEnd : (epoch, log) => console.log ( epoch + " = " + log.loss )}
}); // 학습
터미널에서 아래 명령을 실행한다. 학습이 잘 되는 것을 확인할 수 있다.
node demo.js
웹브라우저에서 딥러닝 모델을 사용하는 방법을 확인해 보기 위해, 우분투 리눅스 터미널에서 아래 명령을 실행하고 관련 예제를 다운로드한다.
git clone https://github.com/tensorflow/tfjs-models
cd tfjs-models
테스트할 딥러닝 모델을 다운로드 설치한다. 기타 필요한 모델은
여기서 확인한다.
npm i @tensorflow-models/coco-ssd
npm i @tensorflow-models/mobilenet
npm i @tensorflow-models/deeplab
yarn 프로젝트 관리 및 빌드 도구를 설치한다. yarn에 대한 설명은
여기를 참고하라.
curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
sudo apt-get update
sudo apt-get install yarn
sudo npm install --global cross-env
패키지를 빌드한다.
yarn
설치된 딥러닝 모델 테스트를 위해 아래 명령을 실행한다.
cd coco-ssd
cd demo
yarn
yarn build-deps
yarn run
watch
웹서버가 실행되었다면, http://localhost:1234/ 에서 결과를 확인해 본다. 다음과 같이 정상적으로 웹브라우저에서 딥러닝이 실행되는 것을 확인할 수 있다.
COCO-SSD 모델의 demo 폴더 구조는 다음과 같다.
주요 코드는 다음과 같다. 아래 index.html에서 웹화면 레이아웃을 정의한다.
<!doctype html>
<html>
<body>
<h1>TensorFlow.js Object Detection</h1>
<select id='base_model'>
<option value="lite_mobilenet_v2">SSD Lite Mobilenet V2</option>
<option value="mobilenet_v1">SSD Mobilenet v1</option>
<option value="mobilenet_v2">SSD Mobilenet v2</option>
</select>
<button type="button" id="run">Run</button>
<button type="button" id="toggle">Toggle Image</button>
<div>
<img id="image" />
<canvas id="canvas" width="600" height="399"></canvas>
</div>
</body>
<script src="index.js"></script>
</html>
실제 동작코드는 index.js 자바스크립트에 코딩된다.
import '@tensorflow/tfjs-backend-cpu'; // tfjs 패키지 임포트
import '@tensorflow/tfjs-backend-webgl';
import * as cocoSsd from '@tensorflow-models/coco-ssd'; // coco-ssd 모델 임포트
import imageURL from './image1.jpg'; // 폴더에 정의된 이미지 임포트
import image2URL from './image2.jpg';
let modelPromise;
window.onload = () => modelPromise = cocoSsd.load();
const button = document.getElementById('toggle'); // 토글버튼 클릭시 이미지 교체
button.onclick = () => {
image.src = image.src.endsWith(imageURL) ? image2URL : imageURL;
};
const select = document.getElementById('base_model');
select.onchange = async (event) => {
const model = await modelPromise; // 모델 선택 변경 시 모델 재로딩
model.dispose();
modelPromise = cocoSsd.load(
{base: event.srcElement.options[event.srcElement.selectedIndex].value});
};
const image = document.getElementById('image');
image.src = imageURL;
const runButton = document.getElementById('run');
runButton.onclick = async () => { // 실행 버튼 클릭시, 이미지 입력 후 모델 예측 실행
const model = await modelPromise;
console.log('model loaded');
console.time('predict1');
const result = await model.detect(image);
console.timeEnd('predict1');
const c = document.getElementById('canvas'); // 캔버스 요소 획득 후 이미지 렌더링
const context = c.getContext('2d');
context.drawImage(image, 0, 0);
context.font = '10px Arial';
console.log('number of detections: ', result.length); // 예측 결과 이미지 및 라벨 렌더링
for (let i = 0; i < result.length; i++) {
context.beginPath();
context.rect(...result[i].bbox);
context.lineWidth = 1;
context.strokeStyle = 'green';
context.fillStyle = 'green';
context.stroke();
context.fillText(
result[i].score.toFixed(3) + ' ' + result[i].class, result[i].bbox[0],
result[i].bbox[1] > 10 ? result[i].bbox[1] - 5 : 10);
}
};
TFJS 라이브러리가 대부분의 딥러닝 모델 사용 과정을 캡슐화하여, 실제 사용되는 함수는 그리 많지 않음을 알 수 있다. 직접 모델을 훈련하고, 웹에서 서비스를 제공하기 위한 목적으로 아래 Tutorial을 참고할 수 있다.
TFLite를 이용하면, GPU가 없는 다양한 플랫폼에서 적은 메모리와 정확도 손실로 딥러닝 모델을 실행할 수 있다.