Deep learning/Caffe

Caffe Library Linking to HEVC HM-15.0

랏츠베리 2017. 7. 24. 18:15

1. Intro


HEVC의 HM-15.0 프로젝트에서 비디오 인코딩 과정 중 첫 단계인 Coding Unit의 xCompressCU라는 함수 내에 Caffe의 Classifier를 활용하기 위해 libcaffe를 연결하는 과정에서 발생하는 에러에 대하여 솔루션을 작성하였다. HEVC의 Compile 환경은 Linux-Ubuntu 16.04.2에서 gcc-5.4.0, g++-5.4.0을 활용하였다.


2. Process


1) Setting a Shared Libary Loading Path


Caffe library를 HM-15.0의 인코더에서 사용하기 위해 먼저 카페 라이브러리 경로를 확인해야 한다.



필자의 Path에서 libcaffe.a라는 Static libarylibcaffe.so , libcaffe.so.1.0.0.-rc5 라는 Shared library를 확인할 수 있다.

Static library는 HM-15.0의 Compile 단계에서 Linking을 하도록 세팅하고, Shared library는 Bash shell에서 LD_LIBRARY_PATH로 불러올 수 있게 설정 한다.

그럼 먼저, 가볍게 Bash의 라이브러리 패스 설정부터 정리해보면,


$vim ~/.bashrc



$source ~/.bashrc


libcaffe.so , libcaffe.so.1.0.0.-rc5의 loading을 마무리하고, 지금부터 Static library를 HM-15.0에 linking하는 과정을 소개하겠다.

※LD_LIBRARY_PATH를 추가하지 않으면 shared library load error가 발생할 수 있다.



2) Linking a libcaffe.a to the HEVC HM-15.0


i) root/caffe/examples/cpp_classification


Caffe의 classification example 코드에서 Classifier라는 Class를 활용하기 위해 해당 경로를 찾아 들어간다.


$cd root/caffe/examples/cpp_classification


해당 디렉토리 내에 classification은 cpp 파일 내에 class의 initialization과 function 알고리즘 그리고 main function이 모두 구현되어있으므로, 우리가 원하는 class의 명세만 header로 분리하여 .hpp파일을 생성하고 classification.cpp와  생성된 classification.hpp를 Encoder내에서 classification.o로 오브젝트화 하여 header만 우리가 원하는 코드 위에 #include하여 사용하는 방향으로 진행한다.


해당 디렉토리에서 cpp파일의 class만 header로 가져온다. header로 가져올 때 cpp에 정의한 namespace는 모두 삭제하고 각각 element에 일괄적으로 설정해준다. 전처리문은 생략해도 좋다.



위와 같이 해당 파일의 .hpp를 생성하고 .cpp의 main function을 모두 삭제한다. 

main function을 삭제하지 않으면 HM-15.0의 Compile 과정에서 multiple definition error가 발생한다.


ii) root/.netbeans/source/Lib/TLibEncoder


classification library를 HM-15.0 Encoder 내에서 직접 Static library 생성하기 위해 i) 단계에서 만든 classification.cpp와 classification.hpp를 모두 TLibEncoder로 불러온다.


$cp classification.* /(netbeans root path)/HM-15.0/source/Lib/TLibEncoder


HM-15.0을 Netbeans라는 IDE (Intergrated Development Environment)위에서 작업하였기 때문에, root directory가 netbeans가 되었다.


iii) root/.netbeans/build/linux/lib/TLibEncoder


자, 이제 본격적으로 Makefile을 수정할 단계이다. HM-15.0의 Makefile은 아래와 같이 여러 Hierarchy로 얽혀있다.

예를 들어, 가장 하위 디렉토리에 존재하는 Makefile들  build/linux/app/TappDecoder 혹은 build/linux/lib/TLibEncoder에 존재하는 makefile들이 makefile.base에 명시된 스크립트에 따라 Compile 과정을 수행한다. 

build/linux에 존재하는 makefile는 하위 디렉토리의 makefile이 Compile되는 순서를 정해준다.



먼저, LibEncoder의 makefile에서 classification.o를 추가하여, Static하게 라이브러리를 생성하여 Classifier를 사용하도록 만들고, 해당 Classifier를 사용하기 위해 필요한 Source들을 모두 include하는 Path를 설정한다.



위의 Path 중에서 Object만 묶여서 .a라는 라이브러리 파일이 되므로, 추가적인 라이브러리와 라이브러리 디렉토리 경로는 포함시키지 않아도 Linking 단계에서 포함시켜주면 되므로 문제되지 않는다.


iv) root/.netbeans/build/linux/app/TAppEncoder


Encoder의 Library를 모아 Application을 만들기 위한 Compile단계에서 linking을 담당하는 부분이다.  여기에서 Library 디렉토리 경로와 필요한 Library를 빠짐없이 추가해주어야 한다. 특히 g++이 linking하는 과정에서 Library의 순서가 뒤죽박죽일 경우 error message를 display하므로 주의해야한다.

예를 들어, HM-15.0에서 Compile하면서 만들어지는 .a의 library파일과 외부에서 link하는 library간의 순서가 외부의 library가 먼저일 경우 Compile error가 발생한다. 

따라서, Compile 순서를 고려하기 위해 아래의 makefile.base에서 적합한 순서를 위해 스크립트의 수정이 필요하다.



v) makefile.base 수정


마지막으로 Compile 옵션을 정리해주어야 한다. 옵션을 정리해주는 이유는 빌드 과정에서 2가지 에러를 볼 수 있는데, 첫 번째는 shared.ptr에 대한 standard namespace error 두 번째는, g++이 linking하는 과정에서 Library의 순서로 인해 linking이 되지 않으며 발생하는 에러이다. 사실 이번 Build 과정에서 이 두 가지의 error가 좀처럼 해결하기 쉽지 않았다. 


classification.cpp에서 활용하는 shared.ptr는 c++ standard library 11에서 추가되어 지금까지 version이 달라지면서 조금씩 변경이 되었는데, caffe의 shared ptr는 std=c++11로 compile해주어야 한다.




다음, g++의 compile순서에서 외부의 Library ($(LIBS))를 모두 가장 뒤로 보내어 정리하면, linking의 문제를 해결할 수 있다.