From fb893e7ba390d1b668efb4b84b3376cf634bd043 Mon Sep 17 00:00:00 2001 From: bruno Date: Tue, 13 Oct 2020 11:36:43 +0200 Subject: [PATCH 1/5] Ensure torchvision operators are registered in C++ via weak symbols --- torchvision/csrc/vision.cpp | 9 +++++++++ torchvision/csrc/vision.h | 19 +++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/torchvision/csrc/vision.cpp b/torchvision/csrc/vision.cpp index 81daa0fd81a..084e39e2cb0 100644 --- a/torchvision/csrc/vision.cpp +++ b/torchvision/csrc/vision.cpp @@ -83,3 +83,12 @@ TORCH_LIBRARY_IMPL(torchvision, Autograd, m) { m.impl("roi_align", ROIAlign_autograd); m.impl("_roi_align_backward", ROIAlign_backward_autograd); } + +namespace vision { + // This function is needed to reference the static variable created by the + // TORCH_LIBRARY macro so that it is not optimized away. + TORCH_API int RegisterOps() noexcept { + (void) TORCH_LIBRARY_static_init_torchvision; + return 0; + } +} diff --git a/torchvision/csrc/vision.h b/torchvision/csrc/vision.h index 1e4957150e6..238faed36fb 100644 --- a/torchvision/csrc/vision.h +++ b/torchvision/csrc/vision.h @@ -2,5 +2,24 @@ #define VISION_H #include +#include + +#if (defined __cpp_inline_variables) || __cplusplus >= 201703L +#define VISION_INLINE_VARIABLE inline +#else +#ifdef _MSC_VER +#define VISION_INLINE_VARIABLE __declspec(selectany) +#else +#define VISION_INLINE_VARIABLE __attribute__((weak)) +#endif +#endif + +namespace vision { + TORCH_API int RegisterOps() noexcept; + + namespace detail { + VISION_INLINE_VARIABLE int dummy = RegisterOps(); + } +} #endif // VISION_H From eca76e6d7ee927ddc63e45a63265860eac1ee991 Mon Sep 17 00:00:00 2001 From: bruno Date: Tue, 13 Oct 2020 11:37:50 +0200 Subject: [PATCH 2/5] Add note to README on how to ensure that torchvision operators are available in C++ --- README.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.rst b/README.rst index e57256e0511..319ac23eb94 100644 --- a/README.rst +++ b/README.rst @@ -123,6 +123,11 @@ so make sure that it is also available to cmake via the ``CMAKE_PREFIX_PATH``. For an example setup, take a look at ``examples/cpp/hello_world``. +TorchVision Operators +--------------------- +In order to get the torchvision operators registered with torch (eg. for the JIT), all you need to do is to ensure that you +:code:`#include ` in your project. + Documentation ============= You can find the API documentation on the pytorch website: https://pytorch.org/docs/stable/torchvision/index.html From 535504dc06205cfee5e1267110ec26686a123e7c Mon Sep 17 00:00:00 2001 From: bruno Date: Tue, 13 Oct 2020 12:23:35 +0200 Subject: [PATCH 3/5] Fix dllimport/dllexport on windows, format files --- CMakeLists.txt | 1 + setup.py | 2 +- torchvision/csrc/vision.cpp | 12 ++++++------ torchvision/csrc/vision.h | 16 +++++++++++----- 4 files changed, 19 insertions(+), 12 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index cd2a4d49c29..e2974657519 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -61,6 +61,7 @@ endif() add_library(${PROJECT_NAME} SHARED ${MODELS_SOURCES} ${OPERATOR_SOURCES} ${IMAGE_SOURCES}) target_link_libraries(${PROJECT_NAME} PRIVATE ${TORCH_LIBRARIES} ${PNG_LIBRARY} ${JPEG_LIBRARIES} Python3::Python) +target_compile_definitions(${PROJECT_NAME} PRIVATE VISION_BUILD_LIB) set_target_properties(${PROJECT_NAME} PROPERTIES EXPORT_NAME TorchVision) include_directories(torchvision/csrc ${JPEG_INCLUDE_DIRS} ${PNG_INCLUDE_DIRS}) diff --git a/setup.py b/setup.py index d6674465405..d1ec2399d88 100644 --- a/setup.py +++ b/setup.py @@ -178,7 +178,7 @@ def get_extensions(): tests = test_file + source_models tests_include_dirs = [test_dir, models_dir] - define_macros = [] + define_macros = [('VISION_BUILD_LIB', None)] extra_compile_args = {} if (torch.cuda.is_available() and ((CUDA_HOME is not None) or is_rocm_pytorch)) \ diff --git a/torchvision/csrc/vision.cpp b/torchvision/csrc/vision.cpp index 084e39e2cb0..9bac5d20526 100644 --- a/torchvision/csrc/vision.cpp +++ b/torchvision/csrc/vision.cpp @@ -85,10 +85,10 @@ TORCH_LIBRARY_IMPL(torchvision, Autograd, m) { } namespace vision { - // This function is needed to reference the static variable created by the - // TORCH_LIBRARY macro so that it is not optimized away. - TORCH_API int RegisterOps() noexcept { - (void) TORCH_LIBRARY_static_init_torchvision; - return 0; - } +// This function is needed to reference the static variable created by the +// TORCH_LIBRARY macro so that it is not optimized away. +int RegisterOps() noexcept { + (void)TORCH_LIBRARY_static_init_torchvision; + return 0; } +} // namespace vision diff --git a/torchvision/csrc/vision.h b/torchvision/csrc/vision.h index 238faed36fb..5060d489edc 100644 --- a/torchvision/csrc/vision.h +++ b/torchvision/csrc/vision.h @@ -1,8 +1,8 @@ #ifndef VISION_H #define VISION_H +#include #include -#include #if (defined __cpp_inline_variables) || __cplusplus >= 201703L #define VISION_INLINE_VARIABLE inline @@ -14,12 +14,18 @@ #endif #endif +#ifdef VISION_BUILD_LIB +#define VISION_API C10_EXPORT +#else +#define VISION_API C10_IMPORT +#endif + namespace vision { - TORCH_API int RegisterOps() noexcept; +VISION_API int RegisterOps() noexcept; - namespace detail { - VISION_INLINE_VARIABLE int dummy = RegisterOps(); - } +namespace detail { +VISION_INLINE_VARIABLE int dummy = RegisterOps(); } +} // namespace vision #endif // VISION_H From 2c3b9d08b1d06eed79e3380d780ae91eb888fd76 Mon Sep 17 00:00:00 2001 From: bruno Date: Tue, 13 Oct 2020 14:49:41 +0200 Subject: [PATCH 4/5] Factor out common macros in single file --- CMakeLists.txt | 1 - setup.py | 2 +- torchvision/csrc/cpu/vision_cpu.h | 11 +---------- torchvision/csrc/cuda/vision_cuda.h | 11 +---------- torchvision/csrc/macros.h | 24 ++++++++++++++++++++++++ torchvision/csrc/vision.h | 18 +----------------- 6 files changed, 28 insertions(+), 39 deletions(-) create mode 100644 torchvision/csrc/macros.h diff --git a/CMakeLists.txt b/CMakeLists.txt index e2974657519..cd2a4d49c29 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -61,7 +61,6 @@ endif() add_library(${PROJECT_NAME} SHARED ${MODELS_SOURCES} ${OPERATOR_SOURCES} ${IMAGE_SOURCES}) target_link_libraries(${PROJECT_NAME} PRIVATE ${TORCH_LIBRARIES} ${PNG_LIBRARY} ${JPEG_LIBRARIES} Python3::Python) -target_compile_definitions(${PROJECT_NAME} PRIVATE VISION_BUILD_LIB) set_target_properties(${PROJECT_NAME} PROPERTIES EXPORT_NAME TorchVision) include_directories(torchvision/csrc ${JPEG_INCLUDE_DIRS} ${PNG_INCLUDE_DIRS}) diff --git a/setup.py b/setup.py index d1ec2399d88..d6674465405 100644 --- a/setup.py +++ b/setup.py @@ -178,7 +178,7 @@ def get_extensions(): tests = test_file + source_models tests_include_dirs = [test_dir, models_dir] - define_macros = [('VISION_BUILD_LIB', None)] + define_macros = [] extra_compile_args = {} if (torch.cuda.is_available() and ((CUDA_HOME is not None) or is_rocm_pytorch)) \ diff --git a/torchvision/csrc/cpu/vision_cpu.h b/torchvision/csrc/cpu/vision_cpu.h index 331043c5d39..c2a2c36ce99 100644 --- a/torchvision/csrc/cpu/vision_cpu.h +++ b/torchvision/csrc/cpu/vision_cpu.h @@ -1,15 +1,6 @@ #pragma once #include - -#ifdef _WIN32 -#if defined(torchvision_EXPORTS) -#define VISION_API __declspec(dllexport) -#else -#define VISION_API __declspec(dllimport) -#endif -#else -#define VISION_API -#endif +#include "../macros.h" VISION_API std::tuple ROIPool_forward_cpu( const at::Tensor& input, diff --git a/torchvision/csrc/cuda/vision_cuda.h b/torchvision/csrc/cuda/vision_cuda.h index e3175ad39e2..2c13d0aeed3 100644 --- a/torchvision/csrc/cuda/vision_cuda.h +++ b/torchvision/csrc/cuda/vision_cuda.h @@ -1,15 +1,6 @@ #pragma once #include - -#ifdef _WIN32 -#if defined(torchvision_EXPORTS) -#define VISION_API __declspec(dllexport) -#else -#define VISION_API __declspec(dllimport) -#endif -#else -#define VISION_API -#endif +#include "../macros.h" VISION_API at::Tensor ROIAlign_forward_cuda( const at::Tensor& input, diff --git a/torchvision/csrc/macros.h b/torchvision/csrc/macros.h new file mode 100644 index 00000000000..cb01005a022 --- /dev/null +++ b/torchvision/csrc/macros.h @@ -0,0 +1,24 @@ +#ifndef TORCHVISION_MACROS_H +#define TORCHVISION_MACROS_H + +#ifdef _WIN32 +#if defined(torchvision_EXPORTS) +#define VISION_API __declspec(dllexport) +#else +#define VISION_API __declspec(dllimport) +#endif +#else +#define VISION_API +#endif + +#if (defined __cpp_inline_variables) || __cplusplus >= 201703L +#define VISION_INLINE_VARIABLE inline +#else +#ifdef _MSC_VER +#define VISION_INLINE_VARIABLE __declspec(selectany) +#else +#define VISION_INLINE_VARIABLE __attribute__((weak)) +#endif +#endif + +#endif // TORCHVISION_MACROS_H diff --git a/torchvision/csrc/vision.h b/torchvision/csrc/vision.h index 5060d489edc..9362cd069e4 100644 --- a/torchvision/csrc/vision.h +++ b/torchvision/csrc/vision.h @@ -1,24 +1,8 @@ #ifndef VISION_H #define VISION_H -#include #include - -#if (defined __cpp_inline_variables) || __cplusplus >= 201703L -#define VISION_INLINE_VARIABLE inline -#else -#ifdef _MSC_VER -#define VISION_INLINE_VARIABLE __declspec(selectany) -#else -#define VISION_INLINE_VARIABLE __attribute__((weak)) -#endif -#endif - -#ifdef VISION_BUILD_LIB -#define VISION_API C10_EXPORT -#else -#define VISION_API C10_IMPORT -#endif +#include "macros.h" namespace vision { VISION_API int RegisterOps() noexcept; From f8b3c7d60c2af941e4a60b9ca314d218691ee127 Mon Sep 17 00:00:00 2001 From: bruno Date: Thu, 15 Oct 2020 11:12:40 +0200 Subject: [PATCH 5/5] Expose cuda_version in the API, use it to avoid pruning of ops initializer --- torchvision/csrc/vision.cpp | 15 ++++----------- torchvision/csrc/vision.h | 10 +++++++--- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/torchvision/csrc/vision.cpp b/torchvision/csrc/vision.cpp index 9bac5d20526..75e65d67661 100644 --- a/torchvision/csrc/vision.cpp +++ b/torchvision/csrc/vision.cpp @@ -34,13 +34,15 @@ PyMODINIT_FUNC PyInit__C(void) { #endif #endif -int64_t _cuda_version() { +namespace vision { +int64_t cuda_version() noexcept { #ifdef WITH_CUDA return CUDA_VERSION; #else return -1; #endif } +} // namespace vision TORCH_LIBRARY(torchvision, m) { m.def("nms(Tensor dets, Tensor scores, float iou_threshold) -> Tensor"); @@ -53,7 +55,7 @@ TORCH_LIBRARY(torchvision, m) { m.def("ps_roi_align", &ps_roi_align); m.def("ps_roi_pool", &ps_roi_pool); m.def("deform_conv2d", &deform_conv2d); - m.def("_cuda_version", &_cuda_version); + m.def("_cuda_version", &vision::cuda_version); } TORCH_LIBRARY_IMPL(torchvision, CPU, m) { @@ -83,12 +85,3 @@ TORCH_LIBRARY_IMPL(torchvision, Autograd, m) { m.impl("roi_align", ROIAlign_autograd); m.impl("_roi_align_backward", ROIAlign_backward_autograd); } - -namespace vision { -// This function is needed to reference the static variable created by the -// TORCH_LIBRARY macro so that it is not optimized away. -int RegisterOps() noexcept { - (void)TORCH_LIBRARY_static_init_torchvision; - return 0; -} -} // namespace vision diff --git a/torchvision/csrc/vision.h b/torchvision/csrc/vision.h index 9362cd069e4..50bebab1fb1 100644 --- a/torchvision/csrc/vision.h +++ b/torchvision/csrc/vision.h @@ -2,14 +2,18 @@ #define VISION_H #include +#include #include "macros.h" namespace vision { -VISION_API int RegisterOps() noexcept; +VISION_API int64_t cuda_version() noexcept; namespace detail { -VISION_INLINE_VARIABLE int dummy = RegisterOps(); -} +// Dummy variable to reference a symbol from vision.cpp. +// This ensures that the torchvision library and the ops registration +// initializers are not pruned. +VISION_INLINE_VARIABLE int64_t _cuda_version = cuda_version(); +} // namespace detail } // namespace vision #endif // VISION_H