TensorFlowを使ったHoudiniノードを作る <C++/HDK>

7 min read読了の目安(約7000字

はじめに

以前にTensorFlowを使ったノード作成は試していたが、ポストとしてまとめていなかったことと、Houdiniのノード作成にCMakeを使うので、そちらに合わせたビルド環境を構築しておきたかったため、それらをまとめる事にした。

余談だが、C++での実装を本格的に始めようとしたきっかけは、機械学習環境の進化に対して、DCCツール側のPythonバージョンが追いついておらず、Pythonのみで実装を進めるには不安定な環境をユーザーに提供してしまう不安があるというのがある。また、Houdini側での実行速度としても担保したい狙いがある。

開発環境

Windows 10
Houdini 18.5.460
TensorFlow 2.4.0 GPU
CUDA 11
Visual Studio 2017

サンプルコード

https://github.com/takavfx/MLHoudiniSamples/tree/master/ML0003_TensorFlowPlugin

準備

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コンフィグを用意しておく。

TensorFlowConfig.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}"
)
TensorFlowConfigVersion.cmake
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版でも書いている様に書く。解説とかもそっちに書いているので、そちらを参考にどうぞ。

CMakeLists.txt
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サンプルを書き換えてテストする。

SOP_TensorFlowTest.C
// ~ 省略 ~
#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>\dsoC:\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ライブラリパッケージには足りないライブラリがある。
(なぜ初歩的なエラーが公式ライブラリに……

https://github.com/tensorflow/tensorflow/issues/46343

解決方法

以下の2通りで解決できる。

  1. Linux版のパッケージをダウンロードし、そこから足りないファイルをコピーする。
  2. Gitレポジトリをクローンしてきて、そこからコピーして使用する。

今回、僕の場合は1の方を選択した。

最後に

これでCMakeでのHoudini TensorFlowノードのビルド環境が構築できた。
また、ここら辺を行うにあたって、今回VSCode側でのタスクランナーの設定をしたりしたのがとても勉強になったので、そこら辺を別途まとめたい。

脚注
  1. TensorFlow - GPU Support - Software requirements ↩︎