본문 바로가기
Study/머신러닝

Bazel을 이용해 Tensorflow Lite 빌드해보기

by 김카비 2020. 3. 31.

Tensorflow Lite는 Bazel로 빌드해서 사용 할 수 있다.

여기서는 C++로 간단하게 테스트코드를 만드는 방법까지 정리해보았다.

 

Tensorflow Lite를 빌드하고 실제 Inference까지 진행하기에는 크게 3단계로 나뉜다

1. Tensorflow 소스코드로부터 libtensorflowlite.so 빌드

2. 모델을 학습한 후 최종 모델을 .tflite형태로 변환

3. C++이나 자바에서 inference할 코드 작성

 

차근차근 해보도록 하자

 


libtensorflowlite.so 빌드

 

1. 원하는 TF 버전 브랜치를 찾아 git clone

 

tensorflow/tensorflow

An Open Source Machine Learning Framework for Everyone - tensorflow/tensorflow

github.com

2. TF 버전에 맞는 Bazel 버전을 확인 한 후 설치 -> tensorflow 소스의 .bazelversion파일을 확인하면 된다

 

bazelbuild/bazel

a fast, scalable, multi-language and extensible build system - bazelbuild/bazel

github.com

3. Bazel 설치 후 환경변수 추가

ex) ~/.bashrc

export BAZEL_HOME=/usr/bin
export PATH=$BAZEL_HOME:$PATH

 

4. ~/tensorflow 폴더로 이동하여 ./configure로 빌드 옵션을 세팅

  • Please specify the location of python. [Default is /usr/bin/python]: /usr/bin/python2.7 -> 아나콘다를 쓰기때문에 /usr/bin/anaconda3/bin/python 로 바꿔주었음 (which python으로 경로 확인)
  • 이 다음에도 여러가지 옵션들이 있는데 일단 로컬에서 테스트 코드만 돌려볼 목적이므로 대부분 NO를 선택해주면 된다. 

5. 빌드 

~/tensorflow에서 

bazel build -c opt --cxxopt='--std=c++11' --fat_apk_cpu=x86_64 tensorflow/lite:libtensorflowlite.so
  • ~/tensorflow/bazel-bin/tensorflow/lite에서 so파일 생성됨
  • --fat_apk_cpu=x86_64 is the option for linux machine

모델을 .tflite로 변환

 

TF lite에서 지원되는 Operation 을 확인 하고 모델링을 한다

특히 RNN 연산의 경우 제약사항이 많은 것 같으니 꼭 확인을 하고 모델링하도록 하자!

 

TensorFlow Lite and TensorFlow operator compatibility

TensorFlow Lite supports a number of TensorFlow operations used in common inference models. As they are processed by the TensorFlow Lite Optimizing Converter, those operations may be elided or fused, before the supported operations are mapped to their Tens

www.tensorflow.org

 

Convert RNN models  |  TensorFlow Lite

The TensorFlow Lite interpreter currently implements a subset of TensorFlow operations, meaning some model architectures cannot immediately be converted due to missing operations. Some RNN-based architectures are affected by this. The following document ou

www.tensorflow.org

 

4. 내가 만든 모델 학습 -> 저장(ckpt or h5) -> .tflite 파일로 변환

 

Sample model and Save as .tflite

# -*- coding: utf-8 -*-

import tensorflow as tf
import numpy as np

model = tf.keras.Sequential([tf.keras.layers.Dense(units=1, input_shape=[1])])
model.compile(optimizer='sgd', loss='mean_squared_error')

xs = np.array([ -1.0, 0.0, 1.0, 2.0, 3.0, 4.0], dtype=float)
ys = np.array([ -3.0, -1.0, 1.0, 3.0, 5.0, 7.0], dtype=float)

model.fit(xs, ys, epochs=500)

print(model.predict([10.0]))

converter = tf.lite.TFLiteConverter.from_keras_model(model)
tflite_model = converter.convert()
open('linear.tflite', 'wb').write(tflite_model)
더보기

*참고

이건 Checkpoint 로 model을 save하고 load하는 예시

 

Training and Save a model 

model = Mymodel()
model.compile(optimizer=optimizer, loss=cross_entropy, metrics=metrics)
 
callbacks = tf.keras.callbacks.ModelCheckpoint(filepath='training_ckpt/cp_{epoc}', save_weights_only=True, monitor='val_loss', save_best_only=True)
model.fit(train_dataset, epochs=100, callbacks=callbacks, validation_data=val_dataset)

Convert model to .tflite

model = Mymodel()
model.compile(optimizer=optimizer, loss=cross_entropy, metrics=metrics)
 
checkpoint_path = 'training_ckpt/ckpt_100' #your ckpt path
model.load_weights(checkpoint_path)
converter = tf.lite.TFLiteConverter.from_keras_model(model)
tflite_model = converter.convert()

C++로 libtensorflowlite.so 와 연동하여 inference해보기

1. Inference코드 작성

#include <stdio.h>
#include "tensorflow/lite/interpreter.h"
#include "tensorflow/lite/kernels/register.h"
#include "tensorflow/lite/model.h"
#include "tensorflow/lite/tools/gen_op_registration.h"

using namespace tflite;

int main(){

    std::unique_ptr<tflite::FlatBufferModel> model = tflite::FlatBufferModel::BuildFromFile("linear.tflite");

    if(!model){
        printf("Failed to mmap model\n");
        exit(0);
    }

    tflite::ops::builtin::BuiltinOpResolver resolver;
    std::unique_ptr<tflite::Interpreter> interpreter;
    tflite::InterpreterBuilder(*model.get(), resolver)(&interpreter);

    // Resize input tensors, if desired.
    interpreter->AllocateTensors();

    float* input = interpreter->typed_input_tensor<float>(0);
    // Dummy input for testing
    *input = 2.0;

    interpreter->Invoke();

    float* output = interpreter->typed_output_tensor<float>(0);

    printf("Result is: %f\n", *output);

    return 0;
}   

 

2. 폴더 구성

.
└── main
       ├── linear.cc
       └── linear.tflite  
       │
       └── lib
       │      └── libtensorflowlite.so
       │
       └── tensorflow
               └── lite
                       └── *headers*
  • tensorflow 폴더의 경우 ~/tensorflow/tensorflow 폴더를 통채로 복사했다

 

3. CMake빌드

  • CMakeLists.txt 예시
CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
PROJECT(tflite_test)
SET(CMAKE_BUILD_TYPE Debug)
SET(CMAKE_VERBOSE_MAKEFILE true)
SET(CMAKE_C_COMPILER "g++")
ADD_COMPILE_OPTIONS (  -g   -Wall -std=c++11 )
SET (CMAKE_EXE_LINKER_FLAGS "-Wl,--gc-sections")
INCLUDE_DIRECTORIES(./ ./flatbuffers/include)
LINK_DIRECTORIES(./lib/)
LINK_LIBRARIES(tensorflowlite)
ADD_EXECUTABLE(tflite_test ./linear.cc)
cmake CMakeLists.txt
make

4. 최종 산출물 확인

./tflite_test
Result is: 3.002121

 

간단하게 so파일과 연동해서 사용해보았다.

안드로이드용 빌드는 나중에 추가로 정리할 예정.

댓글