상세 컨텐츠

본문 제목

windows 환경에서 tensorflow-gpu 2.3.0 dll로 컴파일하기

개발

by 크롱박사 2022. 6. 13. 14:57

본문

tensorflow는 python 환경을 기본으로 하기에 python에서는 편하게 사용할 수 있다.

하지만 나는 C++, MSVC(windows) 환경에서 개발하기 때문에 tensorflow를 dll로 구성하기로 하였다.

c++ api도 있지만 차후 확장성을 고려했을 때 이것이 더 맞을 것 같았다.

예전 버전의 tensorflow는 CMake 를 이용하였지만 1.11 버전부터 bazel로 변경되었다.

 

기본 환경은 tensorflow 홈페이지를 참고하여 구성하였다.

 

Windows의 소스에서 빌드  |  TensorFlow

 

Windows의 소스에서 빌드  |  TensorFlow

Google I/O is a wrap! Catch up on TensorFlow sessions View sessions Windows의 소스에서 빌드 소스에서 TensorFlow pip 패키지를 빌드하고 Windows에 설치합니다.참고: 잘 테스트되고 사전 빌드된 Windows 시스템용 TensorFlow

www.tensorflow.org

글 하단에 cpu 혹은 gpu버전에 대한 환경 구성 표가 있으니 꼭 참고하도록 하자.

외부 소스를 컴파일하는 것에 환경 구성(버전 일치)만큼 중요한 일이 없다.

여기에서는 2.3.0의 gpu 버전으로 진행한다.

구성은 다음과 같다.

tensorflow_gpu-2.3.0 3.5-3.8 MSVC 2019 Bazel 3.1.0 7.6 10.1

 

먼저 버전에 맞는 CUDA Toolkit과 CuDnn을 다운받아 설치한다.

- CUDA Toolkit Archive | NVIDIA Developer

 

CUDA Toolkit Archive

Previous releases of the CUDA Toolkit, GPU Computing SDK, documentation and developer drivers can be found using the links below. Please select the release you want from the list below, and be sure to check www.nvidia.com/drivers for more recent production

developer.nvidia.com

 

 

1.

 홈페이지의 글을 따라 python을 설치한다.

 - Python Releases for Windows | Python.org 페이지의 3.8.10 인스톨러 설치: 링크

 - Windows 환경 변수 path에 설치된 python 폴더 추가 (설치시 옵션에 있음)

 - 패키지 관리를 위한 가상환경 추가

    python -m venv "가상환경 이름" 

 

 - 컴파일하기 위해서 MSVC 2019에서 제공하는 "x64 Native Tools Command Prompt for VS2019"를 사용하였다. 이를 사용하면 커맨드 프롬프트에 2019개발 환경이 로드되었다고 보면된다.

이 환경에서 파이썬 가상환경을 활성화한다.

C:\python 가상환경 경로\Scripts\Activate.bat

 (예시: C:\Users\User1\source\repos\venv\Scripts\Activate.bat)

 

 - 파워쉘일 경우

C:\python 가상환경 경로\Scripts\Activate.ps1

bat 가 아닌 ps1 스크립트를 실행해야 한다. 만약 Security 에러가 난다면 관리자 권한으로 실행후에 

Set-ExecutionPolicy Unrestricted

를 입력하면 가상환경이 설정된다.

제대로 설정되었다면 프롬프트는 "(가상환경이름)경로>"처럼 맨 앞에 가상환경 이름이 뜰 것이다.

 

 가상환경 안으로 들어왔다면 다음과 같이 패키지를 설치한다.

pip3 install -U six numpy wheel packaging
pip3 install -U keras_preprocessing --no-deps

 

2.

Bazel을 설치한다. 버전은 3.1.0 이다.

Bazel의 github 의 releases를 보면 버전마다 바이너리(exe)를 제공한다.

이를 특정 폴더에 넣고 path 환경변수를 설정하여 커맨드 프롬프트에서 인식되도록 한다.

더보기

- 노트

 

직접 설치하지 않고 powershell 의 패키지 관리자인 chocolatey 에도 bazel 이 있지만 별로 추천하지는 않는다.

이유는 제공된 bazel 버전이 한정되어 있기 때문인데, bazel은 버전에 매우 민감한지

tensorflow에서 알려주는 다른 버전의 bazel에서는 컴파일이 제대로 진행되지 않았다.

 

참고로 이전 버전의 tensorflow 를 컴파일하기 위해서 다음과 같은 커맨드를 적었다. (MSVC2017 버전을 사용하는 1.15에서 사용하였음. powershell 사용함)

set BAZEL_VC_FULL_VERSION=141
set BAZEL_WINSDK_FULL_VERSION=10.0.17763.0
set BAZEL_VS="C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools"
set BAZEL_VC="C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC"

 

3.

MSYS2를 설치하고 path 설정, pacman 등을 설정한다.

MSYS2 홈페이지

 

MSYS2

Software Distribution and Building Platform for Windows

www.msys2.org

windows 환경 변수의 path에 MSYS2의 폴더를 추가한 후 커맨드 프롬프트를 재시작한다. (환경변수를 읽어오기 위해)

pacman -S git patch unzip

 

 

4. 

git 을 이용하여 tensorflow를 컴파일할 디렉토리에 clone 한다.

그 후 clone된 디렉토리에서 2.3.0 버전으로 checkout 한다.

이 또한  tensorflow 홈페이지 글을 참고하여 진행하면 된다.

참고로 bazel은 c 드라이브의 사용자 디렉토리에 _bazel_사용자이름 으로 폴더를 만들어 여기에서 컴파일을 한다.

따로 설정방법이 있겠지만 용량이 넉넉하여 그냥 진행하였다.

 

 

5.

python을 이용하여 프로젝트를 설정(configure) 한다.

python ./configure.py

첫 질문인

"Please specify the location of python." 에는 우리의 가상환경에 있는 python.exe이 잡혔는지 보자(가상환경으로 실행하면 자동을 인식된다.)

C:\python 가상환경 경로\Scripts\python.exe

이렇게 하면 자동으로  패키지 디렉토리가 설정된다.

이후 

Do you wish to build TensorFlow with CUDA support? 에 사용함(yes)을 선택한다.

만약 CUDA가 없다면 위쪽 표에 따라 10.1버전과 cudnn 7.6.X 버전을 설치하면 된다.

CUDA가 설치된 후 path 설정을 해주면 자동으로 인식하여 경로를 설정해준다.

 

6.

tensorflow를 빌드한다.

bazel build --config=opt --config=cuda --copt=-mavx2 --copt=-nvcc_options=disable-warnings --define=no_tensorflow_py_deps=true --copt=-nvcc_options=disable-warnings --copt=-DTHRUST_IGNORE_CUB_VERSION_CHECK //tensorflow:libtensorflow_cc.so
bazel build --config=opt --config=cuda --copt=-mavx2 --copt=-nvcc_options=disable-warnings --define=no_tensorflow_py_deps=true --copt=-nvcc_options=disable-warnings --copt=-DTHRUST_IGNORE_CUB_VERSION_CHECK //tensorflow:tensorflow_cc_dll_import_lib
bazel build --config=opt --config=cuda --copt=-mavx2 --copt=-nvcc_options=disable-warnings --define=no_tensorflow_py_deps=true --copt=-nvcc_options=disable-warnings --copt=-DTHRUST_IGNORE_CUB_VERSION_CHECK //tensorflow:install_headers

첫 번째는 tensorflow를 빌드하기 위한 것으로 필요한 라이브러리들을 자동을 받아 컴파일한다.

두번째는 컴파일된 결과를 이용하여 lib 파일과 dll을 만든다.

세번째는 여기저기 흩어져 있는 헤더를 모아서 include 폴더를 생성해준다.

만약 출력 디렉토리를 직접설정하고 싶다면 bazel --output_base=경로 build ~~ 로 하면 된다.

 

7.

생성된 dll 과 lib, headers 를 이용하여 MSVC에서 윈도우 프로그램을 작성한다. 

하지만 사용하다보면 링크 오류에 마주치게 된다.

보통 함수를 찾을 수 없다는 전형적인 링크 오류이다. 이는 lib 파일에 함수의 이름을 찾지 못하여 발생한다.

lib에서 함수이름을 알릴때 def 파일을 이용하는데 bazel에서는 이를 사용되는 함수만 등록되도록 한 것 같다.

그러므로 bazel을 이용하여 직접 우리의 소스를 작성하면 자동으로 링크되겠지만 우리는 MSVC를 이용할 것이므로 직접 def 파일에 선언이 필요하다.

 

tensorflow에는 이를 자동으로 정의해주는 파일이 있다.

tensorflow\tools\def_file_filter\def_file_filter.py.tpl

위의 파일에서 직접 지정하면 된다.

251 라인에 보면 링크 이름이 단촐하게 1개 있을것이다.

이 뒤에 우리가 사용하는 함수 이름을 추가해야한다.

예로, 다음과 같이 추가하였다.

    def_fp.write("\t ??1SavedModelBundleInterface@tensorflow@@UEAA@XZ\n")
    def_fp.write("\t ??0SessionOptions@tensorflow@@QEAA@XZ\n")
    def_fp.write("\t ?NewSession@tensorflow@@YA?AVStatus@1@AEBUSessionOptions@1@PEAPEAVSession@1@@Z\n")
    def_fp.write("\t ??0Operation@tensorflow@@QEAA@PEAVNode@1@@Z\n")
    def_fp.write("\t ??1Scope@tensorflow@@QEAA@XZ\n")
    def_fp.write("\t ?NewRootScope@Scope@tensorflow@@SA?AV12@XZ\n")
    def_fp.write("\t ?ToGraphDef@Scope@tensorflow@@QEBA?AVStatus@2@PEAVGraphDef@2@@Z\n")
    def_fp.write("\t ?WithOpNameImpl@Scope@tensorflow@@AEBA?AV12@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z\n")
    def_fp.write("\t ??0ExpandDims@ops@tensorflow@@QEAA@AEBVScope@2@VInput@2@1@Z\n")
    def_fp.write("\t ??0Placeholder@ops@tensorflow@@QEAA@AEBVScope@2@W4DataType@2@@Z\n")
    def_fp.write("\t ??0Cast@ops@tensorflow@@QEAA@AEBVScope@2@VInput@2@W4DataType@2@@Z\n")
    def_fp.write("\t ??0Div@ops@tensorflow@@QEAA@AEBVScope@2@VInput@2@1@Z\n")
    def_fp.write("\t ?NewSession@tensorflow@@YAPEAVSession@1@AEBUSessionOptions@1@@Z\n")
    def_fp.write("\t ?LoadSavedModel@tensorflow@@YA?AVStatus@1@AEBUSessionOptions@1@AEBVRunOptions@1@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@AEBV?$unordered_set@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@U?$hash@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@2@U?$equal_to@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@2@V?$allocator@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@2@@6@QEAUSavedModelBundle@1@@Z\n")

python 파일로 컴파일 되므로 앞쪽 탭에 신경써야 한다.

우리는 savedModel을 사용하므로 이와 관련된 함수를 추가하였다.

이후 bazel 커맨드로 다시 빌드를 하면 된다.

 

이제 tensorflow_cc.dll을 윈도우에서 사용할 수 있다.

 

 

참고. 콘솔이 아닌 파일로 출력 메세지 얻기

이를 위해서는 tensorflow의 sink 와 TFAddLogSink함수를 이용하여야 한다.

헌데 안타깝게도 2.3.0에는 껍질만 만들어 놓았다.

tensorflow\core\platform\default\logging.cc

tensorflow\core\platform\default\logging.h

두 파일에는 정의만 있고 내용물은 없다. 이를 수정해야 한다.

이는 최신 tensorflow를 보면 정의되어 있기에 이를 바로 복사해서 사용해도 된다.

 

tensorflow/logging.cc at r2.9 · tensorflow/tensorflow (github.com)

 

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

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

github.com

 

적용후에 TFLogSink를 상속받은 클래스를 생성해주고 tensorflow::TFAddLogSink 를 호출하면 된다.

 

클래스 정의

class LogSink : public tensorflow::TFLogSink
{
public:
	LogSink()
    {
        _fs.open("tf_log.txt", std::ios_base::out);
    }
	~LogSink()
    {
    	if(_fs.is_open())
			_fs.close();
	}
	void Send(const tensorflow::TFLogEntry& entry)
    {
    	_fs << entry.ToString() << std::endl;
    }
private:
	std::fstream _fs;
};

 

끝.

댓글 영역