作成したプロパティシートが記事の下部にあるので、それを使えばビルドできる。
要約
- サンプルソースコードを用意して、CMakeで
*.sln
と*.vcxproj
を出力。 -
*.vcxproj
からプロパティシートを作成。 - 次からはVisual Studioの「空のプロジェクト(など)」にプロパティシートを適用すれば、簡単にGPU有効でEXEをビルドできる。
初めに
他のライブラリと連携するために、できればCMakeを挟まずにVisual StudioだけでLibTorchアプリを作りたい、という状況になった。(設定次第でCMakeでできると思うが)
VisualStudioだけでもインクルードパスや依存ファイルを設定すればCPU版LibTorchは使えるが、いろいろな所をこねくり回してもGPU有効にならなかった。
CMakeを使えば(まあまあ)簡単にGPU有効のアプリがビルドできるが、Visual StudioだけでGPU有効にする記事が自分が探した限りだと無かったため、ここに記す。
また、筆者はCMakeやC++、Visual Studioに精通はしていないので、より良い情報があればご教示ください。
実行環境
OS: Windows 10 Enterprise
CPU: Core i7-8700K
GPU: RTX 2080 SUPER
RAM: 8.0x2 GB
Visual Studio 2019 Community
CUDA 10.1
cuDNN 7.5.1
LibTorch 1.6.0
C++17
CMake 3.18.0
準備
まず、PyTorch公式サイトからLibTorchをダウンロード。
Debug版とRelease版両方ダウンロードする。
ダウンロードしたライブラリを解凍して、C直下に移動。
Debug版を"Debug"、Release版を"Release"と名前を変え、フォルダ階層を以下のようにする。
C:\libtorch\1_6_0\(Debug, Release)\(bin, include, libなど)\.....
次にCUDA10.1を公式サイトからダウンロードしてインストールする。
環境変数PATHへの追加を必ずする。
次にcuDNN 7.5.1を公式サイトからダウンロードして、
C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.1
へ、bin, include, libをコピーする。
ダウンロードにはアカウント作成が必要。
CMakeでビルドシステムを出力し、プロパティシートを作成
CMakeでソリューションを作成
CMakeを使って、ビルドシステム(Visual Studioのソリューションやプロジェクトファイル)を出力する。
ここではコマンドで操作するが、VSCodeならば直感的にCMakeを操作できるのでオススメ。
適当な場所にフォルダを作り(ここでは、D直下にcmake_sampleフォルダを作成)、sample.cpp
とCMakeLists.txt
を作成する。
2つのファイルを以下のように編集する。また、今回はC++17を対象とする。
#include <iostream>
#include <torch/torch.h>
int main()
{
torch::DeviceType device_type;
if (torch::cuda::is_available())
{
std::cout << "CUDA available!\n";
device_type = torch::kCUDA;
}
else
{
std::cout << "CPU only.\n";
device_type = torch::kCPU;
}
torch::Device device(device_type);
auto tensor = torch::randn({2, 3});
tensor = tensor.to(device);
std::cout << tensor << std::endl;
}
cmake_minimum_required(VERSION 3.0 FATAL_ERROR)
project(cmake_sample)
set(CMAKE_CXX_STANDARD 17) #add
find_package(Torch REQUIRED)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${TORCH_CXX_FLAGS}")
add_executable(sample sample.cpp)
target_link_libraries(sample "${TORCH_LIBRARIES}")
# set_property(TARGET example-app PROPERTY CXX_STANDARD 14)
# The following code block is suggested to be used on Windows.
# According to https://github.com/pytorch/pytorch/issues/25457,
# the DLLs need to be copied to avoid memory errors.
if (MSVC)
file(GLOB TORCH_DLLS "${TORCH_INSTALL_PREFIX}/lib/*.dll")
add_custom_command(TARGET sample
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
${TORCH_DLLS}
$<TARGET_FILE_DIR:sample>)
endif (MSVC)
x64_x86 Cross Tools Command Prompt for VS 2019
を管理者権限で開き、以下のコマンドを実行していく。
$ D:
$ cd cmake_sample
$ mkdir build
$ cd build
$ cmake .. -G "Visual Studio 16 2019" -DCMAKE_PREFIX_PATH=C:\libtorch\1_6_0\Debug
プロパティシートの作成(Debug構成)
buildフォルダ内にcmake_sample.sln
という名前のVisual Studioのソリューションができているので開く。
構成をDebug|x64
へ変更してビルド(Ctrl + Shift + B)。
プロジェクトsample
をスタートアップへ変更してF5。
CUDA available!
とCUDAFloatType
のテンソルが表示されれば、正しくビルドできている。
CPU
になってしまった場合、ファイルの配置、環境変数、コマンドを見直す。
実行が上手くいったことを確認したら、Visual Studioで「空のプロジェクト」を作成し、プロパティマネージャを開く。
Debug|x64
を右クリック、新しいプロジェクトプロパティシートを追加
し、プロパティシートlibtorch_1_6_0.prop
を作成する。
テキストエディタでプロパティシートを開き、<ItemDefinitionGroup />
の行を削除。
テキストエディタでsample.vcxproj
ファイルを開く。
sample.vcxproj
の、
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
から
</ItemDefinitionGroup>
までをコピーし、libtorch_1_6_0.prop
内の<Project>
タグ内へペースト。
この時、sample.cpp
に依存する部分は全て消去する。
両者を保存して閉じる。
プロパティシートの作成(Release構成)
(先程とほとんど同じのため、いくつか省略している。)
buildフォルダ内のCMakeCache.txt
を削除する。(重要)
その後、buildフォルダ内で次のコマンド
$ cmake .. -G "Visual Studio 16 2019" -DCMAKE_PREFIX_PATH=C:\libtorch\1_6_0\Release
を実行し、buildフォルダ内のVisual Studioのソリューションを開く。
構成をRelease|x64
へ変更、ビルドして実行。
CUDA available!
とCUDAFloatType
のテンソルが表示されれば、正しくビルドできている。
実行が上手くいったことを確認したら、またプロパティシートlibtorch_1_6_0.prop
をテキストエディタで開く。
テキストエディタでsample.vcxproj
ファイルを再度開く。
sample.vcxproj
の、
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
から
</ItemDefinitionGroup>
までをコピーし、libtorch_1_6_0.prop
内の<Project>
タグ範囲内へペースト。
両者を保存して閉じる。
動作確認
VisualStudioで適当な「空のプロジェクト」を作成する。
プロパティマネージャのDebug|x64
とRelease|x64
へlibtorch_1_6_0.prop
を追加する。
ソースファイルを追加し、先ほどのsample.cpp
と同じ内容を書き込む。
初回は*.dll
をコピーしてくるため、実行に時間が掛かる。
両者においてCUDA available!
とCUDAFloatType
のテンソルが表示されれば、正しく設定ができている。
ブレークポイントを打ってデバッグ実行が効くかどうか試してみても良い。
次からはこのプロパティシートを使いまわすことで、GPU対応のプログラムをすぐに作成できる。
最終的なプロパティシート
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ImportGroup Label="PropertySheets" />
<PropertyGroup Label="UserMacros" />
<PropertyGroup />
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<AdditionalIncludeDirectories>C:\libtorch\1_6_0\$(Configuration)\include;C:\libtorch\1_6_0\$(Configuration)\include\torch\csrc\api\include;C:\Program Files\NVIDIA Corporation\NvToolsExt\include;C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.1\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalOptions>%(AdditionalOptions) /bigobj</AdditionalOptions>
<AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<DebugInformationFormat>OldStyle</DebugInformationFormat>
<DisableSpecificWarnings>4267;4251;4522;4838;4305;4244;4190;4101;4996;4275</DisableSpecificWarnings>
<ExceptionHandling>Sync</ExceptionHandling>
<InlineFunctionExpansion>Disabled</InlineFunctionExpansion>
<LanguageStandard>stdcpp17</LanguageStandard>
<Optimization>Disabled</Optimization>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<RuntimeTypeInfo>true</RuntimeTypeInfo>
<UseFullPaths>false</UseFullPaths>
<WarningLevel>Level3</WarningLevel>
<PreprocessorDefinitions>WIN32;_WINDOWS;BUILD_TYPE="Debug";NOMINMAX;CMAKE_INTDIR="Debug";DEBUG_;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ObjectFileName>$(IntDir)</ObjectFileName>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;BUILD_TYPE=\"$(Configuration)\";NOMINMAX;CMAKE_INTDIR=\"$(Configuration)\";%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>C:\libtorch\1_6_0\$(Configuration)\include;C:\libtorch\1_6_0\$(Configuration)\include\torch\csrc\api\include;C:\Program Files\NVIDIA Corporation\NvToolsExt\include;C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.1\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ResourceCompile>
<Midl>
<AdditionalIncludeDirectories>C:\libtorch\1_6_0\$(Configuration)\include;C:\libtorch\1_6_0\$(Configuration)\include\torch\csrc\api\include;C:\Program Files\NVIDIA Corporation\NvToolsExt\include;C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.1\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<OutputDirectory>$(ProjectDir)/$(IntDir)</OutputDirectory>
<HeaderFileName>%(Filename).h</HeaderFileName>
<TypeLibraryName>%(Filename).tlb</TypeLibraryName>
<InterfaceIdentifierFileName>%(Filename)_i.c</InterfaceIdentifierFileName>
<ProxyFileName>%(Filename)_p.c</ProxyFileName>
</Midl>
<Link>
<AdditionalDependencies>C:\libtorch\1_6_0\$(Configuration)\lib\c10.lib;C:\Program Files\NVIDIA Corporation\NvToolsExt\lib\$(PlatformShortName)\nvToolsExt64_1.lib;C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.1\lib\x64\cudart_static.lib;C:\libtorch\1_6_0\$(Configuration)\lib\caffe2_nvrtc.lib;C:\libtorch\1_6_0\$(Configuration)\lib\c10_cuda.lib;C:\libtorch\1_6_0\$(Configuration)\lib\torch.lib;C:\libtorch\1_6_0\$(Configuration)\lib\torch_cuda.lib;C:\libtorch\1_6_0\$(Configuration)\lib\torch_cpu.lib;-INCLUDE:?warp_size@cuda@at@@YAHXZ;C:\libtorch\1_6_0\$(Configuration)\lib\c10_cuda.lib;C:\libtorch\1_6_0\$(Configuration)\lib\c10.lib;C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.1\lib\x64\cufft.lib;C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.1\lib\x64\curand.lib;C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.1\lib\x64\cublas.lib;C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.1\lib\x64\cudnn.lib;C:\Program Files\NVIDIA Corporation\NvToolsExt\lib\x64\nvToolsExt64_1.lib;C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.1\lib\x64\cudart_static.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib</AdditionalDependencies>
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalOptions>%(AdditionalOptions) /machine:$(PlatformShortName)</AdditionalOptions>
<GenerateDebugInformation>true</GenerateDebugInformation>
<IgnoreSpecificDefaultLibraries>%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
<SubSystem>Console</SubSystem>
</Link>
<PostBuildEvent>
<Message>
</Message>
<Command>
setlocal
"C:\Program Files\CMake\bin\cmake.exe" -E copy_if_different C:/libtorch/1_6_0/$(Configuration)/lib/asmjit.dll C:/libtorch/1_6_0/$(Configuration)/lib/c10.dll C:/libtorch/1_6_0/$(Configuration)/lib/c10_cuda.dll C:/libtorch/1_6_0/$(Configuration)/lib/caffe2_detectron_ops_gpu.dll C:/libtorch/1_6_0/$(Configuration)/lib/caffe2_module_test_dynamic.dll C:/libtorch/1_6_0/$(Configuration)/lib/caffe2_nvrtc.dll C:/libtorch/1_6_0/$(Configuration)/lib/cublas64_10.dll C:/libtorch/1_6_0/$(Configuration)/lib/cublasLt64_10.dll C:/libtorch/1_6_0/$(Configuration)/lib/cudart64_101.dll C:/libtorch/1_6_0/$(Configuration)/lib/cudnn64_7.dll C:/libtorch/1_6_0/$(Configuration)/lib/cufft64_10.dll C:/libtorch/1_6_0/$(Configuration)/lib/cufftw64_10.dll C:/libtorch/1_6_0/$(Configuration)/lib/curand64_10.dll C:/libtorch/1_6_0/$(Configuration)/lib/cusparse64_10.dll C:/libtorch/1_6_0/$(Configuration)/lib/fbgemm.dll C:/libtorch/1_6_0/$(Configuration)/lib/libiomp5md.dll C:/libtorch/1_6_0/$(Configuration)/lib/libiompstubs5md.dll C:/libtorch/1_6_0/$(Configuration)/lib/nvToolsExt64_1.dll C:/libtorch/1_6_0/$(Configuration)/lib/nvrtc-builtins64_101.dll C:/libtorch/1_6_0/$(Configuration)/lib/nvrtc64_101_0.dll C:/libtorch/1_6_0/$(Configuration)/lib/torch.dll C:/libtorch/1_6_0/$(Configuration)/lib/torch_cpu.dll C:/libtorch/1_6_0/$(Configuration)/lib/torch_cuda.dll C:/libtorch/1_6_0/$(Configuration)/lib/torch_global_deps.dll $(SolutionDir)$(PlatformShortName)\$(Configuration)\
if %errorlevel% neq 0 goto :cmEnd
:cmEnd
endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone
:cmErrorLevel
exit /b %1
:cmDone
if %errorlevel% neq 0 goto :VCEnd
</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<AdditionalIncludeDirectories>C:\libtorch\1_6_0\$(Configuration)\include;C:\libtorch\1_6_0\$(Configuration)\include\torch\csrc\api\include;C:\Program Files\NVIDIA Corporation\NvToolsExt\include;C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.1\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalOptions>%(AdditionalOptions) /bigobj</AdditionalOptions>
<AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
<DisableSpecificWarnings>4267;4251;4522;4838;4305;4244;4190;4101;4996;4275</DisableSpecificWarnings>
<ExceptionHandling>Sync</ExceptionHandling>
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
<LanguageStandard>stdcpp17</LanguageStandard>
<Optimization>MaxSpeed</Optimization>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<RuntimeTypeInfo>true</RuntimeTypeInfo>
<UseFullPaths>false</UseFullPaths>
<WarningLevel>Level3</WarningLevel>
<PreprocessorDefinitions>WIN32;_WINDOWS;NDEBUG;BUILD_TYPE="$(Configuration)";NOMINMAX;CMAKE_INTDIR="$(Configuration)";%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ObjectFileName>$(IntDir)</ObjectFileName>
<DebugInformationFormat>
</DebugInformationFormat>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>WIN32;_WINDOWS;NDEBUG;BUILD_TYPE=\"$(Configuration)\";NOMINMAX;CMAKE_INTDIR=\"$(Configuration)\";%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>C:\libtorch\1_6_0\$(Configuration)\include;C:\libtorch\1_6_0\$(Configuration)\include\torch\csrc\api\include;C:\Program Files\NVIDIA Corporation\NvToolsExt\include;C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.1\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ResourceCompile>
<Midl>
<AdditionalIncludeDirectories>C:\libtorch\1_6_0\$(Configuration)\include;C:\libtorch\1_6_0\$(Configuration)\include\torch\csrc\api\include;C:\Program Files\NVIDIA Corporation\NvToolsExt\include;C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.1\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<OutputDirectory>$(ProjectDir)/$(IntDir)</OutputDirectory>
<HeaderFileName>%(Filename).h</HeaderFileName>
<TypeLibraryName>%(Filename).tlb</TypeLibraryName>
<InterfaceIdentifierFileName>%(Filename)_i.c</InterfaceIdentifierFileName>
<ProxyFileName>%(Filename)_p.c</ProxyFileName>
</Midl>
<Link>
<AdditionalDependencies>C:\libtorch\1_6_0\$(Configuration)\lib\c10.lib;C:\Program Files\NVIDIA Corporation\NvToolsExt\lib\$(PlatformShortName)\nvToolsExt64_1.lib;C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.1\lib\x64\cudart_static.lib;C:\libtorch\1_6_0\$(Configuration)\lib\caffe2_nvrtc.lib;C:\libtorch\1_6_0\$(Configuration)\lib\c10_cuda.lib;C:\libtorch\1_6_0\$(Configuration)\lib\torch.lib;C:\libtorch\1_6_0\$(Configuration)\lib\torch_cuda.lib;C:\libtorch\1_6_0\$(Configuration)\lib\torch_cpu.lib;-INCLUDE:?warp_size@cuda@at@@YAHXZ;C:\libtorch\1_6_0\$(Configuration)\lib\c10_cuda.lib;C:\libtorch\1_6_0\$(Configuration)\lib\c10.lib;C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.1\lib\x64\cufft.lib;C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.1\lib\x64\curand.lib;C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.1\lib\x64\cublas.lib;C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.1\lib\x64\cudnn.lib;C:\Program Files\NVIDIA Corporation\NvToolsExt\lib\x64\nvToolsExt64_1.lib;C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.1\lib\x64\cudart_static.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib</AdditionalDependencies>
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalOptions>%(AdditionalOptions) /machine:$(PlatformShortName)</AdditionalOptions>
<GenerateDebugInformation>false</GenerateDebugInformation>
<IgnoreSpecificDefaultLibraries>%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
<SubSystem>Console</SubSystem>
</Link>
<PostBuildEvent>
<Message>
</Message>
<Command>
setlocal
"C:\Program Files\CMake\bin\cmake.exe" -E copy_if_different C:/libtorch/1_6_0/$(Configuration)/lib/asmjit.dll C:/libtorch/1_6_0/$(Configuration)/lib/c10.dll C:/libtorch/1_6_0/$(Configuration)/lib/c10_cuda.dll C:/libtorch/1_6_0/$(Configuration)/lib/caffe2_detectron_ops_gpu.dll C:/libtorch/1_6_0/$(Configuration)/lib/caffe2_module_test_dynamic.dll C:/libtorch/1_6_0/$(Configuration)/lib/caffe2_nvrtc.dll C:/libtorch/1_6_0/$(Configuration)/lib/cublas64_10.dll C:/libtorch/1_6_0/$(Configuration)/lib/cublasLt64_10.dll C:/libtorch/1_6_0/$(Configuration)/lib/cudart64_101.dll C:/libtorch/1_6_0/$(Configuration)/lib/cudnn64_7.dll C:/libtorch/1_6_0/$(Configuration)/lib/cufft64_10.dll C:/libtorch/1_6_0/$(Configuration)/lib/cufftw64_10.dll C:/libtorch/1_6_0/$(Configuration)/lib/curand64_10.dll C:/libtorch/1_6_0/$(Configuration)/lib/cusparse64_10.dll C:/libtorch/1_6_0/$(Configuration)/lib/fbgemm.dll C:/libtorch/1_6_0/$(Configuration)/lib/libiomp5md.dll C:/libtorch/1_6_0/$(Configuration)/lib/libiompstubs5md.dll C:/libtorch/1_6_0/$(Configuration)/lib/nvToolsExt64_1.dll C:/libtorch/1_6_0/$(Configuration)/lib/nvrtc-builtins64_101.dll C:/libtorch/1_6_0/$(Configuration)/lib/nvrtc64_101_0.dll C:/libtorch/1_6_0/$(Configuration)/lib/torch.dll C:/libtorch/1_6_0/$(Configuration)/lib/torch_cpu.dll C:/libtorch/1_6_0/$(Configuration)/lib/torch_cuda.dll C:/libtorch/1_6_0/$(Configuration)/lib/torch_global_deps.dll $(SolutionDir)$(PlatformShortName)\$(Configuration)\
if %errorlevel% neq 0 goto :cmEnd
:cmEnd
endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone
:cmErrorLevel
exit /b %1
:cmDone
if %errorlevel% neq 0 goto :VCEnd
</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemGroup />
</Project>
結言
もっときれいにやる方法はないだろうか