こちらは、以前(2021/01/19)に別サービスで展開した内容を Qiita に移行したものです。
はじめに
以前に TensorFlow を使ったノード作成は試していたが、ポストとしてまとめていなかったことと、Houdini のノード作成に CMake を使うので、そちらに合わせたビルド環境を構築しておきたかったため、それらをまとめる事にした。
余談だが、C++ での実装を本格的に始めようとしたきっかけは、機械学習環境の進化に対して、DCC ツール側の Python バージョンが追いついておらず、Python のみで実装を進めるには不安定な環境をユーザーに提供してしまう不安があるというのがある。また、Houdini 側での実行速度としても担保したい狙いがある。
開発環境
Windows 10
Houdini 18.5.460
TensorFlow 2.4.0 GPU
CUDA 11
Visual Studio 2017
サンプルコード
準備
TensorFlow for C をダウンロード
TensorFlow を C++ 上で使用するには、TensorFlow for C を使用する。
ページ内にダウンロードリンクがあるので、任意のライブラリを選択してダウンロードしてくる。
ダウンロードリンクを見つける際、ページの表示言語は英語に設定しておいた方が良い。英語と日本語のページだと、ダウンロードリンクにある TensorFlow のバージョンの差異がある事があり、英語表示のページの方がより最新のライブラリリンクを掲載している事があるため。
CUDA のインストール
CUDA Toolkit もインストールしておく。
もし、CPU 版のライブラリを使用する場合は、こちらはスキップして良い。
TensorFlow v2.4.0 では CUDA 11 を使用する1ので、その点は注意しておく。
CMake
TensorFlow for C の場合、PyTorch と違って中身は非常にシンプルなため、迷うことはさほどないと思う。
しかしながら、Houdini が CMake でのビルドを推奨しており、特にGUI周りの生成の自動化などが Houdini の CMake 側の機能として用意されているため、これに従った方が得策。なので、以下に CMake を使ったビルド方法をまとめる。
TensorFlow 側の CMake
次の様に、CMake コンフィグを用意しておく。
# Find TensorFlow
# ------
# This will define the following variables:
#
# TENSORFLOW_INCLUDE_DIRS -- The include directories for tensorflow
# TENSORFLOW_LIBRARIES -- Libraries to link against
# TENSORFLOW_INSTALL_PREFIX -- Path to library root
#
# and the following imported targets:
#
# tensorflow
if(DEFINED ENV{TENSORFLOW_INSTALL_PREFIX})
set(TENSORFLOW_INSTALL_PREFIX $ENV{TENSORFLOW_INSTALL_PREFIX})
else()
get_filename_component(CMAKE_CURRENT_LIST_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
get_filename_component(TENSORFLOW_INSTALL_PREFIX "${CMAKE_CURRENT_LIST_DIR}/../" ABSOLUTE)
endif()
# Include directories
if(EXISTS "${TENSORFLOW_INSTALL_PREFIX}/include")
set(TENSORFLOW_INCLUDE_DIRS ${TENSORFLOW_INSTALL_PREFIX}/include)
message("-- Tensorflow include directries: ${TENSORFLOW_INCLUDE_DIRS}")
endif()
# Library dependencies.
add_library(tensorflow STATIC IMPORTED)
set(TENSORFLOW_LIBRARIES tensorflow)
find_library(TENSORFLOW_LIBRARY tensorflow PATHS "${TENSORFLOW_INSTALL_PREFIX}/lib")
list(APPEND TENSORFLOW_LIBRARIES ${TENSORFLOW_LIBRARY}) # Append TensorFlow lib
message("-- TensorFlow libraries: ${TENSORFLOW_LIBRARIES}")
set_target_properties(tensorflow PROPERTIES
IMPORTED_LOCATION "${TENSORFLOW_LIBRARY}"
INTERFACE_INCLUDE_DIRECTORIES "${TENSORFLOW_INCLUDE_DIRS}"
)
set(PACKAGE_VERSION "2.4.0")
if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}")
set(PACKAGE_VERSION_COMPATIBLE FALSE)
else()
set(PACKAGE_VERSION_COMPATIBLE TRUE)
if("${PACKAGE_VERSION}" VERSION_EQUAL "${PACKAGE_FIND_VERSION}")
set(PACKAGE_VERSION_EXACT TRUE)
endif()
endif()
Houdini プラグイン側の CMake
こちらは PyTorch 版でも書いている様に書く。解説とかもそっちに書いているので、そちらを参考にどうぞ。
cmake_minimum_required( VERSION 3.6 )
project( TensorFlowTest )
# CMAKE_PREFIX_PATH must contain the path to the toolkit/cmake subdirectory of
# the Houdini installation. See the "Compiling with CMake" section of the HDK
# documentation for more details, which describes several options for
# specifying this path.
list( APPEND CMAKE_PREFIX_PATH "$ENV{HFS}/toolkit/cmake" )
# Locate Houdini's libraries and header files.
# Registers an imported library target named 'Houdini'.
find_package( Houdini REQUIRED )
find_package( TensorFlow REQUIRED )
set( library_name SOP_TensorFlowTest )
# Code generation for the embedded DS file in SOP_TensorFlowTest.C.
houdini_generate_proto_headers( FILES SOP_TensorFlowTest.C )
# Add a library and its source files.
add_library( ${library_name} SHARED
SOP_TensorFlowTest.C
SOP_TensorFlowTest.h
)
# Link against the Houdini libraries, and add required include directories and
# compile definitions.
target_link_libraries( ${library_name} Houdini "${TENSORFLOW_LIBRARIES}")
# Include ${CMAKE_CURRENT_BINARY_DIR} for the generated header.
target_include_directories( ${library_name} PRIVATE
${CMAKE_CURRENT_BINARY_DIR}
)
# Sets several common target properties, such as the library's output directory.
houdini_configure_target( ${library_name} )
if (MSVC)
# Make directory before copy dll
set(binary_dir $<TARGET_FILE_DIR:${library_name}>/../bin)
add_custom_command(TARGET ${library_name}
COMMAND ${CMAKE_COMMAND} -E make_directory
${binary_dir})
# Copy dll to install target bin directory
file(GLOB TENSORFLOW_DLLS "${TENSORFLOW_INSTALL_PREFIX}/lib/*.dll")
add_custom_command(TARGET ${library_name}
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
${TENSORFLOW_DLLS}
${binary_dir})
endif (MSVC)
Houdini プラグインのソースの編集
例によって、SOP_Star サンプルを書き換えてテストする。
// ~ 省略 ~
# include <stdio.h>
# include <tensorflow/c/c_api.h>
// ~ 省略 ~
// ノードクック時の処理
void
SOP_TensorFlowTestVerb::cook(const SOP_NodeVerb::CookParms &cookparms) const
{
// ~ 省略 ~
printf("Hello from TensorFlow C library version %s\n", TF_Version());
// ~ 省略 ~
}
ビルド
CMake ビルド
CMake のビルドと、実際の MSVC でのビルドを実行する。
cmake .. -G "Visual Studio 15 2017 Win64" -DCMAKE_PREFIX_PATH=\path\to\tesnorflow
cmake --build . --config Release
デフォルトでは、C:\Users\<username>\Documents\houdini<houdini_version>\dso
とC:\Users\<username>\Documents\houdini<houdini_version>\bin
以下にインストールされる。
bin ディレクトリと分けているのは、PyTorch 版でも書いた通り、dso 以下には Houidni がバージョン認識できる dll のみを置く必要があり、余計な dll ファイルを置けないため。
Houdini 上でのテスト
先に、PATH
環境変数と、プラグインのエラーを追うために HOUDINI_DSO_ERROR
の環境変数設定を行う。
set PATH=C:\Users\<username>\Documents\houdini18.5\bin
set HOUDINI_DSO_ERROR=1
そして Houdini を起動する。
/obj/geo1 と、Geoemtry ネットワークを作成し、そこで TensorFlowTest ノードを作成してみる。
次の様に動いていればビルド成功。
トラブルシュート
fatal error C1083: Cannot open include file: 'tensorflow/c/c_api_macros.h': No such file or directory
原因
Windows 版の TensorFlow ライブラリパッケージには足りないライブラリがある。
(なぜ初歩的なエラーが公式ライブラリに……
解決方法
以下の2通りで解決できる。
- Linux 版のパッケージをダウンロードし、そこから足りないファイルをコピーする。
- Git レポジトリをクローンしてきて、そこからコピーして使用する。
今回、僕の場合は1の方を選択した。
最後に
これで CMake での Houdini TensorFlow ノードのビルド環境が構築できた。
また、ここら辺を行うにあたって、今回 VSCode 側でのタスクランナーの設定をしたりしたのがとても勉強になったので、そこら辺を別途まとめたい。