Tensorflow C++ 동적 링크드 라이브러리(stanalone C++ project) 만들기

이 글의 번역!입니다.

가끔 텐서플로우를 C++에서 deploy해야 하는 경우가 있습니다. 주로, Tensorflow로 training한 모델을 python을 지원하지 않는 환경에서 사용하고 싶을 때 사용하는 것 같아요. 이 경우, 매번 bazel에서 빌드하지 않고 library를 빌드해 .so 파일로 만들어 사용하는 방법에 대해 다룹니다. 자세한 텐서플로우를 C++에서 사용하는 방법에 대한 가이드는 https://www.tensorflow.org/api_docs/cc/을 참조해주세요.

원본에서는 Raspberry Pi에서의 설정까지 다루고 있지만, 제가 라즈베리 파이를 갖고 있지 않아서 실제로 실행을 못해보기 때문에 Ubuntu 환경에서 build하는 방법만 정리합니다. 또한, 원본 글에서는 Tensorflow 1.3.0 버전을 사용하지만, 이 글에서는 Tensorflow 1.5.0 버전을 사용합니다. 따라서, 사용하는 dependency가 조금 바뀝니다.

Ubuntu 17.04, GCC 6.3.0에서 테스트했습니다. 원본 글은 Raspberry Pi, tensorflow 1.3.0 버전에서 테스트했지만, 저는 ubuntu 17.04 버전,tensorflow 1.5.0에서 테스트했습니다.


개요 이 문서는 Tensorflow를 리눅스 환경(ubuntu)에서 빌드하고, C++ interface를 사용하는 방법에 대해 다룬다.

Overview

이하 설치 명령어 등은 다음과 같은 환경에서 테스트되었습니다. (본문과 살짝 다릅니다!)

  • 우분투 17.04 x86_64 machine
  • Python 3.6
  • GCC(g++) 6.3.0
  • CUDA 8.0에서 CPU, GPU 환경에서 실험을 진행하고, 작동을 확인했다.

빌드하기 위해 필요한 다른 프로그램 설치

먼저, 패키지 매니저 apt-get 를 업데이트한다. 우분투에서는 apt 를 사용하지만, 다른 리눅스 라이브러리에서는 yum 등 다른 명령어를 사용해야 한다.

sudo apt-get update

다음으로 linux 환경에서 C++ 프로그램을 빌드하기 위한 기본적인 프로그램을 설치한다.

Bazel (구글에서 관리하는 소프트웨어 설치 도구. 텐서플로우를 설치하는 데 사용한다) 의존성

sudo apt-get install pkg-config zip g++ zlib1g-dev unzip default-jdk autoconf automake libtool

Bazel 설치

https://github.com/bazelbuild/bazel/releases?after=0.8.1 여기서 자신의 플랫폼에 맞는 Bazel 다운로드 후 설치해주세요. (0.8.0 버전에서 테스트 되었습니다.)

Tensorflow 의존성

sudo apt-get install python3-pip python3-numpy swig python3-dev
sudo pip3 install wheel
sudo apt-get install tensorflow

텐서플로우 빌드

github에서 tensorflow source code를 가져온다.

git clone --recurse-submodules -b v1.5.0 https://github.com/tensorflow/tensorflow.git tensorflow
cd tensorflow

그 다음, 텐서플로우의 옵션을 설정한다.

** 1.5.0 버전에선 살짝 바뀌었지만, 적당히 Configuration을 참고해서 입력해주시면 됩니다!**

Using python library path: /usr/local/lib/python2.7/dist-packages
Do you wish to build TensorFlow with MKL support? [y/N]
Please specify optimization flags to use during compilation when bazel option "--config=opt" is specified [Default is -march=native]:
Do you wish to use jemalloc as the malloc implementation? [Y/n]
Do you wish to build TensorFlow with Google Cloud Platform support? [y/N]
Do you wish to build TensorFlow with Hadoop File System support? [y/N]
Do you wish to build TensorFlow with the XLA just-in-time compiler (experimental)? [y/N]
Do you wish to build TensorFlow with VERBS support? [y/N]
Do you wish to build TensorFlow with OpenCL support? [y/N]
Do you wish to build TensorFlow with CUDA support? [y/N] Y
Do you want to use clang as CUDA compiler? [y/N]
Please specify the Cuda SDK version you want to use, e.g. 7.0. [Leave empty to default to CUDA 8.0]: 8.0
Please specify the location where CUDA 8.0 toolkit is installed. Refer to README.md for more details. [Default is /usr/local/cuda]:
Please specify which gcc should be used by nvcc as the host compiler. [Default is /usr/bin/gcc]:
Please specify the cuDNN version you want to use. [Leave empty to default to cuDNN 6.0]: 6
Please specify the location where cuDNN 6 library is installed. Refer to README.md for more details. [Default is /usr/local/cuda]:
Please specify a list of comma-separated Cuda compute capabilities you want to build with.
You can find the compute capability of your device at: https://developer.nvidia.com/cuda-gpus.
Please note that each additional compute capability significantly increases your build time and binary size.
[Default is: "3.5,5.2"]: 3.0
Do you wish to build TensorFlow with MPI support? [y/N]

MKL 옵션은 intel CPU에서 부동소수점 빠른 연산을 지원하며, OpenCl, CUDA 등은 GPU 연산을 지원하는 옵션이다. 자세한 옵션에 대해서는 https://www.tensorflow.org/install/install_sources#ConfigureInstallation 항목을 참조. 또한, GPU(CUDA) 설정에 관해서는 https://www.tensorflow.org/install/install_sources 을 참조.

모든 설정을 마쳤으면, 이제 텐서플로우를 빌드할 수 있다.

bazel build -c opt --verbose_failures //tensorflow::libtensorflow_cc.so

Protobuf, Eigen, Nsync 설치

텐서플로우를 독립적으로 실행하기 위해서는 추가적으로 3개의 라이브러리를 더 설치해야 한다.

Protobuf 빌드

mkdir /tmp/proto
tensorflow/contrib/makefile/download_dependencies.sh
cd tensorflow/contrib/makefile/downloads/protobuf/
//이 과정은 외부 dependency를 설치하는 과정이며, "tensorflow/contrib/makefile/downloads"에 갖가지 라이브러리가 저장되어 있습니다.
./autogen.sh
./configure --prefix=/tmp/proto/
make
make install

Eigen 빌드

mkdir /tmp/eigen
cd ../eigen
mkdir build_dir
cd build_dir
cmake -DCMAKE_INSTALL_PREFIX=/tmp/eigen/ ../
make install
cd ../../../../../..

Nsync 빌드

mkdir /tmp/nsync
cd ../tensorflow/contrib/downloads/nsync
cmake -DCMAKE_INSTALL_PREFIX=/tmp/nsync
make install

빌드가 완료된 라이브러리 파일들을 옮겨준다.

#프로젝트 디렉토리 생성
mkdir ../tf_test/

mkdir ../tf_test/lib
mkdir ../tf_test/include
#tensorflow
cp bazel-bin/tensorflow/libtensorflow_cc.so ../tf_test/lib/
cp bazel-bin/tensorflow/libtensorflow_framework.so ../tf_test/lib

#protobuf
cp /tmp/proto/lib/libprotobuf.a ../tf_test/lib/

#nsync
cp -r /tmp/nsync/lib/libnsync.a ../tf_test/lib/

다음의 include file도 옮긴다.


cp -r bazel-genfiles/* ../tf_test/include/
cp -r tensorflow/cc ../tf_test/include/tensorflow
cp -r tensorflow/core ../tf_test/include/tensorflow
cp -r third_party ../tf_test/include
cp -r /tmp/proto/include/* ../tf_test/include
cp -r /tmp/eigen/include/eigen3/* ../tf_test/include
cp -r /tmp/nsync/include/* ../tf_test/include

설치 완료. 다음의 테스트 코드를 만들어 실행해본다.

테스트

헤더, 라이브러리 등을 옮긴 디렉토리에서, 테스트 코드를 만든다.

cd ../tf_test
vi test.cpp

이러한 test.cpp파일을 만들어 컴파일 후 작동을 확인한다.

//test.cpp
#include "tensorflow/cc/client/client_session.h"
#include "tensorflow/cc/ops/standard_ops.h"
#include "tensorflow/core/framework/tensor.h"

int main() {
  using namespace tensorflow;
  using namespace tensorflow::ops;
  Scope root = Scope::NewRootScope();
  // Matrix A = [3 2; -1 0]
  auto A = Const(root, { {3.f, 2.f}, {-1.f, 0.f}});
  // Vector b = [3 5]
  auto b = Const(root, { {3.f, 5.f}});
  // v = Ab^T
  auto v = MatMul(root.WithOpName("v"), A, b, MatMul::TransposeB(true));
  std::vector<Tensor> outputs;
  ClientSession session(root);
  // Run and fetch v
  TF_CHECK_OK(session.Run({v}, &outputs));
  // Expect outputs[0] == [19; -3]
  LOG(INFO) << outputs[0].matrix<float>();
  return 0;
}

마지막으로 작성한 test.cpp을 컴파일하고, 실행을 확인한다.

g++ -std=c++11 -Wl,-rpath=lib -Iinclude -Llib -ltensorflow_framework test.cpp -ltensorflow_cc -ltensorflow_framework -o exec
./exec

작동이 잘 된다면, 성공한 것이다.

References

Building TensorFlow 1.3.0 as a standalone project (Raspberry pi 3 included)

  • 사실 여기 있는 글을 그대로 번역한 것이다. 으음 부끄러워;;
PREVIOUS오랜만에 일기
NEXT오늘의 일기