From bbeae24145e3efda7273b9d9a5231bb0d0879cf3 Mon Sep 17 00:00:00 2001 From: Orion Reblitz-Richardson Date: Tue, 10 Jul 2018 09:10:34 -0700 Subject: [PATCH 01/36] Fix Eigen issue on OS X with CUDA and nvcc compile (#9270) Summary: Breaking this out of #8338 This takes care of the Eigen failure we saw on Mac CUDA builds when BUILD_CAFFE2 and BUILD_ATEN were removed. Fix is to isolate Eigen from headers included by cu files and processed by nvcc. This was worked on with smessmer. cc mingzhe09088 smessmer BIT-silence Yangqing Pull Request resolved: https://github.com/pytorch/pytorch/pull/9270 Reviewed By: mingzhe09088 Differential Revision: D8768025 Pulled By: orionr fbshipit-source-id: 5b34017aeb67e35a1b5938d962181ccd4cd37591 --- caffe2/mkl/operators/operator_fallback_mkl.cc | 1 + caffe2/mobile/contrib/ulp2/ulp.cc | 3 + caffe2/operators/abs_op.cc | 1 + caffe2/operators/acos_op.cc | 1 + caffe2/operators/affine_channel_op.cc | 1 + caffe2/operators/asin_op.cc | 1 + caffe2/operators/atan_op.cc | 1 + caffe2/operators/cbrt_op.cc | 1 + caffe2/operators/channel_backprop_stats_op.cc | 1 + caffe2/operators/channel_stats_op.cc | 1 + caffe2/operators/clip_op.cc | 1 + caffe2/operators/conv_op_eigen.cc | 1 + .../operators/conv_transpose_op_mobile_impl.h | 1 + caffe2/operators/cos_op.cc | 1 + caffe2/operators/cross_entropy_op.cc | 1 + caffe2/operators/cube_op.cc | 1 + caffe2/operators/distance_op.cc | 1 + .../operators/elementwise_div_gradient_op.cc | 1 + caffe2/operators/elementwise_ops.cc | 1 + caffe2/operators/elu_op.cc | 1 + caffe2/operators/ensure_clipped_op.h | 1 + .../fused_rowwise_8bit_conversion_ops.h | 1 + .../operators/gather_fused_8bit_rowwise_op.h | 1 + caffe2/operators/gather_ranges_to_dense_op.h | 1 + .../generate_proposals_op_util_boxes_test.cc | 1 + .../generate_proposals_op_util_nms_test.cc | 1 + caffe2/operators/group_norm_op.cc | 1 + caffe2/operators/instance_norm_gradient_op.cc | 1 + caffe2/operators/instance_norm_op.cc | 1 + caffe2/operators/integral_image_op.cc | 116 ++++++++++++++++++ caffe2/operators/integral_image_op.h | 113 +---------------- caffe2/operators/layer_norm_op.cc | 1 + caffe2/operators/leaky_relu_op.cc | 1 + .../lengths_reducer_rowwise_8bit_ops.h | 1 + caffe2/operators/listwise_l2r_op.cc | 1 + caffe2/operators/logit_op.cc | 1 + caffe2/operators/lpnorm_op.cc | 1 + caffe2/operators/minmax_gradient_ops.cc | 1 + caffe2/operators/minmax_ops.cc | 1 + caffe2/operators/norm_planar_yuv_op.cc | 1 + caffe2/operators/normalize_l1_op.cc | 1 + caffe2/operators/normalize_op.cc | 1 + caffe2/operators/pool_gradient_op.cc | 1 + caffe2/operators/pool_op.cc | 1 + caffe2/operators/pow_op.cc | 1 + caffe2/operators/prelu_op.cc | 1 + caffe2/operators/reducer_functors.h | 1 + caffe2/operators/relu_n_op.cc | 1 + caffe2/operators/relu_op.cc | 1 + caffe2/operators/roi_align_op_gpu_test.cc | 1 + caffe2/operators/rsqrt_op.cc | 2 + caffe2/operators/selu_op.cc | 1 + caffe2/operators/sigmoid_gradient_op.cc | 2 + caffe2/operators/sigmoid_op.cc | 2 + caffe2/operators/sin_op.cc | 1 + .../operators/sinusoid_position_encoding_op.h | 1 + caffe2/operators/softplus_op.cc | 1 + caffe2/operators/softsign_op.cc | 2 + caffe2/operators/sparse_normalize_op.cc | 1 + .../spatial_batch_norm_gradient_op.cc | 2 + caffe2/operators/spatial_batch_norm_op.cc | 2 + caffe2/operators/swish_op.cc | 1 + caffe2/operators/tan_op.cc | 2 + caffe2/operators/tanh_gradient_op.cc | 2 + caffe2/operators/tanh_op.cc | 2 + caffe2/operators/thresholded_relu_op.cc | 1 + caffe2/operators/tt_linear_op.h | 1 + caffe2/operators/utility_ops.cc | 2 +- .../variable_length_sequence_padding.h | 1 + caffe2/perfkernels/embedding_lookup.cc | 1 + .../fused_8bit_rowwise_embedding_lookup.cc | 1 + caffe2/sgd/lars_op.cc | 1 + caffe2/sgd/rmsprop_op.cc | 1 + caffe2/utils/eigen_utils.h | 24 ++++ caffe2/utils/math.h | 27 ---- caffe2/utils/math_cpu.cc | 1 + caffe2/utils/math_gpu.cu | 1 + 77 files changed, 226 insertions(+), 139 deletions(-) diff --git a/caffe2/mkl/operators/operator_fallback_mkl.cc b/caffe2/mkl/operators/operator_fallback_mkl.cc index 91c43e746a9ad..106fa05dec70a 100644 --- a/caffe2/mkl/operators/operator_fallback_mkl.cc +++ b/caffe2/mkl/operators/operator_fallback_mkl.cc @@ -15,6 +15,7 @@ #include "caffe2/operators/roi_align_rotated_op.h" #include "caffe2/operators/softmax_op.h" #include "caffe2/operators/utility_ops.h" +#include "caffe2/utils/eigen_utils.h" namespace caffe2 { namespace { diff --git a/caffe2/mobile/contrib/ulp2/ulp.cc b/caffe2/mobile/contrib/ulp2/ulp.cc index 7a1652e6ba343..1d8e0e8fe69a5 100644 --- a/caffe2/mobile/contrib/ulp2/ulp.cc +++ b/caffe2/mobile/contrib/ulp2/ulp.cc @@ -1,5 +1,8 @@ #include "ulp.h" + +#include #include "caffe2/operators/conv_pool_op_base.h" +#include "caffe2/utils/eigen_utils.h" #include "ulp_neon.h" namespace caffe2 { diff --git a/caffe2/operators/abs_op.cc b/caffe2/operators/abs_op.cc index 81881c71c3898..9b9e93f7eff66 100644 --- a/caffe2/operators/abs_op.cc +++ b/caffe2/operators/abs_op.cc @@ -1,4 +1,5 @@ #include "caffe2/operators/abs_op.h" +#include "caffe2/utils/eigen_utils.h" #include #include diff --git a/caffe2/operators/acos_op.cc b/caffe2/operators/acos_op.cc index 8e3c814dbbde4..204bdce146115 100644 --- a/caffe2/operators/acos_op.cc +++ b/caffe2/operators/acos_op.cc @@ -1,4 +1,5 @@ #include "caffe2/operators/acos_op.h" +#include "caffe2/utils/eigen_utils.h" #include #include diff --git a/caffe2/operators/affine_channel_op.cc b/caffe2/operators/affine_channel_op.cc index 0e358f451b9cf..26953876b4891 100644 --- a/caffe2/operators/affine_channel_op.cc +++ b/caffe2/operators/affine_channel_op.cc @@ -1,4 +1,5 @@ #include "caffe2/operators/affine_channel_op.h" +#include "caffe2/utils/eigen_utils.h" #include diff --git a/caffe2/operators/asin_op.cc b/caffe2/operators/asin_op.cc index e3f440e14c764..3f7db59a15cf1 100644 --- a/caffe2/operators/asin_op.cc +++ b/caffe2/operators/asin_op.cc @@ -1,4 +1,5 @@ #include "caffe2/operators/asin_op.h" +#include "caffe2/utils/eigen_utils.h" #include #include diff --git a/caffe2/operators/atan_op.cc b/caffe2/operators/atan_op.cc index ad11136e5b9db..59c0ebbc2b89e 100644 --- a/caffe2/operators/atan_op.cc +++ b/caffe2/operators/atan_op.cc @@ -1,4 +1,5 @@ #include "caffe2/operators/atan_op.h" +#include "caffe2/utils/eigen_utils.h" #include #include diff --git a/caffe2/operators/cbrt_op.cc b/caffe2/operators/cbrt_op.cc index 84d93f33c14a4..6d1a7025cab7c 100644 --- a/caffe2/operators/cbrt_op.cc +++ b/caffe2/operators/cbrt_op.cc @@ -1,4 +1,5 @@ #include "caffe2/operators/cbrt_op.h" +#include "caffe2/utils/eigen_utils.h" #include #include diff --git a/caffe2/operators/channel_backprop_stats_op.cc b/caffe2/operators/channel_backprop_stats_op.cc index c5d26247f049a..bee287d29cef9 100644 --- a/caffe2/operators/channel_backprop_stats_op.cc +++ b/caffe2/operators/channel_backprop_stats_op.cc @@ -1,4 +1,5 @@ #include "caffe2/operators/channel_backprop_stats_op.h" +#include "caffe2/utils/eigen_utils.h" namespace caffe2 { diff --git a/caffe2/operators/channel_stats_op.cc b/caffe2/operators/channel_stats_op.cc index 4cf9ce68743c5..442ab48d764de 100644 --- a/caffe2/operators/channel_stats_op.cc +++ b/caffe2/operators/channel_stats_op.cc @@ -1,4 +1,5 @@ #include "caffe2/operators/channel_stats_op.h" +#include "caffe2/utils/eigen_utils.h" namespace caffe2 { diff --git a/caffe2/operators/clip_op.cc b/caffe2/operators/clip_op.cc index efb40ff8c8afe..02e80bd131beb 100644 --- a/caffe2/operators/clip_op.cc +++ b/caffe2/operators/clip_op.cc @@ -1,4 +1,5 @@ #include "caffe2/operators/clip_op.h" +#include "caffe2/utils/eigen_utils.h" namespace caffe2 { diff --git a/caffe2/operators/conv_op_eigen.cc b/caffe2/operators/conv_op_eigen.cc index 2862d80777b55..b565b567ab294 100644 --- a/caffe2/operators/conv_op_eigen.cc +++ b/caffe2/operators/conv_op_eigen.cc @@ -1,4 +1,5 @@ #include "Eigen/Core" +#include "caffe2/utils/eigen_utils.h" #if EIGEN_VERSION_AT_LEAST(3, 3, 0) diff --git a/caffe2/operators/conv_transpose_op_mobile_impl.h b/caffe2/operators/conv_transpose_op_mobile_impl.h index 2d9e1ba902a27..d434ec49e3e5b 100644 --- a/caffe2/operators/conv_transpose_op_mobile_impl.h +++ b/caffe2/operators/conv_transpose_op_mobile_impl.h @@ -15,6 +15,7 @@ #include "caffe2/operators/conv_op_shared.h" #include "caffe2/operators/conv_transpose_op_mobile.h" #include "caffe2/utils/cpu_neon.h" +#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/fixed_divisor.h" #include "caffe2/utils/math.h" diff --git a/caffe2/operators/cos_op.cc b/caffe2/operators/cos_op.cc index cf2eeb0ae5ed4..262ccee482e1b 100644 --- a/caffe2/operators/cos_op.cc +++ b/caffe2/operators/cos_op.cc @@ -1,4 +1,5 @@ #include "caffe2/operators/cos_op.h" +#include "caffe2/utils/eigen_utils.h" #include #include diff --git a/caffe2/operators/cross_entropy_op.cc b/caffe2/operators/cross_entropy_op.cc index 31a981d18b9db..c288eb7be69d8 100644 --- a/caffe2/operators/cross_entropy_op.cc +++ b/caffe2/operators/cross_entropy_op.cc @@ -1,4 +1,5 @@ #include "caffe2/operators/cross_entropy_op.h" +#include "caffe2/utils/eigen_utils.h" namespace caffe2 { diff --git a/caffe2/operators/cube_op.cc b/caffe2/operators/cube_op.cc index 5b28c5bcdea77..1f0cf7d4bdafc 100644 --- a/caffe2/operators/cube_op.cc +++ b/caffe2/operators/cube_op.cc @@ -1,4 +1,5 @@ #include "caffe2/operators/cube_op.h" +#include "caffe2/utils/eigen_utils.h" #include #include diff --git a/caffe2/operators/distance_op.cc b/caffe2/operators/distance_op.cc index 6d6e5a35c7abf..4e00cd4396726 100644 --- a/caffe2/operators/distance_op.cc +++ b/caffe2/operators/distance_op.cc @@ -1,4 +1,5 @@ #include "caffe2/operators/distance_op.h" +#include "caffe2/utils/eigen_utils.h" namespace caffe2 { diff --git a/caffe2/operators/elementwise_div_gradient_op.cc b/caffe2/operators/elementwise_div_gradient_op.cc index 288b09cdfc3bd..f8562951d1673 100644 --- a/caffe2/operators/elementwise_div_gradient_op.cc +++ b/caffe2/operators/elementwise_div_gradient_op.cc @@ -1,4 +1,5 @@ #include "caffe2/operators/elementwise_div_op.h" +#include "caffe2/utils/eigen_utils.h" #include #include diff --git a/caffe2/operators/elementwise_ops.cc b/caffe2/operators/elementwise_ops.cc index ad46541c8f48a..1cd7d65917a4e 100644 --- a/caffe2/operators/elementwise_ops.cc +++ b/caffe2/operators/elementwise_ops.cc @@ -1,4 +1,5 @@ #include "caffe2/operators/elementwise_ops.h" +#include "caffe2/utils/eigen_utils.h" #include diff --git a/caffe2/operators/elu_op.cc b/caffe2/operators/elu_op.cc index e08d6f2eb2bd9..45c0ebe9b751b 100644 --- a/caffe2/operators/elu_op.cc +++ b/caffe2/operators/elu_op.cc @@ -1,5 +1,6 @@ #include "caffe2/operators/elu_op.h" +#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/math.h" namespace caffe2 { diff --git a/caffe2/operators/ensure_clipped_op.h b/caffe2/operators/ensure_clipped_op.h index e53d5759f4a62..23a10928a0ceb 100644 --- a/caffe2/operators/ensure_clipped_op.h +++ b/caffe2/operators/ensure_clipped_op.h @@ -1,6 +1,7 @@ #pragma once #include "caffe2/core/operator.h" +#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/math.h" namespace caffe2 { diff --git a/caffe2/operators/fused_rowwise_8bit_conversion_ops.h b/caffe2/operators/fused_rowwise_8bit_conversion_ops.h index bf098a610f2cb..ca5002078129a 100644 --- a/caffe2/operators/fused_rowwise_8bit_conversion_ops.h +++ b/caffe2/operators/fused_rowwise_8bit_conversion_ops.h @@ -5,6 +5,7 @@ #include "caffe2/core/logging.h" #include "caffe2/core/operator.h" #include "caffe2/operators/reducer_functors.h" +#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/math.h" namespace caffe2 { diff --git a/caffe2/operators/gather_fused_8bit_rowwise_op.h b/caffe2/operators/gather_fused_8bit_rowwise_op.h index de5dd61255979..621ea335a4993 100644 --- a/caffe2/operators/gather_fused_8bit_rowwise_op.h +++ b/caffe2/operators/gather_fused_8bit_rowwise_op.h @@ -1,6 +1,7 @@ #pragma once #include "caffe2/core/operator.h" +#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/math.h" namespace caffe2 { diff --git a/caffe2/operators/gather_ranges_to_dense_op.h b/caffe2/operators/gather_ranges_to_dense_op.h index c9a4084b9158e..81f4fa53d5599 100644 --- a/caffe2/operators/gather_ranges_to_dense_op.h +++ b/caffe2/operators/gather_ranges_to_dense_op.h @@ -10,6 +10,7 @@ #include "caffe2/core/types.h" #include "caffe2/utils/math.h" +#include #include #include diff --git a/caffe2/operators/generate_proposals_op_util_boxes_test.cc b/caffe2/operators/generate_proposals_op_util_boxes_test.cc index 3ba38929b6b78..78ff4c21cc43d 100644 --- a/caffe2/operators/generate_proposals_op_util_boxes_test.cc +++ b/caffe2/operators/generate_proposals_op_util_boxes_test.cc @@ -1,4 +1,5 @@ #include "caffe2/operators/generate_proposals_op_util_boxes.h" +#include "caffe2/utils/eigen_utils.h" #include diff --git a/caffe2/operators/generate_proposals_op_util_nms_test.cc b/caffe2/operators/generate_proposals_op_util_nms_test.cc index a7825c81b6354..6d9e2a173c836 100644 --- a/caffe2/operators/generate_proposals_op_util_nms_test.cc +++ b/caffe2/operators/generate_proposals_op_util_nms_test.cc @@ -1,3 +1,4 @@ +#include "caffe2/utils/eigen_utils.h" #include "generate_proposals_op_util_nms.h" #include diff --git a/caffe2/operators/group_norm_op.cc b/caffe2/operators/group_norm_op.cc index 733ec52680e1e..9c203f24a8683 100644 --- a/caffe2/operators/group_norm_op.cc +++ b/caffe2/operators/group_norm_op.cc @@ -10,6 +10,7 @@ #include +#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/math.h" namespace caffe2 { diff --git a/caffe2/operators/instance_norm_gradient_op.cc b/caffe2/operators/instance_norm_gradient_op.cc index 079992140022f..077020ee48b9b 100644 --- a/caffe2/operators/instance_norm_gradient_op.cc +++ b/caffe2/operators/instance_norm_gradient_op.cc @@ -1,4 +1,5 @@ #include "caffe2/operators/instance_norm_op.h" +#include "caffe2/utils/eigen_utils.h" namespace caffe2 { diff --git a/caffe2/operators/instance_norm_op.cc b/caffe2/operators/instance_norm_op.cc index 7011ecf40bf7e..b0d0dea73ea28 100644 --- a/caffe2/operators/instance_norm_op.cc +++ b/caffe2/operators/instance_norm_op.cc @@ -1,4 +1,5 @@ #include "caffe2/operators/instance_norm_op.h" +#include "caffe2/utils/eigen_utils.h" namespace caffe2 { diff --git a/caffe2/operators/integral_image_op.cc b/caffe2/operators/integral_image_op.cc index 6da5ee6d5600f..27356104bbd66 100644 --- a/caffe2/operators/integral_image_op.cc +++ b/caffe2/operators/integral_image_op.cc @@ -1,6 +1,122 @@ #include "integral_image_op.h" +#include "caffe2/utils/eigen_utils.h" + namespace caffe2 { +namespace { +template +using EigenMatrixMapRowMajor = Eigen::Map< + Eigen::Matrix>; + +template +using ConstEigenMatrixMapRowMajor = Eigen::Map< + const Eigen::Matrix>; +} // namespace + +template <> +bool IntegralImageOp::RunOnDevice() { + const auto& X = Input(0); + auto* Y = Output(0); + CAFFE_ENFORCE_EQ(X.ndim(), 4, "Only supports 4D tensors for the momement"); + + vector out_shape(X.dims()); + out_shape[2] += 1; // H + 1 output size + out_shape[3] += 1; // W + 1 output size + Y->Resize(out_shape); + const int ind = X.dim32(0); + const int chans = X.dim32(1); + const int rows_in = X.dim32(2); + const int cols_in = X.dim32(3); + const int rows_out = Y->dim32(2); + const int cols_out = Y->dim32(3); + + const float* input_data = X.template data(); + float* output_data = Y->template mutable_data(); + + const int row_out_pass_size = ind * chans * rows_out; + const int row_in_pass_size = ind * chans * rows_in; + EigenMatrixMapRowMajor Y_arr(output_data, row_out_pass_size, cols_out); + ConstEigenMatrixMapRowMajor X_arr( + input_data, row_in_pass_size, cols_in); + + // Row Pass + for (int i = 0; i < row_out_pass_size; i++) { + int row = i % rows_out; + int diff = i / rows_out + 1; + Y_arr(i, 0) = 0.; + if (row == 0) { + for (int j = 1; j < cols_out; ++j) { + Y_arr(i, j) = 0.; + } + } else { + for (int j = 1; j < cols_out; ++j) { + Y_arr(i, j) = Y_arr(i, j - 1) + X_arr(i - diff, j - 1); + } + } + } + + // Col Pass + const int col_out_pass_size = X.dim32(0) * chans * cols_out; + for (int i = 0; i < col_out_pass_size; i++) { + int col = i % cols_out; + int row = i / cols_out; + for (int j = row * rows_out + 1; j < (row + 1) * rows_out; ++j) { + Y_arr(j, col) += Y_arr(j - 1, col); + } + } + return true; +} + +template <> +bool IntegralImageGradientOp::RunOnDevice() { + auto& X = Input(0); // Original input to "forward" op + auto& dY = Input(1); // Gradient of net w.r.t. output of "forward" op + // (aka "gradOutput") + auto* dX = Output(0); // Gradient of net w.r.t. input to "forward" op + // (aka "gradInput") + + dX->ResizeLike(X); + const int ind = X.dim32(0); + const int chans = X.dim32(1); + const int rows_in = dY.dim32(2); + const int cols_in = dY.dim32(3); + const int rows_out = dX->dim32(2); + const int cols_out = dX->dim32(3); + + const float* input_data = dY.template data(); + float* output_data = dX->template mutable_data(); + + const int row_out_pass_size = ind * chans * rows_out; + const int row_in_pass_size = ind * chans * rows_in; + EigenMatrixMapRowMajor dX_arr( + output_data, row_out_pass_size, cols_out); + ConstEigenMatrixMapRowMajor dY_arr( + input_data, row_in_pass_size, cols_in); + Eigen::MatrixXf tmp(row_in_pass_size, cols_out); + + // Row Pass dY(N, C, H+1, W+1) => tmp(N, C, H+1, W) + for (int i = 0; i < row_in_pass_size; i++) { + tmp(i, 0) = dY_arr(i, 0); + for (int j = 1; j < cols_out; ++j) { + tmp(i, j) = tmp(i, j - 1) + dY_arr(i, j); + } + } + + // Col Pass tmp(N, C, H+1, W)=>dX(N, C, H, W) + const int col_out_pass_size = X.dim32(0) * chans * cols_out; + for (int i = 0; i < col_out_pass_size; i++) { + int col = i % cols_out; + int row_out_start = (i / cols_out) * rows_out; + int row_in_start = (i / cols_out) * rows_in; + dX_arr(row_out_start, col) = tmp(row_in_start, col); + for (int j = 1; j < rows_out; ++j) { + dX_arr(row_out_start + j, col) = + dX_arr(row_out_start + j - 1, col) + tmp(row_in_start + j, col); + } + } + return true; +} + REGISTER_CPU_OPERATOR(IntegralImage, IntegralImageOp); REGISTER_CPU_OPERATOR( IntegralImageGradient, diff --git a/caffe2/operators/integral_image_op.h b/caffe2/operators/integral_image_op.h index 71d9b076336fa..b8920d677de83 100644 --- a/caffe2/operators/integral_image_op.h +++ b/caffe2/operators/integral_image_op.h @@ -8,16 +8,6 @@ namespace caffe2 { -namespace { -template -using EigenMatrixMapRowMajor = Eigen::Map< - Eigen::Matrix>; - -template -using ConstEigenMatrixMapRowMajor = Eigen::Map< - const Eigen::Matrix>; -} // namespace - template class IntegralImageOp final : public Operator { public: @@ -25,59 +15,7 @@ class IntegralImageOp final : public Operator { : Operator(operator_def, ws) {} USE_OPERATOR_CONTEXT_FUNCTIONS; - bool RunOnDevice() override { - const auto& X = Input(0); - auto* Y = Output(0); - CAFFE_ENFORCE_EQ(X.ndim(), 4, "Only supports 4D tensors for the momement"); - - vector out_shape(X.dims()); - out_shape[2] += 1; // H + 1 output size - out_shape[3] += 1; // W + 1 output size - Y->Resize(out_shape); - const int ind = X.dim32(0); - const int chans = X.dim32(1); - const int rows_in = X.dim32(2); - const int cols_in = X.dim32(3); - const int rows_out = Y->dim32(2); - const int cols_out = Y->dim32(3); - - const float* input_data = X.template data(); - float* output_data = Y->template mutable_data(); - - const int row_out_pass_size = ind * chans * rows_out; - const int row_in_pass_size = ind * chans * rows_in; - EigenMatrixMapRowMajor Y_arr( - output_data, row_out_pass_size, cols_out); - ConstEigenMatrixMapRowMajor X_arr( - input_data, row_in_pass_size, cols_in); - - // Row Pass - for (int i = 0; i < row_out_pass_size; i++) { - int row = i % rows_out; - int diff = i / rows_out + 1; - Y_arr(i, 0) = 0.; - if (row == 0) { - for (int j = 1; j < cols_out; ++j) { - Y_arr(i, j) = 0.; - } - } else { - for (int j = 1; j < cols_out; ++j) { - Y_arr(i, j) = Y_arr(i, j - 1) + X_arr(i - diff, j - 1); - } - } - } - - // Col Pass - const int col_out_pass_size = X.dim32(0) * chans * cols_out; - for (int i = 0; i < col_out_pass_size; i++) { - int col = i % cols_out; - int row = i / cols_out; - for (int j = row * rows_out + 1; j < (row + 1) * rows_out; ++j) { - Y_arr(j, col) += Y_arr(j - 1, col); - } - } - return true; - } + bool RunOnDevice() override; }; template @@ -87,54 +25,7 @@ class IntegralImageGradientOp final : public Operator { : Operator(def, ws) {} USE_OPERATOR_CONTEXT_FUNCTIONS; - bool RunOnDevice() override { - auto& X = Input(0); // Original input to "forward" op - auto& dY = Input(1); // Gradient of net w.r.t. output of "forward" op - // (aka "gradOutput") - auto* dX = Output(0); // Gradient of net w.r.t. input to "forward" op - // (aka "gradInput") - - dX->ResizeLike(X); - const int ind = X.dim32(0); - const int chans = X.dim32(1); - const int rows_in = dY.dim32(2); - const int cols_in = dY.dim32(3); - const int rows_out = dX->dim32(2); - const int cols_out = dX->dim32(3); - - const float* input_data = dY.template data(); - float* output_data = dX->template mutable_data(); - - const int row_out_pass_size = ind * chans * rows_out; - const int row_in_pass_size = ind * chans * rows_in; - EigenMatrixMapRowMajor dX_arr( - output_data, row_out_pass_size, cols_out); - ConstEigenMatrixMapRowMajor dY_arr( - input_data, row_in_pass_size, cols_in); - Eigen::MatrixXf tmp(row_in_pass_size, cols_out); - - // Row Pass dY(N, C, H+1, W+1) => tmp(N, C, H+1, W) - for (int i = 0; i < row_in_pass_size; i++) { - tmp(i, 0) = dY_arr(i, 0); - for (int j = 1; j < cols_out; ++j) { - tmp(i, j) = tmp(i, j - 1) + dY_arr(i, j); - } - } - - // Col Pass tmp(N, C, H+1, W)=>dX(N, C, H, W) - const int col_out_pass_size = X.dim32(0) * chans * cols_out; - for (int i = 0; i < col_out_pass_size; i++) { - int col = i % cols_out; - int row_out_start = (i / cols_out) * rows_out; - int row_in_start = (i / cols_out) * rows_in; - dX_arr(row_out_start, col) = tmp(row_in_start, col); - for (int j = 1; j < rows_out; ++j) { - dX_arr(row_out_start + j, col) = - dX_arr(row_out_start + j - 1, col) + tmp(row_in_start + j, col); - } - } - return true; - } + bool RunOnDevice() override; protected: Tensor row_pass_buffer_; diff --git a/caffe2/operators/layer_norm_op.cc b/caffe2/operators/layer_norm_op.cc index eb5ae0d33e5b7..4b995fa49d8ce 100644 --- a/caffe2/operators/layer_norm_op.cc +++ b/caffe2/operators/layer_norm_op.cc @@ -1,4 +1,5 @@ #include "caffe2/operators/layer_norm_op.h" +#include "caffe2/utils/eigen_utils.h" namespace caffe2 { diff --git a/caffe2/operators/leaky_relu_op.cc b/caffe2/operators/leaky_relu_op.cc index fc66edcdbbe9b..dcf62084a1207 100644 --- a/caffe2/operators/leaky_relu_op.cc +++ b/caffe2/operators/leaky_relu_op.cc @@ -1,5 +1,6 @@ #include "caffe2/operators/leaky_relu_op.h" +#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/math.h" namespace caffe2 { diff --git a/caffe2/operators/lengths_reducer_rowwise_8bit_ops.h b/caffe2/operators/lengths_reducer_rowwise_8bit_ops.h index 0423fcf34a270..58ebe6cb58e84 100644 --- a/caffe2/operators/lengths_reducer_rowwise_8bit_ops.h +++ b/caffe2/operators/lengths_reducer_rowwise_8bit_ops.h @@ -8,6 +8,7 @@ #include "caffe2/core/operator.h" #include "caffe2/operators/reducer_functors.h" #include "caffe2/perfkernels/embedding_lookup.h" +#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/math.h" namespace caffe2 { diff --git a/caffe2/operators/listwise_l2r_op.cc b/caffe2/operators/listwise_l2r_op.cc index 24c5e26e5faaf..3940dfb2b1670 100644 --- a/caffe2/operators/listwise_l2r_op.cc +++ b/caffe2/operators/listwise_l2r_op.cc @@ -1,6 +1,7 @@ #include "caffe2/operators/listwise_l2r_op.h" #include "caffe2/core/context.h" #include "caffe2/core/operator.h" +#include "caffe2/utils/eigen_utils.h" namespace caffe2 { diff --git a/caffe2/operators/logit_op.cc b/caffe2/operators/logit_op.cc index 8d1859a405a49..225608f87b38d 100644 --- a/caffe2/operators/logit_op.cc +++ b/caffe2/operators/logit_op.cc @@ -4,6 +4,7 @@ #include #include "caffe2/operators/elementwise_ops.h" +#include "caffe2/utils/eigen_utils.h" namespace caffe2 { diff --git a/caffe2/operators/lpnorm_op.cc b/caffe2/operators/lpnorm_op.cc index c302d42c92b07..f79d51ad51c44 100644 --- a/caffe2/operators/lpnorm_op.cc +++ b/caffe2/operators/lpnorm_op.cc @@ -2,6 +2,7 @@ #include "caffe2/core/operator.h" #include "caffe2/core/types.h" +#include "caffe2/utils/eigen_utils.h" namespace caffe2 { diff --git a/caffe2/operators/minmax_gradient_ops.cc b/caffe2/operators/minmax_gradient_ops.cc index 5b223b2551332..0c640d4d58e81 100644 --- a/caffe2/operators/minmax_gradient_ops.cc +++ b/caffe2/operators/minmax_gradient_ops.cc @@ -1,4 +1,5 @@ #include "caffe2/operators/minmax_ops.h" +#include "caffe2/utils/eigen_utils.h" namespace caffe2 { diff --git a/caffe2/operators/minmax_ops.cc b/caffe2/operators/minmax_ops.cc index 802788531e072..16b8f026072e5 100644 --- a/caffe2/operators/minmax_ops.cc +++ b/caffe2/operators/minmax_ops.cc @@ -1,4 +1,5 @@ #include "caffe2/operators/minmax_ops.h" +#include "caffe2/utils/eigen_utils.h" namespace caffe2 { diff --git a/caffe2/operators/norm_planar_yuv_op.cc b/caffe2/operators/norm_planar_yuv_op.cc index b9d9b9c44ecc2..ea3ccc222dc96 100644 --- a/caffe2/operators/norm_planar_yuv_op.cc +++ b/caffe2/operators/norm_planar_yuv_op.cc @@ -1,5 +1,6 @@ #include #include "caffe2/core/operator.h" +#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/math.h" namespace caffe2 { diff --git a/caffe2/operators/normalize_l1_op.cc b/caffe2/operators/normalize_l1_op.cc index cb02ff7d52397..908131f43532d 100644 --- a/caffe2/operators/normalize_l1_op.cc +++ b/caffe2/operators/normalize_l1_op.cc @@ -1,6 +1,7 @@ #include "caffe2/operators/normalize_l1_op.h" #include "caffe2/core/tensor.h" +#include "caffe2/utils/eigen_utils.h" namespace caffe2 { diff --git a/caffe2/operators/normalize_op.cc b/caffe2/operators/normalize_op.cc index 4a1aac7f02a96..1a7d720deb6c3 100644 --- a/caffe2/operators/normalize_op.cc +++ b/caffe2/operators/normalize_op.cc @@ -1,6 +1,7 @@ #include "caffe2/operators/normalize_op.h" #include "caffe2/core/tensor.h" +#include "caffe2/utils/eigen_utils.h" namespace caffe2 { diff --git a/caffe2/operators/pool_gradient_op.cc b/caffe2/operators/pool_gradient_op.cc index 048d8fc06177d..f7062a616dc8d 100644 --- a/caffe2/operators/pool_gradient_op.cc +++ b/caffe2/operators/pool_gradient_op.cc @@ -1,4 +1,5 @@ #include "caffe2/operators/pool_op.h" +#include "caffe2/utils/eigen_utils.h" namespace caffe2 { diff --git a/caffe2/operators/pool_op.cc b/caffe2/operators/pool_op.cc index edb14bc82b7ac..eca7978e024aa 100644 --- a/caffe2/operators/pool_op.cc +++ b/caffe2/operators/pool_op.cc @@ -1,6 +1,7 @@ // TODO(ataei): reduce the apparent redundancy of all the code below. #include "caffe2/operators/pool_op.h" #include "caffe2/utils/cpu_neon.h" +#include "caffe2/utils/eigen_utils.h" namespace caffe2 { diff --git a/caffe2/operators/pow_op.cc b/caffe2/operators/pow_op.cc index bef995093ddaa..a028d6d0bdcea 100644 --- a/caffe2/operators/pow_op.cc +++ b/caffe2/operators/pow_op.cc @@ -1,4 +1,5 @@ #include "caffe2/operators/pow_op.h" +#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/math.h" // definition of NumericTypes and SameTypeAsInput is in below header file //#include "caffe2/operators/elementwise_op.h" diff --git a/caffe2/operators/prelu_op.cc b/caffe2/operators/prelu_op.cc index 680b987e74292..8bacf1e29153c 100644 --- a/caffe2/operators/prelu_op.cc +++ b/caffe2/operators/prelu_op.cc @@ -1,4 +1,5 @@ #include "caffe2/operators/prelu_op.h" +#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/math.h" #include "caffe2/core/types.h" diff --git a/caffe2/operators/reducer_functors.h b/caffe2/operators/reducer_functors.h index 708c964af213c..f3dd35b956078 100644 --- a/caffe2/operators/reducer_functors.h +++ b/caffe2/operators/reducer_functors.h @@ -6,6 +6,7 @@ #include "caffe2/core/context.h" #include "caffe2/core/tensor.h" +#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/math.h" #include "caffe2/utils/proto_utils.h" diff --git a/caffe2/operators/relu_n_op.cc b/caffe2/operators/relu_n_op.cc index b69baff7725bd..4b5afed3528c3 100644 --- a/caffe2/operators/relu_n_op.cc +++ b/caffe2/operators/relu_n_op.cc @@ -16,6 +16,7 @@ #include "caffe2/operators/relu_n_op.h" +#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/math.h" namespace caffe2 { diff --git a/caffe2/operators/relu_op.cc b/caffe2/operators/relu_op.cc index 8737cddc59756..45b622ae8409f 100644 --- a/caffe2/operators/relu_op.cc +++ b/caffe2/operators/relu_op.cc @@ -1,5 +1,6 @@ #include "caffe2/operators/relu_op.h" +#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/math.h" namespace caffe2 { diff --git a/caffe2/operators/roi_align_op_gpu_test.cc b/caffe2/operators/roi_align_op_gpu_test.cc index afbf60c85b4bd..199500f93df3a 100644 --- a/caffe2/operators/roi_align_op_gpu_test.cc +++ b/caffe2/operators/roi_align_op_gpu_test.cc @@ -3,6 +3,7 @@ #include "caffe2/core/context_gpu.h" #include "caffe2/core/flags.h" +#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/math.h" #include "gtest/gtest.h" diff --git a/caffe2/operators/rsqrt_op.cc b/caffe2/operators/rsqrt_op.cc index 0587fea21dcab..de4fc499f4215 100644 --- a/caffe2/operators/rsqrt_op.cc +++ b/caffe2/operators/rsqrt_op.cc @@ -1,5 +1,7 @@ #include "caffe2/operators/rsqrt_op.h" +#include "caffe2/utils/eigen_utils.h" + #include #include #include diff --git a/caffe2/operators/selu_op.cc b/caffe2/operators/selu_op.cc index 715e53cd6ea14..50d823d8bedf1 100644 --- a/caffe2/operators/selu_op.cc +++ b/caffe2/operators/selu_op.cc @@ -1,5 +1,6 @@ #include "caffe2/operators/selu_op.h" +#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/math.h" namespace caffe2 { diff --git a/caffe2/operators/sigmoid_gradient_op.cc b/caffe2/operators/sigmoid_gradient_op.cc index 3db4d60a61b0e..dd3c0c40f701f 100644 --- a/caffe2/operators/sigmoid_gradient_op.cc +++ b/caffe2/operators/sigmoid_gradient_op.cc @@ -1,5 +1,7 @@ #include "caffe2/operators/sigmoid_op.h" +#include "caffe2/utils/eigen_utils.h" + #include #include #include diff --git a/caffe2/operators/sigmoid_op.cc b/caffe2/operators/sigmoid_op.cc index 4dcfdc676472d..f1c4828cb37b2 100644 --- a/caffe2/operators/sigmoid_op.cc +++ b/caffe2/operators/sigmoid_op.cc @@ -1,5 +1,7 @@ #include "caffe2/operators/sigmoid_op.h" +#include "caffe2/utils/eigen_utils.h" + namespace caffe2 { template <> diff --git a/caffe2/operators/sin_op.cc b/caffe2/operators/sin_op.cc index 30d76cd162e37..90fcb97bf0799 100644 --- a/caffe2/operators/sin_op.cc +++ b/caffe2/operators/sin_op.cc @@ -1,4 +1,5 @@ #include "caffe2/operators/sin_op.h" +#include "caffe2/utils/eigen_utils.h" #include #include diff --git a/caffe2/operators/sinusoid_position_encoding_op.h b/caffe2/operators/sinusoid_position_encoding_op.h index 69c8ea8244b38..5591b9749a704 100644 --- a/caffe2/operators/sinusoid_position_encoding_op.h +++ b/caffe2/operators/sinusoid_position_encoding_op.h @@ -9,6 +9,7 @@ #include "caffe2/core/operator.h" #include "Eigen/Core" +#include "caffe2/utils/eigen_utils.h" namespace caffe2 { diff --git a/caffe2/operators/softplus_op.cc b/caffe2/operators/softplus_op.cc index 3a81a80b2235b..7d2efd578560a 100644 --- a/caffe2/operators/softplus_op.cc +++ b/caffe2/operators/softplus_op.cc @@ -1,5 +1,6 @@ #include "caffe2/operators/softplus_op.h" +#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/math.h" namespace caffe2 { diff --git a/caffe2/operators/softsign_op.cc b/caffe2/operators/softsign_op.cc index 8e3be424887cc..4062848105b1c 100644 --- a/caffe2/operators/softsign_op.cc +++ b/caffe2/operators/softsign_op.cc @@ -1,5 +1,7 @@ #include "caffe2/operators/softsign_op.h" +#include "caffe2/utils/eigen_utils.h" + #include #include diff --git a/caffe2/operators/sparse_normalize_op.cc b/caffe2/operators/sparse_normalize_op.cc index 2f0f353b5088a..43ded9024d277 100644 --- a/caffe2/operators/sparse_normalize_op.cc +++ b/caffe2/operators/sparse_normalize_op.cc @@ -1,5 +1,6 @@ #include "caffe2/operators/sparse_normalize_op.h" #include "caffe2/core/tensor.h" +#include "caffe2/utils/eigen_utils.h" namespace caffe2 { diff --git a/caffe2/operators/spatial_batch_norm_gradient_op.cc b/caffe2/operators/spatial_batch_norm_gradient_op.cc index 1c4c1bfb5f05a..dd5434db725a7 100644 --- a/caffe2/operators/spatial_batch_norm_gradient_op.cc +++ b/caffe2/operators/spatial_batch_norm_gradient_op.cc @@ -1,5 +1,7 @@ #include "caffe2/operators/spatial_batch_norm_op.h" +#include "caffe2/utils/eigen_utils.h" + namespace caffe2 { template <> diff --git a/caffe2/operators/spatial_batch_norm_op.cc b/caffe2/operators/spatial_batch_norm_op.cc index f089a288069c4..671493a1df010 100644 --- a/caffe2/operators/spatial_batch_norm_op.cc +++ b/caffe2/operators/spatial_batch_norm_op.cc @@ -1,5 +1,7 @@ #include "caffe2/operators/spatial_batch_norm_op.h" +#include "caffe2/utils/eigen_utils.h" + namespace caffe2 { template <> diff --git a/caffe2/operators/swish_op.cc b/caffe2/operators/swish_op.cc index cd8dfa7ea5d3f..a636d23d85f7c 100644 --- a/caffe2/operators/swish_op.cc +++ b/caffe2/operators/swish_op.cc @@ -4,6 +4,7 @@ #include #include "caffe2/core/types.h" +#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/math.h" namespace caffe2 { diff --git a/caffe2/operators/tan_op.cc b/caffe2/operators/tan_op.cc index 7dd873c18e927..62a48bb520a52 100644 --- a/caffe2/operators/tan_op.cc +++ b/caffe2/operators/tan_op.cc @@ -1,5 +1,7 @@ #include "caffe2/operators/tan_op.h" +#include "caffe2/utils/eigen_utils.h" + #include #include diff --git a/caffe2/operators/tanh_gradient_op.cc b/caffe2/operators/tanh_gradient_op.cc index 6daebce46adb9..385d895c688bb 100644 --- a/caffe2/operators/tanh_gradient_op.cc +++ b/caffe2/operators/tanh_gradient_op.cc @@ -1,5 +1,7 @@ #include "caffe2/operators/tanh_op.h" +#include "caffe2/utils/eigen_utils.h" + #include #include #include diff --git a/caffe2/operators/tanh_op.cc b/caffe2/operators/tanh_op.cc index 28ca87c13a20f..cae08082a9192 100644 --- a/caffe2/operators/tanh_op.cc +++ b/caffe2/operators/tanh_op.cc @@ -1,5 +1,7 @@ #include "caffe2/operators/tanh_op.h" +#include "caffe2/utils/eigen_utils.h" + namespace caffe2 { template <> diff --git a/caffe2/operators/thresholded_relu_op.cc b/caffe2/operators/thresholded_relu_op.cc index d79d20cd5d159..8b5e6b514478c 100644 --- a/caffe2/operators/thresholded_relu_op.cc +++ b/caffe2/operators/thresholded_relu_op.cc @@ -1,5 +1,6 @@ #include "caffe2/operators/thresholded_relu_op.h" +#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/math.h" namespace caffe2 { diff --git a/caffe2/operators/tt_linear_op.h b/caffe2/operators/tt_linear_op.h index 05653c9003913..13196bf3761b7 100644 --- a/caffe2/operators/tt_linear_op.h +++ b/caffe2/operators/tt_linear_op.h @@ -9,6 +9,7 @@ #include "Eigen/Dense" #include "caffe2/core/context.h" #include "caffe2/core/operator.h" +#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/math.h" namespace caffe2 { diff --git a/caffe2/operators/utility_ops.cc b/caffe2/operators/utility_ops.cc index c5bad002779fa..1abf2130953a7 100644 --- a/caffe2/operators/utility_ops.cc +++ b/caffe2/operators/utility_ops.cc @@ -1,6 +1,6 @@ #include "caffe2/operators/utility_ops.h" - #include +#include "caffe2/utils/eigen_utils.h" namespace caffe2 { diff --git a/caffe2/operators/variable_length_sequence_padding.h b/caffe2/operators/variable_length_sequence_padding.h index 53196489b0553..7318b2e78b080 100644 --- a/caffe2/operators/variable_length_sequence_padding.h +++ b/caffe2/operators/variable_length_sequence_padding.h @@ -2,6 +2,7 @@ #include "caffe2/core/context.h" #include "caffe2/core/operator.h" +#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/math.h" namespace caffe2 { diff --git a/caffe2/perfkernels/embedding_lookup.cc b/caffe2/perfkernels/embedding_lookup.cc index 460787e4bdb52..b076d88f5accd 100644 --- a/caffe2/perfkernels/embedding_lookup.cc +++ b/caffe2/perfkernels/embedding_lookup.cc @@ -4,6 +4,7 @@ #include "caffe2/perfkernels/common.h" #include "caffe2/perfkernels/typed_axpy.h" #include "caffe2/utils/cpuid.h" +#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/math.h" namespace caffe2 { diff --git a/caffe2/perfkernels/fused_8bit_rowwise_embedding_lookup.cc b/caffe2/perfkernels/fused_8bit_rowwise_embedding_lookup.cc index 40ab3dafff979..675d7c08ddbf3 100644 --- a/caffe2/perfkernels/fused_8bit_rowwise_embedding_lookup.cc +++ b/caffe2/perfkernels/fused_8bit_rowwise_embedding_lookup.cc @@ -4,6 +4,7 @@ #include "caffe2/perfkernels/common.h" #include "caffe2/perfkernels/typed_axpy.h" #include "caffe2/utils/cpuid.h" +#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/math.h" namespace caffe2 { diff --git a/caffe2/sgd/lars_op.cc b/caffe2/sgd/lars_op.cc index a47d5c94d5f1a..3e013a943464b 100644 --- a/caffe2/sgd/lars_op.cc +++ b/caffe2/sgd/lars_op.cc @@ -1,5 +1,6 @@ #include "caffe2/sgd/lars_op.h" #include +#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/math.h" namespace caffe2 { diff --git a/caffe2/sgd/rmsprop_op.cc b/caffe2/sgd/rmsprop_op.cc index 3d5c01d8542a0..ae73706190077 100644 --- a/caffe2/sgd/rmsprop_op.cc +++ b/caffe2/sgd/rmsprop_op.cc @@ -1,5 +1,6 @@ #include "rmsprop_op.h" +#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/math.h" namespace caffe2 { diff --git a/caffe2/utils/eigen_utils.h b/caffe2/utils/eigen_utils.h index b00e355627fb2..cf41d268d7132 100644 --- a/caffe2/utils/eigen_utils.h +++ b/caffe2/utils/eigen_utils.h @@ -9,6 +9,30 @@ namespace caffe2 { +// Common Eigen types that we will often use +template +using EigenMatrixMap = + Eigen::Map>; +template +using EigenArrayMap = + Eigen::Map>; +template +using EigenVectorMap = Eigen::Map>; +template +using EigenVectorArrayMap = Eigen::Map>; +template +using ConstEigenMatrixMap = + Eigen::Map>; +template +using ConstEigenArrayMap = + Eigen::Map>; +template +using ConstEigenVectorMap = + Eigen::Map>; +template +using ConstEigenVectorArrayMap = + Eigen::Map>; + // 1-d array template using EArrXt = Eigen::Array; diff --git a/caffe2/utils/math.h b/caffe2/utils/math.h index 9a9bdad5b7bba..7138cfd27177a 100644 --- a/caffe2/utils/math.h +++ b/caffe2/utils/math.h @@ -17,9 +17,6 @@ extern "C" { #include "caffe2/core/types.h" #include "caffe2/utils/math_utils.h" -#include "Eigen/Core" -#include "Eigen/Dense" - namespace caffe2 { template @@ -29,30 +26,6 @@ class Tensor; // engine specified. class DefaultEngine {}; -// Common Eigen types that we will often use -template -using EigenMatrixMap = - Eigen::Map>; -template -using EigenArrayMap = - Eigen::Map>; -template -using EigenVectorMap = Eigen::Map>; -template -using EigenVectorArrayMap = Eigen::Map>; -template -using ConstEigenMatrixMap = - Eigen::Map>; -template -using ConstEigenArrayMap = - Eigen::Map>; -template -using ConstEigenVectorMap = - Eigen::Map>; -template -using ConstEigenVectorArrayMap = - Eigen::Map>; - namespace math { template diff --git a/caffe2/utils/math_cpu.cc b/caffe2/utils/math_cpu.cc index 8430cc91b89b5..c4e5f878ccb5d 100644 --- a/caffe2/utils/math_cpu.cc +++ b/caffe2/utils/math_cpu.cc @@ -11,6 +11,7 @@ // platforms, it allows one to quickly port Caffe2 to different platforms // where BLAS may not be present. +#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/math.h" #include diff --git a/caffe2/utils/math_gpu.cu b/caffe2/utils/math_gpu.cu index 1f2f721363406..d10475fc2f2e4 100644 --- a/caffe2/utils/math_gpu.cu +++ b/caffe2/utils/math_gpu.cu @@ -2,6 +2,7 @@ #include "caffe2/utils/math.h" +#include #include #include #include From 8e6e8098cee446ac3c2e4141cba4e5130a976baf Mon Sep 17 00:00:00 2001 From: Mike Kelley Date: Tue, 10 Jul 2018 10:14:01 -0700 Subject: [PATCH 02/36] Revert D8768025: [pytorch][PR] Fix Eigen issue on OS X with CUDA and nvcc compile Differential Revision: D8768025 Original commit changeset: 5b34017aeb67 fbshipit-source-id: 6ec892ff483bb9d966eb7138eadc77443972c8f8 --- caffe2/mkl/operators/operator_fallback_mkl.cc | 1 - caffe2/mobile/contrib/ulp2/ulp.cc | 3 - caffe2/operators/abs_op.cc | 1 - caffe2/operators/acos_op.cc | 1 - caffe2/operators/affine_channel_op.cc | 1 - caffe2/operators/asin_op.cc | 1 - caffe2/operators/atan_op.cc | 1 - caffe2/operators/cbrt_op.cc | 1 - caffe2/operators/channel_backprop_stats_op.cc | 1 - caffe2/operators/channel_stats_op.cc | 1 - caffe2/operators/clip_op.cc | 1 - caffe2/operators/conv_op_eigen.cc | 1 - .../operators/conv_transpose_op_mobile_impl.h | 1 - caffe2/operators/cos_op.cc | 1 - caffe2/operators/cross_entropy_op.cc | 1 - caffe2/operators/cube_op.cc | 1 - caffe2/operators/distance_op.cc | 1 - .../operators/elementwise_div_gradient_op.cc | 1 - caffe2/operators/elementwise_ops.cc | 1 - caffe2/operators/elu_op.cc | 1 - caffe2/operators/ensure_clipped_op.h | 1 - .../fused_rowwise_8bit_conversion_ops.h | 1 - .../operators/gather_fused_8bit_rowwise_op.h | 1 - caffe2/operators/gather_ranges_to_dense_op.h | 1 - .../generate_proposals_op_util_boxes_test.cc | 1 - .../generate_proposals_op_util_nms_test.cc | 1 - caffe2/operators/group_norm_op.cc | 1 - caffe2/operators/instance_norm_gradient_op.cc | 1 - caffe2/operators/instance_norm_op.cc | 1 - caffe2/operators/integral_image_op.cc | 116 ------------------ caffe2/operators/integral_image_op.h | 113 ++++++++++++++++- caffe2/operators/layer_norm_op.cc | 1 - caffe2/operators/leaky_relu_op.cc | 1 - .../lengths_reducer_rowwise_8bit_ops.h | 1 - caffe2/operators/listwise_l2r_op.cc | 1 - caffe2/operators/logit_op.cc | 1 - caffe2/operators/lpnorm_op.cc | 1 - caffe2/operators/minmax_gradient_ops.cc | 1 - caffe2/operators/minmax_ops.cc | 1 - caffe2/operators/norm_planar_yuv_op.cc | 1 - caffe2/operators/normalize_l1_op.cc | 1 - caffe2/operators/normalize_op.cc | 1 - caffe2/operators/pool_gradient_op.cc | 1 - caffe2/operators/pool_op.cc | 1 - caffe2/operators/pow_op.cc | 1 - caffe2/operators/prelu_op.cc | 1 - caffe2/operators/reducer_functors.h | 1 - caffe2/operators/relu_n_op.cc | 1 - caffe2/operators/relu_op.cc | 1 - caffe2/operators/roi_align_op_gpu_test.cc | 1 - caffe2/operators/rsqrt_op.cc | 2 - caffe2/operators/selu_op.cc | 1 - caffe2/operators/sigmoid_gradient_op.cc | 2 - caffe2/operators/sigmoid_op.cc | 2 - caffe2/operators/sin_op.cc | 1 - .../operators/sinusoid_position_encoding_op.h | 1 - caffe2/operators/softplus_op.cc | 1 - caffe2/operators/softsign_op.cc | 2 - caffe2/operators/sparse_normalize_op.cc | 1 - .../spatial_batch_norm_gradient_op.cc | 2 - caffe2/operators/spatial_batch_norm_op.cc | 2 - caffe2/operators/swish_op.cc | 1 - caffe2/operators/tan_op.cc | 2 - caffe2/operators/tanh_gradient_op.cc | 2 - caffe2/operators/tanh_op.cc | 2 - caffe2/operators/thresholded_relu_op.cc | 1 - caffe2/operators/tt_linear_op.h | 1 - caffe2/operators/utility_ops.cc | 2 +- .../variable_length_sequence_padding.h | 1 - caffe2/perfkernels/embedding_lookup.cc | 1 - .../fused_8bit_rowwise_embedding_lookup.cc | 1 - caffe2/sgd/lars_op.cc | 1 - caffe2/sgd/rmsprop_op.cc | 1 - caffe2/utils/eigen_utils.h | 24 ---- caffe2/utils/math.h | 27 ++++ caffe2/utils/math_cpu.cc | 1 - caffe2/utils/math_gpu.cu | 1 - 77 files changed, 139 insertions(+), 226 deletions(-) diff --git a/caffe2/mkl/operators/operator_fallback_mkl.cc b/caffe2/mkl/operators/operator_fallback_mkl.cc index 106fa05dec70a..91c43e746a9ad 100644 --- a/caffe2/mkl/operators/operator_fallback_mkl.cc +++ b/caffe2/mkl/operators/operator_fallback_mkl.cc @@ -15,7 +15,6 @@ #include "caffe2/operators/roi_align_rotated_op.h" #include "caffe2/operators/softmax_op.h" #include "caffe2/operators/utility_ops.h" -#include "caffe2/utils/eigen_utils.h" namespace caffe2 { namespace { diff --git a/caffe2/mobile/contrib/ulp2/ulp.cc b/caffe2/mobile/contrib/ulp2/ulp.cc index 1d8e0e8fe69a5..7a1652e6ba343 100644 --- a/caffe2/mobile/contrib/ulp2/ulp.cc +++ b/caffe2/mobile/contrib/ulp2/ulp.cc @@ -1,8 +1,5 @@ #include "ulp.h" - -#include #include "caffe2/operators/conv_pool_op_base.h" -#include "caffe2/utils/eigen_utils.h" #include "ulp_neon.h" namespace caffe2 { diff --git a/caffe2/operators/abs_op.cc b/caffe2/operators/abs_op.cc index 9b9e93f7eff66..81881c71c3898 100644 --- a/caffe2/operators/abs_op.cc +++ b/caffe2/operators/abs_op.cc @@ -1,5 +1,4 @@ #include "caffe2/operators/abs_op.h" -#include "caffe2/utils/eigen_utils.h" #include #include diff --git a/caffe2/operators/acos_op.cc b/caffe2/operators/acos_op.cc index 204bdce146115..8e3c814dbbde4 100644 --- a/caffe2/operators/acos_op.cc +++ b/caffe2/operators/acos_op.cc @@ -1,5 +1,4 @@ #include "caffe2/operators/acos_op.h" -#include "caffe2/utils/eigen_utils.h" #include #include diff --git a/caffe2/operators/affine_channel_op.cc b/caffe2/operators/affine_channel_op.cc index 26953876b4891..0e358f451b9cf 100644 --- a/caffe2/operators/affine_channel_op.cc +++ b/caffe2/operators/affine_channel_op.cc @@ -1,5 +1,4 @@ #include "caffe2/operators/affine_channel_op.h" -#include "caffe2/utils/eigen_utils.h" #include diff --git a/caffe2/operators/asin_op.cc b/caffe2/operators/asin_op.cc index 3f7db59a15cf1..e3f440e14c764 100644 --- a/caffe2/operators/asin_op.cc +++ b/caffe2/operators/asin_op.cc @@ -1,5 +1,4 @@ #include "caffe2/operators/asin_op.h" -#include "caffe2/utils/eigen_utils.h" #include #include diff --git a/caffe2/operators/atan_op.cc b/caffe2/operators/atan_op.cc index 59c0ebbc2b89e..ad11136e5b9db 100644 --- a/caffe2/operators/atan_op.cc +++ b/caffe2/operators/atan_op.cc @@ -1,5 +1,4 @@ #include "caffe2/operators/atan_op.h" -#include "caffe2/utils/eigen_utils.h" #include #include diff --git a/caffe2/operators/cbrt_op.cc b/caffe2/operators/cbrt_op.cc index 6d1a7025cab7c..84d93f33c14a4 100644 --- a/caffe2/operators/cbrt_op.cc +++ b/caffe2/operators/cbrt_op.cc @@ -1,5 +1,4 @@ #include "caffe2/operators/cbrt_op.h" -#include "caffe2/utils/eigen_utils.h" #include #include diff --git a/caffe2/operators/channel_backprop_stats_op.cc b/caffe2/operators/channel_backprop_stats_op.cc index bee287d29cef9..c5d26247f049a 100644 --- a/caffe2/operators/channel_backprop_stats_op.cc +++ b/caffe2/operators/channel_backprop_stats_op.cc @@ -1,5 +1,4 @@ #include "caffe2/operators/channel_backprop_stats_op.h" -#include "caffe2/utils/eigen_utils.h" namespace caffe2 { diff --git a/caffe2/operators/channel_stats_op.cc b/caffe2/operators/channel_stats_op.cc index 442ab48d764de..4cf9ce68743c5 100644 --- a/caffe2/operators/channel_stats_op.cc +++ b/caffe2/operators/channel_stats_op.cc @@ -1,5 +1,4 @@ #include "caffe2/operators/channel_stats_op.h" -#include "caffe2/utils/eigen_utils.h" namespace caffe2 { diff --git a/caffe2/operators/clip_op.cc b/caffe2/operators/clip_op.cc index 02e80bd131beb..efb40ff8c8afe 100644 --- a/caffe2/operators/clip_op.cc +++ b/caffe2/operators/clip_op.cc @@ -1,5 +1,4 @@ #include "caffe2/operators/clip_op.h" -#include "caffe2/utils/eigen_utils.h" namespace caffe2 { diff --git a/caffe2/operators/conv_op_eigen.cc b/caffe2/operators/conv_op_eigen.cc index b565b567ab294..2862d80777b55 100644 --- a/caffe2/operators/conv_op_eigen.cc +++ b/caffe2/operators/conv_op_eigen.cc @@ -1,5 +1,4 @@ #include "Eigen/Core" -#include "caffe2/utils/eigen_utils.h" #if EIGEN_VERSION_AT_LEAST(3, 3, 0) diff --git a/caffe2/operators/conv_transpose_op_mobile_impl.h b/caffe2/operators/conv_transpose_op_mobile_impl.h index d434ec49e3e5b..2d9e1ba902a27 100644 --- a/caffe2/operators/conv_transpose_op_mobile_impl.h +++ b/caffe2/operators/conv_transpose_op_mobile_impl.h @@ -15,7 +15,6 @@ #include "caffe2/operators/conv_op_shared.h" #include "caffe2/operators/conv_transpose_op_mobile.h" #include "caffe2/utils/cpu_neon.h" -#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/fixed_divisor.h" #include "caffe2/utils/math.h" diff --git a/caffe2/operators/cos_op.cc b/caffe2/operators/cos_op.cc index 262ccee482e1b..cf2eeb0ae5ed4 100644 --- a/caffe2/operators/cos_op.cc +++ b/caffe2/operators/cos_op.cc @@ -1,5 +1,4 @@ #include "caffe2/operators/cos_op.h" -#include "caffe2/utils/eigen_utils.h" #include #include diff --git a/caffe2/operators/cross_entropy_op.cc b/caffe2/operators/cross_entropy_op.cc index c288eb7be69d8..31a981d18b9db 100644 --- a/caffe2/operators/cross_entropy_op.cc +++ b/caffe2/operators/cross_entropy_op.cc @@ -1,5 +1,4 @@ #include "caffe2/operators/cross_entropy_op.h" -#include "caffe2/utils/eigen_utils.h" namespace caffe2 { diff --git a/caffe2/operators/cube_op.cc b/caffe2/operators/cube_op.cc index 1f0cf7d4bdafc..5b28c5bcdea77 100644 --- a/caffe2/operators/cube_op.cc +++ b/caffe2/operators/cube_op.cc @@ -1,5 +1,4 @@ #include "caffe2/operators/cube_op.h" -#include "caffe2/utils/eigen_utils.h" #include #include diff --git a/caffe2/operators/distance_op.cc b/caffe2/operators/distance_op.cc index 4e00cd4396726..6d6e5a35c7abf 100644 --- a/caffe2/operators/distance_op.cc +++ b/caffe2/operators/distance_op.cc @@ -1,5 +1,4 @@ #include "caffe2/operators/distance_op.h" -#include "caffe2/utils/eigen_utils.h" namespace caffe2 { diff --git a/caffe2/operators/elementwise_div_gradient_op.cc b/caffe2/operators/elementwise_div_gradient_op.cc index f8562951d1673..288b09cdfc3bd 100644 --- a/caffe2/operators/elementwise_div_gradient_op.cc +++ b/caffe2/operators/elementwise_div_gradient_op.cc @@ -1,5 +1,4 @@ #include "caffe2/operators/elementwise_div_op.h" -#include "caffe2/utils/eigen_utils.h" #include #include diff --git a/caffe2/operators/elementwise_ops.cc b/caffe2/operators/elementwise_ops.cc index 1cd7d65917a4e..ad46541c8f48a 100644 --- a/caffe2/operators/elementwise_ops.cc +++ b/caffe2/operators/elementwise_ops.cc @@ -1,5 +1,4 @@ #include "caffe2/operators/elementwise_ops.h" -#include "caffe2/utils/eigen_utils.h" #include diff --git a/caffe2/operators/elu_op.cc b/caffe2/operators/elu_op.cc index 45c0ebe9b751b..e08d6f2eb2bd9 100644 --- a/caffe2/operators/elu_op.cc +++ b/caffe2/operators/elu_op.cc @@ -1,6 +1,5 @@ #include "caffe2/operators/elu_op.h" -#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/math.h" namespace caffe2 { diff --git a/caffe2/operators/ensure_clipped_op.h b/caffe2/operators/ensure_clipped_op.h index 23a10928a0ceb..e53d5759f4a62 100644 --- a/caffe2/operators/ensure_clipped_op.h +++ b/caffe2/operators/ensure_clipped_op.h @@ -1,7 +1,6 @@ #pragma once #include "caffe2/core/operator.h" -#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/math.h" namespace caffe2 { diff --git a/caffe2/operators/fused_rowwise_8bit_conversion_ops.h b/caffe2/operators/fused_rowwise_8bit_conversion_ops.h index ca5002078129a..bf098a610f2cb 100644 --- a/caffe2/operators/fused_rowwise_8bit_conversion_ops.h +++ b/caffe2/operators/fused_rowwise_8bit_conversion_ops.h @@ -5,7 +5,6 @@ #include "caffe2/core/logging.h" #include "caffe2/core/operator.h" #include "caffe2/operators/reducer_functors.h" -#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/math.h" namespace caffe2 { diff --git a/caffe2/operators/gather_fused_8bit_rowwise_op.h b/caffe2/operators/gather_fused_8bit_rowwise_op.h index 621ea335a4993..de5dd61255979 100644 --- a/caffe2/operators/gather_fused_8bit_rowwise_op.h +++ b/caffe2/operators/gather_fused_8bit_rowwise_op.h @@ -1,7 +1,6 @@ #pragma once #include "caffe2/core/operator.h" -#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/math.h" namespace caffe2 { diff --git a/caffe2/operators/gather_ranges_to_dense_op.h b/caffe2/operators/gather_ranges_to_dense_op.h index 81f4fa53d5599..c9a4084b9158e 100644 --- a/caffe2/operators/gather_ranges_to_dense_op.h +++ b/caffe2/operators/gather_ranges_to_dense_op.h @@ -10,7 +10,6 @@ #include "caffe2/core/types.h" #include "caffe2/utils/math.h" -#include #include #include diff --git a/caffe2/operators/generate_proposals_op_util_boxes_test.cc b/caffe2/operators/generate_proposals_op_util_boxes_test.cc index 78ff4c21cc43d..3ba38929b6b78 100644 --- a/caffe2/operators/generate_proposals_op_util_boxes_test.cc +++ b/caffe2/operators/generate_proposals_op_util_boxes_test.cc @@ -1,5 +1,4 @@ #include "caffe2/operators/generate_proposals_op_util_boxes.h" -#include "caffe2/utils/eigen_utils.h" #include diff --git a/caffe2/operators/generate_proposals_op_util_nms_test.cc b/caffe2/operators/generate_proposals_op_util_nms_test.cc index 6d9e2a173c836..a7825c81b6354 100644 --- a/caffe2/operators/generate_proposals_op_util_nms_test.cc +++ b/caffe2/operators/generate_proposals_op_util_nms_test.cc @@ -1,4 +1,3 @@ -#include "caffe2/utils/eigen_utils.h" #include "generate_proposals_op_util_nms.h" #include diff --git a/caffe2/operators/group_norm_op.cc b/caffe2/operators/group_norm_op.cc index 9c203f24a8683..733ec52680e1e 100644 --- a/caffe2/operators/group_norm_op.cc +++ b/caffe2/operators/group_norm_op.cc @@ -10,7 +10,6 @@ #include -#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/math.h" namespace caffe2 { diff --git a/caffe2/operators/instance_norm_gradient_op.cc b/caffe2/operators/instance_norm_gradient_op.cc index 077020ee48b9b..079992140022f 100644 --- a/caffe2/operators/instance_norm_gradient_op.cc +++ b/caffe2/operators/instance_norm_gradient_op.cc @@ -1,5 +1,4 @@ #include "caffe2/operators/instance_norm_op.h" -#include "caffe2/utils/eigen_utils.h" namespace caffe2 { diff --git a/caffe2/operators/instance_norm_op.cc b/caffe2/operators/instance_norm_op.cc index b0d0dea73ea28..7011ecf40bf7e 100644 --- a/caffe2/operators/instance_norm_op.cc +++ b/caffe2/operators/instance_norm_op.cc @@ -1,5 +1,4 @@ #include "caffe2/operators/instance_norm_op.h" -#include "caffe2/utils/eigen_utils.h" namespace caffe2 { diff --git a/caffe2/operators/integral_image_op.cc b/caffe2/operators/integral_image_op.cc index 27356104bbd66..6da5ee6d5600f 100644 --- a/caffe2/operators/integral_image_op.cc +++ b/caffe2/operators/integral_image_op.cc @@ -1,122 +1,6 @@ #include "integral_image_op.h" -#include "caffe2/utils/eigen_utils.h" - namespace caffe2 { -namespace { -template -using EigenMatrixMapRowMajor = Eigen::Map< - Eigen::Matrix>; - -template -using ConstEigenMatrixMapRowMajor = Eigen::Map< - const Eigen::Matrix>; -} // namespace - -template <> -bool IntegralImageOp::RunOnDevice() { - const auto& X = Input(0); - auto* Y = Output(0); - CAFFE_ENFORCE_EQ(X.ndim(), 4, "Only supports 4D tensors for the momement"); - - vector out_shape(X.dims()); - out_shape[2] += 1; // H + 1 output size - out_shape[3] += 1; // W + 1 output size - Y->Resize(out_shape); - const int ind = X.dim32(0); - const int chans = X.dim32(1); - const int rows_in = X.dim32(2); - const int cols_in = X.dim32(3); - const int rows_out = Y->dim32(2); - const int cols_out = Y->dim32(3); - - const float* input_data = X.template data(); - float* output_data = Y->template mutable_data(); - - const int row_out_pass_size = ind * chans * rows_out; - const int row_in_pass_size = ind * chans * rows_in; - EigenMatrixMapRowMajor Y_arr(output_data, row_out_pass_size, cols_out); - ConstEigenMatrixMapRowMajor X_arr( - input_data, row_in_pass_size, cols_in); - - // Row Pass - for (int i = 0; i < row_out_pass_size; i++) { - int row = i % rows_out; - int diff = i / rows_out + 1; - Y_arr(i, 0) = 0.; - if (row == 0) { - for (int j = 1; j < cols_out; ++j) { - Y_arr(i, j) = 0.; - } - } else { - for (int j = 1; j < cols_out; ++j) { - Y_arr(i, j) = Y_arr(i, j - 1) + X_arr(i - diff, j - 1); - } - } - } - - // Col Pass - const int col_out_pass_size = X.dim32(0) * chans * cols_out; - for (int i = 0; i < col_out_pass_size; i++) { - int col = i % cols_out; - int row = i / cols_out; - for (int j = row * rows_out + 1; j < (row + 1) * rows_out; ++j) { - Y_arr(j, col) += Y_arr(j - 1, col); - } - } - return true; -} - -template <> -bool IntegralImageGradientOp::RunOnDevice() { - auto& X = Input(0); // Original input to "forward" op - auto& dY = Input(1); // Gradient of net w.r.t. output of "forward" op - // (aka "gradOutput") - auto* dX = Output(0); // Gradient of net w.r.t. input to "forward" op - // (aka "gradInput") - - dX->ResizeLike(X); - const int ind = X.dim32(0); - const int chans = X.dim32(1); - const int rows_in = dY.dim32(2); - const int cols_in = dY.dim32(3); - const int rows_out = dX->dim32(2); - const int cols_out = dX->dim32(3); - - const float* input_data = dY.template data(); - float* output_data = dX->template mutable_data(); - - const int row_out_pass_size = ind * chans * rows_out; - const int row_in_pass_size = ind * chans * rows_in; - EigenMatrixMapRowMajor dX_arr( - output_data, row_out_pass_size, cols_out); - ConstEigenMatrixMapRowMajor dY_arr( - input_data, row_in_pass_size, cols_in); - Eigen::MatrixXf tmp(row_in_pass_size, cols_out); - - // Row Pass dY(N, C, H+1, W+1) => tmp(N, C, H+1, W) - for (int i = 0; i < row_in_pass_size; i++) { - tmp(i, 0) = dY_arr(i, 0); - for (int j = 1; j < cols_out; ++j) { - tmp(i, j) = tmp(i, j - 1) + dY_arr(i, j); - } - } - - // Col Pass tmp(N, C, H+1, W)=>dX(N, C, H, W) - const int col_out_pass_size = X.dim32(0) * chans * cols_out; - for (int i = 0; i < col_out_pass_size; i++) { - int col = i % cols_out; - int row_out_start = (i / cols_out) * rows_out; - int row_in_start = (i / cols_out) * rows_in; - dX_arr(row_out_start, col) = tmp(row_in_start, col); - for (int j = 1; j < rows_out; ++j) { - dX_arr(row_out_start + j, col) = - dX_arr(row_out_start + j - 1, col) + tmp(row_in_start + j, col); - } - } - return true; -} - REGISTER_CPU_OPERATOR(IntegralImage, IntegralImageOp); REGISTER_CPU_OPERATOR( IntegralImageGradient, diff --git a/caffe2/operators/integral_image_op.h b/caffe2/operators/integral_image_op.h index b8920d677de83..71d9b076336fa 100644 --- a/caffe2/operators/integral_image_op.h +++ b/caffe2/operators/integral_image_op.h @@ -8,6 +8,16 @@ namespace caffe2 { +namespace { +template +using EigenMatrixMapRowMajor = Eigen::Map< + Eigen::Matrix>; + +template +using ConstEigenMatrixMapRowMajor = Eigen::Map< + const Eigen::Matrix>; +} // namespace + template class IntegralImageOp final : public Operator { public: @@ -15,7 +25,59 @@ class IntegralImageOp final : public Operator { : Operator(operator_def, ws) {} USE_OPERATOR_CONTEXT_FUNCTIONS; - bool RunOnDevice() override; + bool RunOnDevice() override { + const auto& X = Input(0); + auto* Y = Output(0); + CAFFE_ENFORCE_EQ(X.ndim(), 4, "Only supports 4D tensors for the momement"); + + vector out_shape(X.dims()); + out_shape[2] += 1; // H + 1 output size + out_shape[3] += 1; // W + 1 output size + Y->Resize(out_shape); + const int ind = X.dim32(0); + const int chans = X.dim32(1); + const int rows_in = X.dim32(2); + const int cols_in = X.dim32(3); + const int rows_out = Y->dim32(2); + const int cols_out = Y->dim32(3); + + const float* input_data = X.template data(); + float* output_data = Y->template mutable_data(); + + const int row_out_pass_size = ind * chans * rows_out; + const int row_in_pass_size = ind * chans * rows_in; + EigenMatrixMapRowMajor Y_arr( + output_data, row_out_pass_size, cols_out); + ConstEigenMatrixMapRowMajor X_arr( + input_data, row_in_pass_size, cols_in); + + // Row Pass + for (int i = 0; i < row_out_pass_size; i++) { + int row = i % rows_out; + int diff = i / rows_out + 1; + Y_arr(i, 0) = 0.; + if (row == 0) { + for (int j = 1; j < cols_out; ++j) { + Y_arr(i, j) = 0.; + } + } else { + for (int j = 1; j < cols_out; ++j) { + Y_arr(i, j) = Y_arr(i, j - 1) + X_arr(i - diff, j - 1); + } + } + } + + // Col Pass + const int col_out_pass_size = X.dim32(0) * chans * cols_out; + for (int i = 0; i < col_out_pass_size; i++) { + int col = i % cols_out; + int row = i / cols_out; + for (int j = row * rows_out + 1; j < (row + 1) * rows_out; ++j) { + Y_arr(j, col) += Y_arr(j - 1, col); + } + } + return true; + } }; template @@ -25,7 +87,54 @@ class IntegralImageGradientOp final : public Operator { : Operator(def, ws) {} USE_OPERATOR_CONTEXT_FUNCTIONS; - bool RunOnDevice() override; + bool RunOnDevice() override { + auto& X = Input(0); // Original input to "forward" op + auto& dY = Input(1); // Gradient of net w.r.t. output of "forward" op + // (aka "gradOutput") + auto* dX = Output(0); // Gradient of net w.r.t. input to "forward" op + // (aka "gradInput") + + dX->ResizeLike(X); + const int ind = X.dim32(0); + const int chans = X.dim32(1); + const int rows_in = dY.dim32(2); + const int cols_in = dY.dim32(3); + const int rows_out = dX->dim32(2); + const int cols_out = dX->dim32(3); + + const float* input_data = dY.template data(); + float* output_data = dX->template mutable_data(); + + const int row_out_pass_size = ind * chans * rows_out; + const int row_in_pass_size = ind * chans * rows_in; + EigenMatrixMapRowMajor dX_arr( + output_data, row_out_pass_size, cols_out); + ConstEigenMatrixMapRowMajor dY_arr( + input_data, row_in_pass_size, cols_in); + Eigen::MatrixXf tmp(row_in_pass_size, cols_out); + + // Row Pass dY(N, C, H+1, W+1) => tmp(N, C, H+1, W) + for (int i = 0; i < row_in_pass_size; i++) { + tmp(i, 0) = dY_arr(i, 0); + for (int j = 1; j < cols_out; ++j) { + tmp(i, j) = tmp(i, j - 1) + dY_arr(i, j); + } + } + + // Col Pass tmp(N, C, H+1, W)=>dX(N, C, H, W) + const int col_out_pass_size = X.dim32(0) * chans * cols_out; + for (int i = 0; i < col_out_pass_size; i++) { + int col = i % cols_out; + int row_out_start = (i / cols_out) * rows_out; + int row_in_start = (i / cols_out) * rows_in; + dX_arr(row_out_start, col) = tmp(row_in_start, col); + for (int j = 1; j < rows_out; ++j) { + dX_arr(row_out_start + j, col) = + dX_arr(row_out_start + j - 1, col) + tmp(row_in_start + j, col); + } + } + return true; + } protected: Tensor row_pass_buffer_; diff --git a/caffe2/operators/layer_norm_op.cc b/caffe2/operators/layer_norm_op.cc index 4b995fa49d8ce..eb5ae0d33e5b7 100644 --- a/caffe2/operators/layer_norm_op.cc +++ b/caffe2/operators/layer_norm_op.cc @@ -1,5 +1,4 @@ #include "caffe2/operators/layer_norm_op.h" -#include "caffe2/utils/eigen_utils.h" namespace caffe2 { diff --git a/caffe2/operators/leaky_relu_op.cc b/caffe2/operators/leaky_relu_op.cc index dcf62084a1207..fc66edcdbbe9b 100644 --- a/caffe2/operators/leaky_relu_op.cc +++ b/caffe2/operators/leaky_relu_op.cc @@ -1,6 +1,5 @@ #include "caffe2/operators/leaky_relu_op.h" -#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/math.h" namespace caffe2 { diff --git a/caffe2/operators/lengths_reducer_rowwise_8bit_ops.h b/caffe2/operators/lengths_reducer_rowwise_8bit_ops.h index 58ebe6cb58e84..0423fcf34a270 100644 --- a/caffe2/operators/lengths_reducer_rowwise_8bit_ops.h +++ b/caffe2/operators/lengths_reducer_rowwise_8bit_ops.h @@ -8,7 +8,6 @@ #include "caffe2/core/operator.h" #include "caffe2/operators/reducer_functors.h" #include "caffe2/perfkernels/embedding_lookup.h" -#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/math.h" namespace caffe2 { diff --git a/caffe2/operators/listwise_l2r_op.cc b/caffe2/operators/listwise_l2r_op.cc index 3940dfb2b1670..24c5e26e5faaf 100644 --- a/caffe2/operators/listwise_l2r_op.cc +++ b/caffe2/operators/listwise_l2r_op.cc @@ -1,7 +1,6 @@ #include "caffe2/operators/listwise_l2r_op.h" #include "caffe2/core/context.h" #include "caffe2/core/operator.h" -#include "caffe2/utils/eigen_utils.h" namespace caffe2 { diff --git a/caffe2/operators/logit_op.cc b/caffe2/operators/logit_op.cc index 225608f87b38d..8d1859a405a49 100644 --- a/caffe2/operators/logit_op.cc +++ b/caffe2/operators/logit_op.cc @@ -4,7 +4,6 @@ #include #include "caffe2/operators/elementwise_ops.h" -#include "caffe2/utils/eigen_utils.h" namespace caffe2 { diff --git a/caffe2/operators/lpnorm_op.cc b/caffe2/operators/lpnorm_op.cc index f79d51ad51c44..c302d42c92b07 100644 --- a/caffe2/operators/lpnorm_op.cc +++ b/caffe2/operators/lpnorm_op.cc @@ -2,7 +2,6 @@ #include "caffe2/core/operator.h" #include "caffe2/core/types.h" -#include "caffe2/utils/eigen_utils.h" namespace caffe2 { diff --git a/caffe2/operators/minmax_gradient_ops.cc b/caffe2/operators/minmax_gradient_ops.cc index 0c640d4d58e81..5b223b2551332 100644 --- a/caffe2/operators/minmax_gradient_ops.cc +++ b/caffe2/operators/minmax_gradient_ops.cc @@ -1,5 +1,4 @@ #include "caffe2/operators/minmax_ops.h" -#include "caffe2/utils/eigen_utils.h" namespace caffe2 { diff --git a/caffe2/operators/minmax_ops.cc b/caffe2/operators/minmax_ops.cc index 16b8f026072e5..802788531e072 100644 --- a/caffe2/operators/minmax_ops.cc +++ b/caffe2/operators/minmax_ops.cc @@ -1,5 +1,4 @@ #include "caffe2/operators/minmax_ops.h" -#include "caffe2/utils/eigen_utils.h" namespace caffe2 { diff --git a/caffe2/operators/norm_planar_yuv_op.cc b/caffe2/operators/norm_planar_yuv_op.cc index ea3ccc222dc96..b9d9b9c44ecc2 100644 --- a/caffe2/operators/norm_planar_yuv_op.cc +++ b/caffe2/operators/norm_planar_yuv_op.cc @@ -1,6 +1,5 @@ #include #include "caffe2/core/operator.h" -#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/math.h" namespace caffe2 { diff --git a/caffe2/operators/normalize_l1_op.cc b/caffe2/operators/normalize_l1_op.cc index 908131f43532d..cb02ff7d52397 100644 --- a/caffe2/operators/normalize_l1_op.cc +++ b/caffe2/operators/normalize_l1_op.cc @@ -1,7 +1,6 @@ #include "caffe2/operators/normalize_l1_op.h" #include "caffe2/core/tensor.h" -#include "caffe2/utils/eigen_utils.h" namespace caffe2 { diff --git a/caffe2/operators/normalize_op.cc b/caffe2/operators/normalize_op.cc index 1a7d720deb6c3..4a1aac7f02a96 100644 --- a/caffe2/operators/normalize_op.cc +++ b/caffe2/operators/normalize_op.cc @@ -1,7 +1,6 @@ #include "caffe2/operators/normalize_op.h" #include "caffe2/core/tensor.h" -#include "caffe2/utils/eigen_utils.h" namespace caffe2 { diff --git a/caffe2/operators/pool_gradient_op.cc b/caffe2/operators/pool_gradient_op.cc index f7062a616dc8d..048d8fc06177d 100644 --- a/caffe2/operators/pool_gradient_op.cc +++ b/caffe2/operators/pool_gradient_op.cc @@ -1,5 +1,4 @@ #include "caffe2/operators/pool_op.h" -#include "caffe2/utils/eigen_utils.h" namespace caffe2 { diff --git a/caffe2/operators/pool_op.cc b/caffe2/operators/pool_op.cc index eca7978e024aa..edb14bc82b7ac 100644 --- a/caffe2/operators/pool_op.cc +++ b/caffe2/operators/pool_op.cc @@ -1,7 +1,6 @@ // TODO(ataei): reduce the apparent redundancy of all the code below. #include "caffe2/operators/pool_op.h" #include "caffe2/utils/cpu_neon.h" -#include "caffe2/utils/eigen_utils.h" namespace caffe2 { diff --git a/caffe2/operators/pow_op.cc b/caffe2/operators/pow_op.cc index a028d6d0bdcea..bef995093ddaa 100644 --- a/caffe2/operators/pow_op.cc +++ b/caffe2/operators/pow_op.cc @@ -1,5 +1,4 @@ #include "caffe2/operators/pow_op.h" -#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/math.h" // definition of NumericTypes and SameTypeAsInput is in below header file //#include "caffe2/operators/elementwise_op.h" diff --git a/caffe2/operators/prelu_op.cc b/caffe2/operators/prelu_op.cc index 8bacf1e29153c..680b987e74292 100644 --- a/caffe2/operators/prelu_op.cc +++ b/caffe2/operators/prelu_op.cc @@ -1,5 +1,4 @@ #include "caffe2/operators/prelu_op.h" -#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/math.h" #include "caffe2/core/types.h" diff --git a/caffe2/operators/reducer_functors.h b/caffe2/operators/reducer_functors.h index f3dd35b956078..708c964af213c 100644 --- a/caffe2/operators/reducer_functors.h +++ b/caffe2/operators/reducer_functors.h @@ -6,7 +6,6 @@ #include "caffe2/core/context.h" #include "caffe2/core/tensor.h" -#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/math.h" #include "caffe2/utils/proto_utils.h" diff --git a/caffe2/operators/relu_n_op.cc b/caffe2/operators/relu_n_op.cc index 4b5afed3528c3..b69baff7725bd 100644 --- a/caffe2/operators/relu_n_op.cc +++ b/caffe2/operators/relu_n_op.cc @@ -16,7 +16,6 @@ #include "caffe2/operators/relu_n_op.h" -#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/math.h" namespace caffe2 { diff --git a/caffe2/operators/relu_op.cc b/caffe2/operators/relu_op.cc index 45b622ae8409f..8737cddc59756 100644 --- a/caffe2/operators/relu_op.cc +++ b/caffe2/operators/relu_op.cc @@ -1,6 +1,5 @@ #include "caffe2/operators/relu_op.h" -#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/math.h" namespace caffe2 { diff --git a/caffe2/operators/roi_align_op_gpu_test.cc b/caffe2/operators/roi_align_op_gpu_test.cc index 199500f93df3a..afbf60c85b4bd 100644 --- a/caffe2/operators/roi_align_op_gpu_test.cc +++ b/caffe2/operators/roi_align_op_gpu_test.cc @@ -3,7 +3,6 @@ #include "caffe2/core/context_gpu.h" #include "caffe2/core/flags.h" -#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/math.h" #include "gtest/gtest.h" diff --git a/caffe2/operators/rsqrt_op.cc b/caffe2/operators/rsqrt_op.cc index de4fc499f4215..0587fea21dcab 100644 --- a/caffe2/operators/rsqrt_op.cc +++ b/caffe2/operators/rsqrt_op.cc @@ -1,7 +1,5 @@ #include "caffe2/operators/rsqrt_op.h" -#include "caffe2/utils/eigen_utils.h" - #include #include #include diff --git a/caffe2/operators/selu_op.cc b/caffe2/operators/selu_op.cc index 50d823d8bedf1..715e53cd6ea14 100644 --- a/caffe2/operators/selu_op.cc +++ b/caffe2/operators/selu_op.cc @@ -1,6 +1,5 @@ #include "caffe2/operators/selu_op.h" -#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/math.h" namespace caffe2 { diff --git a/caffe2/operators/sigmoid_gradient_op.cc b/caffe2/operators/sigmoid_gradient_op.cc index dd3c0c40f701f..3db4d60a61b0e 100644 --- a/caffe2/operators/sigmoid_gradient_op.cc +++ b/caffe2/operators/sigmoid_gradient_op.cc @@ -1,7 +1,5 @@ #include "caffe2/operators/sigmoid_op.h" -#include "caffe2/utils/eigen_utils.h" - #include #include #include diff --git a/caffe2/operators/sigmoid_op.cc b/caffe2/operators/sigmoid_op.cc index f1c4828cb37b2..4dcfdc676472d 100644 --- a/caffe2/operators/sigmoid_op.cc +++ b/caffe2/operators/sigmoid_op.cc @@ -1,7 +1,5 @@ #include "caffe2/operators/sigmoid_op.h" -#include "caffe2/utils/eigen_utils.h" - namespace caffe2 { template <> diff --git a/caffe2/operators/sin_op.cc b/caffe2/operators/sin_op.cc index 90fcb97bf0799..30d76cd162e37 100644 --- a/caffe2/operators/sin_op.cc +++ b/caffe2/operators/sin_op.cc @@ -1,5 +1,4 @@ #include "caffe2/operators/sin_op.h" -#include "caffe2/utils/eigen_utils.h" #include #include diff --git a/caffe2/operators/sinusoid_position_encoding_op.h b/caffe2/operators/sinusoid_position_encoding_op.h index 5591b9749a704..69c8ea8244b38 100644 --- a/caffe2/operators/sinusoid_position_encoding_op.h +++ b/caffe2/operators/sinusoid_position_encoding_op.h @@ -9,7 +9,6 @@ #include "caffe2/core/operator.h" #include "Eigen/Core" -#include "caffe2/utils/eigen_utils.h" namespace caffe2 { diff --git a/caffe2/operators/softplus_op.cc b/caffe2/operators/softplus_op.cc index 7d2efd578560a..3a81a80b2235b 100644 --- a/caffe2/operators/softplus_op.cc +++ b/caffe2/operators/softplus_op.cc @@ -1,6 +1,5 @@ #include "caffe2/operators/softplus_op.h" -#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/math.h" namespace caffe2 { diff --git a/caffe2/operators/softsign_op.cc b/caffe2/operators/softsign_op.cc index 4062848105b1c..8e3be424887cc 100644 --- a/caffe2/operators/softsign_op.cc +++ b/caffe2/operators/softsign_op.cc @@ -1,7 +1,5 @@ #include "caffe2/operators/softsign_op.h" -#include "caffe2/utils/eigen_utils.h" - #include #include diff --git a/caffe2/operators/sparse_normalize_op.cc b/caffe2/operators/sparse_normalize_op.cc index 43ded9024d277..2f0f353b5088a 100644 --- a/caffe2/operators/sparse_normalize_op.cc +++ b/caffe2/operators/sparse_normalize_op.cc @@ -1,6 +1,5 @@ #include "caffe2/operators/sparse_normalize_op.h" #include "caffe2/core/tensor.h" -#include "caffe2/utils/eigen_utils.h" namespace caffe2 { diff --git a/caffe2/operators/spatial_batch_norm_gradient_op.cc b/caffe2/operators/spatial_batch_norm_gradient_op.cc index dd5434db725a7..1c4c1bfb5f05a 100644 --- a/caffe2/operators/spatial_batch_norm_gradient_op.cc +++ b/caffe2/operators/spatial_batch_norm_gradient_op.cc @@ -1,7 +1,5 @@ #include "caffe2/operators/spatial_batch_norm_op.h" -#include "caffe2/utils/eigen_utils.h" - namespace caffe2 { template <> diff --git a/caffe2/operators/spatial_batch_norm_op.cc b/caffe2/operators/spatial_batch_norm_op.cc index 671493a1df010..f089a288069c4 100644 --- a/caffe2/operators/spatial_batch_norm_op.cc +++ b/caffe2/operators/spatial_batch_norm_op.cc @@ -1,7 +1,5 @@ #include "caffe2/operators/spatial_batch_norm_op.h" -#include "caffe2/utils/eigen_utils.h" - namespace caffe2 { template <> diff --git a/caffe2/operators/swish_op.cc b/caffe2/operators/swish_op.cc index a636d23d85f7c..cd8dfa7ea5d3f 100644 --- a/caffe2/operators/swish_op.cc +++ b/caffe2/operators/swish_op.cc @@ -4,7 +4,6 @@ #include #include "caffe2/core/types.h" -#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/math.h" namespace caffe2 { diff --git a/caffe2/operators/tan_op.cc b/caffe2/operators/tan_op.cc index 62a48bb520a52..7dd873c18e927 100644 --- a/caffe2/operators/tan_op.cc +++ b/caffe2/operators/tan_op.cc @@ -1,7 +1,5 @@ #include "caffe2/operators/tan_op.h" -#include "caffe2/utils/eigen_utils.h" - #include #include diff --git a/caffe2/operators/tanh_gradient_op.cc b/caffe2/operators/tanh_gradient_op.cc index 385d895c688bb..6daebce46adb9 100644 --- a/caffe2/operators/tanh_gradient_op.cc +++ b/caffe2/operators/tanh_gradient_op.cc @@ -1,7 +1,5 @@ #include "caffe2/operators/tanh_op.h" -#include "caffe2/utils/eigen_utils.h" - #include #include #include diff --git a/caffe2/operators/tanh_op.cc b/caffe2/operators/tanh_op.cc index cae08082a9192..28ca87c13a20f 100644 --- a/caffe2/operators/tanh_op.cc +++ b/caffe2/operators/tanh_op.cc @@ -1,7 +1,5 @@ #include "caffe2/operators/tanh_op.h" -#include "caffe2/utils/eigen_utils.h" - namespace caffe2 { template <> diff --git a/caffe2/operators/thresholded_relu_op.cc b/caffe2/operators/thresholded_relu_op.cc index 8b5e6b514478c..d79d20cd5d159 100644 --- a/caffe2/operators/thresholded_relu_op.cc +++ b/caffe2/operators/thresholded_relu_op.cc @@ -1,6 +1,5 @@ #include "caffe2/operators/thresholded_relu_op.h" -#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/math.h" namespace caffe2 { diff --git a/caffe2/operators/tt_linear_op.h b/caffe2/operators/tt_linear_op.h index 13196bf3761b7..05653c9003913 100644 --- a/caffe2/operators/tt_linear_op.h +++ b/caffe2/operators/tt_linear_op.h @@ -9,7 +9,6 @@ #include "Eigen/Dense" #include "caffe2/core/context.h" #include "caffe2/core/operator.h" -#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/math.h" namespace caffe2 { diff --git a/caffe2/operators/utility_ops.cc b/caffe2/operators/utility_ops.cc index 1abf2130953a7..c5bad002779fa 100644 --- a/caffe2/operators/utility_ops.cc +++ b/caffe2/operators/utility_ops.cc @@ -1,6 +1,6 @@ #include "caffe2/operators/utility_ops.h" + #include -#include "caffe2/utils/eigen_utils.h" namespace caffe2 { diff --git a/caffe2/operators/variable_length_sequence_padding.h b/caffe2/operators/variable_length_sequence_padding.h index 7318b2e78b080..53196489b0553 100644 --- a/caffe2/operators/variable_length_sequence_padding.h +++ b/caffe2/operators/variable_length_sequence_padding.h @@ -2,7 +2,6 @@ #include "caffe2/core/context.h" #include "caffe2/core/operator.h" -#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/math.h" namespace caffe2 { diff --git a/caffe2/perfkernels/embedding_lookup.cc b/caffe2/perfkernels/embedding_lookup.cc index b076d88f5accd..460787e4bdb52 100644 --- a/caffe2/perfkernels/embedding_lookup.cc +++ b/caffe2/perfkernels/embedding_lookup.cc @@ -4,7 +4,6 @@ #include "caffe2/perfkernels/common.h" #include "caffe2/perfkernels/typed_axpy.h" #include "caffe2/utils/cpuid.h" -#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/math.h" namespace caffe2 { diff --git a/caffe2/perfkernels/fused_8bit_rowwise_embedding_lookup.cc b/caffe2/perfkernels/fused_8bit_rowwise_embedding_lookup.cc index 675d7c08ddbf3..40ab3dafff979 100644 --- a/caffe2/perfkernels/fused_8bit_rowwise_embedding_lookup.cc +++ b/caffe2/perfkernels/fused_8bit_rowwise_embedding_lookup.cc @@ -4,7 +4,6 @@ #include "caffe2/perfkernels/common.h" #include "caffe2/perfkernels/typed_axpy.h" #include "caffe2/utils/cpuid.h" -#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/math.h" namespace caffe2 { diff --git a/caffe2/sgd/lars_op.cc b/caffe2/sgd/lars_op.cc index 3e013a943464b..a47d5c94d5f1a 100644 --- a/caffe2/sgd/lars_op.cc +++ b/caffe2/sgd/lars_op.cc @@ -1,6 +1,5 @@ #include "caffe2/sgd/lars_op.h" #include -#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/math.h" namespace caffe2 { diff --git a/caffe2/sgd/rmsprop_op.cc b/caffe2/sgd/rmsprop_op.cc index ae73706190077..3d5c01d8542a0 100644 --- a/caffe2/sgd/rmsprop_op.cc +++ b/caffe2/sgd/rmsprop_op.cc @@ -1,6 +1,5 @@ #include "rmsprop_op.h" -#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/math.h" namespace caffe2 { diff --git a/caffe2/utils/eigen_utils.h b/caffe2/utils/eigen_utils.h index cf41d268d7132..b00e355627fb2 100644 --- a/caffe2/utils/eigen_utils.h +++ b/caffe2/utils/eigen_utils.h @@ -9,30 +9,6 @@ namespace caffe2 { -// Common Eigen types that we will often use -template -using EigenMatrixMap = - Eigen::Map>; -template -using EigenArrayMap = - Eigen::Map>; -template -using EigenVectorMap = Eigen::Map>; -template -using EigenVectorArrayMap = Eigen::Map>; -template -using ConstEigenMatrixMap = - Eigen::Map>; -template -using ConstEigenArrayMap = - Eigen::Map>; -template -using ConstEigenVectorMap = - Eigen::Map>; -template -using ConstEigenVectorArrayMap = - Eigen::Map>; - // 1-d array template using EArrXt = Eigen::Array; diff --git a/caffe2/utils/math.h b/caffe2/utils/math.h index 7138cfd27177a..9a9bdad5b7bba 100644 --- a/caffe2/utils/math.h +++ b/caffe2/utils/math.h @@ -17,6 +17,9 @@ extern "C" { #include "caffe2/core/types.h" #include "caffe2/utils/math_utils.h" +#include "Eigen/Core" +#include "Eigen/Dense" + namespace caffe2 { template @@ -26,6 +29,30 @@ class Tensor; // engine specified. class DefaultEngine {}; +// Common Eigen types that we will often use +template +using EigenMatrixMap = + Eigen::Map>; +template +using EigenArrayMap = + Eigen::Map>; +template +using EigenVectorMap = Eigen::Map>; +template +using EigenVectorArrayMap = Eigen::Map>; +template +using ConstEigenMatrixMap = + Eigen::Map>; +template +using ConstEigenArrayMap = + Eigen::Map>; +template +using ConstEigenVectorMap = + Eigen::Map>; +template +using ConstEigenVectorArrayMap = + Eigen::Map>; + namespace math { template diff --git a/caffe2/utils/math_cpu.cc b/caffe2/utils/math_cpu.cc index c4e5f878ccb5d..8430cc91b89b5 100644 --- a/caffe2/utils/math_cpu.cc +++ b/caffe2/utils/math_cpu.cc @@ -11,7 +11,6 @@ // platforms, it allows one to quickly port Caffe2 to different platforms // where BLAS may not be present. -#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/math.h" #include diff --git a/caffe2/utils/math_gpu.cu b/caffe2/utils/math_gpu.cu index d10475fc2f2e4..1f2f721363406 100644 --- a/caffe2/utils/math_gpu.cu +++ b/caffe2/utils/math_gpu.cu @@ -2,7 +2,6 @@ #include "caffe2/utils/math.h" -#include #include #include #include From d86775764909b6524b7b7c31a06344b877161dac Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 10 Jul 2018 10:14:11 -0700 Subject: [PATCH 03/36] Fix CUDA 8 build for Windows (#9300) Summary: Replacement of #9023. Pull Request resolved: https://github.com/pytorch/pytorch/pull/9300 Differential Revision: D8781492 Pulled By: soumith fbshipit-source-id: 6c0994da46d3112c24769f92366836c397891d93 --- aten/src/ATen/cpu/vec256/intrinsics.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/aten/src/ATen/cpu/vec256/intrinsics.h b/aten/src/ATen/cpu/vec256/intrinsics.h index ca649d61e6c42..442e8fd0511fc 100644 --- a/aten/src/ATen/cpu/vec256/intrinsics.h +++ b/aten/src/ATen/cpu/vec256/intrinsics.h @@ -4,10 +4,10 @@ /* Microsoft C/C++-compatible compiler */ #include #if _MSC_VER <= 1900 -#define _mm256_extract_epi64(X, Y) (_mm_extract_epi16(_mm256_extractf128_si256(X, Y >> 1), Y % 2)) -#define _mm256_extract_epi32(X, Y) (_mm_extract_epi16(_mm256_extractf128_si256(X, Y >> 2), Y % 4)) +#define _mm256_extract_epi64(X, Y) (_mm_extract_epi64(_mm256_extractf128_si256(X, Y >> 1), Y % 2)) +#define _mm256_extract_epi32(X, Y) (_mm_extract_epi32(_mm256_extractf128_si256(X, Y >> 2), Y % 4)) #define _mm256_extract_epi16(X, Y) (_mm_extract_epi16(_mm256_extractf128_si256(X, Y >> 3), Y % 8)) -#define _mm256_extract_epi8(X, Y) (_mm_extract_epi16(_mm256_extractf128_si256(X, Y >> 4), Y % 16)) +#define _mm256_extract_epi8(X, Y) (_mm_extract_epi8(_mm256_extractf128_si256(X, Y >> 4), Y % 16)) #endif #elif defined(__GNUC__) && (defined(__x86_64__) || defined(__i386__)) /* GCC-compatible compiler, targeting x86/x86-64 */ From efefd1d7cf3736cfb5c494a5eb3b5b22ab949dc4 Mon Sep 17 00:00:00 2001 From: Zachary DeVito Date: Tue, 10 Jul 2018 10:20:24 -0700 Subject: [PATCH 04/36] Unify aten_dispatch and aten_schema into a single operator abstraction with human-readable schema. (#8885) Summary: This is a series of two commits that should probably be read separately. They are stacked on top of #9018 since the second commit requires it for correctness. Commit 1 ======= This commit is the first in a series that will clean up how we handle declaring operators and intrinsics in the JIT to make it more modular and readable. This introduces readable declarations that can be used to register operators and switches gen_jit_dispatch to generate this schema. A follow up PR will remove the dispatch keys like "add-3" and resolve ops directly based on the registered schema, further simplifying the generation process. * Switches schema over to parsed declarations, in the future this will allow something like: ``` registry.register_intrinsic("foo(Tensor a, Tensor b) -> Tensor", [](Stack& stack) { ... }) ``` This will allow the scalable registration of intrinsics for lists, tuples, and other ops, as long as meta-data for these ops (e.g. derivatives and size propagation routines). The declarations resemble those used by PythonArgParser but have been singificantly cleaned up to minimize the number of types that can appear in the declaration. We should strive to get the other parts of PyTorch switched over to this restricted declaration set when possible, but it is too much to do in a single PR. My hope is that eventually we will use a very similar language to describe declarations in C10, and this can serve as a guide for that. Parsing is done using the script lexer, so it is very robust to whitespace and extensible for future types. This removes the other way we encoded schema, and makes it easier to see what schema are registered. Current generated declarations: https://gist.github.com/zdevito/a96a17766fb3a098d69a91ee00abaaf6 * Switches how we handle attempting to use an integer in the place of a fixed-sized int list, such as in conv (e.g. 'int[3] stride=1'). Now that we can statically distinguish between int and Tensor, we handle the expansion as an implicit conversion in the compiler. This allows us to simplify the interpreter since it no longer needs to handle the conversion itself. * Schema declarations have been changed so that they match the type system in the IR exactly. In particular, attribute_info which was used by liftConstantAttributes has been dropped and constant attributes are lifted purely based on the type of the input. Type conversions in compiler have been simplified due to this change. * Error highlighting in ErrorReport now only reports at most 20 lines of code, to make reading where an error occurred easier. Commit 2 ======= This commit unifies aten_dispatch and aten_schema into a single Operator object that both contains schema and implementation information. In the future we can use this object to also contain functionality like shape prop and autodiff needed by all operators. Operators are registered globally, and dispatch logic uses the schema information to figure out which variant to use. Descriptor keys, a frequent source of inscrutable debug errors, have been removed. * Introduce Operator, to replace TensorOp. Unlike TensorOp, we use Operator for all op implementations, including primitives that may occur in the graphs. The only exceptions are ops that are only known to the interpreter like jumps, and GraphExecutors where we need to record additional debug info. * Adds a global registry for Operator implementations. aten_dispatch.cpp turns into register_aten_ops.cpp, which registers all the Operators for aten with the operator registry. register_prim_ops.cpp now contains the implementations for primitive operators that used to be in the interpreter. This means that it is now safe to use `getOperation(node)` to lookup the true interpreter function for the node, which will simplify const-propagation passes. * Remove addInterpreterOpHandler in favor of global operator registry. * Instead of descriptors, we match Node arguments directly against FunctionSchema describing expected inputs in `matchSchema`. `matchSchema` knows how parse both attributes and positional inputs from a node and match it to the appropriate registered operator. Debug error messages when we try to run an invalid operator are significantly improved: they now automatically display the schema for the op with the same name that are registered. * Merge aten_schema into regsiter_aten_ops. Each Operator takes a string schema which is parsed to determine when to dispatch to that op. * Cleans up gen_jit_dispatch.py now that we do not need to write out descriptors. In particular, skip_scalar_overloads can be removed since Richard's code sorts declarations to put Tensor, Tensor declarations first. * remove matchSchemaAndLiftConstantAttributes and use emitBuiltinCall instead to remove code duplication * refactor stack manipulation functions into a separate header file. Pull Request resolved: https://github.com/pytorch/pytorch/pull/8885 Reviewed By: jamesr66a Differential Revision: D8751048 Pulled By: zdevito fbshipit-source-id: 312aabfbf88307c5f6ab947b6caf691468b94557 --- setup.py | 5 +- ...test_call_script_mod_from_script_fn.expect | 2 +- .../TestScript.test_math_numbers-float.expect | 8 +- .../TestScript.test_math_numbers-int.expect | 8 +- test/test_jit.py | 4 +- tools/autograd/gen_autograd.py | 16 +- tools/jit/gen_jit_dispatch.py | 334 +++++++-------- tools/jit/templates/aten_dispatch.cpp | 157 ------- tools/jit/templates/aten_schema.cpp | 106 ----- .../templates/aten_schema_declarations.cpp | 5 + tools/jit/templates/register_aten_ops.cpp | 61 +++ tools/setup_helpers/generate_code.py | 4 +- torch/CMakeLists.txt | 10 +- torch/csrc/jit/aten_dispatch.h | 68 ---- torch/csrc/jit/aten_schema.h | 14 - torch/csrc/jit/function_schema.h | 95 +++-- torch/csrc/jit/init.cpp | 3 - torch/csrc/jit/interpreter.cpp | 217 +--------- torch/csrc/jit/interpreter.h | 3 - torch/csrc/jit/operator.cpp | 383 ++++++++++++++++++ torch/csrc/jit/operator.h | 73 ++++ torch/csrc/jit/passes/shape_analysis.cpp | 6 +- torch/csrc/jit/python_interpreter.cpp | 22 +- torch/csrc/jit/python_interpreter.h | 4 - torch/csrc/jit/python_ir.cpp | 2 +- torch/csrc/jit/register_prim_ops.cpp | 218 ++++++++++ torch/csrc/jit/script/compiler.cpp | 246 +++++------ torch/csrc/jit/script/init.cpp | 12 +- torch/csrc/jit/script/lexer.h | 56 ++- torch/csrc/jit/script/module.cpp | 5 +- torch/csrc/jit/stack.h | 94 +++++ torch/csrc/jit/type.cpp | 3 + torch/csrc/jit/type.h | 43 +- torch/onnx/symbolic.py | 4 +- 34 files changed, 1298 insertions(+), 993 deletions(-) delete mode 100644 tools/jit/templates/aten_dispatch.cpp delete mode 100644 tools/jit/templates/aten_schema.cpp create mode 100644 tools/jit/templates/aten_schema_declarations.cpp create mode 100644 tools/jit/templates/register_aten_ops.cpp delete mode 100644 torch/csrc/jit/aten_dispatch.h delete mode 100644 torch/csrc/jit/aten_schema.h create mode 100644 torch/csrc/jit/operator.cpp create mode 100644 torch/csrc/jit/operator.h delete mode 100644 torch/csrc/jit/python_interpreter.h create mode 100644 torch/csrc/jit/register_prim_ops.cpp create mode 100644 torch/csrc/jit/stack.h diff --git a/setup.py b/setup.py index 79b2d5fe90d3c..7c4bfac6c9d39 100644 --- a/setup.py +++ b/setup.py @@ -754,6 +754,7 @@ def run(self): "torch/csrc/finalizer.cpp", "torch/csrc/jit/init.cpp", "torch/csrc/jit/interpreter.cpp", + "torch/csrc/jit/register_prim_ops.cpp", "torch/csrc/jit/python_interpreter.cpp", "torch/csrc/jit/ir.cpp", "torch/csrc/jit/fusion_compiler.cpp", @@ -789,8 +790,8 @@ def run(self): "torch/csrc/jit/passes/loop_unrolling.cpp", "torch/csrc/jit/passes/onnx/peephole.cpp", "torch/csrc/jit/passes/onnx/fixup_onnx_loop.cpp", - "torch/csrc/jit/generated/aten_dispatch.cpp", - "torch/csrc/jit/generated/aten_schema.cpp", + "torch/csrc/jit/generated/register_aten_ops.cpp", + "torch/csrc/jit/operator.cpp", "torch/csrc/jit/script/lexer.cpp", "torch/csrc/jit/script/compiler.cpp", "torch/csrc/jit/script/module.cpp", diff --git a/test/expect/TestScript.test_call_script_mod_from_script_fn.expect b/test/expect/TestScript.test_call_script_mod_from_script_fn.expect index 8a2638b5be578..f67fb0073a22f 100644 --- a/test/expect/TestScript.test_call_script_mod_from_script_fn.expect +++ b/test/expect/TestScript.test_call_script_mod_from_script_fn.expect @@ -1,5 +1,5 @@ graph(%x : Dynamic) { - %1 : Dynamic = aten::zeros[size=[4, 3], dtype=6, device=[0, -1], layout=0]() + %1 : Dynamic = aten::zeros[size=[4, 3], dtype=6, layout=0, device=[0, -1]]() %2 : Dynamic = aten::mm(%x, %1) %3 : int = prim::Constant[value={1}]() %4 : Dynamic = prim::NumToTensor(%3) diff --git a/test/expect/TestScript.test_math_numbers-float.expect b/test/expect/TestScript.test_math_numbers-float.expect index 1a38d0c7962ee..4f4a7eddc1a16 100644 --- a/test/expect/TestScript.test_math_numbers-float.expect +++ b/test/expect/TestScript.test_math_numbers-float.expect @@ -5,10 +5,10 @@ graph(%x : Dynamic) { %4 : Dynamic = prim::NumToTensor(%2) %5 : Dynamic = aten::add[alpha={1}](%3, %4) %c : float = prim::TensorToNum(%5) - %7 : Long() = prim::Constant[value={6}]() - %8 : Long(2) = prim::Constant[value= 0 -1 [ CPULongTensor{2} ]]() - %9 : Long() = prim::Constant[value={0}]() - %10 : Long(1) = prim::Constant[value={1}]() + %7 : int = prim::Constant[value={6}]() + %8 : int = prim::Constant[value={0}]() + %9 : int[] = prim::Constant[value= 0 -1 [ CPULongTensor{2} ]]() + %10 : int[] = prim::Constant[value={1}]() %11 : Dynamic = aten::full(%10, %c, %7, %8, %9) return (%11); } diff --git a/test/expect/TestScript.test_math_numbers-int.expect b/test/expect/TestScript.test_math_numbers-int.expect index 66123af8e9232..d3d43b8bfd3ad 100644 --- a/test/expect/TestScript.test_math_numbers-int.expect +++ b/test/expect/TestScript.test_math_numbers-int.expect @@ -5,10 +5,10 @@ graph(%x : Dynamic) { %4 : Dynamic = prim::NumToTensor(%2) %5 : Dynamic = aten::add[alpha={1}](%3, %4) %c : int = prim::TensorToNum(%5) - %7 : Long() = prim::Constant[value={6}]() - %8 : Long(2) = prim::Constant[value= 0 -1 [ CPULongTensor{2} ]]() - %9 : Long() = prim::Constant[value={0}]() - %10 : Long(1) = prim::Constant[value={1}]() + %7 : int = prim::Constant[value={6}]() + %8 : int = prim::Constant[value={0}]() + %9 : int[] = prim::Constant[value= 0 -1 [ CPULongTensor{2} ]]() + %10 : int[] = prim::Constant[value={1}]() %11 : Dynamic = aten::full(%10, %c, %7, %8, %9) return (%11); } diff --git a/test/test_jit.py b/test/test_jit.py index 19e654eb6a344..06ccd7a0f38e3 100644 --- a/test/test_jit.py +++ b/test/test_jit.py @@ -3160,7 +3160,7 @@ def f4(a): def f5(a): torch.cat([[a]]) - with self.assertRaisesRegex(RuntimeError, 'a value of type Tensor for argument \'size\' but found'): + with self.assertRaisesRegex(RuntimeError, 'expected a value of type int\\[\\] for argument \'size\''): @torch.jit.script def f6(a): a.expand(size=[3, [4]]) @@ -4564,7 +4564,7 @@ def forward(self, x, y): # Right now, the following is happening: # - Shorter schemas come before longer schemas # - bool, int are treated as IntType rather than DynamicType like before - # So the schemas look like the following in aten_schema: + # So the schemas look like the following in operator: # (2) var(DynamicType, IntType) # (1) var(DynamicType, IntType, IntType, DynamicType) # Now, when one calls torch.var(tensor, dim=1), the compiler mistakingly diff --git a/tools/autograd/gen_autograd.py b/tools/autograd/gen_autograd.py index 2c6ba59a5adaf..2960204b0727b 100644 --- a/tools/autograd/gen_autograd.py +++ b/tools/autograd/gen_autograd.py @@ -45,6 +45,13 @@ def format_return_type(returns): return 'std::tuple<{}>'.format(','.join(return_types)) +def get_simple_type(arg): + simple_type = arg['type'] + simple_type = simple_type.replace(' &', '').replace('const ', '') + simple_type = simple_type.replace('Generator *', 'Generator') + return simple_type + + def load_aten_declarations(path): with open(path, 'r') as f: declarations = yaml.load(f, Loader=YamlLoader) @@ -54,11 +61,12 @@ def load_aten_declarations(path): for declaration in declarations: if declaration.get('deprecated'): continue + for arg in declaration['arguments']: - simple_type = arg['type'] - simple_type = simple_type.replace(' &', '').replace('const ', '') - simple_type = simple_type.replace('Generator *', 'Generator') - arg['simple_type'] = simple_type + arg['simple_type'] = get_simple_type(arg) + for ret in declaration['returns']: + ret['simple_type'] = get_simple_type(ret) + declaration['formals'] = [arg['type'] + ' ' + arg['name'] for arg in declaration['arguments']] declaration['args'] = [arg['name'] for arg in declaration['arguments']] diff --git a/tools/jit/gen_jit_dispatch.py b/tools/jit/gen_jit_dispatch.py index 05fcefa76f58d..6fc454ca12c07 100644 --- a/tools/jit/gen_jit_dispatch.py +++ b/tools/jit/gen_jit_dispatch.py @@ -1,42 +1,113 @@ import os import argparse +import re from itertools import count, combinations, groupby from ..autograd.utils import CodeTemplate, write, uninplace_api_name from ..autograd.gen_autograd import load_aten_declarations from collections import OrderedDict +# JIT has a type system of +# Scalar = int | float | bool # int is the largest int (int64_t), +# float is the largest float (double) we don't have the others because they are never held in tensors +# Type = Scalar # primitive numbers +# | Tensor # any tensor, as defined by at::Tensor +# | Type[] # a dynamically sized list[ of a type +# | Scalar[N] # a homogenous fixed size scalar list, single scalars can expand to this list +# | (Type1, Type2, ...) # a heterogenous tuple +# | Layout | ScalarType | Device | Generator # special singleton types for built-in concepts in tensor lib + +# clean up the variety of C++ types in the ATen declarations +# to be in the restricted set of types that the IR represents +# note: no default values for this map, to make it clear what types +# can be passedthrough + +TYPE_MAP = { + 'std::array': 'bool[2]', + 'std::array': 'bool[3]', + 'std::array': 'bool[4]', + 'Scalar': 'Scalar', + 'Tensor': 'Tensor', + 'TensorList': 'Tensor[]', + # this appears in return values instead of TensorList + # since TensorList is a ArrayRef in arguments but a vector + # in returns + 'std::vector': 'Tensor[]', + 'IntList': 'int[]', + 'Layout': 'Layout', + 'Device': 'Device', + 'ScalarType': 'ScalarType', + 'int64_t': 'int', + 'double': 'float', + 'bool': 'bool', + 'Generator': 'Generator', +} + + +def jit_type_of(arg): + typ = TYPE_MAP[arg['simple_type']] + if is_sized_intlist_arg(arg): + typ = 'int[{}]'.format(arg['size']) + + if arg.get('is_nullable'): + typ = '{}?'.format(typ) + return typ + +# map from _jit type_, generated from jit_type_of to attribute used to store it ATTR_METHOD_MAP = { - 'int64_t': 'i', - 'IntList': 'is', - 'Scalar': 't', + 'int': 'i', + 'float': 'f', 'bool': 'i', - 'double': 'f', - 'std::array': 'is', - 'std::array': 'is', - 'std::array': 'is', + 'Scalar': 't', + 'int[]': 'is', + 'bool[]': 'is', + 'Layout': 'i', + 'Device': 'is', + 'ScalarType': 'i', } -TYPE_CASTS = { + +def attr_of(jit_type): + # for attributes, we dont care about the length of an array, + # so strip it from the type + jit_type = re.sub("\\[\d+\\]", "[]", jit_type) + return ATTR_METHOD_MAP[jit_type] + +# map from aten 'simple_type' to the function that will cast a attribute value +# to that type +FROM_ATTRIBUTE = { 'std::array': 'as_bool_array<2>', 'std::array': 'as_bool_array<3>', 'std::array': 'as_bool_array<4>', 'Scalar': 'Scalar', 'IntList': 'std::vector', + 'Layout': 'int64_t', + 'Device': 'std::vector', + 'ScalarType': 'int64_t', +} + +# map from aten 'simple_type' to the function that will turn a tensor into +# that type +FROM_TENSOR = { + 'Device': 'tensor_as', + 'ScalarType': 'tensor_as', + 'Layout': 'tensor_as', } + +def from_tensor(arg): + simple_type = arg['simple_type'] + if simple_type in FROM_TENSOR: + return FROM_TENSOR[simple_type] + else: + return 'tensor_as<{}>'.format(arg['simple_type']) + + KW_ASSIGNMENT = CodeTemplate("""\ auto ${name} = ${type_cast}(node->${method}(Symbol::attr("${name}")));\ """) POS_ASSIGNMENT = CodeTemplate("""\ -auto ${name} = tensor_as<${type}>(std::move(peek(stack, ${i}, ${N})));\ -""") - -POS_INTLIST_ASSIGNMENT = CodeTemplate("""\ -auto ${name}_tensor = peek(stack, ${i}, ${N}); -if (${name}_tensor.dim() == 0) - ${name}_tensor = ${name}_tensor.expand(${size}); -auto ${name} = tensor_as(std::move(${name}_tensor));\ +auto ${name} = ${from_tensor}(std::move(peek(stack, ${i}, ${N})));\ """) CALL_NAMESPACE = CodeTemplate("""\ @@ -56,17 +127,24 @@ """) CONSTRUCTOR = CodeTemplate("""\ -{"${descriptor}", [](Node *node) { +[](Node *node) { ${kw_assignments} - return TensorOp([=](Stack & stack) { + return Operation([=](Stack & stack) { autograd::profiler::RecordFunction record("${name}"); ${pos_assignments} ${call} drop(stack, ${num_dynamic_inputs}); pack(stack, std::move(result)); return 0; - }, "${name}", ${num_dynamic_inputs}, ${num_outputs}); -}}, + }); +} +""") + +OPERATOR = CodeTemplate("""\ +Operator( + "${signature}", + ${ops} +), """) @@ -74,7 +152,7 @@ def is_magic_method(api_name): return api_name.startswith('__') and api_name.endswith('__') -blacklisted_types = {'SparseTensorRef', 'Storage', 'ScalarType', 'optional', 'std::string'} +blacklisted_types = {'SparseTensorRef', 'Storage', 'ScalarType', 'optional', 'std::string', 'void*'} default_only_types = {'Generator'} @@ -104,20 +182,8 @@ def is_jit_op(decl): return ((not decl['api_name'].endswith('_') or is_magic_method(decl['api_name'])) and not decl['name'].endswith('_out') and ('namespace' in decl['method_of'] or 'Tensor' in decl['method_of']) and - all(is_jit_arg(i, arg) for i, arg in enumerate(decl['arguments']))) - -# Scalar overloads like add(Tensor self, Scalar other) are not supported atm. -# TODO: Why are they not supported? -skip_scalar_overload = { - 'lt-2': [1], 'gt-2': [1], 'le-2': [1], 'ge-2': [1], 'eq-2': [1], 'ne-2': [1], - 'pow-2': [0, 1], 'add-3': [1], 'sub-3': [1], - 'mul-2': [1], 'th_mul-2': [1], 'native_mul-2': [1], - 'div-2': [1], 'th_div-2': [1], 'native_div-2': [1], - 'fmod-2': [1], 'remainder-2': [1], '__and__-2': [1], '__or__-2': [1], - '__iand__-2': [1], '__ior__-2': [1], '__xor__-2': [1], '__ixor__-2': [1], - '__lshift__-2': [1], '__ilshift__-2': [1], '__rshift__-2': [1], '__irshift__-2': [1], - 'normal-2': [0, 1], 'bernoulli-2': [0, 1], -} + all(is_jit_arg(i, arg) for i, arg in enumerate(decl['arguments'])) and + all(is_jit_arg(i, arg) for i, arg in enumerate(decl['returns']))) def is_tensor_arg(arg): @@ -130,10 +196,10 @@ def is_sized_intlist_arg(arg): def gen_jit_dispatch(declarations, out, template_path): - ATEN_DISPATCH_CPP = CodeTemplate.from_file(template_path + '/aten_dispatch.cpp') + REGISTER_ATEN_OPS_CPP = CodeTemplate.from_file(template_path + '/register_aten_ops.cpp') ATEN_INTERNED_STRINGS_H = CodeTemplate.from_file(template_path + '/aten_interned_strings.h') - ops = {} + ops = [] def get_invocation(decl, args, num_dynamic_inputs): if decl.get('has_tensor_options'): @@ -150,7 +216,6 @@ def emit_decl_variant(decl, is_positional_arg, has_tensorlist): # that indicates if the argument should come from the postional list # of inputs. If false, the argument comes from the constant attributes kw_assignments = [] - attr_names = [] pos_assignments = [] arguments = [] @@ -204,61 +269,36 @@ def emit_decl_variant(decl, is_positional_arg, has_tensorlist): arguments.append('std::move(peek(stack, {}, {}))'.format(real_inputs, view_length)) real_inputs += 1 elif is_positional_arg[i]: - template_kwargs = dict(type=arg['simple_type'], + template_kwargs = dict(from_tensor=from_tensor(arg), name=arg['name'], i=real_inputs, N=view_length) real_inputs += 1 - if is_sized_intlist_arg(arg): - assign = POS_INTLIST_ASSIGNMENT.substitute(size=arg['size'], - **template_kwargs) - else: - assign = POS_ASSIGNMENT.substitute(**template_kwargs) + assign = POS_ASSIGNMENT.substitute(**template_kwargs) pos_assignments.append(assign) arguments.append(arg['name']) else: + attr_method = attr_of(jit_type_of(arg)) simple_type = arg['simple_type'] - - assert simple_type in ATTR_METHOD_MAP, (decl['name'], simple_type) - attr_method = ATTR_METHOD_MAP[simple_type] - assign = KW_ASSIGNMENT.substitute(type_cast=TYPE_CASTS.get(simple_type, simple_type), + assign = KW_ASSIGNMENT.substitute(type_cast=FROM_ATTRIBUTE.get(simple_type, simple_type), name=arg['name'], method=attr_method) kw_assignments.append(assign) - attr_names.append('{}_{}'.format(arg['name'], attr_method)) arguments.append(arg['name']) call = get_invocation(decl, arguments, num_dynamic_inputs) - # Descriptor is a unique identifier for a particular overload of an op. - attr_names = sorted(attr_names) - num_inputs = '*' if has_tensorlist else static_inputs - descriptor = '-'.join([decl['name'], str(num_inputs)] + attr_names) - - # If there are two overloads with the same descriptor, that differ only by a type of a - # single argument, where one of them takes a tensor, while another one takes an - # at::Scalar as a positional scalar arg, then prefer the tensor overload. - # It should get broadcasted correctly. - if descriptor in skip_scalar_overload: - if any(decl['arguments'][idx]['simple_type'] in {'Scalar', 'double'} - for idx in skip_scalar_overload[descriptor]): - return - returns = decl['returns'] all_scalars = all(r['dynamic_type'] != 'TensorList' for r in returns) - num_outputs = str(len(returns)) if all_scalars else 'UNKNOWN_OUTPUTS' - constructor = CONSTRUCTOR.substitute(descriptor=descriptor, name=decl['name'], - call=call, + constructor = CONSTRUCTOR.substitute(name=decl['name'], + call=[call], # in an array so that substitute handles newlines correctly kw_assignments=kw_assignments, pos_assignments=pos_assignments, - num_dynamic_inputs=num_dynamic_inputs, - num_outputs=num_outputs) - - assert descriptor not in ops, descriptor - ops[descriptor] = constructor + num_dynamic_inputs=num_dynamic_inputs) + return constructor def emit_decl(decl): arguments = decl['arguments'] @@ -274,9 +314,15 @@ def emit_decl(decl): all_real_arguments_are_inputs = tuple(arg['simple_type'] not in default_only_types for arg in arguments) only_tensors_are_inputs = tuple(is_tensor_arg(arg) for arg in arguments) - # NB: if there are no scalar args then both options on LHS are equivalent, so deduplicate them. - for variant in {all_real_arguments_are_inputs, only_tensors_are_inputs}: - emit_decl_variant(decl, variant, has_tensorlist) + variants = [emit_decl_variant(decl, all_real_arguments_are_inputs, has_tensorlist)] + # in some cases there are no inputs that are possibly attributes, so the + # variants are actually the same. If so avoid generating both to save compilation + # time. + if all_real_arguments_are_inputs != only_tensors_are_inputs: + variants += [',', emit_decl_variant(decl, only_tensors_are_inputs, has_tensorlist)] + + ops.append(OPERATOR.substitute(signature=signature(decl), + ops=variants)) # This function declares an order on declarations. This is necessary because # there is some ambiguity in the choice of overload: if an argument is overloaded @@ -312,7 +358,7 @@ def declkey(decl): 'api_name': name, 'method_of': ['Tensor'], 'arguments': [{'name': 'self', 'simple_type': 'Tensor'}], - 'returns': [{'name': 'result', 'type': 'int64_t', 'dynamic_type': 'int64_t'}], + 'returns': [{'name': 'result', 'type': 'int64_t', 'dynamic_type': 'int64_t', 'simple_type': 'int64_t'}], } for name in ['sizes', 'strides', 'dim']] aten_decls = load_aten_declarations(declarations) + tensor_impl_methods @@ -325,13 +371,16 @@ def declkey(decl): if arg['simple_type'] == 'TensorOptions': del arguments[n] arguments.extend([ + # XXX - until we actually have first-class interpreter types for these + # concepts, the default values to be encoded in Tensors + # dtype is specified as an int64_t of at::ScalarType - {'name': 'dtype', 'simple_type': 'int64_t', 'default': 'static_cast(at::kFloat)'}, - # device is specified as an IntList of { at::Device::Type, device_id } - {'name': 'device', 'simple_type': 'IntList', - 'default': '{static_cast(at::Device::Type::CPU), -1}'}, + {'name': 'dtype', 'simple_type': 'ScalarType', 'default': 'float', 'kwarg_only': True}, # layout is specified as an int64_t of at::Layout - {'name': 'layout', 'simple_type': 'int64_t', 'default': 'static_cast(at::kStrided)'} + {'name': 'layout', 'simple_type': 'Layout', 'default': 'strided', 'kwarg_only': True}, + # device is specified as an IntList of { at::Device::Type, device_id } + {'name': 'device', 'simple_type': 'Device', 'kwarg_only': True, + 'default': '[cpu, -1]'}, ]) decl['has_tensor_options'] = True @@ -341,11 +390,9 @@ def declkey(decl): # Sort the generated snippets to ensure that the generation is deterministic env = { - 'constructors': sorted(ops.values()), + 'constructors': ops, } - write(out, 'aten_dispatch.cpp', ATEN_DISPATCH_CPP, env) - - emit_schema(jit_decls, out, template_path) + write(out, 'register_aten_ops.cpp', REGISTER_ATEN_OPS_CPP, env) # NB: Operate on aten_decls, not jit_decls, because VariableType is # a client for these symbols as well @@ -365,88 +412,43 @@ def declkey(decl): } write(out, 'aten_interned_strings.h', ATEN_INTERNED_STRINGS_H, strings_env) - -def emit_schema(jit_decls, out, template_path): - ATEN_SCHEMA_CPP = CodeTemplate.from_file(template_path + '/aten_schema.cpp') - - # see [aten_schema encoding] for how this gets translated to C++ object - - names = OrderedDict() - types = OrderedDict() - tensors = OrderedDict() - attributes = OrderedDict() - - env = { - 'arguments': [], - 'operators': [], - 'n_operators': len(jit_decls), - } - - # de-duplicate v strings and return the index in to d where v will occur - def interned(d, v): - v = v + ", " - if v not in d: - d[v] = len(d) - return d[v] - - def get_name(name): - return interned(names, '"{}"'.format(name)) - - def emit_arg(arg, is_return): - n = get_name(arg['name']) - if arg.get('type') == 'TensorList': - typ = 'ListType::ofTensors()' - elif arg.get('type') == 'int64_t': - typ = 'IntType::get()' - elif arg.get('type') == 'bool': - typ = 'IntType::get()' - elif arg.get('type') == 'Scalar': - typ = 'NumberType::get()' - else: - typ = 'DynamicType::get()' - tensor = 'at::nullopt' - attribute = 'at::nullopt' - if not is_return: - if is_tensor_arg(arg): - if 'default' in arg and arg['default'] == '{}': - tensor = 'at::Tensor()' - else: - data = 'at::nullopt' if not is_sized_intlist_arg(arg) else str(arg['size']) - attribute = 'AttributeInfo{{ AttributeKind::{}, {} }}'.format(ATTR_METHOD_MAP[arg['simple_type']], data) - if 'default' in arg: - value = arg['default'] - # conversion in yaml turns string 'true' into python bool - # we need it to turn into - value = str(value).lower() if type(value) == bool else value - tensor = 'as_tensor({}({}))'.format(arg['simple_type'], value) - d = interned(tensors, tensor) - a = interned(attributes, attribute) - t = interned(types, typ) - comment = '// Argument("{}", {}, {}, {})'.format(arg['name'], tensor, attribute, typ) - env['arguments'].append("{{ {}, {}, {}, {} }}, {} ".format(n, t, d, a, comment)) - - def emit(decl): - arguments = [a for a in decl['arguments'] if a['simple_type'] not in default_only_types] - n = get_name(decl['name']) - n_args = len(arguments) - n_returns = len(decl['returns']) - env['arguments'].append('// Arguments for {} ({} args, {} returns)'.format(decl['name'], n_args, n_returns)) - for a in arguments: - emit_arg(a, False) - for a in decl['returns']: - emit_arg(a, True) - env['operators'].append('{{ {}, {}, {} }}, // FunctionSchema("{}", <{} arguments>, <{} returns>) '.format( - n, n_args, n_returns, decl['name'], n_args, n_returns)) - - for decl in jit_decls: - emit(decl) - - env['names'] = list(names.keys()) - env['tensors'] = list(tensors.keys()) - env['attributes'] = list(attributes.keys()) - env['types'] = list(types.keys()) - - write(out, 'aten_schema.cpp', ATEN_SCHEMA_CPP, env) +default_map = {'{}': 'None', 'nullptr': 'None'} + + +def signature(decl): + def format_arg(arg): + name = arg['name'] + typ = jit_type_of(arg) + decl = '{} {}'.format(typ, name) + if 'default' in arg: + # clean up initializer lists {{true, true}} -> [true, true] + default = str(arg['default']) \ + .replace('{{', '[') \ + .replace('}}', ']') \ + .replace('true', 'True') \ + .replace('false', 'False') \ + .replace('nullptr', 'None') \ + .replace('Reduction::ElementwiseMean', 'ElementwiseMean') \ + .replace('{}', 'None' if is_tensor_arg(arg) else '[]') + + default = default_map.get(default, default) + decl = '{}={}'.format(decl, default) + return decl + + args = [] + kwarg_only = False + for a in decl['arguments']: + if not kwarg_only and a.get('kwarg_only'): + args.append('*') + kwarg_only = True + args.append(format_arg(a)) + + arg_list = ', '.join(args) + if len(decl['returns']) == 1: + ret_list = jit_type_of(decl['returns'][0]) + else: + ret_list = '({})'.format(', '.join(jit_type_of(r) for r in decl['returns'])) + return 'aten::{}({}) -> {}'.format(decl['name'], arg_list, ret_list) def main(): diff --git a/tools/jit/templates/aten_dispatch.cpp b/tools/jit/templates/aten_dispatch.cpp deleted file mode 100644 index 8869a2f5ee0f0..0000000000000 --- a/tools/jit/templates/aten_dispatch.cpp +++ /dev/null @@ -1,157 +0,0 @@ -#include "torch/csrc/jit/aten_dispatch.h" - -#include "torch/csrc/autograd/profiler.h" -#include "torch/csrc/jit/interned_strings.h" -#include "torch/csrc/jit/tensor_conversions.h" -#include "torch/csrc/utils/functional.h" -#include "torch/csrc/variable_tensor_functions.h" -#include "torch/csrc/autograd/generated/variable_factories.h" - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// ${generated_comment} - -namespace torch { namespace jit { - -using autograd::Variable; -using autograd::variable_list; -using at::Scalar; -using at::Tensor; -using at::IntList; -using at::TensorList; -using at::TensorOptions; -using at::DeviceGuard; - -namespace { - -// The packer here is carefully written not to make any unnecessary -// copies. - -// pack takes the return values of aten functions pushes them onto the stack -template -void pack(Stack & stack, T&& v) { - stack.push_back(as_variable(std::move(v))); -} -template<> -void pack(Stack & stack, Tensor&& v) { - stack.push_back(std::move(v)); -} -template<> -void pack(Stack & stack, autograd::Variable&& v) { - stack.push_back(std::move(v)); -} -template<> -void pack(Stack & stack, std::vector&& ts) { - for(auto& t : ts) { - stack.push_back(std::move(t)); - } -} - -template -struct TuplePacker -{ - // NB: *Not* a universal reference. - static void execute(Stack & stack, std::tuple && t) - { - // NB: The move here does not "destroy" the entire tuple, that is - // not what std::move does; only the particular tuple index - // processed here gets stolen. - pack(stack, std::get(std::move(t))); - TuplePacker::execute(stack, std::move(t)); - } -}; - -template -struct TuplePacker<0, Args...> -{ - static void execute(Stack & stack, std::tuple && t) {}; -}; - -template -void pack(Stack & stack, std::tuple && t) { - TuplePacker::execute(stack, std::move(t)); -} - -int deviceForInputs(Stack & stack, size_t N) { - if(N == 0) - return -1; - auto & t = *(stack.end() - N); - return t.type().is_cuda() ? (int) t.get_device() : -1; -} - -// A list of functions taking TensorList arguments (where we can't use -// the number of inputs to choose an overload). -std::unordered_set tensor_vararg_fns = { - aten::cat, - aten::stack, - aten::index, - aten::index_put, -}; - -template -std::array as_bool_array(const std::vector& vec) { - std::array res; - JIT_ASSERT(vec.size() == N); - std::copy(vec.begin(), vec.end(), res.begin()); - return res; -} - -using operator_constructor = std::function; -std::unordered_map constructors = { - ${constructors} -}; - -std::string getDescriptor(jit::Node* n) { - std::stringstream s; - JIT_ASSERTM(n->kind().is_aten(), "%s is not an ATen op", n->kind().toDisplayString()); - s << n->kind().toUnqualString(); - if (tensor_vararg_fns.count(n->kind()) == 0) - s << "-" << n->inputs().size(); - else - s << "-*"; - std::vector attr_names = fmap(n->attributeNames(), [&](Symbol x) { - std::stringstream ss; - ss << x.toUnqualString() << "_" << toString(n->kindOf(x)); - return ss.str(); - }); - std::sort(attr_names.begin(), attr_names.end()); - - for (const auto & name : attr_names) - s << "-" << name; - return s.str(); -} - -} // anonymous namespace - -at::optional findTensorOp(jit::Node* n) { - auto signature = getDescriptor(n); - auto it = constructors.find(signature); - if(it == constructors.end()) { - return at::nullopt; - } - return it->second(n); -} -TensorOp getTensorOp(jit::Node* n) { - auto op = findTensorOp(n); - if (!op) { - throw std::runtime_error( - "Unsupported op descriptor: " + getDescriptor(n) + - ". " - "File a bug report."); - } - return op.value(); -} - -}} // namespace torch::jit diff --git a/tools/jit/templates/aten_schema.cpp b/tools/jit/templates/aten_schema.cpp deleted file mode 100644 index ae1978387a46a..0000000000000 --- a/tools/jit/templates/aten_schema.cpp +++ /dev/null @@ -1,106 +0,0 @@ -#include "torch/csrc/jit/aten_schema.h" -#include "torch/csrc/jit/tensor_conversions.h" - -namespace torch { namespace jit { - -using SchemaMap = std::unordered_map>; - - -std::vector createOperatorSchemas() { - using namespace at; // for tensor initialization - std::vector schemas; - - // [aten_schema encoding] - // This format tries to minimize the actual amount of code produced here to keep - // compile times low. A naive encoding of this data directly into constructor - // literals took over 3 minutes in gcc, while this format takes only 10 seconds. - - // However, it is more complicated because of this issue and described below - - // literals are stored uniqued and interned in these arrays: - - // string literals - const char* names[] = { - ${names} - }; - - // Types - TypePtr types[] = { - ${types} - }; - - // default argument values for all ops, represented as using tensors via as_tensor - at::optional tensors[] = { - ${tensors} - }; - - // the attribute kind tag for any arguments that have optional attribute encodings - // in the IR. - at::optional attributes[] = { - ${attributes} - }; - - // for compound objects, it uses 1 integer per argument to the object's constructor - // which is an index into one of the above tables - using ArgumentCtor = uint32_t[4]; - ArgumentCtor arguments[] = { - ${arguments} - }; - - // FunctionSchema(string name, vector args, vector returns) - // the integer for args and returns is the _number_ of argument objects - // which are read sequentially off of the arguments array above - using OperatorCtor = uint32_t[3]; - OperatorCtor operators[] = { - ${operators} - }; - size_t n_operators = ${n_operators}; - - size_t next_argument = 0; - - auto getArgumentList = [&](uint32_t N){ - std::vector result; - for(size_t i = 0; i < N; ++i) { - auto & a = arguments[next_argument++]; - result.push_back({ names[a[0]], types[a[1]], tensors[a[2]], attributes[a[3]] }); - } - return result; - }; - - for(size_t i = 0; i < n_operators; ++i) { - auto & op = operators[i]; - schemas.push_back({names[op[0]], getArgumentList(op[1]), getArgumentList(op[2])}); - } - return schemas; -} - -std::vector & getOperatorSchemas() { - static std::vector schema = createOperatorSchemas(); - return schema; -} - -static SchemaMap createSchemaMap() { - auto& schemas = getOperatorSchemas(); - SchemaMap result; - for(auto & schema : schemas) { - auto it = result.find(schema.name); - if(it == result.end()) { - it = result.insert({schema.name, {}}).first; - } - it->second.push_back(std::move(schema)); - } - return result; -} - -const std::vector& getOperatorSchema(const std::string& name) { - static SchemaMap map = createSchemaMap(); - static std::vector empty; - auto it = map.find(name); - if(it != map.end()) - return it->second; - return empty; -} - - - -}} diff --git a/tools/jit/templates/aten_schema_declarations.cpp b/tools/jit/templates/aten_schema_declarations.cpp new file mode 100644 index 0000000000000..7b955c0ca18ad --- /dev/null +++ b/tools/jit/templates/aten_schema_declarations.cpp @@ -0,0 +1,5 @@ +namespace torch { namespace jit { +const char * schema_declarations = R"===( + ${declarations} +)==="; +}} diff --git a/tools/jit/templates/register_aten_ops.cpp b/tools/jit/templates/register_aten_ops.cpp new file mode 100644 index 0000000000000..4cb7fbaaaaeae --- /dev/null +++ b/tools/jit/templates/register_aten_ops.cpp @@ -0,0 +1,61 @@ +#include "torch/csrc/jit/operator.h" + +#include "torch/csrc/autograd/profiler.h" +#include "torch/csrc/jit/interned_strings.h" +#include "torch/csrc/jit/tensor_conversions.h" +#include "torch/csrc/utils/functional.h" +#include "torch/csrc/variable_tensor_functions.h" +#include "torch/csrc/autograd/generated/variable_factories.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// ${generated_comment} + +namespace torch { namespace jit { + +using autograd::Variable; +using autograd::variable_list; +using at::Scalar; +using at::Tensor; +using at::IntList; +using at::TensorList; +using at::TensorOptions; +using at::DeviceGuard; + +namespace { + +int deviceForInputs(Stack & stack, size_t N) { + if(N == 0) + return -1; + auto & t = *(stack.end() - N); + return t.type().is_cuda() ? (int) t.get_device() : -1; +} + +template +std::array as_bool_array(const std::vector& vec) { + std::array res; + JIT_ASSERT(vec.size() == N); + std::copy(vec.begin(), vec.end(), res.begin()); + return res; +} + +RegisterOperators reg({ +${constructors} +}); + +} // anon namespace + + +}} // namespace torch::jit diff --git a/tools/setup_helpers/generate_code.py b/tools/setup_helpers/generate_code.py index 6fdf56477b7dc..33daa663ca0d4 100644 --- a/tools/setup_helpers/generate_code.py +++ b/tools/setup_helpers/generate_code.py @@ -40,8 +40,8 @@ def all_generator_source(): 'torch/csrc/autograd/generated/variable_factories.h', 'torch/csrc/autograd/generated/VariableType.cpp', 'torch/csrc/autograd/generated/VariableType.h', - 'torch/csrc/jit/generated/aten_dispatch.cpp', - 'torch/csrc/jit/generated/aten_schema.cpp', + 'torch/csrc/jit/generated/register_aten_ops.cpp', + 'torch/csrc/jit/generated/operator.cpp', ] diff --git a/torch/CMakeLists.txt b/torch/CMakeLists.txt index 7a486aba09f9a..cd8d5cefebc8e 100644 --- a/torch/CMakeLists.txt +++ b/torch/CMakeLists.txt @@ -160,8 +160,7 @@ add_custom_command( "${TORCH_SRC_DIR}/csrc/autograd/generated/python_nn_functions.h" "${TORCH_SRC_DIR}/csrc/autograd/generated/python_nn_functions_dispatch.h" "${TORCH_SRC_DIR}/csrc/autograd/generated/variable_factories.h" - "${TORCH_SRC_DIR}/csrc/jit/generated/aten_dispatch.cpp" - "${TORCH_SRC_DIR}/csrc/jit/generated/aten_schema.cpp" + "${TORCH_SRC_DIR}/csrc/jit/generated/register_aten_ops.cpp" "${TORCH_SRC_DIR}/csrc/jit/generated/aten_interned_strings.h" COMMAND python tools/setup_helpers/generate_code.py @@ -187,7 +186,7 @@ add_custom_command( "${TOOLS_PATH}/autograd/gen_autograd.py" "${TOOLS_PATH}/autograd/gen_autograd_functions.py" "${TOOLS_PATH}/autograd/gen_variable_type.py" - "${TOOLS_PATH}/jit/templates/aten_dispatch.cpp" + "${TOOLS_PATH}/jit/templates/register_aten_ops.cpp" "${TOOLS_PATH}/jit/templates/aten_interned_strings.h" WORKING_DIRECTORY "${TORCH_SRC_DIR}/..") @@ -210,10 +209,11 @@ set(TORCH_SRCS ${TORCH_SRC_DIR}/csrc/autograd/engine.cpp ${TORCH_SRC_DIR}/csrc/assertions.cpp ${TORCH_SRC_DIR}/csrc/utils/variadic.cpp - ${TORCH_SRC_DIR}/csrc/jit/generated/aten_dispatch.cpp - ${TORCH_SRC_DIR}/csrc/jit/generated/aten_schema.cpp + ${TORCH_SRC_DIR}/csrc/jit/generated/register_aten_ops.cpp + ${TORCH_SRC_DIR}/csrc/jit/operator.cpp ${TORCH_SRC_DIR}/csrc/jit/variable_flags.cpp ${TORCH_SRC_DIR}/csrc/jit/interpreter.cpp + ${TORCH_SRC_DIR}/csrc/jit/register_prim_ops.cpp ${TORCH_SRC_DIR}/csrc/jit/ir.cpp ${TORCH_SRC_DIR}/csrc/jit/graph_executor.cpp ${TORCH_SRC_DIR}/csrc/jit/fusion_compiler.cpp diff --git a/torch/csrc/jit/aten_dispatch.h b/torch/csrc/jit/aten_dispatch.h deleted file mode 100644 index f797087754481..0000000000000 --- a/torch/csrc/jit/aten_dispatch.h +++ /dev/null @@ -1,68 +0,0 @@ -#pragma once -#include "torch/csrc/jit/ir.h" -#include "torch/csrc/autograd/function.h" - -#include - -// ${generated_comment} - -namespace torch { namespace jit { - - - -using Stack = std::vector; -using Operation = std::function; - -// An operation with N inputs and M outputs pops the last N inputs off -// the stack and pushes its M inputs onto the stack -// before: I0, I1, ... IN <- stack.back() -// after: O0, O1, ... OM -// operations are defined this way so that ownership of inputs can be transferred -// to the operation and it can incrementally drop ownership of tensors -// when they become unneeded. For large operations, like 'run an entire subgraph', -// this functionality is very important for minimizing gpu memory usage -// return value is the relative 'offset' to jump to for the next operation: -// pc += 1 + offset -// so a return value of 0 goes to the next instruction - -// treat the last N elements of the stack as a list, looking up -// element i -static inline at::Tensor & peek(Stack & stack, size_t i, size_t N) { - return *(stack.end() - N + i); -} -// treat the last N elements of the stack as a list, looking up the -// slice starting at index i and having length len -static inline ArrayRef peekSlice(Stack & stack, size_t i, size_t len, size_t N) { - return ArrayRef(stack).slice(stack.size() - N + i, len); -} -static inline ArrayRef last(Stack & stack, size_t N) { - return peekSlice(stack, 0, N, N); -} -static inline void drop(Stack & stack, size_t n) { - stack.erase(stack.end() - n, stack.end()); -} -static inline at::Tensor pop(Stack & stack) { - auto r = std::move(stack.back()); - stack.pop_back(); - return r; -} - -constexpr size_t UNKNOWN_OUTPUTS = std::numeric_limits::max(); - -struct TensorOp { - TensorOp(Operation op, std::string name, size_t num_inputs, size_t num_outputs) - : op(op) - , name(name) - , num_inputs(num_inputs) - , num_outputs(num_outputs) {} - - const Operation op; - const std::string name; - const size_t num_inputs; - const size_t num_outputs; -}; - -at::optional findTensorOp(jit::Node* n); -TensorOp getTensorOp(jit::Node* n); - -}} // namespace torch::jit; diff --git a/torch/csrc/jit/aten_schema.h b/torch/csrc/jit/aten_schema.h deleted file mode 100644 index 171db943726c2..0000000000000 --- a/torch/csrc/jit/aten_schema.h +++ /dev/null @@ -1,14 +0,0 @@ -// in memory description of all ATen Ops similar to Caffe2 schema -// once C10 exists this can be removed, or stubbed out, but we need -// it now to implement correct semantic checking for script -#pragma once -#include "ATen/ATen.h" -#include "torch/csrc/jit/ir.h" -#include "torch/csrc/jit/function_schema.h" - -namespace torch { namespace jit { - -const std::vector& getOperatorSchema(const std::string& name); -std::vector & getOperatorSchemas(); - -}} diff --git a/torch/csrc/jit/function_schema.h b/torch/csrc/jit/function_schema.h index f26103c1a5350..13c81dc296cf5 100644 --- a/torch/csrc/jit/function_schema.h +++ b/torch/csrc/jit/function_schema.h @@ -4,29 +4,70 @@ namespace torch { namespace jit { -struct AttributeInfo { - AttributeKind kind; - at::optional data; // extra data field, current only used for the k in IntList[k] -}; - // schema as used in the compiler for resolving function calls and reporting // errors. These objects should be constructed from C10 schema once those // are availiable struct Argument { - const std::string name; - const TypePtr type; + Argument( + std::string name = "", + TypePtr type = nullptr, + at::optional N = at::nullopt, + at::optional default_value = at::nullopt, + bool kwarg_only = true) + : name(std::move(name)), + type(type? type : DynamicType::get()), + N(N), + default_value(default_value), + kwarg_only(kwarg_only) {} + std::string name; + TypePtr type; + + // for list types, an optional statically known length for the list + // e.g. for int[3]: type = ListType::ofInts(), N = 3 + // If present, this will allow scalars to be broadcast to this length to + // become a list. + at::optional N; + // encoded using as_tensor, use tensor_as to get value for attribute - const at::optional default_value; - // if this can be a graph attribute, the kind of that attribute - // that matches it - const at::optional attribute_info; + at::optional default_value; + // is this only specifyable as a keyword argument? + bool kwarg_only; }; struct FunctionSchema { + FunctionSchema( + std::string name, + std::vector arguments, + std::vector returns, + bool is_vararg = false, + bool is_varret = false) + : name(std::move(name)), + arguments(std::move(arguments)), + returns(std::move(returns)), + is_vararg(is_vararg), + is_varret(is_varret) {} + FunctionSchema( + Symbol name, + std::vector arguments, + std::vector returns, + bool is_vararg = false, + bool is_varret = false) + : FunctionSchema( + name.toQualString(), + std::move(arguments), + std::move(returns), + is_vararg, + is_varret) {} + const std::string name; const std::vector arguments; const std::vector returns; - + // if true then this schema takes an arbitrary number of additional arguments + // after the argument specified in arguments + // currently this is used primarily to represent 'primtive' operators whose + // arguments are not checked by schema + const bool is_vararg; + const bool is_varret; at::optional argumentIndexWithName(const std::string& name) const { for(size_t i = 0; i < arguments.size(); ++i) { if(name == arguments[i].name) @@ -38,32 +79,7 @@ struct FunctionSchema { // for debugging, make sure we can describe the call site inline std::ostream& operator<<(std::ostream& out, const Argument& arg) { - // if can report more friendly types if we have an attribute - if(arg.attribute_info) { - switch(arg.attribute_info->kind) { - case AttributeKind::i: - out << "int64_t"; - break; - case AttributeKind::is: - out << "IntList"; - if(arg.attribute_info->data) - out << "[" << *arg.attribute_info->data << "]"; - break; - case AttributeKind::f: - out << "float"; - break; - default: - out << arg.type->name(); - break; - } - } else { - out << arg.type->name(); - } - out << " " << arg.name; - if(arg.default_value) { - out << "="; - } - return out; + return out << arg.type->str() << " " << arg.name << (arg.default_value ? "=" : ""); } inline std::ostream& operator<<(std::ostream& out, const FunctionSchema& schema) { @@ -88,7 +104,4 @@ inline std::ostream& operator<<(std::ostream& out, const FunctionSchema& schema) return out; } -const std::vector& getFunctionSchema(const std::string& name); -std::vector & getFunctionSchemas(); - }} diff --git a/torch/csrc/jit/init.cpp b/torch/csrc/jit/init.cpp index 1275be21ab6f1..4787546e7e86f 100644 --- a/torch/csrc/jit/init.cpp +++ b/torch/csrc/jit/init.cpp @@ -23,10 +23,8 @@ #include "torch/csrc/jit/script/init.h" #include "torch/csrc/jit/script/python_tree_views.h" #include "torch/csrc/jit/batched/BatchTensor.h" -#include "torch/csrc/jit/python_interpreter.h" #include "torch/csrc/jit/pybind_utils.h" - namespace torch { namespace jit { namespace { @@ -207,7 +205,6 @@ void initJITBindings(PyObject *module) { script::initTreeViewBindings(module); script::initJitScriptBindings(module); initBatchTensorBindings(module); - registerPythonInterpreterOps(); } }} diff --git a/torch/csrc/jit/interpreter.cpp b/torch/csrc/jit/interpreter.cpp index f5fc65b5846f4..d582f80a6fb2e 100644 --- a/torch/csrc/jit/interpreter.cpp +++ b/torch/csrc/jit/interpreter.cpp @@ -5,8 +5,8 @@ #include "torch/csrc/autograd/functions/special.h" #include "torch/csrc/autograd/profiler.h" #include "torch/csrc/autograd/variable.h" -#include "torch/csrc/jit/aten_dispatch.h" #include "torch/csrc/jit/fusion_compiler.h" +#include "torch/csrc/jit/operator.h" #include "torch/csrc/jit/graph_executor.h" #include "torch/csrc/jit/ir.h" #include "torch/csrc/jit/tensor_conversions.h" @@ -27,25 +27,6 @@ namespace torch { namespace jit { - -// externally registered handles, currently used so that python ops -// can be in a separate compilation unit -static std::mutex handler_mutex; -static std::vector handlers; -void addInterpreterOpHandler(OpHandler handler) { - std::lock_guard guard(handler_mutex); - handlers.push_back(handler); -} -at::optional lookupExternalOp(Node* n) { - std::lock_guard guard(handler_mutex); - for(auto & handler : handlers) { - if(auto r = handler(n)) { - return *r; - } - } - return at::nullopt; -} - // Before we translate to intepreter instructions, we do // some preprocessing of the graph to turn it into a form that is closer // to what the instructions will look like. @@ -391,24 +372,6 @@ bool hasHandleOutput(Node * n) { return last->isHandle() && last->uses().size() > 0; // don't bother creating a handle if it is never used } -Operation createCppOperation(CppOp* op) { - std::shared_ptr func = op->fn; - JIT_ASSERT(!hasHandleOutput(op)); - auto num_inputs = op->inputs().size(); - return [=](Stack & stack) { - autograd::variable_list v_inputs; - for(size_t i = 0; i < num_inputs; i++) { - v_inputs.push_back(std::move(peek(stack, i, num_inputs))); - } - drop(stack, num_inputs); - autograd::variable_list v_outputs = (*func)(v_inputs); - for(auto & output : v_outputs) { - stack.push_back(output); - } - return 0; - }; -} - // We need some lists for inputs and outputs. To keep all the memory // contiguous we allocate a single vector and use offsets into the vector // which are stored in the ListHandle struct @@ -570,7 +533,7 @@ struct CodeImpl { size_t insertInstruction(Node * n) { auto inst = insertInstruction(n->kind(), n->getSourceLocation(), n->inputs(), moveFlags(n) , n->outputs()); - instructions[inst].callback = getOperation(n); + instructions[inst].callback = getInterpreterOperation(n); return inst; } size_t insertInstruction(Symbol sym, @@ -660,165 +623,27 @@ struct CodeImpl { // Returns a function implementing functionality of a given node, // or nullptr if it's a no-op for autograd. - Operation getOperation(jit::Node* node) { - IR_IFM(node, CppOp) - JIT_ASSERT(!dynamic_cast(value->fn.get())); - return createCppOperation(value); - IR_ELSEIF(FusionGroup) - auto fusion_fn = sharedFusionCompiler().getOrCompile(value); - auto num_inputs = value->inputs().size(); - return [fusion_fn, num_inputs](Stack & stack) { - autograd::profiler::RecordFunction record("FusionGroup"); - std::vector toutputs; - // TODO: have fusion_fn work off of a stack as well - fusion_fn->launch(last(stack, num_inputs), toutputs); - drop(stack, num_inputs); - stack.insert(stack.end(), toutputs.begin(), toutputs.end()); - return 0; - }; - IR_ELSEIF(Constant) - auto t = autograd::make_variable(value->t(attr::value)); - return [t](Stack & stack) { - stack.push_back(t); - return 0; - }; - IR_ELSEIF(TensorToNum) - // no-op - return [](Stack & stack) { - return 0; - }; - IR_ELSEIF(NumToTensor) - // no-op - return [](Stack & stack) { - return 0; - }; - IR_ELSEIF(Undefined) - return [](Stack & stack) { - stack.push_back(at::Tensor()); + Operation getInterpreterOperation(jit::Node* node) { + if(node->kind() != prim::GraphExecutor) { + return getOperation(node); + } + // recursive graph executors cannot be Operators because they + // have to register themselves with the interpreter so that + // we can provide useful debugging information + + auto executor = std::make_shared(node->g(attr::Subgraph)); + graph_executors.emplace_back(executor.get()); + auto num_inputs = node->inputs().size(); + return [=](Stack& stack) mutable { + autograd::profiler::RecordFunction record("GraphExecutor"); + auto inputs = last(stack, num_inputs); + variable_tensor_list tinputs(inputs.begin(), inputs.end()); + drop(stack, num_inputs); + //TODO: has graph executor work from a stack as well + variable_tensor_list toutputs = executor->run(variable_tensor_list(std::move(tinputs))); + stack.insert(stack.end(), toutputs.begin(), toutputs.end()); return 0; }; - IR_ELSEIF(AnyDefined) - size_t num_inputs = value->inputs().size(); - auto true_ = at::full({}, 1, at::kLong); - auto false_ = at::full({}, 0, at::kLong); - return [=](Stack & stack) { - bool result = false; - for(const at::Tensor& t : last(stack, num_inputs)) { - if(t.defined()) { - result = true; - break; - } - } - drop(stack, num_inputs); - stack.push_back(result ? true_ : false_); - return 0; - }; - IR_ELSEIF(AutogradAdd) - return [=](Stack & stack) { - auto a = pop(stack); - auto b = pop(stack); - if(!a.defined()) - stack.push_back(b); - else if(!b.defined()) - stack.push_back(a); - else - stack.push_back(a + b); - return 0; - }; - IR_ELSEIF(Print) - size_t num_inputs = value->inputs().size(); - return [num_inputs](Stack & stack) { - bool first = true; - for (at::Tensor i : last(stack, num_inputs)) { - if (!first) std::cout << " "; - first = false; - if (auto tensor_impl = dynamic_cast(i.get())) { - std::cout << at::Tensor(tensor_impl, true); - } else if (!i.defined()) { - std::cout << ""; - } else { - auto& r = *i.get(); - std::cout << "<" << typeid(r).name() << " at " << i << ">"; - } - } - drop(stack, num_inputs); - std::cout << std::endl; - return 0; - }; - IR_ELSEIF(GraphExecutor) - auto executor = std::make_shared(value->g(attr::Subgraph)); - graph_executors.emplace_back(executor.get()); - auto num_inputs = value->inputs().size(); - return [=](Stack& stack) mutable { - autograd::profiler::RecordFunction record("GraphExecutor"); - auto inputs = last(stack, num_inputs); - variable_tensor_list tinputs(inputs.begin(), inputs.end()); - drop(stack, num_inputs); - //TODO: has graph executor work from a stack as well - variable_tensor_list toutputs = executor->run(variable_tensor_list(std::move(tinputs))); - stack.insert(stack.end(), toutputs.begin(), toutputs.end()); - return 0; - }; - - // Load x, y - // loads values from registers onto the stack, the actual callback does - // nothing since the stack manipulation is already encoded in inst.inputs - // and inst.outputs - IR_ELSEIF(Load) - return [=](Stack& stack) { - return 0; - }; - - // x, y = Store - // stores values from stack into registers, the actual callback does - // nothing since the stack manipulation is already encoded in inst.inputs - // and inst.outputs - IR_ELSEIF(Store) - return [=](Stack& stack) { - return 0; - }; - IR_ELSEIF(Drop) - auto N = value->inputs().size(); - return [=](Stack& stack) { - drop(stack, N); - return 0; - }; - IR_ELSE() - switch (node->kind()) { - case onnx::Reshape: { - return [=](Stack& stack) { - auto shape = pop(stack).contiguous(); - auto input = pop(stack); - JIT_ASSERT(shape.ndimension() == 1); - at::IntList shape_list(shape.data(), shape.size(0)); - stack.push_back(input.reshape(shape_list)); - return 0; - }; - } break; - case onnx::Shape: { - return [=](Stack& stack) { - auto t = pop(stack); - at::IntList sizes = t.sizes(); - auto sizes_tensor = torch::empty({static_cast(sizes.size())}, at::dtype(at::kLong)); - auto accessor = sizes_tensor.accessor(); - for (size_t i=0; i& executors() { diff --git a/torch/csrc/jit/interpreter.h b/torch/csrc/jit/interpreter.h index 7f91935aaba21..b6c9238e15cc9 100644 --- a/torch/csrc/jit/interpreter.h +++ b/torch/csrc/jit/interpreter.h @@ -55,9 +55,6 @@ struct InterpreterState { std::shared_ptr pImpl; }; -using Operation = std::function&)>; -using OpHandler = std::function(Node* n)>; -void addInterpreterOpHandler(OpHandler handler); bool hasHandleOutput(Node * n); }} diff --git a/torch/csrc/jit/operator.cpp b/torch/csrc/jit/operator.cpp new file mode 100644 index 0000000000000..90c43fe7145dd --- /dev/null +++ b/torch/csrc/jit/operator.cpp @@ -0,0 +1,383 @@ +#include "ATen/ATen.h" +#include "torch/csrc/jit/script/lexer.h" +#include "torch/csrc/jit/script/tree.h" +#include "torch/csrc/jit/operator.h" +#include "torch/csrc/jit/tensor_conversions.h" +#include "torch/csrc/jit/script/error_report.h" + +namespace torch { namespace jit { + +namespace script { +struct SchemaParser { + SchemaParser(const std::string& str) + : L(str) {} + + FunctionSchema parseDeclaration() { + auto name = L.expect(TK_IDENT).text(); + if(L.nextIf(':')) { + L.expect(':'); + name = name + "::" + L.expect(TK_IDENT).text(); + } + std::vector arguments; + std::vector returns; + kwarg_only = false; + parseList('(', ',', ')', arguments, &SchemaParser::parseArgument); + L.expect(TK_ARROW); + if(L.cur().kind == '(') { + parseList('(', ',', ')', returns, &SchemaParser::parseReturn); + } else { + parseReturn(returns); + } + return FunctionSchema { name, arguments, returns }; + } + + std::vector parseDeclarations() { + std::vector results; + do { + results.push_back(parseDeclaration()); + } while(L.nextIf(TK_NEWLINE)); + L.expect(TK_EOF); + return results; + } + + TreeRef parseIdent() { + return String::create(L.expect(TK_IDENT).text()); + } + TypePtr parseBaseType() { + static std::unordered_map type_map = { + {"Tensor", DynamicType::get() }, + {"Generator", DynamicType::get() }, + {"ScalarType", IntType::get() }, + {"Layout", IntType::get() }, + {"Device", ListType::ofInts() }, + {"Scalar", NumberType::get() }, + }; + switch(L.cur().kind) { + case TK_FLOAT: + L.next(); + return FloatType::get(); + case TK_INT: + case TK_BOOL: // TODO: add separate bool type + L.next(); + return IntType::get(); + default: + auto tok = L.expect(TK_IDENT); + auto text = tok.text(); + auto it = type_map.find(text); + if(it == type_map.end()) + throw ErrorReport(tok.range) << "unknown type specifier"; + return it->second; + } + } + void parseType(Argument& arg) { + arg.type = parseBaseType(); + if(L.nextIf('[')) { + arg.type = std::make_shared(arg.type); + if(L.cur().kind == TK_NUMBER) { + arg.N = std::stoll(L.next().text()); + } + L.expect(']'); + } + } + + void parseArgument(std::vector& arguments) { + // varargs + if(L.nextIf('*')) { + kwarg_only = true; + return; + } + Argument arg; + parseType(arg); + + // nullability is ignored for now, since the JIT never cares about it + L.nextIf('?'); + arg.name = L.expect(TK_IDENT).text(); + if(L.nextIf('=')) { + parseDefaultValue(arg); + } + arg.kwarg_only = kwarg_only; + arguments.push_back(std::move(arg)); + } + void parseReturn(std::vector& args) { + Argument arg("ret" + std::to_string(args.size())); + parseType(arg); + args.push_back(std::move(arg)); + } + at::Tensor parseSingleConstant(TypeKind kind) { + switch(L.cur().kind) { + case TK_TRUE: + L.next(); + return one(); + case TK_FALSE: + L.next(); + return zero(); + case TK_FLOAT: + L.next(); + return as_tensor(static_cast(at::kFloat)); + case TK_IDENT: { + auto tok = L.next(); + auto text = tok.text(); + if("cpu" == text) { + return as_tensor(static_cast(at::Device::Type::CPU)); + } else if("strided" == text) { + return as_tensor(static_cast(at::kStrided)); + } else if("ElementwiseMean" == text) { + return as_tensor(static_cast(Reduction::ElementwiseMean)); + } else { + throw ErrorReport(L.cur().range) << "invalid numeric default value"; + } + } default: + std::string n; + if(L.nextIf('-')) + n = "-" + L.expect(TK_NUMBER).text(); + else + n = L.expect(TK_NUMBER).text(); + if(kind == TypeKind::FloatType || n.find(".") != std::string::npos || n.find("e") != std::string::npos) { + return at::full({}, std::stod(n), at::kDouble); // float? + } else { + int64_t v = std::stoll(n); + return at::full({}, v, at::kLong); + } + } + } + at::Tensor parseConstantList(TypeKind kind) { + auto tok = L.expect('['); + std::vector vs; + if(L.cur().kind != ']') { + do { + vs.push_back(parseSingleConstant(kind)); + } while(L.nextIf(',')); + } + L.expect(']'); + if(vs.size() == 0) { + switch(kind) { + case TypeKind::FloatType: + return at::empty({}, at::kFloat); + case TypeKind::IntType: + return at::empty({}, at::kLong); + default: + throw ErrorReport(tok) << "empty lists are only supported for float or int types."; + } + } + return at::stack(vs); + } + at::Tensor parseTensorDefault(const SourceRange& range) { + if("None" == L.expect(TK_IDENT).text()) { + return at::Tensor(); + } else { + throw ErrorReport(range) << "invalid tensor default value"; + } + } + void parseDefaultValue(Argument& arg) { + auto range = L.cur().range; + switch(arg.type->kind()) { + case TypeKind::DynamicType: { + arg.default_value = parseTensorDefault(range); + } break; + case TypeKind::NumberType: + case TypeKind::IntType: + case TypeKind::FloatType: + arg.default_value = parseSingleConstant(arg.type->kind()); + break; + case TypeKind::ListType: { + auto elem_kind = arg.type->cast()->getElementType(); + if(L.cur().kind == TK_IDENT) { + arg.default_value = parseTensorDefault(range); + } else if(arg.N && L.cur().kind != '[') { + arg.default_value = parseSingleConstant(elem_kind->kind()).expand({*arg.N}); + } else { + arg.default_value = parseConstantList(elem_kind->kind()); + } + } break; + default: + throw ErrorReport(range) << "unexpected type, file a bug report"; + } + } + + template + void parseList(int begin, int sep, int end, std::vector& result, void (SchemaParser::*parse)(std::vector&)) { + auto r = L.cur().range; + if (begin != TK_NOTHING) + L.expect(begin); + if (L.cur().kind != end) { + do { + (this->*parse)(result); + } while (L.nextIf(sep)); + } + if (end != TK_NOTHING) + L.expect(end); + } + Lexer L; + bool kwarg_only; + static at::Tensor one() { + static at::Tensor v = at::full({}, 1, at::kLong); + return v; + } + static at::Tensor zero() { + static at::Tensor v = at::full({}, 0, at::kLong); + return v; + } +}; +} + + +namespace { + +using OperatorMap = std::unordered_map>>; +struct OperatorRegistry { + OperatorMap operators; + std::mutex lock; + void registerOperator(Operator&& op){ + std::lock_guard guard(lock); + Symbol sym = Symbol::fromQualString(op.schema.name); + operators[sym].push_back(std::make_shared(std::move(op))); + } + const std::vector>& getOperators(Symbol name) { + std::lock_guard guard(lock); + static std::vector> empty; + auto it = operators.find(name); + if(it != operators.end()) + return it->second; + return empty; + } +}; + +OperatorRegistry& getRegsitry() { + static OperatorRegistry r; + return r; +} + +} + +void registerOperator(Operator&& op) { + getRegsitry().registerOperator(std::move(op)); +} + +const std::vector>& getAllOperatorsFor(Symbol name) { + return getRegsitry().getOperators(name); +} + +FunctionSchema parseSchema(const std::string& schema) { + return script::SchemaParser(schema).parseDeclarations().at(0); +} + +at::optional attributeKindOf(TypePtr type) { + switch(type->kind()) { + case TypeKind::IntType: return AttributeKind::i; + case TypeKind::FloatType: return AttributeKind::f; + case TypeKind::NumberType: return AttributeKind::t; + case TypeKind::ListType: + if(type->isSubtypeOf(*ListType::ofInts())) + return AttributeKind::is; + else + return at::nullopt; + default: + return at::nullopt; + } +} + +bool typeMatches(TypePtr actual, TypePtr formal) { + if(actual->isSubtypeOf(*formal)) + return true; + + // XXX - this is here because we allow tensors to be used in place of numbers + // or lists of numbers in the script because of the restriction that all inputs to script must be tensors. + // Once numbers are always treated as seperate types from Tensors, this line + // should be removed, since it opens up the possibility of ambigous declarations + // dispatching to the wrong implementation. + if ((formal->isSubtypeOf(*NumberType::get()) || + formal->isSubtypeOf(*ListType::ofInts())) && + actual->isSubtypeOf(*DynamicType::get())) + return true; + + return false; +} + +bool Operator::matchesNode(Node* node) const { + size_t attributes_size = node->numAttributes(); + size_t attributes_seen = 0; + auto inputs_size = node->inputs().size(); + size_t input_i = 0; + for(size_t arg_i = 0; arg_i < schema.arguments.size(); ++arg_i) { + at::optional attribute_kind; + const Argument& arg = schema.arguments[arg_i]; + if(attributes_size > 0 && (attribute_kind = attributeKindOf(arg.type))) { + auto name = Symbol::fromQualString("attr::" + arg.name); + if(!node->hasAttribute(name) || node->kindOf(name) != *attribute_kind) { + // std::cout << "missing attribute: " << name << "\n"; + return false; + } + attributes_seen++; + } else if(*arg.type == *ListType::ofTensors()) { + // Tensor[] is handled as varargs, consume inputs until the remaining required arguments + // XXX - there can only be a single Tensor[] in a declaration + size_t remaining_required = 0; + for(size_t j = arg_i + 1; j < schema.arguments.size(); ++j){ + // remaining arguments are only those that won't be consumed from attributes + if(attributes_size == 0 || !attributeKindOf(schema.arguments[j].type)) + remaining_required++; + } + while(inputs_size - input_i > remaining_required) { + auto input = node->inputs()[input_i++]; + if(!typeMatches(input->type(), DynamicType::get())) { + // std::cout << "vararg argument is not Dynamic\n"; + return false; + } + } + } else { + if(input_i == inputs_size) { + // std::cout << "not enough inputs\n"; + return false; + } + auto input = node->inputs()[input_i++]; + if(!typeMatches(input->type(), arg.type)) { + // std::cout << "argument " << arg_i << " has the wrong type\n"; + return false; + } + } + } + + if(!schema.is_vararg && input_i != inputs_size) { + // std::cout << "not all inputs used\n" << input_i << " " << inputs_size << "\n"; + return false; + } + if(!schema.is_vararg && attributes_seen != attributes_size) { + // std::cout << "not all attributes used\n" << attributes_seen << " " << attributes_size << "\n"; + return false; + } + return true; +} + +std::shared_ptr findOperatorFor(Node* node) { + const auto& candidates = getAllOperatorsFor(node->kind()); + for(const auto& candidate : candidates) { + if(candidate->matchesNode(node)) { + return candidate; + } + } + return nullptr; +} + +const Operator& getOperatorFor(Node* node) { + auto op = findOperatorFor(node); + if(op) + return *op; + + auto er = script::ErrorReport(node->getSourceLocation()); + er << "Schema not found for node. File a bug report.\n"; + er << "Node: " << *node << "\n"; + er << "Input types:"; + for(size_t i = 0; i < node->inputs().size(); ++i) { + if(i > 0) + er << ", "; + er << *node->inputs()[i]->type(); + } + er << "\ncandidates were:\n"; + const auto& candidates = getAllOperatorsFor(node->kind()); + for(auto & candidate : candidates) { + er << " " << candidate->schema << "\n"; + } + throw er; +} + +}} diff --git a/torch/csrc/jit/operator.h b/torch/csrc/jit/operator.h new file mode 100644 index 0000000000000..9db66cd4c1f7d --- /dev/null +++ b/torch/csrc/jit/operator.h @@ -0,0 +1,73 @@ +// in memory description of all ATen Ops similar to Caffe2 schema +// once C10 exists this can be removed, or stubbed out, but we need +// it now to implement correct semantic checking for script +#pragma once +#include "ATen/ATen.h" +#include "torch/csrc/jit/ir.h" +#include "torch/csrc/jit/function_schema.h" +#include "torch/csrc/jit/stack.h" + +namespace torch { namespace jit { + +FunctionSchema parseSchema(const std::string& decl); + +using OperationCreator = std::function; + +struct Operator { + Operator(FunctionSchema schema, OperationCreator op, OperationCreator op_const_attributes = nullptr) + : schema(std::move(schema)) + , op(std::move(op)) + , op_const_attributes(std::move(op_const_attributes)) {} + + Operator(const std::string& schema, OperationCreator op, OperationCreator op_const_attributes = nullptr) + : Operator(parseSchema(schema), std::move(op), std::move(op_const_attributes)) {} + + // Helper constructor to regsiter `op` to run + // run for _every_ IR Node where n.kind() == name, regardless of arguments. + // This is accomplished by marking the schema varargs and having no required arguments. + // This is used for things like prim::While or prim::If that can take a number + // of different valid input types and lengths. + Operator(Symbol name, OperationCreator op) + : Operator(FunctionSchema(name, {}, {}, true), op, op) {} + + FunctionSchema schema; + + bool matchesNode(Node* n) const; + // Operators have different versions depending on if some inputs are encoded + // as attributes or inputs. This function returns the right Operation function, + // given a node encoded for one variant. + // Behavior is undefined if matchesNode(n) == false + Operation selectVariant(Node* n) const { + if(n->hasAttributes()) { + JIT_ASSERT(op_const_attributes != nullptr); + return op_const_attributes(n); + } else { + return op(n); + } + } +private: + OperationCreator op; + OperationCreator op_const_attributes; +}; + +const std::vector>& getAllOperatorsFor(Symbol name); +std::shared_ptr findOperatorFor(Node* node); +const Operator& getOperatorFor(Node* node); + +inline Operation getOperation(Node* node) { + // note: getOperatorFor ensures that getOperatorFor(node).matchesNode(node) == true + // so the call to selectVariant is always valid. + return getOperatorFor(node).selectVariant(node); +} + +void registerOperator(Operator&& op); + +struct RegisterOperators { + RegisterOperators(std::vector operators) { + for(Operator& o : operators) { + registerOperator(std::move(o)); + } + } +}; + +}} diff --git a/torch/csrc/jit/passes/shape_analysis.cpp b/torch/csrc/jit/passes/shape_analysis.cpp index 9954ab270be0b..7e4b45e986eeb 100644 --- a/torch/csrc/jit/passes/shape_analysis.cpp +++ b/torch/csrc/jit/passes/shape_analysis.cpp @@ -2,7 +2,7 @@ #include "torch/csrc/jit/ir.h" #include "torch/csrc/jit/argument_spec.h" -#include "torch/csrc/jit/aten_dispatch.h" +#include "torch/csrc/jit/operator.h" #include #include @@ -87,7 +87,7 @@ void broadcastPointwise(Node *node, std::vector& types) { } void PropagateShapeOnNodeByRunningIt(Node* node, const std::vector& types) { - auto op_info = getTensorOp(node); + auto op = getOperation(node); std::vector stack; for(auto & type : types) { @@ -98,7 +98,7 @@ void PropagateShapeOnNodeByRunningIt(Node* node, const std::vector& // is to uncover any mistakes we could make when editing this code, // and eventually it shouldn't matter, because this phase should be // preceded by schema checking. - op_info.op(stack); + op(stack); JIT_ASSERT(stack.size() == node->outputs().size()); for(size_t i = 0; i < stack.size(); ++i) { diff --git a/torch/csrc/jit/python_interpreter.cpp b/torch/csrc/jit/python_interpreter.cpp index 95cf2d9e04772..6a979c241c5c0 100644 --- a/torch/csrc/jit/python_interpreter.cpp +++ b/torch/csrc/jit/python_interpreter.cpp @@ -1,6 +1,5 @@ #include "torch/csrc/python_headers.h" #include "torch/csrc/jit/interpreter.h" -#include "torch/csrc/jit/python_interpreter.h" #include "torch/csrc/autograd/edge.h" #include "torch/csrc/autograd/function.h" @@ -8,7 +7,7 @@ #include "torch/csrc/autograd/profiler.h" #include "torch/csrc/autograd/variable.h" #include "torch/csrc/jit/fusion_compiler.h" -#include "torch/csrc/jit/aten_dispatch.h" +#include "torch/csrc/jit/operator.h" #include "torch/csrc/jit/graph_executor.h" #include "torch/csrc/jit/ir.h" #include "torch/csrc/jit/tensor_conversions.h" @@ -25,7 +24,10 @@ namespace py = pybind11; namespace torch { namespace jit { -Operation createPythonOperation(PythonOp* op) { +namespace { + +Operation createPythonOperation(Node* op_) { + PythonOp* op = static_cast(op_); py::function func = py::reinterpret_borrow(py::handle(op->pyobj.get())); JIT_ASSERT(!hasHandleOutput(op)); size_t num_inputs = 0; @@ -85,15 +87,9 @@ Operation createPythonOperation(PythonOp* op) { }; } -at::optional lookupOp(Node* n) { - if(n->kind() == prim::PythonOp) { - return createPythonOperation(static_cast(n)); - } - return at::nullopt; -} -void registerPythonInterpreterOps() { - addInterpreterOpHandler(lookupOp); -} +RegisterOperators reg({ + Operator(prim::PythonOp, createPythonOperation) +}); -}} +}}} // torch::jit::anon diff --git a/torch/csrc/jit/python_interpreter.h b/torch/csrc/jit/python_interpreter.h deleted file mode 100644 index c431c0c3ac48e..0000000000000 --- a/torch/csrc/jit/python_interpreter.h +++ /dev/null @@ -1,4 +0,0 @@ -#pragma once -namespace torch { namespace jit { -void registerPythonInterpreterOps(); -}} diff --git a/torch/csrc/jit/python_ir.cpp b/torch/csrc/jit/python_ir.cpp index 0cc1826dfdc74..337024059f028 100644 --- a/torch/csrc/jit/python_ir.cpp +++ b/torch/csrc/jit/python_ir.cpp @@ -422,7 +422,7 @@ void initPythonIRBindings(PyObject * module_) { py::class_>(m,"Type") .def("__repr__",[](Type & t) { - return t.name(); + return t.str(); }) .def("kind",[](Type& t_) { Type * t = &t_; diff --git a/torch/csrc/jit/register_prim_ops.cpp b/torch/csrc/jit/register_prim_ops.cpp new file mode 100644 index 0000000000000..29e404626a1be --- /dev/null +++ b/torch/csrc/jit/register_prim_ops.cpp @@ -0,0 +1,218 @@ +#include "torch/csrc/autograd/edge.h" +#include "torch/csrc/autograd/function.h" +#include "torch/csrc/autograd/functions/special.h" +#include "torch/csrc/autograd/generated/variable_factories.h" +#include "torch/csrc/autograd/profiler.h" +#include "torch/csrc/autograd/variable.h" +#include "torch/csrc/jit/fusion_compiler.h" +#include "torch/csrc/jit/graph_executor.h" +#include "torch/csrc/jit/ir.h" +#include "torch/csrc/jit/operator.h" +#include "torch/csrc/jit/tensor_conversions.h" +#include "torch/csrc/variable_tensor_functions.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace torch { +namespace jit { + +namespace { + +Operation noop(Node* n) { + return [](Stack& stack) { return 0; }; +} + +RegisterOperators reg({ + + Operator( + prim::CppOp, + [](Node* node) { + CppOp* op = static_cast(node); + std::shared_ptr func = op->fn; + JIT_ASSERT(!hasHandleOutput(op)); + auto num_inputs = op->inputs().size(); + return [=](Stack& stack) { + autograd::variable_list v_inputs; + for (size_t i = 0; i < num_inputs; i++) { + v_inputs.push_back(std::move(peek(stack, i, num_inputs))); + } + drop(stack, num_inputs); + autograd::variable_list v_outputs = (*func)(v_inputs); + for (auto& output : v_outputs) { + stack.push_back(output); + } + return 0; + }; + }), + + Operator( + prim::FusionGroup, + [](Node* node) { + auto fusion_fn = sharedFusionCompiler().getOrCompile(node); + auto num_inputs = node->inputs().size(); + return [fusion_fn, num_inputs](Stack& stack) { + autograd::profiler::RecordFunction record("FusionGroup"); + std::vector toutputs; + // TODO: have fusion_fn work off of a stack as well + fusion_fn->launch(last(stack, num_inputs), toutputs); + drop(stack, num_inputs); + stack.insert(stack.end(), toutputs.begin(), toutputs.end()); + return 0; + }; + }), + + Operator( + prim::Constant, + [](Node* node) { + auto t = autograd::make_variable(node->t(attr::value)); + return [t](Stack& stack) { + stack.push_back(t); + return 0; + }; + }), + + Operator(prim::NumToTensor, noop), + Operator(prim::TensorToNum, noop), + Operator( + prim::Undefined, + [](Node* node) { + return [](Stack& stack) { + stack.push_back(at::Tensor()); + return 0; + }; + }), + Operator( + prim::ReplaceIfUndef, + [](Node* n) { + return [](Stack& stack) { + auto alternate = pop(stack); + auto result = pop(stack); + if (result.defined()) { + stack.push_back(std::move(result)); + } else { + stack.push_back(std::move(alternate)); + } + return 0; + }; + }), + + Operator( + prim::Print, + [](Node* node) { + size_t num_inputs = node->inputs().size(); + return [num_inputs](Stack& stack) { + bool first = true; + for (at::Tensor i : last(stack, num_inputs)) { + if (!first) + std::cout << " "; + first = false; + if (auto tensor_impl = dynamic_cast(i.get())) { + std::cout << at::Tensor(tensor_impl, true); + } else if (!i.defined()) { + std::cout << ""; + } else { + auto& r = *i.get(); + std::cout << "<" << typeid(r).name() << " at " << i << ">"; + } + } + drop(stack, num_inputs); + std::cout << std::endl; + return 0; + }; + }), + // Load x, y + // loads values from registers onto the stack, the actual callback does + // nothing since the stack manipulation is already encoded in inst.inputs + // and inst.outputs + Operator(prim::Load, noop), + // x, y = Store + // stores values from stack into registers, the actual callback does + // nothing since the stack manipulation is already encoded in inst.inputs + // and inst.outputs + Operator(prim::Store, noop), + + Operator( + prim::Drop, + [](Node* node) { + auto N = node->inputs().size(); + return [=](Stack& stack) { + drop(stack, N); + return 0; + }; + }), + Operator( + onnx::Reshape, + [](Node* node) { + return [=](Stack& stack) { + auto shape = pop(stack).contiguous(); + auto input = pop(stack); + JIT_ASSERT(shape.ndimension() == 1); + at::IntList shape_list(shape.data(), shape.size(0)); + stack.push_back(input.reshape(shape_list)); + return 0; + }; + }), + Operator( + onnx::Shape, + [](Node* node) { + return [=](Stack& stack) { + auto t = pop(stack); + at::IntList sizes = t.sizes(); + auto sizes_tensor = torch::empty( + {static_cast(sizes.size())}, at::dtype(at::kLong)); + auto accessor = sizes_tensor.accessor(); + for (size_t i = 0; i < sizes.size(); ++i) { + accessor[i] = sizes[i]; + } + stack.push_back(sizes_tensor); + return 0; + }; + }), + + Operator( + prim::AnyDefined, + [](Node* node) { + size_t num_inputs = node->inputs().size(); + auto true_ = at::full({}, 1, at::kLong); + auto false_ = at::full({}, 0, at::kLong); + return [=](Stack& stack) { + bool result = false; + for (const at::Tensor& t : last(stack, num_inputs)) { + if (t.defined()) { + result = true; + break; + } + } + drop(stack, num_inputs); + stack.push_back(result ? true_ : false_); + return 0; + }; + }), + + Operator( + prim::AutogradAdd, + [](Node* node) { + return [=](Stack& stack) { + auto a = pop(stack); + auto b = pop(stack); + if (!a.defined()) + stack.push_back(b); + else if (!b.defined()) + stack.push_back(a); + else + stack.push_back(a + b); + return 0; + }; + }), +}); +}}} // torch::jit::anon diff --git a/torch/csrc/jit/script/compiler.cpp b/torch/csrc/jit/script/compiler.cpp index 846a22aef2606..2db051bf5c29f 100644 --- a/torch/csrc/jit/script/compiler.cpp +++ b/torch/csrc/jit/script/compiler.cpp @@ -1,11 +1,11 @@ #include "torch/csrc/jit/script/compiler.h" #include "torch/csrc/jit/passes/lower_tuples.h" -#include "torch/csrc/jit/aten_dispatch.h" +#include "torch/csrc/jit/operator.h" #include "torch/csrc/jit/interpreter.h" #include "torch/csrc/jit/ir.h" #include "torch/csrc/jit/script/parser.h" #include "torch/csrc/utils/object_ptr.h" -#include "torch/csrc/jit/aten_schema.h" +#include "torch/csrc/jit/operator.h" #include "torch/csrc/jit/tensor_conversions.h" #include "ATen/optional.h" @@ -171,8 +171,8 @@ struct Environment { " and " << name << " is not a first-class value. Only reassignments to first-class values are allowed"; } if(!as_simple_value->type()->isSubtypeOf(*interpreterType(simple_parent->type()))) { - throw ErrorReport(loc) << "variable '" << name << "' previously has type " << simple_parent->type()->name() - << " but is now being assigned to a value of type " << as_simple_value->type()->name(); + throw ErrorReport(loc) << "variable '" << name << "' previously has type " << simple_parent->type()->str() + << " but is now being assigned to a value of type " << as_simple_value->type()->str(); } } if (as_simple_value) @@ -319,11 +319,9 @@ void liftConstantAttributes(const FunctionSchema& schema, Node* node) { for(size_t i = 0, n = 0; i < schema.arguments.size(); ++i) { const auto& arg = schema.arguments[i]; // this was a builtin with a vararg list lowered, - if(arg.type->kind() == TypeKind::ListType) { - // we do not support constant lifting of the arg itself - if(arg.attribute_info) - return; - // but we do support it for other values so we need to skip all the vararg nodes: + if(*arg.type == *ListType::ofTensors()) { + // we need to skip all the vararg nodes, and continue parsing the + // possible attribute nodes size_t vararg_list_size = node->inputs().size() - (schema.arguments.size() - 1); while(n < i + vararg_list_size) { new_inputs.push_back(node->input(n++)); @@ -331,38 +329,40 @@ void liftConstantAttributes(const FunctionSchema& schema, Node* node) { continue; } auto input = node->input(n++); - if(arg.attribute_info) { - switch(arg.attribute_info->kind) { - case AttributeKind::i: { - auto r = constant_as(input); - if(!r) - return; - attributes.i_(Symbol::attr(arg.name), *r); - } break; - case AttributeKind::is: { - auto r = getIntListAttribute(arg.attribute_info->data, input); + switch(arg.type->kind()) { + case TypeKind::IntType:{ + auto r = constant_as(input); + if(!r) + return; + attributes.i_(Symbol::attr(arg.name), *r); + } break; + case TypeKind::FloatType: { + auto r = constant_as(input); + if(!r) + return; + attributes.f_(Symbol::attr(arg.name), *r); + } break; + case TypeKind::NumberType: { + auto r = constant_as(input); + if(!r) + return; + attributes.t_(Symbol::attr(arg.name), *r); + } break; + case TypeKind::ListType: { + auto elem = arg.type->expect()->getElementType(); + if(elem->kind() == TypeKind::IntType) { + auto r = getIntListAttribute(arg.N, input); if(!r) return; attributes.is_(Symbol::attr(arg.name), *r); - } break; - case AttributeKind::f: { - auto r = constant_as(input); - if(!r) - return; - attributes.f_(Symbol::attr(arg.name), *r); - } break; - case AttributeKind::t: { - auto r = constant_as(input); - if(!r) - return; - attributes.t_(Symbol::attr(arg.name), *r); - } break; - default: - barf("AttributeKind not handled in LiftConstantAttributes file a bug report."); - return; - } - } else { - new_inputs.push_back(input); + } else { + // only IntLists can become attributes, other + // types are not attribute-able + new_inputs.push_back(input); + } + } break; + default: + new_inputs.push_back(input); } } // nothing changed no need to modify the node @@ -415,10 +415,9 @@ static Value* tensorToNum( static inline bool isIntUsedAsIntList( const Value* value, const Argument& arg) { - // NB: attribute_info->data equals the "k" in IntList[k] + // Look for int[N] return value->type()->kind() == TypeKind::IntType && - arg.type->isSubtypeOf(*DynamicType::get()) && - arg.attribute_info && arg.attribute_info->data; + *arg.type == *ListType::ofInts() && arg.N; } at::optional> tryMatchSchema( @@ -467,13 +466,11 @@ at::optional> tryMatchSchema( err() << "argument '" << schema.arguments[i].name << "' not provided.\n" << loc; return at::nullopt; } - if (isNumberSubtype(schema.arguments[i].type)) { - positional_inputs[i] = NamedValue( - loc, i, createNumber(graph, loc, *default_value)); - } else { - positional_inputs[i] = NamedValue( - loc, i, createConstant(graph, loc, *default_value)); - } + positional_inputs[i] = NamedValue( + loc, + i, + createConstant(graph, loc, *default_value) + ->setType(schema.arguments[i].type)); } // check input types @@ -482,40 +479,28 @@ at::optional> tryMatchSchema( NamedValue v = *positional_inputs[i]; const auto& arg = schema.arguments[i]; - // TODO: revisit this. - // An IntList[1] is a union of int and IntList. Consider - // - // import torch - // @torch.jit.script - // def func(x): - // return x.sum(dim=1) - // - // dim is specified in native_functions.yaml as a IntList[1]. - // This means it is okay to pass a python int into to it, or a python - // list. - // - // If we see an IntType being used where an IntList[1] is in the schema, - // we reinterpret an int as an "IntList" (which is a tensor right now) + + // some functions that take lists of integers for fixed size arrays + // also allow single ints to be passed in their place. + // the single int is then repeated to the length of the list if (isIntUsedAsIntList(v.value, arg)) { - if (v.value->node()->kind() == prim::Constant) { - // peephole optimization where we make a Tensor rather than - // a prim::TupleConstruct to wrap the int - auto* node = v.value->node(); - v.value = createConstant(graph, loc, node->t(attr::value)); - } else { - auto* node = graph.insertNode(graph.create(prim::TupleConstruct, { v.value })); - std::vector tmp = { IntType::get() }; - v.value = node->output()->setType(std::make_shared(tmp)); - } + std::vector repeated(*arg.N, v.value); + v.value = graph.insertNode(graph.createTuple(repeated))->output(); } - // implicit conversion from List[int] -> Tensor for when the argument - // is an IntList in aten, for things like x.expand(sizes=[3,4,5]) - if(arg.attribute_info && - arg.attribute_info->kind == AttributeKind::is && + // Tuples of integers are created using TuplePack which we do not actually + // support in the interpreter, so we have to replace it with a + // stack call, which creates a Tensor to represent the list. + if(*ListType::ofInts() == *arg.type && + v.value->type()->kind() == TypeKind::TupleType && v.value->type()->isSubtypeOf(*ListType::ofInts())) { auto unpacked = createTupleUnpack(v.value); - v.value = createStack(graph, loc, unpacked); + // elements are numbers so we have to convert to tensors before + // stack will be valid + auto unpacked_t = fmap(unpacked, [&](Value* e) { + return numToTensor(v.loc, graph, e); + }); + v.value = createStack(graph, loc, unpacked_t)->setType(ListType::ofInts()); } // implicit conversion from Tensor to Python Number @@ -525,14 +510,14 @@ at::optional> tryMatchSchema( } if(!v.value->type()->isSubtypeOf(*arg.type)) { - err() << "expected a value of type " << arg.type->name() << " for argument '" << arg.name << "' but found " - << v.value->type()->name() << "\n" + err() << "expected a value of type " << arg.type->str() << " for argument '" << arg.name << "' but found " + << v.value->type()->str() << "\n" << v.loc; return at::nullopt; } - // we only support lists for builtins, where they must be flattened - if(arg.type->kind() == TypeKind::ListType) { + // we only support tensor lists for builtins, where they must be flattened + if(arg.type->isSubtypeOf(*ListType::ofTensors())) { auto outputs = createTupleUnpack(v.value); flat_inputs.insert(flat_inputs.end(), outputs.begin(), outputs.end()); } else { @@ -587,7 +572,7 @@ static std::shared_ptr tryEmitBuiltin( // assert that we did indeed create an op that has implementation // otherwise schema and dispatch are not in sync - getTensorOp(n); + getOperation(n); return packOutputs(*graph, n->outputs()); } @@ -614,11 +599,11 @@ std::shared_ptr emitBuiltinCall( // otherwise it will return nullptr if the builtin is not found. bool required) { - auto variants = getOperatorSchema(name); + const auto& variants = getAllOperatorsFor(Symbol::aten(name)); std::stringstream failure_messages; - for (const FunctionSchema& schema : variants) { + for (const std::shared_ptr& op : variants) { if (auto result = tryEmitBuiltin( - schema, failure_messages, loc, method, name, inputs, attributes)) { + op->schema, failure_messages, loc, method, name, inputs, attributes)) { return result; } } @@ -698,7 +683,6 @@ struct to_ir { pushFrame(graph->block()); std::vector arguments, returns; // for schema - // inputs auto it = def.params().begin(); auto end = def.params().end(); @@ -710,7 +694,7 @@ struct to_ir { } for(;it != end; ++it) { auto& name = (*it).ident().name(); - arguments.push_back({name, DynamicType::get(), at::nullopt, at::nullopt}); + arguments.push_back({name, DynamicType::get()}); environment_stack->setVar((*it).ident().range(), name, graph->addInput(name)); } // body @@ -740,7 +724,7 @@ struct to_ir { ensureTensors(return_stmt.range(), results); for(auto r : results) { graph->registerOutput(r); - returns.push_back({"", DynamicType::get(), at::nullopt, at::nullopt}); + returns.push_back({"", DynamicType::get()}); } } @@ -1617,37 +1601,6 @@ struct to_ir { return n; } - void matchSchemaAndLiftConstantAttributes( - const SourceRange& loc, - Node* n, - std::vector input_vals, - const std::string& name) { - std::vector named_input_vals; - for (Value* inp : input_vals) { - named_input_vals.push_back(NamedValue(loc, "", inp)); - } - - // Match schema and lift constant attributes - auto variants = getOperatorSchema(name); - bool schema_valid = false; - std::stringstream failure_messages; - for (const FunctionSchema& schema : variants) { - if (tryMatchSchema( - schema, loc, *graph, named_input_vals, {}, failure_messages)) { - schema_valid = true; - liftConstantAttributes(schema, n); - break; - } - } - - // none of the options worked - if (!schema_valid) { - throw ErrorReport(loc) - << "arguments for call are not valid:\n" - << prefixLine(failure_messages.str(), " ") << "for call at"; - } - } - // Desugars slice syntactic sugar tensor[begin:end] -> tensor.slice(begin, // end). Value* emitSlice( @@ -1655,24 +1608,20 @@ struct to_ir { TreeList&& inputs) { const auto applyInputs = Compound::create(TK_LIST, loc, std::move(inputs)); - const auto input_values = getValues(applyInputs->trees(), - /*maybe_unpack*/false, - ensureTensorOrNumber); - Value* tensor = input_values[0]; - Value* begin = input_values[1]; - Value* end = input_values[2]; - Value* dim = - createConstant(*graph, loc, at::CPU(at::kLong).scalarTensor(0)); - Value* step = - createConstant(*graph, loc, at::CPU(at::kLong).scalarTensor(1)); - std::vector input_vals{tensor, dim, begin, end, step}; - Value* sliced_val = - emitNode(Symbol::aten("slice"), loc, input_vals, 1)->output(); - - matchSchemaAndLiftConstantAttributes( - loc, sliced_val->node(), input_vals, "slice"); - - return sliced_val; + const auto input_values = getNamedValues(applyInputs->trees(), + /*maybe_unpack*/false, + ensureTensorOrNumber); + NamedValue tensor = input_values[0]; + NamedValue begin = input_values[1]; + NamedValue end = input_values[2]; + NamedValue dim = NamedValue(loc, "dim", + createConstant(*graph, loc, at::CPU(at::kLong).scalarTensor(0))); + NamedValue step = NamedValue(loc, "step", + createConstant(*graph, loc, at::CPU(at::kLong).scalarTensor(1))); + + return emitBuiltinCall( + loc, method, "slice", {tensor, dim, begin, end, step}, {}, true) + ->asValue(loc, method); } // Desugars gather syntactic sugar tensor[idx] -> tensor.select(idx). @@ -1681,19 +1630,18 @@ struct to_ir { TreeList&& inputs) { const auto applyInputs = Compound::create(TK_LIST, loc, std::move(inputs)); - const auto input_values = getValues(applyInputs->trees(), + auto input_values = getNamedValues(applyInputs->trees(), /*maybe_unpack*/false, ensureTensorOrNumber); - Value* tensor = input_values[0]; - Value* dim = - createConstant(*graph, loc, at::CPU(at::kLong).scalarTensor(0)); - Value* idx = input_values[1]; - std::vector input_vals{tensor, dim, idx}; - Value* gathered_val = - emitNode(Symbol::aten("select"), loc, input_vals, 1)->output(); - matchSchemaAndLiftConstantAttributes( - loc, gathered_val->node(), input_vals, "select"); - return gathered_val; + NamedValue tensor = input_values[0]; + NamedValue dim = NamedValue( + loc, + "dim", + createConstant(*graph, loc, at::CPU(at::kLong).scalarTensor(0))); + NamedValue idx = input_values[1]; + + return emitBuiltinCall(loc, method, "select", {tensor, dim, idx}, {}, true) + ->asValue(loc, method); } }; @@ -1775,7 +1723,7 @@ std::vector> SimpleValue::asTuple(SourceRange loc, return std::make_shared(v); }); } - throw ErrorReport(loc) << value->type()->name() << " cannot be used as a tuple"; + throw ErrorReport(loc) << value->type()->str() << " cannot be used as a tuple"; } void ensureSizeMatches(SourceRange loc, size_t expected, size_t actual, const std::string& what) { diff --git a/torch/csrc/jit/script/init.cpp b/torch/csrc/jit/script/init.cpp index 2be0326bd668b..a481eb601f8af 100644 --- a/torch/csrc/jit/script/init.cpp +++ b/torch/csrc/jit/script/init.cpp @@ -38,8 +38,10 @@ static std::string typeString(py::handle h) { return py::str(h.get_type().attr("__name__")); } -static std::shared_ptr createConstant(SourceRange loc, Method& m, const at::Tensor& val) { +static std::shared_ptr createConstant(SourceRange loc, Method& m, const at::Tensor& val, TypePtr typ=nullptr) { auto n = m.graph()->createConstant(val); + if(typ) + n->output()->setType(typ); n->setSourceLocation(std::make_shared(loc)); return std::make_shared(m.graph()->insertNode(n)->output()); } @@ -67,7 +69,7 @@ struct VISIBILITY_HIDDEN PythonValue : public SugaredValue { for (size_t i = 0; i < arg_types.size(); ++i) { if (!inputs[i]->type()->isSubtypeOf(*arg_types[i])) throw ErrorReport(loc) << "type mismatch at argument " << i << ": expected " - << arg_types[i]->name() << ", but got " << inputs[i]->type()->name(); + << arg_types[i]->str() << ", but got " << inputs[i]->type()->str(); } // We have to do this check here, because implementation of this function is tightly // coupled with the impl for PythonOp in the interpreter. Right now it assumes that @@ -196,15 +198,15 @@ struct VISIBILITY_HIDDEN ConstantPythonValue : public PythonValue { } else if(THPDevice_Check(self.ptr())) { auto device = (THPDevice*) self.ptr(); auto t = as_tensor({static_cast(device->device.type()), device->device.index()}); - return createConstant(loc, m, t); + return createConstant(loc, m, t, ListType::ofInts()); } else if(THPLayout_Check(self.ptr())) { auto layout = (THPLayout*) self.ptr(); const auto v = static_cast(layout->layout); - return createConstant(loc, m, at::CPU(at::kLong).scalarTensor(v)); + return createConstant(loc, m, at::CPU(at::kLong).scalarTensor(v), IntType::get()); } else if(THPDtype_Check(self.ptr())) { auto dtype = (THPDtype*)(self.ptr()); const auto v = static_cast(dtype->scalar_type); - return createConstant(loc, m, at::CPU(at::kLong).scalarTensor(v)); + return createConstant(loc, m, at::CPU(at::kLong).scalarTensor(v), IntType::get()); } return std::make_shared(self); } diff --git a/torch/csrc/jit/script/lexer.h b/torch/csrc/jit/script/lexer.h index 6db2caa32a064..7e2c81233ce76 100644 --- a/torch/csrc/jit/script/lexer.h +++ b/torch/csrc/jit/script/lexer.h @@ -1,5 +1,4 @@ #pragma once -#include #include #include #include @@ -7,6 +6,7 @@ #include #include #include +#include "torch/csrc/assertions.h" #include "torch/csrc/jit/source_location.h" @@ -47,7 +47,7 @@ namespace script { _(TK_RANGE_CONSTRAINT, "range_constraint", "") \ _(TK_PARAM, "param", "") \ _(TK_INFERRED, "inferred", "") \ - _(TK_BOOL, "bool", "") \ + _(TK_BOOL, "bool", "bool") \ _(TK_ACCESS, "access", "") \ _(TK_ASSIGN, "assign", "") \ _(TK_ATTRIBUTE, "attribute", "") \ @@ -83,9 +83,10 @@ namespace script { _(TK_IN, "in", "in") \ _(TK_STARRED, "starred", "") \ _(TK_UNARY_MINUS, "unary minus", "") \ - _(TK_POW, "pow operator", "**") + _(TK_POW, "pow operator", "**") \ + _(TK_ARROW, "arrow", "->") \ -static const char* valid_single_char_tokens = "+-*/@()[]:,={}><."; +static const char* valid_single_char_tokens = "+-*/@()[]:,={}><.?"; enum TokenKind { // we use characters to represent themselves so skip all valid characters @@ -107,7 +108,7 @@ struct TokenTrie { TokenTrie() : kind(0) {} void insert(const char* str, int tok) { if (*str == '\0') { - assert(kind == 0); + TORCH_ASSERT(kind == 0); kind = tok; return; } @@ -328,20 +329,43 @@ struct SourceRange : public SourceLocation { size_t size() const { return end() - start(); } + + static const size_t CONTEXT = 10; virtual void highlight(std::ostream& out) const override { const std::string& str = file(); - size_t begin = start(); - size_t end = start(); - while (begin > 0 && str[begin - 1] != '\n') - --begin; - while (end < str.size() && str[end] != '\n') - ++end; - out << str.substr(0, end) << "\n"; - out << std::string(start() - begin, ' '); - size_t len = std::min(size(), end - start()); + size_t begin_line = start(); // beginning of line to highlight + size_t end_line = start(); // end of line to highlight + while (begin_line > 0 && str[begin_line - 1] != '\n') + --begin_line; + while (end_line < str.size() && str[end_line] != '\n') + ++end_line; + TORCH_ASSERT(begin_line == 0 || str[begin_line - 1] == '\n'); + TORCH_ASSERT(end_line == str.size() || str[end_line] == '\n'); + + size_t begin_highlight = begin_line; // beginning of context, CONTEXT lines before the highlight line + for(size_t i = 0; begin_highlight > 0; --begin_highlight) { + if(str[begin_highlight - 1] == '\n') + ++i; + if(i >= CONTEXT) + break; + } + TORCH_ASSERT(begin_highlight == 0 || str[begin_highlight - 1] == '\n'); + + size_t end_highlight = end_line; // end of context, CONTEXT lines after the highlight line + for(size_t i = 0; end_highlight < str.size(); ++end_highlight) { + if(str[end_highlight] == '\n') + ++i; + if(i >= CONTEXT) + break; + } + TORCH_ASSERT(end_highlight == str.size() || str[end_highlight] == '\n'); + + out << str.substr(begin_highlight, end_line - begin_highlight) << "\n"; + out << std::string(start() - begin_line, ' '); + size_t len = std::min(size(), end_line - start()); out << std::string(len, '~') << (len < size() ? "... <--- HERE" : " <--- HERE"); - out << str.substr(end); + out << str.substr(end_line, end_highlight - end_line); if (str.size() > 0 && str.back() != '\n') out << "\n"; } @@ -492,7 +516,7 @@ struct Lexer { int kind; size_t start; size_t length; - assert(file); + TORCH_ASSERT(file); if (!shared.match( *file, pos, diff --git a/torch/csrc/jit/script/module.cpp b/torch/csrc/jit/script/module.cpp index 76a23e53e7d1d..1058b6aa186df 100644 --- a/torch/csrc/jit/script/module.cpp +++ b/torch/csrc/jit/script/module.cpp @@ -1,6 +1,7 @@ #include "torch/csrc/jit/script/module.h" #include "torch/csrc/jit/script/compiler.h" #include "torch/csrc/jit/script/error_report.h" +#include "torch/csrc/jit/operator.h" namespace torch { namespace jit { namespace script { @@ -18,10 +19,10 @@ static FunctionSchema defaultSchemaFor(Method& method) { for(size_t i = 0; i < num_inputs; ++i) { const Value* v = g.inputs().at(i); std::string name = v->hasUniqueName() ? v->uniqueName() : ("argument_" + std::to_string(i)); - args.push_back({std::move(name), DynamicType::get(), at::nullopt, at::nullopt}); + args.push_back({std::move(name), DynamicType::get()}); } for(size_t i = 0; i < g.outputs().size(); ++i) { - returns.push_back({"", DynamicType::get(), at::nullopt, at::nullopt}); + returns.push_back({"", DynamicType::get()}); } return { method.name(), std::move(args), std::move(returns) }; } diff --git a/torch/csrc/jit/stack.h b/torch/csrc/jit/stack.h new file mode 100644 index 0000000000000..503725396f086 --- /dev/null +++ b/torch/csrc/jit/stack.h @@ -0,0 +1,94 @@ +#pragma once +#include "ATen/ATen.h" +#include "torch/csrc/jit/tensor_conversions.h" + +namespace torch { namespace jit { + +using Stack = std::vector; +using Operation = std::function; + +// An operation with N inputs and M outputs pops the last N inputs off +// the stack and pushes its M inputs onto the stack +// before: I0, I1, ... IN <- stack.back() +// after: O0, O1, ... OM +// operations are defined this way so that ownership of inputs can be transferred +// to the operation and it can incrementally drop ownership of tensors +// when they become unneeded. For large operations, like 'run an entire subgraph', +// this functionality is very important for minimizing gpu memory usage +// return value is the relative 'offset' to jump to for the next operation: +// pc += 1 + offset +// so a return value of 0 goes to the next instruction + +// treat the last N elements of the stack as a list, looking up +// element i +static inline at::Tensor & peek(Stack & stack, size_t i, size_t N) { + return *(stack.end() - N + i); +} +// treat the last N elements of the stack as a list, looking up the +// slice starting at index i and having length len +static inline at::ArrayRef peekSlice(Stack & stack, size_t i, size_t len, size_t N) { + return at::ArrayRef(stack).slice(stack.size() - N + i, len); +} +static inline at::ArrayRef last(Stack & stack, size_t N) { + return peekSlice(stack, 0, N, N); +} +static inline void drop(Stack & stack, size_t n) { + stack.erase(stack.end() - n, stack.end()); +} +static inline at::Tensor pop(Stack & stack) { + auto r = std::move(stack.back()); + stack.pop_back(); + return r; +} + +// The packer here is carefully written not to make any unnecessary +// copies. + +// pack takes the return values of aten functions pushes them onto the stack +template +inline void pack(Stack & stack, T&& v) { + stack.push_back(as_variable(std::move(v))); +} +template<> +inline void pack(Stack & stack, at::Tensor&& v) { + stack.push_back(std::move(v)); +} + +template<> +inline void pack(Stack & stack, autograd::Variable&& v) { + stack.push_back(std::move(v)); +} + +template<> +inline void pack(Stack & stack, std::vector&& ts) { + for(auto& t : ts) { + stack.push_back(std::move(t)); + } +} + +template +struct TuplePacker +{ + // NB: *Not* a universal reference. + static void execute(Stack & stack, std::tuple && t) + { + // NB: The move here does not "destroy" the entire tuple, that is + // not what std::move does; only the particular tuple index + // processed here gets stolen. + pack(stack, std::get(std::move(t))); + TuplePacker::execute(stack, std::move(t)); + } +}; + +template +struct TuplePacker<0, Args...> +{ + static void execute(Stack & stack, std::tuple && t) {}; +}; + +template +inline void pack(Stack & stack, std::tuple && t) { + TuplePacker::execute(stack, std::move(t)); +} + +}} diff --git a/torch/csrc/jit/type.cpp b/torch/csrc/jit/type.cpp index ba248f110d7bc..32484a441123d 100644 --- a/torch/csrc/jit/type.cpp +++ b/torch/csrc/jit/type.cpp @@ -35,6 +35,9 @@ std::ostream& operator<<(std::ostream & out, const Type & t) { out << "float"; } else if(t.kind() == TypeKind::IntType) { out << "int"; + } else if(t.kind() == TypeKind::ListType) { + auto prim = t.cast()->getElementType(); + out << *prim << "[]"; } else { barf("unknown type kind"); } diff --git a/torch/csrc/jit/type.h b/torch/csrc/jit/type.h index 0b0f886a12214..541669d89cdff 100644 --- a/torch/csrc/jit/type.h +++ b/torch/csrc/jit/type.h @@ -47,7 +47,10 @@ struct Type : std::enable_shared_from_this { virtual bool isSubtypeOf(const Type& rhs) const { return *this == rhs; } - virtual std::string name() const = 0; + // user-friendly form of the type, separate from + // operator<< which is verbose and unambiguous + virtual std::string str() const = 0; + TypeKind kind() const { return kind_; } @@ -93,7 +96,7 @@ struct DynamicType : public Type { virtual bool operator==(const Type& rhs) const override { return rhs.kind() == kind(); } - virtual std::string name() const override { + virtual std::string str() const override { return "Tensor"; } static const TypeKind Kind = TypeKind::DynamicType; @@ -161,13 +164,10 @@ struct TensorType : public Type { virtual bool isSubtypeOf(const Type& rhs) const override { return *this == rhs || rhs.kind() == TypeKind::DynamicType; } - virtual std::string name() const override { - std::string retval = std::string(at::toString(scalarType())) + "Tensor["; - for (size_t i=0; i < sizes_.size(); ++i) { - retval += std::to_string(sizes_[i]) + (i == sizes_.size() - 1 ? "" : ","); - } - retval += "]"; - return retval; + virtual std::string str() const override { + // str is used for user-facing error messages, where we + // don't want to reveal underlying size information. + return "Tensor"; } private: static std::vector contiguousStridesOf(at::IntList sizes) { @@ -210,7 +210,7 @@ struct HandleType : public Type { virtual bool operator==(const Type& rhs) const override { return rhs.kind() == kind(); } - virtual std::string name() const override { + virtual std::string str() const override { return "Handle"; } static const TypeKind Kind = TypeKind::HandleType; @@ -224,18 +224,21 @@ struct ListType : public Type { ListType(TypePtr elem) : Type(TypeKind::ListType), elem(elem) {} virtual bool operator==(const Type& rhs) const override { - return rhs.kind() == kind(); + if(auto rhs_ = rhs.cast()) { + return *getElementType() == *rhs_->getElementType(); + } + return false; } - virtual std::string name() const override { + virtual std::string str() const override { std::stringstream ss; - ss << "List[" << getElementType()->name() << "]"; + ss << getElementType()->str() << "[]"; return ss.str(); } TypePtr getElementType() const { return elem; } // common cast List[Tensor] - static TypePtr ofTensors(); + static TypePtr ofTensors(); static TypePtr ofInts(); private: TypePtr elem; @@ -269,13 +272,13 @@ struct TupleType : public Type { return a.isSubtypeOf(b); }); } - virtual std::string name() const override { + virtual std::string str() const override { std::stringstream ss; ss << "("; for(size_t i = 0; i < elements().size(); ++i) { if(i > 0) ss << ", "; - ss << elements()[i]->name(); + ss << elements()[i]->str(); } ss << ")"; return ss.str(); @@ -304,8 +307,8 @@ struct NumberType : public Type { virtual bool operator==(const Type& rhs) const override { return rhs.kind() == kind(); } - virtual std::string name() const override { - return "Number"; + virtual std::string str() const override { + return "Scalar"; // match what PythonArgParser says for clarity } static const TypeKind Kind = TypeKind::NumberType; // global singleton @@ -319,7 +322,7 @@ struct FloatType : public Type { virtual bool operator==(const Type& rhs) const override { return rhs.kind() == kind(); } - virtual std::string name() const override { + virtual std::string str() const override { return "float"; } virtual bool isSubtypeOf(const Type& rhs) const override { @@ -337,7 +340,7 @@ struct IntType : public Type { virtual bool operator==(const Type& rhs) const override { return rhs.kind() == kind(); } - virtual std::string name() const override { + virtual std::string str() const override { return "int"; } virtual bool isSubtypeOf(const Type& rhs) const override { diff --git a/torch/onnx/symbolic.py b/torch/onnx/symbolic.py index 10ca090dae25e..f164d80fd945d 100644 --- a/torch/onnx/symbolic.py +++ b/torch/onnx/symbolic.py @@ -296,8 +296,8 @@ def stack(g, *tensors, **kwargs): dim = kwargs.pop('dim') if kwargs: raise RuntimeError("Unexpected kwargs: " + ','.join(kwargs.keys())) - if len(tensors) < 2: - raise RuntimeError("Expected at least two arguments to stack node") + if len(tensors) < 1: + raise RuntimeError("Expected at least one argument to stack node") unsqueezed = [g.op("Unsqueeze", t, axes_i=[dim]) for t in tensors] return g.op("Concat", *unsqueezed, axis_i=dim) From e9e47ce8f1860270281cffa2adc07b139fab652e Mon Sep 17 00:00:00 2001 From: Christian Puhrsch Date: Tue, 10 Jul 2018 12:30:38 -0700 Subject: [PATCH 05/36] Vectorize sigmoid (#8612) Summary: This PR ports the vectorization of sigmoid to also enable better performance for non-contiguous arrays. Detailed timings will follow shortly. Pull Request resolved: https://github.com/pytorch/pytorch/pull/8612 Reviewed By: ezyang Differential Revision: D8712298 Pulled By: cpuhrsch fbshipit-source-id: 01a3d06af8d04513edd024ab1d01a6b753fc6f6a --- aten/src/ATen/CPUApplyUtils.h | 13 +- aten/src/ATen/Declarations.cwrap | 16 +- aten/src/ATen/cpu/vec256/vec256_base.h | 6 + aten/src/ATen/cpu/vec256/vec256_double.h | 6 + aten/src/ATen/cpu/vec256/vec256_float.h | 6 + aten/src/ATen/cpu/vec256/vec256_int.h | 8 +- aten/src/ATen/cpu/vml.h | 150 ++++++++++++------ aten/src/ATen/native/UnaryOps.cpp | 3 +- aten/src/ATen/native/cpu/CapabilityDispatch.h | 3 +- aten/src/ATen/native/cpu/UnaryOpsKernel.cpp | 95 ++++++++++- aten/src/ATen/native/cpu/UnaryOpsKernel.h | 1 + aten/src/ATen/native/cuda/CUDAUnaryOps.cpp | 12 +- aten/src/ATen/native/native_functions.yaml | 13 ++ cmake/Codegen.cmake | 2 +- 14 files changed, 246 insertions(+), 88 deletions(-) diff --git a/aten/src/ATen/CPUApplyUtils.h b/aten/src/ATen/CPUApplyUtils.h index 230e18bb4a80a..2db2786b1c66c 100644 --- a/aten/src/ATen/CPUApplyUtils.h +++ b/aten/src/ATen/CPUApplyUtils.h @@ -253,16 +253,15 @@ apply_op(int64_t numel, int64_t offset, const Op& op, Args... iters) { } } + inline void apply_kernel(){}; +// TODO: Deal elegantly with 0-dim tensors. iters.strides_ of 0-dim +// strided_tensor_iter will be of size 0 for dim 0 and iters.strides_[iters.dim_ +// - 1] will index at -1. C++14 integer_sequence could be of use here. template inline void apply_kernel(int64_t numel, int64_t offset, const Op& op, Args... iters) { - // For 0-dim tensors - if (numel == 1 && max_dim(iters...) == 0) { - op(1, iters.data_..., iters.strides_[iters.dim_ - 1]...); - return; - } if (offset > 0) forward(offset, iters...); int64_t size = std::min(numel, max_iterate_size(iters...)); @@ -284,6 +283,10 @@ inline void CPU_tensor_parallel_kernel_apply2(Tensor tensor1, Tensor tensor2, const Op op) { if (!_apply_preamble({tensor1, tensor2})) return; + if (tensor1.numel() == 1) { + op(1, tensor1.data(), tensor2.data(), 0, 0); + return; + } if (tensor1.ndimension() < 8 && tensor2.ndimension() < 8) { parallel_for( 0, diff --git a/aten/src/ATen/Declarations.cwrap b/aten/src/ATen/Declarations.cwrap index a8afd46e4ad1f..80a9ce00c8d00 100644 --- a/aten/src/ATen/Declarations.cwrap +++ b/aten/src/ATen/Declarations.cwrap @@ -1114,24 +1114,10 @@ - THTensor* self ]] [[ - name: sigmoid_ + name: _th_sigmoid types: - floating_point backends: - - CPU - - CUDA - cname: sigmoid - return: self - arguments: - - THTensor* self - - THTensor* self -]] -[[ - name: sigmoid - types: - - floating_point - backends: - - CPU - CUDA cname: sigmoid variants: diff --git a/aten/src/ATen/cpu/vec256/vec256_base.h b/aten/src/ATen/cpu/vec256/vec256_base.h index 4e119bd79f72a..abdf01d900a3e 100644 --- a/aten/src/ATen/cpu/vec256/vec256_base.h +++ b/aten/src/ATen/cpu/vec256/vec256_base.h @@ -125,6 +125,9 @@ struct Vec256 { Vec256 floor() const { return map(std::floor); } + Vec256 neg() const { + return map([](T x) { return -x; }); + } Vec256 round() const { return map(std::round); } @@ -146,6 +149,9 @@ struct Vec256 { Vec256 sqrt() const { return map(std::sqrt); } + Vec256 reciprocal() const { + return map([](T x) { return (T)(1) / x; }); + } Vec256 rsqrt() const { return map([](T x) { return 1 / std::sqrt(x); }); } diff --git a/aten/src/ATen/cpu/vec256/vec256_double.h b/aten/src/ATen/cpu/vec256/vec256_double.h index c99e4d44ebb8c..60e2be37a4c1d 100644 --- a/aten/src/ATen/cpu/vec256/vec256_double.h +++ b/aten/src/ATen/cpu/vec256/vec256_double.h @@ -121,6 +121,9 @@ template <> class Vec256 { Vec256 floor() const { return _mm256_floor_pd(values); } + Vec256 neg() const { + return _mm256_xor_pd(_mm256_set1_pd(-0.), values); + } Vec256 round() const { return _mm256_round_pd(values, (_MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC)); } @@ -136,6 +139,9 @@ template <> class Vec256 { Vec256 sqrt() const { return _mm256_sqrt_pd(values); } + Vec256 reciprocal() const { + return _mm256_div_pd(_mm256_set1_pd(1), values); + } Vec256 rsqrt() const { return _mm256_div_pd(_mm256_set1_pd(1), _mm256_sqrt_pd(values)); } diff --git a/aten/src/ATen/cpu/vec256/vec256_float.h b/aten/src/ATen/cpu/vec256/vec256_float.h index 492a8cb8a0f33..4851318203809 100644 --- a/aten/src/ATen/cpu/vec256/vec256_float.h +++ b/aten/src/ATen/cpu/vec256/vec256_float.h @@ -126,6 +126,9 @@ template <> class Vec256 { Vec256 floor() const { return _mm256_floor_ps(values); } + Vec256 neg() const { + return _mm256_xor_ps(_mm256_set1_ps(-0.f), values); + } Vec256 round() const { return _mm256_round_ps(values, (_MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC)); } @@ -141,6 +144,9 @@ template <> class Vec256 { Vec256 sqrt() const { return _mm256_sqrt_ps(values); } + Vec256 reciprocal() const { + return _mm256_div_ps(_mm256_set1_ps(1), values); + } Vec256 rsqrt() const { return _mm256_div_ps(_mm256_set1_ps(1), _mm256_sqrt_ps(values)); } diff --git a/aten/src/ATen/cpu/vec256/vec256_int.h b/aten/src/ATen/cpu/vec256/vec256_int.h index cb40a9f9892e8..4c2d88f1cf646 100644 --- a/aten/src/ATen/cpu/vec256/vec256_int.h +++ b/aten/src/ATen/cpu/vec256/vec256_int.h @@ -29,13 +29,13 @@ struct Vec256 : public Vec256i { __at_align32__ int64_t tmp_values[size]; a.store(tmp_values); if (mask & 0x01) - tmp_values[0] = _mm256_extract_epi16(b.values, 0); + tmp_values[0] = _mm256_extract_epi64(b.values, 0); if (mask & 0x02) - tmp_values[1] = _mm256_extract_epi16(b.values, 1); + tmp_values[1] = _mm256_extract_epi64(b.values, 1); if (mask & 0x04) - tmp_values[2] = _mm256_extract_epi16(b.values, 2); + tmp_values[2] = _mm256_extract_epi64(b.values, 2); if (mask & 0x08) - tmp_values[3] = _mm256_extract_epi16(b.values, 3); + tmp_values[3] = _mm256_extract_epi64(b.values, 3); return loadu(tmp_values); } static Vec256 diff --git a/aten/src/ATen/cpu/vml.h b/aten/src/ATen/cpu/vml.h index 2dd55cfa2a460..6424a21c4e1df 100644 --- a/aten/src/ATen/cpu/vml.h +++ b/aten/src/ATen/cpu/vml.h @@ -8,6 +8,21 @@ // This header implements various unary operations using a MKL VML style // interface. +// It implements various functions with a simple interface +// For example it enables the user to call vsin(float* out, const float* in, +// size) This functions takes a pointer to a contious output array of floats and +// a constant input array. It will then apply sin to each value in in the input +// array and write the result into the output array. out and in may point to the +// same memory, i.e. this fully supports in-place operations. These functions +// also implement their own parallelization, so take precautions when calling +// these from threaded functions. + +// When MKL is available it will call into MKL's VML library similar to NumPy +// If MKL is not available it will use SLEEF. + +// This file might be compiled under AVX or AVX2 when called from e.g. +// UnaryOpsKernel.cpp + #include #include #include @@ -16,7 +31,19 @@ #if AT_MKL_ENABLED() && !defined(__APPLE__) #include -#include +#endif + +// [Note SSE-AVX transitions] +// There is a bug in Glibc2.23 +// https://bugs.launchpad.net/ubuntu/+source/glibc/+bug/1663280. Calling zeroall +// when using AVX/AVX2 code resolves this. +#if defined(__AVX__) && defined(__GLIBC__) && __GLIBC_MINOR__ == 23 +#define DL_RUNTIME_BUG(op, type) \ + volatile type x = (type)(1); \ + x = std::op(x); \ + _mm256_zeroall(); +#else +#define DL_RUNTIME_BUG(op, type) #endif namespace at { @@ -40,9 +67,16 @@ inline void vrsqrt(scalar_t* out, scalar_t* in, int64_t size) { // NB: We ignore numerical errors by convention and leave them to the user -#define IMPLEMENT_VML(op) \ +// We unfortunately need to duplicate code here to deal with the SSE-AVX +// transition bug (see [Note SSE-AVX transitions]). As soon as we can expect +// users to use a version of glibc newer than 2.23 we will be able to ditch +// this. This duplication is also necessary since not all functions (e.g. rsqrt) +// might be part of cmath. + +#define IMPLEMENT_VML_BUG(op) \ template \ - inline void v##op(scalar_t* out, scalar_t* in, int64_t size) { \ + inline void v##op(scalar_t* out, const scalar_t* in, int64_t size) { \ + DL_RUNTIME_BUG(op, scalar_t) \ parallel_for(0, size, 2048, [out, in](int64_t begin, int64_t end) { \ map([](const Vec256& x) { return x.op(); }, \ out + begin, \ @@ -51,70 +85,82 @@ inline void vrsqrt(scalar_t* out, scalar_t* in, int64_t size) { }); \ } -#define IMPLEMENT_FLOAT_MKL_VML(op, mklop) \ - template \ - inline void v##op(scalar_t* out, scalar_t* in, int64_t size); \ +#define IMPLEMENT_VML(op) \ + template \ + inline void v##op(scalar_t* out, const scalar_t* in, int64_t size) { \ + parallel_for(0, size, 2048, [out, in](int64_t begin, int64_t end) { \ + map([](const Vec256& x) { return x.op(); }, \ + out + begin, \ + in + begin, \ + end - begin); \ + }); \ + } + +IMPLEMENT_VML_BUG(abs) +IMPLEMENT_VML_BUG(acos) +IMPLEMENT_VML_BUG(asin) +IMPLEMENT_VML_BUG(atan) +IMPLEMENT_VML_BUG(ceil) +IMPLEMENT_VML_BUG(cos) +// IMPLEMENT_VML_BUG(cosh) +IMPLEMENT_VML_BUG(erf) +IMPLEMENT_VML_BUG(exp) +IMPLEMENT_VML_BUG(expm1) +IMPLEMENT_VML_BUG(floor) +IMPLEMENT_VML(reciprocal) +IMPLEMENT_VML_BUG(log) +IMPLEMENT_VML_BUG(log10) +IMPLEMENT_VML_BUG(log1p) +IMPLEMENT_VML_BUG(log2) +IMPLEMENT_VML(neg) +IMPLEMENT_VML_BUG(sin) +// IMPLEMENT_VML_BUG(sinh) +IMPLEMENT_VML_BUG(sqrt) +IMPLEMENT_VML_BUG(round) +IMPLEMENT_VML(rsqrt) +IMPLEMENT_VML_BUG(tan) +IMPLEMENT_VML_BUG(tanh) +IMPLEMENT_VML_BUG(trunc) + +#if AT_MKL_ENABLED() && !defined(__APPLE__) + +#define IMPLEMENT_VML_MKL(op, mklop) \ template <> \ - inline void v##op(float* out, float* in, int64_t size) { \ + inline void v##op(float* out, const float* in, int64_t size) { \ vms##mklop(size, in, out, VML_HA | VML_FTZDAZ_OFF | VML_ERRMODE_IGNORE); \ } \ template <> \ - inline void v##op(double* out, double* in, int64_t size) { \ + inline void v##op(double* out, const double* in, int64_t size) { \ vmd##mklop(size, in, out, VML_HA | VML_FTZDAZ_OFF | VML_ERRMODE_IGNORE); \ } // NB: abs, cosh and sinh were temporarily disabled due to issues with Apple clang -#if AT_MKL_ENABLED() && !defined(__APPLE__) -IMPLEMENT_FLOAT_MKL_VML(acos, Acos) -IMPLEMENT_FLOAT_MKL_VML(asin, Asin) -IMPLEMENT_FLOAT_MKL_VML(atan, Atan) -IMPLEMENT_FLOAT_MKL_VML(cos, Cos) -// IMPLEMENT_FLOAT_MKL_VML(cosh, Cosh) -IMPLEMENT_FLOAT_MKL_VML(erf, Erf) -IMPLEMENT_FLOAT_MKL_VML(exp, Exp) -IMPLEMENT_FLOAT_MKL_VML(expm1, Expm1) -IMPLEMENT_FLOAT_MKL_VML(log, Ln) -IMPLEMENT_FLOAT_MKL_VML(log10, Log10) -IMPLEMENT_FLOAT_MKL_VML(log1p, Log1p) -IMPLEMENT_FLOAT_MKL_VML(sin, Sin) -// IMPLEMENT_FLOAT_MKL_VML(sinh, Sinh) -IMPLEMENT_FLOAT_MKL_VML(sqrt, Sqrt) -IMPLEMENT_FLOAT_MKL_VML(tan, Tan) -IMPLEMENT_FLOAT_MKL_VML(tanh, Tanh) -IMPLEMENT_FLOAT_MKL_VML(trunc, Trunc) +IMPLEMENT_VML_MKL(abs, Abs) +IMPLEMENT_VML_MKL(acos, Acos) +IMPLEMENT_VML_MKL(asin, Asin) +IMPLEMENT_VML_MKL(atan, Atan) +IMPLEMENT_VML_MKL(cos, Cos) +// IMPLEMENT_VML_MKL(cosh, Cosh) +IMPLEMENT_VML_MKL(erf, Erf) +IMPLEMENT_VML_MKL(exp, Exp) +IMPLEMENT_VML_MKL(expm1, Expm1) +IMPLEMENT_VML_MKL(log, Ln) +IMPLEMENT_VML_MKL(log10, Log10) +IMPLEMENT_VML_MKL(log1p, Log1p) +IMPLEMENT_VML_MKL(sin, Sin) +// IMPLEMENT_VML_MKL(sinh, Sinh) +IMPLEMENT_VML_MKL(sqrt, Sqrt) +IMPLEMENT_VML_MKL(tan, Tan) +IMPLEMENT_VML_MKL(tanh, Tanh) +IMPLEMENT_VML_MKL(trunc, Trunc) #if INTEL_MKL_VERSION >= 20180406 -IMPLEMENT_FLOAT_MKL_VML(log2, Log2) -#else -IMPLEMENT_VML(log2) +IMPLEMENT_VML_MKL(log2, Log2) #endif -#else -IMPLEMENT_VML(acos) -IMPLEMENT_VML(asin) -IMPLEMENT_VML(atan) -IMPLEMENT_VML(cos) -// IMPLEMENT_VML(cosh) -IMPLEMENT_VML(erf) -IMPLEMENT_VML(exp) -IMPLEMENT_VML(expm1) -IMPLEMENT_VML(log) -IMPLEMENT_VML(log10) -IMPLEMENT_VML(log1p) -IMPLEMENT_VML(log2) -IMPLEMENT_VML(sin) -// IMPLEMENT_VML(sinh) -IMPLEMENT_VML(sqrt) -IMPLEMENT_VML(tan) -IMPLEMENT_VML(tanh) #endif -IMPLEMENT_VML(ceil) -IMPLEMENT_VML(floor) -IMPLEMENT_VML(round) -IMPLEMENT_VML(trunc) - } // namespace } // namespace vml } // namespace at diff --git a/aten/src/ATen/native/UnaryOps.cpp b/aten/src/ATen/native/UnaryOps.cpp index 125d26be56b08..5960d743ac1f0 100644 --- a/aten/src/ATen/native/UnaryOps.cpp +++ b/aten/src/ATen/native/UnaryOps.cpp @@ -35,7 +35,7 @@ Tensor& fill_(Tensor& self, const Tensor& value) { // NB: If you use this macro, you may also need to add a CUDA forwarding // stub in CUDAUnaryOps -#define IMPLEMENT_UNARY_OP_VEC(op) \ +#define IMPLEMENT_UNARY_OP_VEC(op) \ Tensor op(const Tensor& self) { \ Tensor result = self.type().tensor(); \ return at::op##_out(result, self); \ @@ -87,6 +87,7 @@ IMPLEMENT_UNARY_OP_VEC(log1p) IMPLEMENT_UNARY_OP_VEC(log2) IMPLEMENT_UNARY_OP_VEC(round) IMPLEMENT_UNARY_OP_VEC(rsqrt) +IMPLEMENT_UNARY_OP_VEC(sigmoid) IMPLEMENT_UNARY_OP_VEC(sin) IMPLEMENT_UNARY_OP_TH(sinh) IMPLEMENT_UNARY_OP_VEC(sqrt) diff --git a/aten/src/ATen/native/cpu/CapabilityDispatch.h b/aten/src/ATen/native/cpu/CapabilityDispatch.h index fb72450bf4ad3..6cb0f279872d6 100644 --- a/aten/src/ATen/native/cpu/CapabilityDispatch.h +++ b/aten/src/ATen/native/cpu/CapabilityDispatch.h @@ -48,7 +48,8 @@ struct DispatchStub { #ifndef __powerpc__ if (cpuinfo_initialize()) { int avx2 = static_cast(CPUCapability::AVX2); - if (!std::getenv("ATEN_DISABLE_AVX2") && cpuinfo_has_x86_avx2() && table[avx2]) { + if (!std::getenv("ATEN_DISABLE_AVX2") && cpuinfo_has_x86_avx2() && + cpuinfo_has_x86_fma3() && table[avx2]) { return table[avx2]; } int avx = static_cast(CPUCapability::AVX); diff --git a/aten/src/ATen/native/cpu/UnaryOpsKernel.cpp b/aten/src/ATen/native/cpu/UnaryOpsKernel.cpp index 434975e027d74..e34d7ad161c9b 100644 --- a/aten/src/ATen/native/cpu/UnaryOpsKernel.cpp +++ b/aten/src/ATen/native/cpu/UnaryOpsKernel.cpp @@ -5,15 +5,106 @@ #include "ATen/cpu/vml.h" #include "ATen/CPUApplyUtils.h" #include "ATen/native/cpu/CapabilityDispatch.h" +#ifdef __AVX2__ +#include "ATen/native/cpu/avx_mathfun.h" +#endif namespace at { namespace native { namespace { using namespace vec256; +template +static int64_t _sigmoid(scalar_t* x, scalar_t* y, int64_t size); + +// This should be a temporary solution until we understand why SLEEF is slower +// for sigmoid + +template <> +int64_t _sigmoid(float* x, float* y, int64_t size) { + using Vec = Vec256; + int64_t i = 0; + for (; i < size - (size % (2 * Vec::size)); i += 2 * Vec::size) { + Vec ret = Vec::loadu(y + i); + Vec ret2 = Vec::loadu(y + i + Vec::size); + ret = ret.neg(); + ret2 = ret2.neg(); +#if defined(__AVX2__) && !defined(_MSC_VER) + ret.values = exp256_ps(ret.values); + ret2.values = exp256_ps(ret2.values); +#else + ret = ret.exp(); + ret2 = ret2.exp(); +#endif + ret = Vec((float)(1)) + ret; + ret2 = Vec((float)(1)) + ret2; + ret = ret.reciprocal(); + ret2 = ret2.reciprocal(); + ret.store(x + i); + ret2.store(x + i + Vec::size); + } + return i; +} + +template <> +int64_t _sigmoid(double* x, double* y, int64_t size) { + using Vec = Vec256; + int64_t i = 0; + for (; i < size - (size % (2 * Vec::size)); i += 2 * Vec::size) { + Vec ret = Vec::loadu(y + i); + Vec ret2 = Vec::loadu(y + i + Vec::size); + ret = ret.neg(); + ret2 = ret2.neg(); + ret = ret.exp(); + ret2 = ret2.exp(); + ret = Vec((double)(1)) + ret; + ret2 = Vec((double)(1)) + ret2; + ret = ret.reciprocal(); + ret2 = ret2.reciprocal(); + ret.store(x + i); + ret2.store(x + i + Vec::size); + } + return i; +} + +static void sigmoid_kernel(Tensor& result, const Tensor& self) { + AT_DISPATCH_FLOATING_TYPES(self.type(), "sigmoid", [&] { + using Vec = Vec256; + CPU_tensor_parallel_kernel_apply2( + result, + self, + [](int64_t size, + scalar_t* x, + scalar_t* y, + int64_t stridex, + int64_t stridey) { + int64_t i = 0; + if (stridex == 1 && stridey == 1) { + i = _sigmoid(x, y, size); + } + for (; i < size; i += Vec::size) { + scalar_t buffer[Vec::size]; + int64_t width = Vec::size; + width = std::min(width, size - i); + for (int64_t j = 0; j < width; j++) { + buffer[j] = y[stridey * (i + j)]; + } + Vec ret = Vec::loadu(buffer); + ret = Vec((scalar_t)(0)) - ret; + ret = ret.exp(); + ret = Vec((scalar_t)(1)) + ret; + ret = ret.reciprocal(); + ret.store(buffer); + for (int64_t j = 0; j < width; j++) + x[stridex * (i + j)] = buffer[j]; + } + }); + }); +} + #define IMPLEMENT_FLOAT_KERNEL(dispatchtypes, op) \ static void op##_kernel(Tensor& result, const Tensor& self) { \ - AT_DISPATCH_##dispatchtypes##_TYPES(self.type(), #op, [&] { \ + AT_DISPATCH_##dispatchtypes##_TYPES(self.type(), #op, [&] { \ if (self.is_contiguous() && result.is_contiguous()) { \ vml::v##op( \ result.data(), self.data(), self.numel()); \ @@ -50,6 +141,8 @@ using namespace vec256; } // anonymous namespace +REGISTER_DISPATCH(sigmoidImpl, &sigmoid_kernel) + // IMPLEMENT_FLOAT_KERNEL(ALL, abs) IMPLEMENT_FLOAT_KERNEL(FLOATING, acos) IMPLEMENT_FLOAT_KERNEL(FLOATING, asin) diff --git a/aten/src/ATen/native/cpu/UnaryOpsKernel.h b/aten/src/ATen/native/cpu/UnaryOpsKernel.h index 252d53aeaf76e..da23e675c1daa 100644 --- a/aten/src/ATen/native/cpu/UnaryOpsKernel.h +++ b/aten/src/ATen/native/cpu/UnaryOpsKernel.h @@ -25,6 +25,7 @@ extern DispatchStub log1pImpl; extern DispatchStub log2Impl; extern DispatchStub roundImpl; extern DispatchStub rsqrtImpl; +extern DispatchStub sigmoidImpl; extern DispatchStub sinImpl; // extern DispatchStub sinhImpl; extern DispatchStub sqrtImpl; diff --git a/aten/src/ATen/native/cuda/CUDAUnaryOps.cpp b/aten/src/ATen/native/cuda/CUDAUnaryOps.cpp index cfbae42e54452..87b1f0a1df771 100644 --- a/aten/src/ATen/native/cuda/CUDAUnaryOps.cpp +++ b/aten/src/ATen/native/cuda/CUDAUnaryOps.cpp @@ -12,6 +12,7 @@ namespace at { namespace native { return at::_##op##_out(result, self); \ } + IMPLEMENT_UNARY_OP_PREQUEL(abs) IMPLEMENT_UNARY_OP_PREQUEL(acos) IMPLEMENT_UNARY_OP_PREQUEL(asin) @@ -28,18 +29,13 @@ IMPLEMENT_UNARY_OP_PREQUEL(log10) IMPLEMENT_UNARY_OP_PREQUEL(log1p) IMPLEMENT_UNARY_OP_PREQUEL(log2) IMPLEMENT_UNARY_OP_PREQUEL(round) +IMPLEMENT_UNARY_OP_PREQUEL(rsqrt) +IMPLEMENT_UNARY_OP_PREQUEL(sigmoid) IMPLEMENT_UNARY_OP_PREQUEL(sin) IMPLEMENT_UNARY_OP_PREQUEL(sinh) IMPLEMENT_UNARY_OP_PREQUEL(sqrt) -IMPLEMENT_UNARY_OP_PREQUEL(rsqrt) IMPLEMENT_UNARY_OP_PREQUEL(tan) +IMPLEMENT_UNARY_OP_PREQUEL(tanh) IMPLEMENT_UNARY_OP_PREQUEL(trunc) -Tensor& _tanh__cuda(Tensor& self) { - return at::_th_tanh_out(self, self); -} -Tensor& _tanh_out_cuda(Tensor& result, const Tensor& self) { - return at::_th_tanh_out(result, self); -} - }} diff --git a/aten/src/ATen/native/native_functions.yaml b/aten/src/ATen/native/native_functions.yaml index 7c9c546c4ea2b..1a2206a7f148a 100644 --- a/aten/src/ATen/native/native_functions.yaml +++ b/aten/src/ATen/native/native_functions.yaml @@ -1146,6 +1146,19 @@ - func: selu_(Tensor self) -> Tensor variants: function +- func: sigmoid(Tensor self) -> Tensor + +- func: sigmoid_(Tensor self) -> Tensor + dispatch: + CPU: _sigmoid__cpu + CUDA: _sigmoid__cuda + +- func: sigmoid_out(Tensor result, Tensor self) -> Tensor + variants: function + dispatch: + CPU: _sigmoid_out_cpu + CUDA: _sigmoid_out_cuda + - func: sin(Tensor self) -> Tensor - func: sin_(Tensor self) -> Tensor diff --git a/cmake/Codegen.cmake b/cmake/Codegen.cmake index e7bf1ff7d5563..bc30f35f2a2ee 100644 --- a/cmake/Codegen.cmake +++ b/cmake/Codegen.cmake @@ -83,7 +83,7 @@ if (BUILD_ATEN) IF(MSVC) LIST(APPEND CPU_CAPABILITY_FLAGS "${MSVC_OPT_FLAG}/arch:AVX2") ELSE(MSVC) - LIST(APPEND CPU_CAPABILITY_FLAGS "-O3 -mavx2") + LIST(APPEND CPU_CAPABILITY_FLAGS "-O3 -mavx2 -mfma") ENDIF(MSVC) ENDIF(CXX_AVX2_FOUND) From 0a679105ff93b0a6586258f521c3542e9e676df9 Mon Sep 17 00:00:00 2001 From: Zachary DeVito Date: Tue, 10 Jul 2018 13:26:18 -0700 Subject: [PATCH 06/36] Fix missing accept file changes Summary: Pull Request resolved: https://github.com/pytorch/pytorch/pull/9313 Reviewed By: ezyang Differential Revision: D8789043 Pulled By: zdevito fbshipit-source-id: 283607116c49a4f3a82658d9b4d45f5df3ae283b --- ...test_call_script_mod_from_script_fn.expect | 22 +++++++++++++------ .../TestScript.test_math_numbers-float.expect | 14 +++++++----- .../TestScript.test_math_numbers-int.expect | 14 +++++++----- test/expect/TestScript.test_sum-1.expect | 8 +++++-- test/expect/TestScript.test_sum-2.expect | 8 +++++-- 5 files changed, 43 insertions(+), 23 deletions(-) diff --git a/test/expect/TestScript.test_call_script_mod_from_script_fn.expect b/test/expect/TestScript.test_call_script_mod_from_script_fn.expect index f67fb0073a22f..e3008f4e24634 100644 --- a/test/expect/TestScript.test_call_script_mod_from_script_fn.expect +++ b/test/expect/TestScript.test_call_script_mod_from_script_fn.expect @@ -1,9 +1,17 @@ graph(%x : Dynamic) { - %1 : Dynamic = aten::zeros[size=[4, 3], dtype=6, layout=0, device=[0, -1]]() - %2 : Dynamic = aten::mm(%x, %1) - %3 : int = prim::Constant[value={1}]() - %4 : Dynamic = prim::NumToTensor(%3) - %5 : Dynamic = aten::type_as(%4, %2) - %7 : Dynamic = aten::add[alpha={1}](%2, %5) - return (%7); + %1 : int = prim::Constant[value={4}]() + %2 : int = prim::Constant[value={3}]() + %3 : int = prim::Constant[value={6}]() + %4 : int = prim::Constant[value={0}]() + %5 : int[] = prim::Constant[value= 0 -1 [ CPULongTensor{2} ]]() + %6 : Dynamic = prim::NumToTensor(%1) + %7 : Dynamic = prim::NumToTensor(%2) + %8 : int[] = aten::stack[dim=0](%6, %7) + %9 : Dynamic = aten::zeros(%8, %3, %4, %5) + %10 : Dynamic = aten::mm(%x, %9) + %11 : int = prim::Constant[value={1}]() + %12 : Dynamic = prim::NumToTensor(%11) + %13 : Dynamic = aten::type_as(%12, %10) + %15 : Dynamic = aten::add[alpha={1}](%10, %13) + return (%15); } diff --git a/test/expect/TestScript.test_math_numbers-float.expect b/test/expect/TestScript.test_math_numbers-float.expect index 4f4a7eddc1a16..67ea8b4c5eb39 100644 --- a/test/expect/TestScript.test_math_numbers-float.expect +++ b/test/expect/TestScript.test_math_numbers-float.expect @@ -5,10 +5,12 @@ graph(%x : Dynamic) { %4 : Dynamic = prim::NumToTensor(%2) %5 : Dynamic = aten::add[alpha={1}](%3, %4) %c : float = prim::TensorToNum(%5) - %7 : int = prim::Constant[value={6}]() - %8 : int = prim::Constant[value={0}]() - %9 : int[] = prim::Constant[value= 0 -1 [ CPULongTensor{2} ]]() - %10 : int[] = prim::Constant[value={1}]() - %11 : Dynamic = aten::full(%10, %c, %7, %8, %9) - return (%11); + %7 : int = prim::Constant[value={1}]() + %8 : int = prim::Constant[value={6}]() + %9 : int = prim::Constant[value={0}]() + %10 : int[] = prim::Constant[value= 0 -1 [ CPULongTensor{2} ]]() + %11 : Dynamic = prim::NumToTensor(%7) + %12 : int[] = aten::stack[dim=0](%11) + %13 : Dynamic = aten::full(%12, %c, %8, %9, %10) + return (%13); } diff --git a/test/expect/TestScript.test_math_numbers-int.expect b/test/expect/TestScript.test_math_numbers-int.expect index d3d43b8bfd3ad..9f028597ca071 100644 --- a/test/expect/TestScript.test_math_numbers-int.expect +++ b/test/expect/TestScript.test_math_numbers-int.expect @@ -5,10 +5,12 @@ graph(%x : Dynamic) { %4 : Dynamic = prim::NumToTensor(%2) %5 : Dynamic = aten::add[alpha={1}](%3, %4) %c : int = prim::TensorToNum(%5) - %7 : int = prim::Constant[value={6}]() - %8 : int = prim::Constant[value={0}]() - %9 : int[] = prim::Constant[value= 0 -1 [ CPULongTensor{2} ]]() - %10 : int[] = prim::Constant[value={1}]() - %11 : Dynamic = aten::full(%10, %c, %7, %8, %9) - return (%11); + %7 : int = prim::Constant[value={1}]() + %8 : int = prim::Constant[value={6}]() + %9 : int = prim::Constant[value={0}]() + %10 : int[] = prim::Constant[value= 0 -1 [ CPULongTensor{2} ]]() + %11 : Dynamic = prim::NumToTensor(%7) + %12 : int[] = aten::stack[dim=0](%11) + %13 : Dynamic = aten::full(%12, %c, %8, %9, %10) + return (%13); } diff --git a/test/expect/TestScript.test_sum-1.expect b/test/expect/TestScript.test_sum-1.expect index 5b87ae8a0e5f3..8e165369778fe 100644 --- a/test/expect/TestScript.test_sum-1.expect +++ b/test/expect/TestScript.test_sum-1.expect @@ -1,4 +1,8 @@ graph(%x : Dynamic) { - %1 : Dynamic = aten::sum[dim=[4], keepdim=0](%x) - return (%1); + %1 : int = prim::Constant[value={4}]() + %2 : int = prim::Constant[value={0}]() + %3 : Dynamic = prim::NumToTensor(%1) + %4 : int[] = aten::stack[dim=0](%3) + %5 : Dynamic = aten::sum(%x, %4, %2) + return (%5); } diff --git a/test/expect/TestScript.test_sum-2.expect b/test/expect/TestScript.test_sum-2.expect index f556ba434d0bd..dece8c4d7cc0b 100644 --- a/test/expect/TestScript.test_sum-2.expect +++ b/test/expect/TestScript.test_sum-2.expect @@ -1,4 +1,8 @@ graph(%x : Double(1, 1, 1, 1, 4)) { - %1 : Double(1, 1, 1, 1) = aten::sum[dim=[4], keepdim=0](%x) - return (%1); + %1 : Long() = prim::Constant[value={4}]() + %2 : Long() = prim::Constant[value={0}]() + %3 : Long() = prim::NumToTensor(%1) + %4 : Dynamic = aten::stack[dim=0](%3) + %5 : Dynamic = aten::sum(%x, %4, %2) + return (%5); } From ea1869244ff84b256dd1f0b4de20fb604ec92bec Mon Sep 17 00:00:00 2001 From: Keren Zhou Date: Tue, 10 Jul 2018 14:16:27 -0700 Subject: [PATCH 07/36] Change depthwise convolution bandwidth formula (#9317) Summary: Pull Request resolved: https://github.com/pytorch/pytorch/pull/9317 Change depthwise convolution bandwidth formula Reviewed By: hlu1 Differential Revision: D8786684 fbshipit-source-id: ba76fea94a6d2fda8d87f40dd626b3dfd90770ed --- caffe2/mobile/contrib/nnapi/nnapi_benchmark.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/caffe2/mobile/contrib/nnapi/nnapi_benchmark.cc b/caffe2/mobile/contrib/nnapi/nnapi_benchmark.cc index 46798f2e3b28d..db0e867aa07ce 100644 --- a/caffe2/mobile/contrib/nnapi/nnapi_benchmark.cc +++ b/caffe2/mobile/contrib/nnapi/nnapi_benchmark.cc @@ -445,7 +445,9 @@ int main(int argc, char** argv) { warmup, mainrun); const double dwise_bandwidth = sizeof(float) * double(channel) * - (2 * (space - 2) * (space - 2) + kernel * kernel); + (space * space + kernel == 1 + ? space * space + : (space - 2) * (space - 2) + kernel * kernel); printf( "Conv: X: %ix%i \tC: %i -> %i\tK: %ix%i\t32b" "Caffe2 Dwise GB/s: %.2f\t32b" From a47a30b9ce4e515358bb2a53c540a45b04108ad6 Mon Sep 17 00:00:00 2001 From: Roy Li Date: Tue, 10 Jul 2018 15:05:10 -0700 Subject: [PATCH 08/36] Implement grid_sampler in aten (#8929) Summary: Partially addresses #8928. Maybe #7273? Pull Request resolved: https://github.com/pytorch/pytorch/pull/8929 Reviewed By: ezyang Differential Revision: D8668919 Pulled By: li-roy fbshipit-source-id: 8ad07b224d2ab211c274c4c10f042501efaae32c --- aten/src/ATen/native/Vision.cpp | 28 ++++++++++ aten/src/ATen/native/native_functions.yaml | 3 + aten/src/ATen/nn.yaml | 8 +++ aten/src/ATen/nn_parse.py | 2 +- test/test_nn.py | 7 +++ tools/autograd/derivatives.yaml | 6 ++ torch/nn/_functions/vision.py | 65 ---------------------- torch/nn/functional.py | 12 +++- 8 files changed, 64 insertions(+), 67 deletions(-) create mode 100644 aten/src/ATen/native/Vision.cpp diff --git a/aten/src/ATen/native/Vision.cpp b/aten/src/ATen/native/Vision.cpp new file mode 100644 index 0000000000000..458e9aca23f0f --- /dev/null +++ b/aten/src/ATen/native/Vision.cpp @@ -0,0 +1,28 @@ +#include "ATen/ATen.h" +#include "ATen/NativeFunctions.h" +#include "ATen/detail/CUDAHooksInterface.h" + +namespace { + enum GridSamplerMode {GridSamplerModeZeros, GridSamplerModeBorder}; +} + +namespace at { namespace native { + +Tensor grid_sampler(const Tensor& input, const Tensor& grid, int64_t padding_mode) { + // cudnn does not support inputs larger than 1024 + if (at::native::cudnn_is_acceptable(input) && + padding_mode == GridSamplerModeZeros && + input.dim() == 4 && + input.size(1) <= 1024) { + return cudnn_grid_sampler(input, grid); + } + if (input.dim() == 4) { + return thnn_grid_sampler_bilinear2d(input, grid, padding_mode); + } + if (input.dim() == 5) { + return thnn_grid_sampler_bilinear3d(input, grid, padding_mode); + } + AT_ERROR("grid_sampler(): input must be 4d or 5d but got input of shape: ", input.dim()); +} + +}} // namespace at::native diff --git a/aten/src/ATen/native/native_functions.yaml b/aten/src/ATen/native/native_functions.yaml index 1a2206a7f148a..d3a226fad3d15 100644 --- a/aten/src/ATen/native/native_functions.yaml +++ b/aten/src/ATen/native/native_functions.yaml @@ -621,6 +621,9 @@ variants: function deprecated: true +- func: grid_sampler(Tensor input, Tensor grid, int64_t padding_mode) -> Tensor + variants: function + - func: hann_window(int64_t window_length, TensorOptions options={}) -> Tensor variants: function diff --git a/aten/src/ATen/nn.yaml b/aten/src/ATen/nn.yaml index a57b7d94b3d64..45907776a8be0 100644 --- a/aten/src/ATen/nn.yaml +++ b/aten/src/ATen/nn.yaml @@ -274,3 +274,11 @@ - name: thnn_conv_dilated3d(Tensor self, Tensor weight, IntList[3] kernel_size, Tensor bias={}, IntList[3] stride=1, IntList[3] padding=0, IntList[3] dilation=1) cname: VolumetricDilatedConvolution buffers: [columns, ones] + +# Vision + +- name: thnn_grid_sampler_bilinear2d(Tensor self, Tensor grid, int64_t padding_mode) + cname: SpatialGridSamplerBilinear + +- name: thnn_grid_sampler_bilinear3d(Tensor self, Tensor grid, int64_t padding_mode) + cname: VolumetricGridSamplerBilinear diff --git a/aten/src/ATen/nn_parse.py b/aten/src/ATen/nn_parse.py index 9070c23779672..d3e46f8e9b85a 100644 --- a/aten/src/ATen/nn_parse.py +++ b/aten/src/ATen/nn_parse.py @@ -66,7 +66,7 @@ def map_to_th_type(t): def is_output_arg(arg_name, func_name): if arg_name == 'output' and 'updateOutput' in cname: return True - if name in {'gradInput', 'gradWeight', 'gradBias'}: + if name in {'gradInput', 'gradWeight', 'gradBias', 'gradGrid'}: return True if arg_name == 'indices' and 'updateOutput' in cname and 'Unpool' not in cname: # indices is an output argument in pooling and an input in unpooling diff --git a/test/test_nn.py b/test/test_nn.py index d3c673f37391c..c2661c68654c4 100644 --- a/test/test_nn.py +++ b/test/test_nn.py @@ -4740,6 +4740,13 @@ def test_shape(N, C, IH, IW, H, W, padding_mode): if TEST_CUDA: test_cpu_against_cuda(N, C, H, W, padding_mode) + # test channels >1024, which doesn't work on cudnn 7102 and further + N, C, H, W = 1, 1025, 3, 3 + self.assertTrue(gradcheck( + lambda inp, grid: F.grid_sample(inp, grid, padding_mode=padding_mode), + (input, grid))) + test_cpu_against_cuda(N, C, H, W, padding_mode) + def test_grid_sample_3d(self): def test_cpu_against_cuda(N, C, D, H, W, padding_mode): def test_shape(N, C, ID, IH, IW, D, H, W, padding_mode): diff --git a/tools/autograd/derivatives.yaml b/tools/autograd/derivatives.yaml index 9bab6c5c2fb8d..7387703062750 100644 --- a/tools/autograd/derivatives.yaml +++ b/tools/autograd/derivatives.yaml @@ -978,6 +978,12 @@ - name: thnn_conv_dilated3d_backward(Tensor grad_output, Tensor self, Tensor weight, IntList kernel_size, IntList stride, IntList padding, IntList dilation, Tensor columns, Tensor ones, std::array output_mask) grad_output, self, weight: _convolution_double_backward(grads[0], grads[1], grads[2], grad_output, weight, self, stride, padding, dilation, false, {{0, 0, 0}}, 1, false, false, false, grad_input_mask) +- name: thnn_grid_sampler_bilinear2d_forward(Tensor self, Tensor grid, int64_t padding_mode) + self, grid: thnn_grid_sampler_bilinear2d_backward(grad, self, grid, padding_mode) + +- name: thnn_grid_sampler_bilinear3d_forward(Tensor self, Tensor grid, int64_t padding_mode) + self, grid: thnn_grid_sampler_bilinear3d_backward(grad, self, grid, padding_mode) + # NN double backwards support - name: adaptive_avg_pool2d_backward(Tensor grad_output, Tensor self) diff --git a/torch/nn/_functions/vision.py b/torch/nn/_functions/vision.py index 7331b4a263fc0..0ccf0ba461027 100644 --- a/torch/nn/_functions/vision.py +++ b/torch/nn/_functions/vision.py @@ -5,19 +5,6 @@ from .thnn.auto import function_by_name import torch.backends.cudnn as cudnn -MODE_ZEROS = 0 -MODE_BORDER = 1 - - -def grid_sampler(input, grid, padding_mode): - if cudnn.is_acceptable(input.data) \ - and padding_mode == 'zeros' \ - and input.dim() == 4 \ - and input.size(1) <= 1024: # as of cudnn 7102, will not work for larger than 1024 - return torch.cudnn_grid_sampler(input, grid) - else: - return GridSampler.apply(input, grid, padding_mode) - def affine_grid_generator(theta, size): if theta.data.is_cuda: @@ -35,58 +22,6 @@ def affine_grid_generator(theta, size): # TODO: Port these completely into C++ -class GridSampler(Function): - - @staticmethod - def forward(ctx, input, grid, padding_mode='zeros'): - ctx.save_for_backward(input, grid) - - if input.device != grid.device: - raise RuntimeError(("input (device {}) and grid (device {}) must be on the same device" + - "for grid_sampler").format(input.device, grid.device)) - if padding_mode == 'zeros': - ctx.padding_mode = MODE_ZEROS - elif padding_mode == 'border': - ctx.padding_mode = MODE_BORDER - else: - raise ValueError("padding_mode needs to be 'zeros' or 'border', but got {}".format(padding_mode)) - - grid_sz = grid.size() - backend = type2backend[input.type()] - if input.dim() == 4: - output = input.new(grid_sz[0], input.size(1), grid_sz[1], grid_sz[2]) - backend.SpatialGridSamplerBilinear_updateOutput(backend.library_state, input, grid, - output, ctx.padding_mode) - elif input.dim() == 5: - output = input.new(grid_sz[0], input.size(1), grid_sz[1], grid_sz[2], grid_sz[3]) - backend.VolumetricGridSamplerBilinear_updateOutput(backend.library_state, input, grid, - output, ctx.padding_mode) - else: - raise ValueError("input has to be 4d or 5d but got input of shape: {}".format(input.shape)) - return output - - @staticmethod - @once_differentiable - def backward(ctx, grad_output): - input, grid = ctx.saved_tensors - padding_mode = ctx.padding_mode - - backend = type2backend[input.type()] - grad_input = input.new(input.size()) - grad_grid = grid.new(grid.size()) - if input.dim() == 4: - backend.SpatialGridSamplerBilinear_updateGradInput( - backend.library_state, input, grad_input, - grid, grad_grid, grad_output, padding_mode) - elif input.dim() == 5: - backend.VolumetricGridSamplerBilinear_updateGradInput( - backend.library_state, input, grad_input, - grid, grad_grid, grad_output, padding_mode) - else: - raise ValueError("input has to be 4d or 5d but got input of shape: {}".format(input.shape)) - return grad_input, grad_grid, None - - class AffineGridGenerator(Function): @staticmethod diff --git a/torch/nn/functional.py b/torch/nn/functional.py index 4727b44dbc9bc..3de3a00cbd02a 100644 --- a/torch/nn/functional.py +++ b/torch/nn/functional.py @@ -2058,6 +2058,10 @@ def upsample_bilinear(input, size=None, scale_factor=None): return interpolate(input, size, scale_factor, mode='bilinear', align_corners=True) +GRID_SAMPLE_MODE_ZEROS = 0 +GRID_SAMPLE_MODE_BORDER = 1 + + def grid_sample(input, grid, mode='bilinear', padding_mode='zeros'): r"""Given an :attr:`input` and a flow-field :attr:`grid`, computes the `output` using input pixel locations from the grid. @@ -2099,7 +2103,13 @@ def grid_sample(input, grid, mode='bilinear', padding_mode='zeros'): """ if mode != 'bilinear': raise NotImplementedError("nn.functional.grid_sample got unsupported mode: '{}'".format(mode)) - return vision.grid_sampler(input, grid, padding_mode) + if padding_mode == 'zeros': + padding_mode = GRID_SAMPLE_MODE_ZEROS + elif padding_mode == 'border': + padding_mode = GRID_SAMPLE_MODE_BORDER + else: + raise ValueError("padding_mode needs to be 'zeros' or 'border', but got {}".format(padding_mode)) + return torch.grid_sampler(input, grid, padding_mode) def affine_grid(theta, size): From b4c66459c5d59a38cbce2f13396215c2d94c5551 Mon Sep 17 00:00:00 2001 From: Johannes M Dieterich Date: Tue, 10 Jul 2018 17:52:45 -0700 Subject: [PATCH 09/36] Add pyHIPIFY scripts needed for ROCm transpilation to PyTorch (#8812) Summary: As discussed in call, this will allow us to keep this integral part of the effort to run PyTorch on ROCm in sync with the main code. Pull Request resolved: https://github.com/pytorch/pytorch/pull/8812 Reviewed By: ezyang Differential Revision: D8796245 Pulled By: bddppq fbshipit-source-id: 8e12c2acf6a7e0740f31b21e50be74e10ed8b12c --- .jenkins/pytorch/build.sh | 5 - caffe2/requirements.txt | 1 + tools/amd_build/build_pytorch_amd.py | 2 +- tools/amd_build/pyHIPIFY/constants.py | 47 + .../pyHIPIFY/cuda_to_hip_mappings.py | 2098 +++++++++++++++++ tools/amd_build/pyHIPIFY/hipify-python.py | 975 ++++++++ tox.ini | 2 +- 7 files changed, 3123 insertions(+), 7 deletions(-) create mode 100644 tools/amd_build/pyHIPIFY/constants.py create mode 100644 tools/amd_build/pyHIPIFY/cuda_to_hip_mappings.py create mode 100755 tools/amd_build/pyHIPIFY/hipify-python.py diff --git a/.jenkins/pytorch/build.sh b/.jenkins/pytorch/build.sh index 7addd5b577081..bb06df22868ea 100755 --- a/.jenkins/pytorch/build.sh +++ b/.jenkins/pytorch/build.sh @@ -34,11 +34,6 @@ if [[ "$BUILD_ENVIRONMENT" == *rocm* ]]; then export LANG=C.UTF-8 export LC_ALL=C.UTF-8 - # TODO: Install pyHIPIFY in the docker image - rm -rf pyHIPIFY || true - git clone https://github.com/ROCm-Developer-Tools/pyHIPIFY.git - chmod a+x pyHIPIFY/*.py - sudo cp -p pyHIPIFY/*.py /opt/rocm/bin sudo chown -R jenkins:jenkins /usr/local rm -rf "$(dirname "${BASH_SOURCE[0]}")/../../../pytorch_amd/" || true python "$(dirname "${BASH_SOURCE[0]}")/../../tools/amd_build/build_pytorch_amd.py" diff --git a/caffe2/requirements.txt b/caffe2/requirements.txt index 24ce15ab7ead3..9a1d67efc7c2f 100644 --- a/caffe2/requirements.txt +++ b/caffe2/requirements.txt @@ -1 +1,2 @@ numpy +enum34 diff --git a/tools/amd_build/build_pytorch_amd.py b/tools/amd_build/build_pytorch_amd.py index 3ef1c4f3b4c45..52a04acbe5d4b 100644 --- a/tools/amd_build/build_pytorch_amd.py +++ b/tools/amd_build/build_pytorch_amd.py @@ -64,4 +64,4 @@ args = ["--project-directory", proj_dir, "--output-directory", proj_dir, "--include-dirs"] + include_dirs + ["--yaml-settings", yaml_file, "--add-static-casts", "True"] -os.execv("/opt/rocm/bin/hipify-python.py", ['python'] + args) +os.execv(os.path.join(amd_build_dir, "pyHIPIFY", "hipify-python.py"), ['python'] + args) diff --git a/tools/amd_build/pyHIPIFY/constants.py b/tools/amd_build/pyHIPIFY/constants.py new file mode 100644 index 0000000000000..c67a332fe4f4d --- /dev/null +++ b/tools/amd_build/pyHIPIFY/constants.py @@ -0,0 +1,47 @@ +CONV_VERSION = 0, +CONV_INIT = 1 +CONV_DEVICE = 2 +CONV_MEM = 3 +CONV_KERN = 4 +CONV_COORD_FUNC = 5 +CONV_MATH_FUNC = 6 +CONV_DEVICE_FUNC = 7 +CONV_SPECIAL_FUNC = 8 +CONV_STREAM = 9 +CONV_EVENT = 10 +CONV_OCCUPANCY = 11 +CONV_CONTEXT = 12 +CONV_PEER = 13 +CONV_MODULE = 14 +CONV_CACHE = 15 +CONV_EXEC = 16 +CONV_ERROR = 17 +CONV_DEF = 18 +CONV_TEX = 19 +CONV_GL = 20 +CONV_GRAPHICS = 21 +CONV_SURFACE = 22 +CONV_JIT = 23 +CONV_D3D9 = 24 +CONV_D3D10 = 25 +CONV_D3D11 = 26 +CONV_VDPAU = 27 +CONV_EGL = 28 +CONV_THREAD = 29 +CONV_OTHER = 30 +CONV_INCLUDE = 31 +CONV_INCLUDE_CUDA_MAIN_H = 32 +CONV_TYPE = 33 +CONV_LITERAL = 34 +CONV_NUMERIC_LITERAL = 35 +CONV_LAST = 36 + +API_DRIVER = 37 +API_RUNTIME = 38 +API_BLAS = 39 +API_SPARSE = 40 +API_RAND = 41 +API_LAST = 42 + +HIP_UNSUPPORTED = 43 +API_PYTORCH = 1337 diff --git a/tools/amd_build/pyHIPIFY/cuda_to_hip_mappings.py b/tools/amd_build/pyHIPIFY/cuda_to_hip_mappings.py new file mode 100644 index 0000000000000..7a9be64cf6bb5 --- /dev/null +++ b/tools/amd_build/pyHIPIFY/cuda_to_hip_mappings.py @@ -0,0 +1,2098 @@ +from constants import * + +CUDA_TYPE_NAME_MAP = { + "CUresult": ("hipError_t", CONV_TYPE, API_DRIVER), + "cudaError_t": ("hipError_t", CONV_TYPE, API_RUNTIME), + "cudaError": ("hipError_t", CONV_TYPE, API_RUNTIME), + "CUDA_ARRAY3D_DESCRIPTOR": ("HIP_ARRAY3D_DESCRIPTOR", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CUDA_ARRAY_DESCRIPTOR": ("HIP_ARRAY_DESCRIPTOR", CONV_TYPE, API_DRIVER), + "CUDA_MEMCPY2D": ("hip_Memcpy2D", CONV_TYPE, API_DRIVER), + "CUDA_MEMCPY3D": ("HIP_MEMCPY3D", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CUDA_MEMCPY3D_PEER": ("HIP_MEMCPY3D_PEER", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CUDA_POINTER_ATTRIBUTE_P2P_TOKENS": ("HIP_POINTER_ATTRIBUTE_P2P_TOKENS", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CUDA_RESOURCE_DESC": ("HIP_RESOURCE_DESC", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CUDA_RESOURCE_VIEW_DESC": ("HIP_RESOURCE_VIEW_DESC", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CUipcEventHandle": ("hipIpcEventHandle", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CUipcMemHandle": ("hipIpcMemHandle", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CUaddress_mode": ("hipAddress_mode", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CUarray_cubemap_face": ("hipArray_cubemap_face", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CUarray_format": ("hipArray_format", CONV_TYPE, API_DRIVER), + "CUcomputemode": ("hipComputemode", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CUmem_advise": ("hipMemAdvise", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CUmem_range_attribute": ("hipMemRangeAttribute", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CUctx_flags": ("hipCctx_flags", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CUdevice": ("hipDevice_t", CONV_TYPE, API_DRIVER), + "CUdevice_attribute_enum": ("hipDeviceAttribute_t", CONV_TYPE, API_DRIVER), + "CUdevice_attribute": ("hipDeviceAttribute_t", CONV_TYPE, API_DRIVER), + "CUdeviceptr": ("hipDeviceptr_t", CONV_TYPE, API_DRIVER), + "CUarray_st": ("hipArray", CONV_TYPE, API_DRIVER), + "CUarray": ("hipArray *", CONV_TYPE, API_DRIVER), + "CUdevprop_st": ("hipDeviceProp_t", CONV_TYPE, API_DRIVER), + "CUdevprop": ("hipDeviceProp_t", CONV_TYPE, API_DRIVER), + "CUfunction": ("hipFunction_t", CONV_TYPE, API_DRIVER), + "CUgraphicsResource": ("hipGraphicsResource_t", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CUmipmappedArray": ("hipMipmappedArray_t", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CUfunction_attribute": ("hipFuncAttribute_t", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CUfunction_attribute_enum": ("hipFuncAttribute_t", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CUgraphicsMapResourceFlags": ("hipGraphicsMapFlags", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CUgraphicsMapResourceFlags_enum": ("hipGraphicsMapFlags", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CUgraphicsRegisterFlags": ("hipGraphicsRegisterFlags", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CUgraphicsRegisterFlags_enum": ("hipGraphicsRegisterFlags", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CUoccupancy_flags": ("hipOccupancyFlags", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CUoccupancy_flags_enum": ("hipOccupancyFlags", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CUfunc_cache_enum": ("hipFuncCache", CONV_TYPE, API_DRIVER), + "CUfunc_cache": ("hipFuncCache", CONV_TYPE, API_DRIVER), + "CUipcMem_flags": ("hipIpcMemFlags", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CUipcMem_flags_enum": ("hipIpcMemFlags", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CUjit_cacheMode": ("hipJitCacheMode", CONV_JIT, API_DRIVER, HIP_UNSUPPORTED), + "CUjit_cacheMode_enum": ("hipJitCacheMode", CONV_JIT, API_DRIVER, HIP_UNSUPPORTED), + "CUjit_fallback": ("hipJitFallback", CONV_JIT, API_DRIVER, HIP_UNSUPPORTED), + "CUjit_fallback_enum": ("hipJitFallback", CONV_JIT, API_DRIVER, HIP_UNSUPPORTED), + "CUjit_option": ("hipJitOption", CONV_JIT, API_DRIVER), + "CUjit_option_enum": ("hipJitOption", CONV_JIT, API_DRIVER), + "CUjit_target": ("hipJitTarget", CONV_JIT, API_DRIVER, HIP_UNSUPPORTED), + "CUjit_target_enum": ("hipJitTarget", CONV_JIT, API_DRIVER, HIP_UNSUPPORTED), + "CUjitInputType": ("hipJitInputType", CONV_JIT, API_DRIVER, HIP_UNSUPPORTED), + "CUjitInputType_enum": ("hipJitInputType", CONV_JIT, API_DRIVER, HIP_UNSUPPORTED), + "CUlimit": ("hipLimit_t", CONV_TYPE, API_DRIVER), + "CUlimit_enum": ("hipLimit_t", CONV_TYPE, API_DRIVER), + "CUmemAttach_flags": ("hipMemAttachFlags_t", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CUmemAttach_flags_enum": ("hipMemAttachFlags_t", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CUmemorytype": ("hipMemType_t", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CUmemorytype_enum": ("hipMemType_t", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CUresourcetype": ("hipResourceType", CONV_TEX, API_DRIVER, HIP_UNSUPPORTED), + "CUresourcetype_enum": ("hipResourceType", CONV_TEX, API_DRIVER, HIP_UNSUPPORTED), + "CUresourceViewFormat": ("hipResourceViewFormat", CONV_TEX, API_DRIVER), + "CUresourceViewFormat_enum": ("hipResourceViewFormat", CONV_TEX, API_DRIVER), + "CUsharedconfig": ("hipSharedMemConfig", CONV_TYPE, API_DRIVER), + "CUsharedconfig_enum": ("hipSharedMemConfig", CONV_TYPE, API_DRIVER), + "CUcontext": ("hipCtx_t", CONV_TYPE, API_DRIVER), + "CUmodule": ("hipModule_t", CONV_TYPE, API_DRIVER), + "CUstream": ("hipStream_t", CONV_TYPE, API_DRIVER), + "CUstream_st": ("ihipStream_t", CONV_TYPE, API_DRIVER), + "CUstreamCallback": ("hipStreamCallback_t", CONV_TYPE, API_DRIVER), + "CUsurfObject": ("hipSurfaceObject", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CUsurfref": ("hipSurfaceReference_t", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CUtexObject": ("hipTextureObject_t", CONV_TYPE, API_DRIVER), + "CUtexref": ("textureReference", CONV_TYPE, API_DRIVER), + "CUstream_flags": ("hipStreamFlags", CONV_TYPE, API_DRIVER), + "CUstreamWaitValue_flags": ("hipStreamWaitValueFlags", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CUstreamWriteValue_flags": ("hipStreamWriteValueFlags", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CUstreamBatchMemOpType": ("hipStreamBatchMemOpType", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CUdevice_P2PAttribute": ("hipDeviceP2PAttribute", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CUevent": ("hipEvent_t", CONV_TYPE, API_DRIVER), + "CUevent_flags": ("hipEventFlags", CONV_EVENT, API_DRIVER, HIP_UNSUPPORTED), + "CUfilter_mode": ("hipTextureFilterMode", CONV_TEX, API_DRIVER), + "CUGLDeviceList": ("hipGLDeviceList", CONV_GL, API_DRIVER, HIP_UNSUPPORTED), + "CUGLmap_flags": ("hipGLMapFlags", CONV_GL, API_DRIVER, HIP_UNSUPPORTED), + "CUd3d9DeviceList": ("hipD3D9DeviceList", CONV_D3D9, API_DRIVER, HIP_UNSUPPORTED), + "CUd3d9map_flags": ("hipD3D9MapFlags", CONV_D3D9, API_DRIVER, HIP_UNSUPPORTED), + "CUd3d9register_flags": ("hipD3D9RegisterFlags", CONV_D3D9, API_DRIVER, HIP_UNSUPPORTED), + "CUd3d10DeviceList": ("hipd3d10DeviceList", CONV_D3D10, API_DRIVER, HIP_UNSUPPORTED), + "CUd3d10map_flags": ("hipD3D10MapFlags", CONV_D3D10, API_DRIVER, HIP_UNSUPPORTED), + "CUd3d10register_flags": ("hipD3D10RegisterFlags", CONV_D3D10, API_DRIVER, HIP_UNSUPPORTED), + "CUd3d11DeviceList": ("hipd3d11DeviceList", CONV_D3D11, API_DRIVER, HIP_UNSUPPORTED), + "CUeglStreamConnection_st": ("hipEglStreamConnection", CONV_EGL, API_DRIVER, HIP_UNSUPPORTED), + "CUeglStreamConnection": ("hipEglStreamConnection", CONV_EGL, API_DRIVER, HIP_UNSUPPORTED), + "libraryPropertyType_t": ("hipLibraryPropertyType_t", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "libraryPropertyType": ("hipLibraryPropertyType_t", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaStreamCallback_t": ("hipStreamCallback_t", CONV_TYPE, API_RUNTIME), + "cudaArray": ("hipArray", CONV_MEM, API_RUNTIME), + "cudaArray_t": ("hipArray_t", CONV_MEM, API_RUNTIME), + "cudaArray_const_t": ("hipArray_const_t", CONV_MEM, API_RUNTIME), + "cudaMipmappedArray_t": ("hipMipmappedArray_t", CONV_MEM, API_RUNTIME), + "cudaMipmappedArray_const_t": ("hipMipmappedArray_const_t", CONV_MEM, API_RUNTIME), + "cudaArrayDefault": ("hipArrayDefault", CONV_MEM, API_RUNTIME), + "cudaArrayLayered": ("hipArrayLayered", CONV_MEM, API_RUNTIME), + "cudaArraySurfaceLoadStore": ("hipArraySurfaceLoadStore", CONV_MEM, API_RUNTIME), + "cudaArrayCubemap": ("hipArrayCubemap", CONV_MEM, API_RUNTIME), + "cudaArrayTextureGather": ("hipArrayTextureGather", CONV_MEM, API_RUNTIME), + "cudaMemoryAdvise": ("hipMemAdvise", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaMemRangeAttribute": ("hipMemRangeAttribute", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaMemcpyKind": ("hipMemcpyKind", CONV_MEM, API_RUNTIME), + "cudaMemoryType": ("hipMemoryType", CONV_MEM, API_RUNTIME), + "cudaExtent": ("hipExtent", CONV_MEM, API_RUNTIME), + "cudaPitchedPtr": ("hipPitchedPtr", CONV_MEM, API_RUNTIME), + "cudaPos": ("hipPos", CONV_MEM, API_RUNTIME), + "cudaEvent_t": ("hipEvent_t", CONV_TYPE, API_RUNTIME), + "cudaStream_t": ("hipStream_t", CONV_TYPE, API_RUNTIME), + "cudaPointerAttributes": ("hipPointerAttribute_t", CONV_TYPE, API_RUNTIME), + "cudaDeviceAttr": ("hipDeviceAttribute_t", CONV_TYPE, API_RUNTIME), + "cudaDeviceProp": ("hipDeviceProp_t", CONV_TYPE, API_RUNTIME), + "cudaDeviceP2PAttr": ("hipDeviceP2PAttribute", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaComputeMode": ("hipComputeMode", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaFuncCache": ("hipFuncCache_t", CONV_CACHE, API_RUNTIME), + "cudaFuncAttributes": ("hipFuncAttributes", CONV_EXEC, API_RUNTIME, HIP_UNSUPPORTED), + "cudaSharedMemConfig": ("hipSharedMemConfig", CONV_TYPE, API_RUNTIME), + "cudaLimit": ("hipLimit_t", CONV_TYPE, API_RUNTIME), + "cudaOutputMode": ("hipOutputMode", CONV_OTHER, API_RUNTIME, HIP_UNSUPPORTED), + "cudaTextureReadMode": ("hipTextureReadMode", CONV_TEX, API_RUNTIME), + "cudaTextureFilterMode": ("hipTextureFilterMode", CONV_TEX, API_RUNTIME), + "cudaChannelFormatKind": ("hipChannelFormatKind", CONV_TEX, API_RUNTIME), + "cudaChannelFormatDesc": ("hipChannelFormatDesc", CONV_TEX, API_RUNTIME), + "cudaResourceDesc": ("hipResourceDesc", CONV_TEX, API_RUNTIME), + "cudaResourceViewDesc": ("hipResourceViewDesc", CONV_TEX, API_RUNTIME), + "cudaTextureDesc": ("hipTextureDesc", CONV_TEX, API_RUNTIME), + "surfaceReference": ("hipSurfaceReference", CONV_SURFACE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaTextureObject_t": ("hipTextureObject_t", CONV_TEX, API_RUNTIME), + "cudaResourceType": ("hipResourceType", CONV_TEX, API_RUNTIME), + "cudaResourceViewFormat": ("hipResourceViewFormat", CONV_TEX, API_RUNTIME), + "cudaTextureAddressMode": ("hipTextureAddressMode", CONV_TEX, API_RUNTIME), + "cudaSurfaceBoundaryMode": ("hipSurfaceBoundaryMode", CONV_SURFACE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaSurfaceFormatMode": ("hipSurfaceFormatMode", CONV_SURFACE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaTextureType1D": ("hipTextureType1D", CONV_TEX, API_RUNTIME), + "cudaTextureType2D": ("hipTextureType2D", CONV_TEX, API_RUNTIME), + "cudaTextureType3D": ("hipTextureType3D", CONV_TEX, API_RUNTIME), + "cudaTextureTypeCubemap": ("hipTextureTypeCubemap", CONV_TEX, API_RUNTIME), + "cudaTextureType1DLayered": ("hipTextureType1DLayered", CONV_TEX, API_RUNTIME), + "cudaTextureType2DLayered": ("hipTextureType2DLayered", CONV_TEX, API_RUNTIME), + "cudaTextureTypeCubemapLayered": ("hipTextureTypeCubemapLayered", CONV_TEX, API_RUNTIME), + "cudaIpcEventHandle_t": ("hipIpcEventHandle_t", CONV_TYPE, API_RUNTIME), + "cudaIpcEventHandle_st": ("hipIpcEventHandle_t", CONV_TYPE, API_RUNTIME), + "cudaIpcMemHandle_t": ("hipIpcMemHandle_t", CONV_TYPE, API_RUNTIME), + "cudaIpcMemHandle_st": ("hipIpcMemHandle_t", CONV_TYPE, API_RUNTIME), + "cudaGraphicsCubeFace": ("hipGraphicsCubeFace", CONV_GRAPHICS, API_RUNTIME, HIP_UNSUPPORTED), + "cudaGraphicsMapFlags": ("hipGraphicsMapFlags", CONV_GRAPHICS, API_RUNTIME, HIP_UNSUPPORTED), + "cudaGraphicsRegisterFlags": ("hipGraphicsRegisterFlags", CONV_GRAPHICS, API_RUNTIME, HIP_UNSUPPORTED), + "cudaGLDeviceList": ("hipGLDeviceList", CONV_GL, API_RUNTIME, HIP_UNSUPPORTED), + "cudaGLMapFlags": ("hipGLMapFlags", CONV_GL, API_RUNTIME, HIP_UNSUPPORTED), + "cudaD3D9DeviceList": ("hipD3D9DeviceList", CONV_D3D9, API_RUNTIME, HIP_UNSUPPORTED), + "cudaD3D9MapFlags": ("hipD3D9MapFlags", CONV_D3D9, API_RUNTIME, HIP_UNSUPPORTED), + "cudaD3D9RegisterFlags": ("hipD3D9RegisterFlags", CONV_D3D9, API_RUNTIME, HIP_UNSUPPORTED), + "cudaD3D10DeviceList": ("hipd3d10DeviceList", CONV_D3D10, API_RUNTIME, HIP_UNSUPPORTED), + "cudaD3D10MapFlags": ("hipD3D10MapFlags", CONV_D3D10, API_RUNTIME, HIP_UNSUPPORTED), + "cudaD3D10RegisterFlags": ("hipD3D10RegisterFlags", CONV_D3D10, API_RUNTIME, HIP_UNSUPPORTED), + "cudaD3D11DeviceList": ("hipd3d11DeviceList", CONV_D3D11, API_RUNTIME, HIP_UNSUPPORTED), + "cudaEglStreamConnection": ("hipEglStreamConnection", CONV_EGL, API_RUNTIME, HIP_UNSUPPORTED), + "cublasHandle_t": ("hipblasHandle_t", CONV_TYPE, API_BLAS), + "cublasOperation_t": ("hipblasOperation_t", CONV_TYPE, API_BLAS), + "cublasStatus_t": ("hipblasStatus_t", CONV_TYPE, API_BLAS), + "cublasFillMode_t": ("hipblasFillMode_t", CONV_TYPE, API_BLAS), + "cublasDiagType_t": ("hipblasDiagType_t", CONV_TYPE, API_BLAS), + "cublasSideMode_t": ("hipblasSideMode_t", CONV_TYPE, API_BLAS), + "cublasPointerMode_t": ("hipblasPointerMode_t", CONV_TYPE, API_BLAS), + "cublasAtomicsMode_t": ("hipblasAtomicsMode_t", CONV_TYPE, API_BLAS, HIP_UNSUPPORTED), + "cublasDataType_t": ("hipblasDataType_t", CONV_TYPE, API_BLAS, HIP_UNSUPPORTED), + "curandStatus": ("hiprngStatus_t", CONV_TYPE, API_RAND), + "curandStatus_t": ("hiprngStatus_t", CONV_TYPE, API_RAND), + "curandRngType": ("hiprngRngType_t", CONV_TYPE, API_RAND), + "curandRngType_t": ("hiprngRngType_t", CONV_TYPE, API_RAND), + "curandGenerator_st": ("hiprngGenerator_st", CONV_TYPE, API_RAND), + "curandGenerator_t": ("hiprngGenerator_t", CONV_TYPE, API_RAND), + "curandDirectionVectorSet": ("hiprngDirectionVectorSet_t", CONV_TYPE, API_RAND, HIP_UNSUPPORTED), + "curandDirectionVectorSet_t": ("hiprngDirectionVectorSet_t", CONV_TYPE, API_RAND, HIP_UNSUPPORTED), + "curandOrdering": ("hiprngOrdering_t", CONV_TYPE, API_RAND, HIP_UNSUPPORTED), + "curandOrdering_t": ("hiprngOrdering_t", CONV_TYPE, API_RAND, HIP_UNSUPPORTED), + "curandDistribution_st": ("hiprngDistribution_st", CONV_TYPE, API_RAND, HIP_UNSUPPORTED), + "curandHistogramM2V_st": ("hiprngDistribution_st", CONV_TYPE, API_RAND, HIP_UNSUPPORTED), + "curandDistribution_t": ("hiprngDistribution_t", CONV_TYPE, API_RAND, HIP_UNSUPPORTED), + "curandHistogramM2V_t": ("hiprngDistribution_t", CONV_TYPE, API_RAND, HIP_UNSUPPORTED), + "curandDistributionShift_st": ("hiprngDistributionShift_st", CONV_TYPE, API_RAND, HIP_UNSUPPORTED), + "curandDistributionShift_t": ("hiprngDistributionShift_t", CONV_TYPE, API_RAND, HIP_UNSUPPORTED), + "curandDistributionM2Shift_st": ("hiprngDistributionM2Shift_st", CONV_TYPE, API_RAND, HIP_UNSUPPORTED), + "curandDistributionM2Shift_t": ("hiprngDistributionM2Shift_t", CONV_TYPE, API_RAND, HIP_UNSUPPORTED), + "curandHistogramM2_st": ("hiprngHistogramM2_st", CONV_TYPE, API_RAND, HIP_UNSUPPORTED), + "curandHistogramM2_t": ("hiprngHistogramM2_t", CONV_TYPE, API_RAND, HIP_UNSUPPORTED), + "curandHistogramM2K_st": ("hiprngHistogramM2K_st", CONV_TYPE, API_RAND, HIP_UNSUPPORTED), + "curandHistogramM2K_t": ("hiprngHistogramM2K_t", CONV_TYPE, API_RAND, HIP_UNSUPPORTED), + "curandDiscreteDistribution_st": ("hiprngDiscreteDistribution_st", CONV_TYPE, API_RAND), + "curandDiscreteDistribution_t": ("hiprngDiscreteDistribution_t", CONV_TYPE, API_RAND), + "curandMethod": ("hiprngMethod_t", CONV_TYPE, API_RAND, HIP_UNSUPPORTED), + "curandMethod_t": ("hiprngMethod_t", CONV_TYPE, API_RAND, HIP_UNSUPPORTED), + "curandDirectionVectors32_t": ("hiprngDirectionVectors32_t", CONV_TYPE, API_RAND), + "curandDirectionVectors64_t": ("hiprngDirectionVectors64_t", CONV_TYPE, API_RAND, HIP_UNSUPPORTED), + "curandStateMtgp32_t": ("hiprngStateMtgp32_t", CONV_TYPE, API_RAND), + "curandStateMtgp32": ("hcrngStateMtgp32", CONV_TYPE, API_RAND), + "curandStateScrambledSobol64_t": ("hiprngStateScrambledSobol64_t", CONV_TYPE, API_RAND, HIP_UNSUPPORTED), + "curandStateSobol64_t": ("hiprngStateSobol64_t", CONV_TYPE, API_RAND, HIP_UNSUPPORTED), + "curandStateScrambledSobol32_t": ("hiprngStateScrambledSobol32_t", CONV_TYPE, API_RAND, HIP_UNSUPPORTED), + "curandStateSobol32_t": ("hiprngStateSobol32_t", CONV_TYPE, API_RAND), + "curandStateMRG32k3a_t": ("hiprngStateMRG32k3a_t", CONV_TYPE, API_RAND), + "curandStatePhilox4_32_10_t": ("hiprngStatePhilox4_32_10_t", CONV_TYPE, API_RAND), + "curandStateXORWOW_t": ("hiprngStateXORWOW_t", CONV_TYPE, API_RAND), + "curandState_t": ("hiprngState_t", CONV_TYPE, API_RAND), + "curandState": ("hiprngState_t", CONV_TYPE, API_RAND) +} + +CUDA_INCLUDE_MAP = { + "cuda.h": ("hip/hip_runtime.h", CONV_INCLUDE_CUDA_MAIN_H, API_DRIVER), + "cuda_runtime.h": ("hip/hip_runtime.h", CONV_INCLUDE_CUDA_MAIN_H, API_RUNTIME), + "cuda_runtime_api.h": ("hip/hip_runtime_api.h", CONV_INCLUDE, API_RUNTIME), + "channel_descriptor.h": ("hip/channel_descriptor.h", CONV_INCLUDE, API_RUNTIME), + "device_functions.h": ("hip/device_functions.h", CONV_INCLUDE, API_RUNTIME), + "driver_types.h": ("hip/driver_types.h", CONV_INCLUDE, API_RUNTIME), + "cuComplex.h": ("hip/hip_complex.h", CONV_INCLUDE, API_RUNTIME), + "cuda_fp16.h": ("hip/hip_fp16.h", CONV_INCLUDE, API_RUNTIME), + "cuda_texture_types.h": ("hip/hip_texture_types.h", CONV_INCLUDE, API_RUNTIME), + "vector_types.h": ("hip/hip_vector_types.h", CONV_INCLUDE, API_RUNTIME), + "cublas.h": ("hipblas.h", CONV_INCLUDE_CUDA_MAIN_H, API_BLAS), + "cublas_v2.h": ("hipblas.h", CONV_INCLUDE_CUDA_MAIN_H, API_BLAS), + "curand.h": ("hiprng.h", CONV_INCLUDE_CUDA_MAIN_H, API_RAND), + "curand_kernel.h": ("hiprng_kernel.h", CONV_INCLUDE, API_RAND), + "curand_discrete.h": ("hiprng_kernel.h", CONV_INCLUDE, API_RAND), + "curand_discrete2.h": ("hiprng_kernel.h", CONV_INCLUDE, API_RAND), + "curand_globals.h": ("hiprng_kernel.h", CONV_INCLUDE, API_RAND), + "curand_lognormal.h": ("hiprng_kernel.h", CONV_INCLUDE, API_RAND), + "curand_mrg32k3a.h": ("hiprng_kernel.h", CONV_INCLUDE, API_RAND), + "curand_mtgp32.h": ("hiprng_kernel.h", CONV_INCLUDE, API_RAND), + "curand_mtgp32_host.h": ("hiprng_kernel.h", CONV_INCLUDE, API_RAND), + "curand_mtgp32_kernel.h": ("hiprng_kernel.h", CONV_INCLUDE, API_RAND), + "curand_mtgp32dc_p_11213.h": ("hiprng_kernel.h", CONV_INCLUDE, API_RAND), + "curand_normal.h": ("hiprng_kernel.h", CONV_INCLUDE, API_RAND), + "curand_normal_static.h": ("hiprng_kernel.h", CONV_INCLUDE, API_RAND), + "curand_philox4x32_x.h": ("hiprng_kernel.h", CONV_INCLUDE, API_RAND), + "curand_poisson.h": ("hiprng_kernel.h", CONV_INCLUDE, API_RAND), + "curand_precalc.h": ("hiprng_kernel.h", CONV_INCLUDE, API_RAND), + "curand_uniform.h": ("hiprng_kernel.h", CONV_INCLUDE, API_RAND), + "cusparse.h": ("hipsparse.h", CONV_INCLUDE, API_RAND), + "#include ": ("", CONV_INCLUDE, API_RAND, HIP_UNSUPPORTED), + "#include ": ("", CONV_INCLUDE, API_RAND, HIP_UNSUPPORTED), + "#include ": ("", CONV_INCLUDE, API_RAND, HIP_UNSUPPORTED), +} + +CUDA_IDENTIFIER_MAP = { + "__CUDACC__": ("__HIPCC__", CONV_DEF, API_RUNTIME), + "CUDA_ERROR_INVALID_CONTEXT": ("hipErrorInvalidContext", CONV_TYPE, API_DRIVER), + "CUDA_ERROR_CONTEXT_ALREADY_CURRENT": ("hipErrorContextAlreadyCurrent", CONV_TYPE, API_DRIVER), + "CUDA_ERROR_ARRAY_IS_MAPPED": ("hipErrorArrayIsMapped", CONV_TYPE, API_DRIVER), + "CUDA_ERROR_ALREADY_MAPPED": ("hipErrorAlreadyMapped", CONV_TYPE, API_DRIVER), + "CUDA_ERROR_ALREADY_ACQUIRED": ("hipErrorAlreadyAcquired", CONV_TYPE, API_DRIVER), + "CUDA_ERROR_NOT_MAPPED": ("hipErrorNotMapped", CONV_TYPE, API_DRIVER), + "CUDA_ERROR_NOT_MAPPED_AS_ARRAY": ("hipErrorNotMappedAsArray", CONV_TYPE, API_DRIVER), + "CUDA_ERROR_NOT_MAPPED_AS_POINTER": ("hipErrorNotMappedAsPointer", CONV_TYPE, API_DRIVER), + "CUDA_ERROR_CONTEXT_ALREADY_IN_USE": ("hipErrorContextAlreadyInUse", CONV_TYPE, API_DRIVER), + "CUDA_ERROR_INVALID_SOURCE": ("hipErrorInvalidSource", CONV_TYPE, API_DRIVER), + "CUDA_ERROR_FILE_NOT_FOUND": ("hipErrorFileNotFound", CONV_TYPE, API_DRIVER), + "CUDA_ERROR_NOT_FOUND": ("hipErrorNotFound", CONV_TYPE, API_DRIVER), + "CUDA_ERROR_LAUNCH_INCOMPATIBLE_TEXTURING": ("hipErrorLaunchIncompatibleTexturing", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CUDA_ERROR_PRIMARY_CONTEXT_ACTIVE": ("hipErrorPrimaryContextActive", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CUDA_ERROR_CONTEXT_IS_DESTROYED": ("hipErrorContextIsDestroyed", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CUDA_ERROR_NOT_PERMITTED": ("hipErrorNotPermitted", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CUDA_ERROR_NOT_SUPPORTED": ("hipErrorNotSupported", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "cudaErrorMissingConfiguration": ("hipErrorMissingConfiguration", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaErrorPriorLaunchFailure": ("hipErrorPriorLaunchFailure", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaErrorInvalidDeviceFunction": ("hipErrorInvalidDeviceFunction", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaErrorInvalidConfiguration": ("hipErrorInvalidConfiguration", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaErrorInvalidPitchValue": ("hipErrorInvalidPitchValue", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaErrorInvalidSymbol": ("hipErrorInvalidSymbol", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaErrorInvalidHostPointer": ("hipErrorInvalidHostPointer", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaErrorInvalidDevicePointer": ("hipErrorInvalidDevicePointer", CONV_TYPE, API_RUNTIME), + "cudaErrorInvalidTexture": ("hipErrorInvalidTexture", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaErrorInvalidTextureBinding": ("hipErrorInvalidTextureBinding", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaErrorInvalidChannelDescriptor": ("hipErrorInvalidChannelDescriptor", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaErrorInvalidMemcpyDirection": ("hipErrorInvalidMemcpyDirection", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaErrorAddressOfConstant": ("hipErrorAddressOfConstant", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaErrorTextureFetchFailed": ("hipErrorTextureFetchFailed", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaErrorTextureNotBound": ("hipErrorTextureNotBound", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaErrorSynchronizationError": ("hipErrorSynchronizationError", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaErrorInvalidFilterSetting": ("hipErrorInvalidFilterSetting", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaErrorInvalidNormSetting": ("hipErrorInvalidNormSetting", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaErrorMixedDeviceExecution": ("hipErrorMixedDeviceExecution", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaErrorNotYetImplemented": ("hipErrorNotYetImplemented", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaErrorMemoryValueTooLarge": ("hipErrorMemoryValueTooLarge", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaErrorInsufficientDriver": ("hipErrorInsufficientDriver", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaErrorSetOnActiveProcess": ("hipErrorSetOnActiveProcess", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaErrorInvalidSurface": ("hipErrorInvalidSurface", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaErrorDuplicateVariableName": ("hipErrorDuplicateVariableName", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaErrorDuplicateTextureName": ("hipErrorDuplicateTextureName", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaErrorDuplicateSurfaceName": ("hipErrorDuplicateSurfaceName", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaErrorDevicesUnavailable": ("hipErrorDevicesUnavailable", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaErrorIncompatibleDriverContext": ("hipErrorIncompatibleDriverContext", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaErrorDeviceAlreadyInUse": ("hipErrorDeviceAlreadyInUse", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaErrorLaunchMaxDepthExceeded": ("hipErrorLaunchMaxDepthExceeded", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaErrorLaunchFileScopedTex": ("hipErrorLaunchFileScopedTex", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaErrorLaunchFileScopedSurf": ("hipErrorLaunchFileScopedSurf", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaErrorSyncDepthExceeded": ("hipErrorSyncDepthExceeded", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaErrorLaunchPendingCountExceeded": ("hipErrorLaunchPendingCountExceeded", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaErrorNotPermitted": ("hipErrorNotPermitted", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaErrorNotSupported": ("hipErrorNotSupported", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaErrorStartupFailure": ("hipErrorStartupFailure", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaErrorApiFailureBase": ("hipErrorApiFailureBase", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "CUDA_SUCCESS": ("hipSuccess", CONV_TYPE, API_DRIVER), + "cudaSuccess": ("hipSuccess", CONV_TYPE, API_RUNTIME), + "CUDA_ERROR_INVALID_VALUE": ("hipErrorInvalidValue", CONV_TYPE, API_DRIVER), + "cudaErrorInvalidValue": ("hipErrorInvalidValue", CONV_TYPE, API_RUNTIME), + "CUDA_ERROR_OUT_OF_MEMORY": ("hipErrorMemoryAllocation", CONV_TYPE, API_DRIVER), + "cudaErrorMemoryAllocation": ("hipErrorMemoryAllocation", CONV_TYPE, API_RUNTIME), + "CUDA_ERROR_NOT_INITIALIZED": ("hipErrorNotInitialized", CONV_TYPE, API_DRIVER), + "cudaErrorInitializationError": ("hipErrorInitializationError", CONV_TYPE, API_RUNTIME), + "CUDA_ERROR_DEINITIALIZED": ("hipErrorDeinitialized", CONV_TYPE, API_DRIVER), + "cudaErrorCudartUnloading": ("hipErrorDeinitialized", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "CUDA_ERROR_PROFILER_DISABLED": ("hipErrorProfilerDisabled", CONV_TYPE, API_DRIVER), + "cudaErrorProfilerDisabled": ("hipErrorProfilerDisabled", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "CUDA_ERROR_PROFILER_NOT_INITIALIZED": ("hipErrorProfilerNotInitialized", CONV_TYPE, API_DRIVER), + "cudaErrorProfilerNotInitialized": ("hipErrorProfilerNotInitialized", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "CUDA_ERROR_PROFILER_ALREADY_STARTED": ("hipErrorProfilerAlreadyStarted", CONV_TYPE, API_DRIVER), + "cudaErrorProfilerAlreadyStarted": ("hipErrorProfilerAlreadyStarted", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "CUDA_ERROR_PROFILER_ALREADY_STOPPED": ("hipErrorProfilerAlreadyStopped", CONV_TYPE, API_DRIVER), + "cudaErrorProfilerAlreadyStopped": ("hipErrorProfilerAlreadyStopped", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "CUDA_ERROR_NO_DEVICE": ("hipErrorNoDevice", CONV_TYPE, API_DRIVER), + "cudaErrorNoDevice": ("hipErrorNoDevice", CONV_TYPE, API_RUNTIME), + "CUDA_ERROR_INVALID_DEVICE": ("hipErrorInvalidDevice", CONV_TYPE, API_DRIVER), + "cudaErrorInvalidDevice": ("hipErrorInvalidDevice", CONV_TYPE, API_RUNTIME), + "CUDA_ERROR_INVALID_IMAGE": ("hipErrorInvalidImage", CONV_TYPE, API_DRIVER), + "cudaErrorInvalidKernelImage": ("hipErrorInvalidImage", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "CUDA_ERROR_MAP_FAILED": ("hipErrorMapFailed", CONV_TYPE, API_DRIVER), + "cudaErrorMapBufferObjectFailed": ("hipErrorMapFailed", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "CUDA_ERROR_UNMAP_FAILED": ("hipErrorUnmapFailed", CONV_TYPE, API_DRIVER), + "cudaErrorUnmapBufferObjectFailed": ("hipErrorUnmapFailed", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "CUDA_ERROR_NO_BINARY_FOR_GPU": ("hipErrorNoBinaryForGpu", CONV_TYPE, API_DRIVER), + "cudaErrorNoKernelImageForDevice": ("hipErrorNoBinaryForGpu", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "CUDA_ERROR_ECC_UNCORRECTABLE": ("hipErrorECCNotCorrectable", CONV_TYPE, API_DRIVER), + "cudaErrorECCUncorrectable": ("hipErrorECCNotCorrectable", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "CUDA_ERROR_UNSUPPORTED_LIMIT": ("hipErrorUnsupportedLimit", CONV_TYPE, API_DRIVER), + "cudaErrorUnsupportedLimit": ("hipErrorUnsupportedLimit", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "CUDA_ERROR_PEER_ACCESS_UNSUPPORTED": ("hipErrorPeerAccessUnsupported", CONV_TYPE, API_DRIVER), + "cudaErrorPeerAccessUnsupported": ("hipErrorPeerAccessUnsupported", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "CUDA_ERROR_INVALID_PTX": ("hipErrorInvalidKernelFile", CONV_TYPE, API_DRIVER), + "cudaErrorInvalidPtx": ("hipErrorInvalidKernelFile", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "CUDA_ERROR_INVALID_GRAPHICS_CONTEXT": ("hipErrorInvalidGraphicsContext", CONV_TYPE, API_DRIVER), + "cudaErrorInvalidGraphicsContext": ("hipErrorInvalidGraphicsContext", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "CUDA_ERROR_NVLINK_UNCORRECTABLE": ("hipErrorNvlinkUncorrectable", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "cudaErrorNvlinkUncorrectable": ("hipErrorNvlinkUncorrectable", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "CUDA_ERROR_SHARED_OBJECT_SYMBOL_NOT_FOUND": ("hipErrorSharedObjectSymbolNotFound", CONV_TYPE, API_DRIVER), + "cudaErrorSharedObjectSymbolNotFound": ("hipErrorSharedObjectSymbolNotFound", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "CUDA_ERROR_SHARED_OBJECT_INIT_FAILED": ("hipErrorSharedObjectInitFailed", CONV_TYPE, API_DRIVER), + "cudaErrorSharedObjectInitFailed": ("hipErrorSharedObjectInitFailed", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "CUDA_ERROR_OPERATING_SYSTEM": ("hipErrorOperatingSystem", CONV_TYPE, API_DRIVER), + "cudaErrorOperatingSystem": ("hipErrorOperatingSystem", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "CUDA_ERROR_INVALID_HANDLE": ("hipErrorInvalidResourceHandle", CONV_TYPE, API_DRIVER), + "cudaErrorInvalidResourceHandle": ("hipErrorInvalidResourceHandle", CONV_TYPE, API_RUNTIME), + "CUDA_ERROR_NOT_READY": ("hipErrorNotReady", CONV_TYPE, API_DRIVER), + "cudaErrorNotReady": ("hipErrorNotReady", CONV_TYPE, API_RUNTIME), + "CUDA_ERROR_ILLEGAL_ADDRESS": ("hipErrorIllegalAddress", CONV_TYPE, API_DRIVER), + "cudaErrorIllegalAddress": ("hipErrorIllegalAddress", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "CUDA_ERROR_LAUNCH_OUT_OF_RESOURCES": ("hipErrorLaunchOutOfResources", CONV_TYPE, API_DRIVER), + "cudaErrorLaunchOutOfResources": ("hipErrorLaunchOutOfResources", CONV_TYPE, API_RUNTIME), + "CUDA_ERROR_LAUNCH_TIMEOUT": ("hipErrorLaunchTimeOut", CONV_TYPE, API_DRIVER), + "cudaErrorLaunchTimeout": ("hipErrorLaunchTimeOut", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "CUDA_ERROR_PEER_ACCESS_ALREADY_ENABLED": ("hipErrorPeerAccessAlreadyEnabled", CONV_TYPE, API_DRIVER), + "cudaErrorPeerAccessAlreadyEnabled": ("hipErrorPeerAccessAlreadyEnabled", CONV_TYPE, API_RUNTIME), + "CUDA_ERROR_PEER_ACCESS_NOT_ENABLED": ("hipErrorPeerAccessNotEnabled", CONV_TYPE, API_DRIVER), + "cudaErrorPeerAccessNotEnabled": ("hipErrorPeerAccessNotEnabled", CONV_TYPE, API_RUNTIME), + "CUDA_ERROR_ASSERT": ("hipErrorAssert", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "cudaErrorAssert": ("hipErrorAssert", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "CUDA_ERROR_TOO_MANY_PEERS": ("hipErrorTooManyPeers", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "cudaErrorTooManyPeers": ("hipErrorTooManyPeers", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "CUDA_ERROR_HOST_MEMORY_ALREADY_REGISTERED": ("hipErrorHostMemoryAlreadyRegistered", CONV_TYPE, API_DRIVER), + "cudaErrorHostMemoryAlreadyRegistered": ("hipErrorHostMemoryAlreadyRegistered", CONV_TYPE, API_RUNTIME), + "CUDA_ERROR_HOST_MEMORY_NOT_REGISTERED": ("hipErrorHostMemoryNotRegistered", CONV_TYPE, API_DRIVER), + "cudaErrorHostMemoryNotRegistered": ("hipErrorHostMemoryNotRegistered", CONV_TYPE, API_RUNTIME), + "CUDA_ERROR_HARDWARE_STACK_ERROR": ("hipErrorHardwareStackError", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "cudaErrorHardwareStackError": ("hipErrorHardwareStackError", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "CUDA_ERROR_ILLEGAL_INSTRUCTION": ("hipErrorIllegalInstruction", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "cudaErrorIllegalInstruction": ("hipErrorIllegalInstruction", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "CUDA_ERROR_MISALIGNED_ADDRESS": ("hipErrorMisalignedAddress", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "cudaErrorMisalignedAddress": ("hipErrorMisalignedAddress", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "CUDA_ERROR_INVALID_ADDRESS_SPACE": ("hipErrorInvalidAddressSpace", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "cudaErrorInvalidAddressSpace": ("hipErrorInvalidAddressSpace", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "CUDA_ERROR_INVALID_PC": ("hipErrorInvalidPc", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "cudaErrorInvalidPc": ("hipErrorInvalidPc", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "CUDA_ERROR_LAUNCH_FAILED": ("hipErrorLaunchFailure", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "cudaErrorLaunchFailure": ("hipErrorLaunchFailure", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "CUDA_ERROR_UNKNOWN": ("hipErrorUnknown", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "cudaErrorUnknown": ("hipErrorUnknown", CONV_TYPE, API_RUNTIME), + "CU_TR_ADDRESS_MODE_WRAP": ("HIP_TR_ADDRESS_MODE_WRAP", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_TR_ADDRESS_MODE_CLAMP": ("HIP_TR_ADDRESS_MODE_CLAMP", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_TR_ADDRESS_MODE_MIRROR": ("HIP_TR_ADDRESS_MODE_MIRROR", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_TR_ADDRESS_MODE_BORDER": ("HIP_TR_ADDRESS_MODE_BORDER", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_CUBEMAP_FACE_POSITIVE_X": ("HIP_CUBEMAP_FACE_POSITIVE_X", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_CUBEMAP_FACE_NEGATIVE_X": ("HIP_CUBEMAP_FACE_NEGATIVE_X", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_CUBEMAP_FACE_POSITIVE_Y": ("HIP_CUBEMAP_FACE_POSITIVE_Y", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_CUBEMAP_FACE_NEGATIVE_Y": ("HIP_CUBEMAP_FACE_NEGATIVE_Y", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_CUBEMAP_FACE_POSITIVE_Z": ("HIP_CUBEMAP_FACE_POSITIVE_Z", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_CUBEMAP_FACE_NEGATIVE_Z": ("HIP_CUBEMAP_FACE_NEGATIVE_Z", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_AD_FORMAT_UNSIGNED_INT8": ("HIP_AD_FORMAT_UNSIGNED_INT8", CONV_TYPE, API_DRIVER), + "CU_AD_FORMAT_UNSIGNED_INT16": ("HIP_AD_FORMAT_UNSIGNED_INT16", CONV_TYPE, API_DRIVER), + "CU_AD_FORMAT_UNSIGNED_INT32": ("HIP_AD_FORMAT_UNSIGNED_INT32", CONV_TYPE, API_DRIVER), + "CU_AD_FORMAT_SIGNED_INT8": ("HIP_AD_FORMAT_SIGNED_INT8", CONV_TYPE, API_DRIVER), + "CU_AD_FORMAT_SIGNED_INT16": ("HIP_AD_FORMAT_SIGNED_INT16", CONV_TYPE, API_DRIVER), + "CU_AD_FORMAT_SIGNED_INT32": ("HIP_AD_FORMAT_SIGNED_INT32", CONV_TYPE, API_DRIVER), + "CU_AD_FORMAT_HALF": ("HIP_AD_FORMAT_HALF", CONV_TYPE, API_DRIVER), + "CU_AD_FORMAT_FLOAT": ("HIP_AD_FORMAT_FLOAT", CONV_TYPE, API_DRIVER), + "CU_COMPUTEMODE_DEFAULT": ("hipComputeModeDefault", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_COMPUTEMODE_EXCLUSIVE": ("hipComputeModeExclusive", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_COMPUTEMODE_PROHIBITED": ("hipComputeModeProhibited", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_COMPUTEMODE_EXCLUSIVE_PROCESS": ("hipComputeModeExclusiveProcess", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_MEM_ADVISE_SET_READ_MOSTLY": ("hipMemAdviseSetReadMostly", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_MEM_ADVISE_UNSET_READ_MOSTLY": ("hipMemAdviseUnsetReadMostly", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_MEM_ADVISE_SET_PREFERRED_LOCATION": ("hipMemAdviseSetPreferredLocation", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_MEM_ADVISE_UNSET_PREFERRED_LOCATION": ("hipMemAdviseUnsetPreferredLocation", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_MEM_ADVISE_SET_ACCESSED_BY": ("hipMemAdviseSetAccessedBy", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_MEM_ADVISE_UNSET_ACCESSED_BY": ("hipMemAdviseUnsetAccessedBy", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_MEM_RANGE_ATTRIBUTE_READ_MOSTLY": ("hipMemRangeAttributeReadMostly", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_MEM_RANGE_ATTRIBUTE_PREFERRED_LOCATION": ("hipMemRangeAttributePreferredLocation", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_MEM_RANGE_ATTRIBUTE_ACCESSED_BY": ("hipMemRangeAttributeAccessedBy", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_MEM_RANGE_ATTRIBUTE_LAST_PREFETCH_LOCATION": ("hipMemRangeAttributeLastPrefetchLocation", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_CTX_SCHED_AUTO": ("HIP_CTX_SCHED_AUTO", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_CTX_SCHED_SPIN": ("HIP_CTX_SCHED_SPIN", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_CTX_SCHED_YIELD": ("HIP_CTX_SCHED_YIELD", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_CTX_SCHED_BLOCKING_SYNC": ("HIP_CTX_SCHED_BLOCKING_SYNC", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_CTX_BLOCKING_SYNC": ("HIP_CTX_BLOCKING_SYNC", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_CTX_SCHED_MASK": ("HIP_CTX_SCHED_MASK", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_CTX_MAP_HOST": ("HIP_CTX_MAP_HOST", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_CTX_LMEM_RESIZE_TO_MAX": ("HIP_CTX_LMEM_RESIZE_TO_MAX", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_CTX_FLAGS_MASK": ("HIP_CTX_FLAGS_MASK", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_LAUNCH_PARAM_BUFFER_POINTER": ("HIP_LAUNCH_PARAM_BUFFER_POINTER", CONV_TYPE, API_DRIVER), + "CU_LAUNCH_PARAM_BUFFER_SIZE": ("HIP_LAUNCH_PARAM_BUFFER_SIZE", CONV_TYPE, API_DRIVER), + "CU_LAUNCH_PARAM_END": ("HIP_LAUNCH_PARAM_END", CONV_TYPE, API_DRIVER), + "CU_IPC_HANDLE_SIZE": ("HIP_LAUNCH_PARAM_END", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_MEMHOSTALLOC_DEVICEMAP": ("HIP_MEMHOSTALLOC_DEVICEMAP", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_MEMHOSTALLOC_PORTABLE": ("HIP_MEMHOSTALLOC_PORTABLE", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_MEMHOSTALLOC_WRITECOMBINED": ("HIP_MEMHOSTALLOC_WRITECOMBINED", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_MEMHOSTREGISTER_DEVICEMAP": ("HIP_MEMHOSTREGISTER_DEVICEMAP", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_MEMHOSTREGISTER_IOMEMORY": ("HIP_MEMHOSTREGISTER_IOMEMORY", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_MEMHOSTREGISTER_PORTABLE": ("HIP_MEMHOSTREGISTER_PORTABLE", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_PARAM_TR_DEFAULT": ("HIP_PARAM_TR_DEFAULT", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_STREAM_LEGACY": ("HIP_STREAM_LEGACY", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_STREAM_PER_THREAD": ("HIP_STREAM_PER_THREAD", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_TRSA_OVERRIDE_FORMAT": ("HIP_TRSA_OVERRIDE_FORMAT", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_TRSF_NORMALIZED_COORDINATES": ("HIP_TRSF_NORMALIZED_COORDINATES", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_TRSF_READ_AS_INTEGER": ("HIP_TRSF_READ_AS_INTEGER", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_TRSF_SRGB": ("HIP_TRSF_SRGB", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CUDA_ARRAY3D_2DARRAY": ("HIP_ARRAY3D_LAYERED", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CUDA_ARRAY3D_CUBEMAP": ("HIP_ARRAY3D_CUBEMAP", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CUDA_ARRAY3D_DEPTH_TEXTURE": ("HIP_ARRAY3D_DEPTH_TEXTURE", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CUDA_ARRAY3D_LAYERED": ("HIP_ARRAY3D_LAYERED", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CUDA_ARRAY3D_SURFACE_LDST": ("HIP_ARRAY3D_SURFACE_LDST", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CUDA_ARRAY3D_TEXTURE_GATHER": ("HIP_ARRAY3D_TEXTURE_GATHER", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + # "CUDA_VERSION": ("HIP_VERSION", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_MAX_THREADS_PER_BLOCK": ("hipDeviceAttributeMaxThreadsPerBlock", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_MAX_BLOCK_DIM_X": ("hipDeviceAttributeMaxBlockDimX", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_MAX_BLOCK_DIM_Y": ("hipDeviceAttributeMaxBlockDimY", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_MAX_BLOCK_DIM_Z": ("hipDeviceAttributeMaxBlockDimZ", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_MAX_GRID_DIM_X": ("hipDeviceAttributeMaxGridDimX", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_MAX_GRID_DIM_Y": ("hipDeviceAttributeMaxGridDimY", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_MAX_GRID_DIM_Z": ("hipDeviceAttributeMaxGridDimZ", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_MAX_SHARED_MEMORY_PER_BLOCK": ("hipDeviceAttributeMaxSharedMemoryPerBlock", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_SHARED_MEMORY_PER_BLOCK": ("hipDeviceAttributeMaxSharedMemoryPerBlock", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_TOTAL_CONSTANT_MEMORY": ("hipDeviceAttributeTotalConstantMemory", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_WARP_SIZE": ("hipDeviceAttributeWarpSize", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_MAX_PITCH": ("hipDeviceAttributeMaxPitch", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_MAX_REGISTERS_PER_BLOCK": ("hipDeviceAttributeMaxRegistersPerBlock", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_REGISTERS_PER_BLOCK": ("hipDeviceAttributeMaxRegistersPerBlock", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_CLOCK_RATE": ("hipDeviceAttributeClockRate", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_TEXTURE_ALIGNMENT": ("hipDeviceAttributeTextureAlignment", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_GPU_OVERLAP": ("hipDeviceAttributeAsyncEngineCount", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_MULTIPROCESSOR_COUNT": ("hipDeviceAttributeMultiprocessorCount", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_KERNEL_EXEC_TIMEOUT": ("hipDeviceAttributeKernelExecTimeout", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_INTEGRATED": ("hipDeviceAttributeIntegrated", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_CAN_MAP_HOST_MEMORY": ("hipDeviceAttributeCanMapHostMemory", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_COMPUTE_MODE": ("hipDeviceAttributeComputeMode", CONV_TYPE, API_DRIVER), + "CU_DEVICE_ATTRIBUTE_MAXIMUM_TEXTURE1D_WIDTH": ("hipDeviceAttributeMaxTexture1DWidth", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_MAXIMUM_TEXTURE2D_WIDTH": ("hipDeviceAttributeMaxTexture2DWidth", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_MAXIMUM_TEXTURE2D_HEIGHT": ("hipDeviceAttributeMaxTexture2DHeight", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_MAXIMUM_TEXTURE3D_WIDTH": ("hipDeviceAttributeMaxTexture3DWidth", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_MAXIMUM_TEXTURE3D_HEIGHT": ("hipDeviceAttributeMaxTexture3DHeight", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_MAXIMUM_TEXTURE3D_DEPTH": ("hipDeviceAttributeMaxTexture3DDepth", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_MAXIMUM_TEXTURE2D_LAYERED_WIDTH": ("hipDeviceAttributeMaxTexture2DLayeredWidth", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_MAXIMUM_TEXTURE2D_LAYERED_HEIGHT": ("hipDeviceAttributeMaxTexture2DLayeredHeight", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_MAXIMUM_TEXTURE2D_LAYERED_LAYERS": ("hipDeviceAttributeMaxTexture2DLayeredLayers", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_MAXIMUM_TEXTURE2D_ARRAY_WIDTH": ("hipDeviceAttributeMaxTexture2DLayeredWidth", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_MAXIMUM_TEXTURE2D_ARRAY_HEIGHT": ("hipDeviceAttributeMaxTexture2DLayeredHeight", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_MAXIMUM_TEXTURE2D_ARRAY_NUMSLICES": ("hipDeviceAttributeMaxTexture2DLayeredLayers", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_SURFACE_ALIGNMENT": ("hipDeviceAttributeSurfaceAlignment", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_CONCURRENT_KERNELS": ("hipDeviceAttributeConcurrentKernels", CONV_TYPE, API_DRIVER), + "CU_DEVICE_ATTRIBUTE_ECC_ENABLED": ("hipDeviceAttributeEccEnabled", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_PCI_BUS_ID": ("hipDeviceAttributePciBusId", CONV_TYPE, API_DRIVER), + "CU_DEVICE_ATTRIBUTE_PCI_DEVICE_ID": ("hipDeviceAttributePciDeviceId", CONV_TYPE, API_DRIVER), + "CU_DEVICE_ATTRIBUTE_TCC_DRIVER": ("hipDeviceAttributeTccDriver", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_MEMORY_CLOCK_RATE": ("hipDeviceAttributeMemoryClockRate", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_GLOBAL_MEMORY_BUS_WIDTH": ("hipDeviceAttributeMemoryBusWidth", CONV_TYPE, API_DRIVER), + "CU_DEVICE_ATTRIBUTE_L2_CACHE_SIZE": ("hipDeviceAttributeL2CacheSize", CONV_TYPE, API_DRIVER), + "CU_DEVICE_ATTRIBUTE_MAX_THREADS_PER_MULTIPROCESSOR": ("hipDeviceAttributeMaxThreadsPerMultiProcessor", CONV_TYPE, API_DRIVER), + "CU_DEVICE_ATTRIBUTE_ASYNC_ENGINE_COUNT": ("hipDeviceAttributeAsyncEngineCount", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_UNIFIED_ADDRESSING": ("hipDeviceAttributeUnifiedAddressing", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_MAXIMUM_TEXTURE1D_LAYERED_WIDTH": ("hipDeviceAttributeMaxTexture1DLayeredWidth", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_MAXIMUM_TEXTURE1D_LAYERED_LAYERS": ("hipDeviceAttributeMaxTexture1DLayeredLayers", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_CAN_TEX2D_GATHER": ("hipDeviceAttributeCanTex2DGather", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_MAXIMUM_TEXTURE2D_GATHER_WIDTH": ("hipDeviceAttributeMaxTexture2DGatherWidth", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_MAXIMUM_TEXTURE2D_GATHER_HEIGHT": ("hipDeviceAttributeMaxTexture2DGatherHeight", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_MAXIMUM_TEXTURE3D_WIDTH_ALTERNATE": ("hipDeviceAttributeMaxTexture3DWidthAlternate", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_MAXIMUM_TEXTURE3D_HEIGHT_ALTERNATE": ("hipDeviceAttributeMaxTexture3DHeightAlternate", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_MAXIMUM_TEXTURE3D_DEPTH_ALTERNATE": ("hipDeviceAttributeMaxTexture3DDepthAlternate", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_PCI_DOMAIN_ID": ("hipDeviceAttributePciDomainId", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_TEXTURE_PITCH_ALIGNMENT": ("hipDeviceAttributeTexturePitchAlignment", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_MAXIMUM_TEXTURECUBEMAP_WIDTH": ("hipDeviceAttributeMaxTextureCubemapWidth", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_MAXIMUM_TEXTURECUBEMAP_LAYERED_WIDTH": ("hipDeviceAttributeMaxTextureCubemapLayeredWidth", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_MAXIMUM_TEXTURECUBEMAP_LAYERED_LAYERS": ("hipDeviceAttributeMaxTextureCubemapLayeredLayers", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_MAXIMUM_SURFACE1D_WIDTH": ("hipDeviceAttributeMaxSurface1DWidth", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_MAXIMUM_SURFACE2D_WIDTH": ("hipDeviceAttributeMaxSurface2DWidth", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_MAXIMUM_SURFACE2D_HEIGHT": ("hipDeviceAttributeMaxSurface2DHeight", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_MAXIMUM_SURFACE3D_WIDTH": ("hipDeviceAttributeMaxSurface3DWidth", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_MAXIMUM_SURFACE3D_HEIGHT": ("hipDeviceAttributeMaxSurface3DHeight", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_MAXIMUM_SURFACE3D_DEPTH": ("hipDeviceAttributeMaxSurface3DDepth", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_MAXIMUM_SURFACE1D_LAYERED_WIDTH": ("hipDeviceAttributeMaxSurface1DLayeredWidth", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_MAXIMUM_SURFACE1D_LAYERED_LAYERS": ("hipDeviceAttributeMaxSurface1DLayeredLayers", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_MAXIMUM_SURFACE2D_LAYERED_WIDTH": ("hipDeviceAttributeMaxSurface2DLayeredWidth", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_MAXIMUM_SURFACE2D_LAYERED_HEIGHT": ("hipDeviceAttributeMaxSurface2DLayeredHeight", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_MAXIMUM_SURFACE2D_LAYERED_LAYERS": ("hipDeviceAttributeMaxSurface2DLayeredLayers", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_MAXIMUM_SURFACECUBEMAP_WIDTH": ("hipDeviceAttributeMaxSurfaceCubemapWidth", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_MAXIMUM_SURFACECUBEMAP_LAYERED_WIDTH": ("hipDeviceAttributeMaxSurfaceCubemapLayeredWidth", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_MAXIMUM_SURFACECUBEMAP_LAYERED_LAYERS": ("hipDeviceAttributeMaxSurfaceCubemapLayeredLayers", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_MAXIMUM_TEXTURE1D_LINEAR_WIDTH": ("hipDeviceAttributeMaxTexture1DLinearWidth", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_MAXIMUM_TEXTURE2D_LINEAR_WIDTH": ("hipDeviceAttributeMaxTexture2DLinearWidth", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_MAXIMUM_TEXTURE2D_LINEAR_HEIGHT": ("hipDeviceAttributeMaxTexture2DLinearHeight", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_MAXIMUM_TEXTURE2D_LINEAR_PITCH": ("hipDeviceAttributeMaxTexture2DLinearPitch", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_MAXIMUM_TEXTURE2D_MIPMAPPED_WIDTH": ("hipDeviceAttributeMaxTexture2DMipmappedWidth", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_MAXIMUM_TEXTURE2D_MIPMAPPED_HEIGHT": ("hipDeviceAttributeMaxTexture2DMipmappedHeight", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR": ("hipDeviceAttributeComputeCapabilityMajor", CONV_TYPE, API_DRIVER), + "CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR": ("hipDeviceAttributeComputeCapabilityMinor", CONV_TYPE, API_DRIVER), + "CU_DEVICE_ATTRIBUTE_MAXIMUM_TEXTURE1D_MIPMAPPED_WIDTH": ("hipDeviceAttributeMaxTexture1DMipmappedWidth", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_STREAM_PRIORITIES_SUPPORTED": ("hipDeviceAttributeStreamPrioritiesSupported", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_GLOBAL_L1_CACHE_SUPPORTED": ("hipDeviceAttributeGlobalL1CacheSupported", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_LOCAL_L1_CACHE_SUPPORTED": ("hipDeviceAttributeLocalL1CacheSupported", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_MAX_SHARED_MEMORY_PER_MULTIPROCESSOR": ("hipDeviceAttributeMaxSharedMemoryPerMultiprocessor", CONV_TYPE, API_DRIVER), + "CU_DEVICE_ATTRIBUTE_MAX_REGISTERS_PER_MULTIPROCESSOR": ("hipDeviceAttributeMaxRegistersPerMultiprocessor", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_MANAGED_MEMORY": ("hipDeviceAttributeManagedMemory", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_MULTI_GPU_BOARD": ("hipDeviceAttributeIsMultiGpuBoard", CONV_TYPE, API_DRIVER), + "CU_DEVICE_ATTRIBUTE_MULTI_GPU_BOARD_GROUP_ID": ("hipDeviceAttributeMultiGpuBoardGroupId", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_HOST_NATIVE_ATOMIC_SUPPORTED": ("hipDeviceAttributeHostNativeAtomicSupported", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_SINGLE_TO_DOUBLE_PRECISION_PERF_RATIO": ("hipDeviceAttributeSingleToDoublePrecisionPerfRatio", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_PAGEABLE_MEMORY_ACCESS": ("hipDeviceAttributePageableMemoryAccess", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_CONCURRENT_MANAGED_ACCESS": ("hipDeviceAttributeConcurrentManagedAccess", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_COMPUTE_PREEMPTION_SUPPORTED": ("hipDeviceAttributeComputePreemptionSupported", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_CAN_USE_HOST_POINTER_FOR_REGISTERED_MEM": ("hipDeviceAttributeCanUseHostPointerForRegisteredMem", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_ATTRIBUTE_MAX": ("hipDeviceAttributeMax", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_POINTER_ATTRIBUTE_CONTEXT": ("hipPointerAttributeContext", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_POINTER_ATTRIBUTE_MEMORY_TYPE": ("hipPointerAttributeMemoryType", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_POINTER_ATTRIBUTE_DEVICE_POINTER": ("hipPointerAttributeDevicePointer", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_POINTER_ATTRIBUTE_HOST_POINTER": ("hipPointerAttributeHostPointer", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_POINTER_ATTRIBUTE_P2P_TOKENS": ("hipPointerAttributeP2pTokens", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_POINTER_ATTRIBUTE_SYNC_MEMOPS": ("hipPointerAttributeSyncMemops", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_POINTER_ATTRIBUTE_BUFFER_ID": ("hipPointerAttributeBufferId", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_POINTER_ATTRIBUTE_IS_MANAGED": ("hipPointerAttributeIsManaged", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_FUNC_ATTRIBUTE_MAX_THREADS_PER_BLOCK": ("hipFuncAttributeMaxThreadsPerBlocks", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_FUNC_ATTRIBUTE_SHARED_SIZE_BYTES": ("hipFuncAttributeSharedSizeBytes", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_FUNC_ATTRIBUTE_CONST_SIZE_BYTES": ("hipFuncAttributeConstSizeBytes", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_FUNC_ATTRIBUTE_LOCAL_SIZE_BYTES": ("hipFuncAttributeLocalSizeBytes", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_FUNC_ATTRIBUTE_NUM_REGS": ("hipFuncAttributeNumRegs", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_FUNC_ATTRIBUTE_PTX_VERSION": ("hipFuncAttributePtxVersion", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_FUNC_ATTRIBUTE_BINARY_VERSION": ("hipFuncAttributeBinaryVersion", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_FUNC_ATTRIBUTE_CACHE_MODE_CA": ("hipFuncAttributeCacheModeCA", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_FUNC_ATTRIBUTE_MAX": ("hipFuncAttributeMax", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_GRAPHICS_MAP_RESOURCE_FLAGS_NONE": ("hipGraphicsMapFlagsNone", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_GRAPHICS_MAP_RESOURCE_FLAGS_READ_ONLY": ("hipGraphicsMapFlagsReadOnly", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_GRAPHICS_MAP_RESOURCE_FLAGS_WRITE_DISCARD": ("hipGraphicsMapFlagsWriteDiscard", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_GRAPHICS_REGISTER_FLAGS_NONE": ("hipGraphicsRegisterFlagsNone", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_GRAPHICS_REGISTER_FLAGS_READ_ONLY": ("hipGraphicsRegisterFlagsReadOnly", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_GRAPHICS_REGISTER_FLAGS_WRITE_DISCARD": ("hipGraphicsRegisterFlagsWriteDiscard", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_GRAPHICS_REGISTER_FLAGS_SURFACE_LDST": ("hipGraphicsRegisterFlagsSurfaceLoadStore", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_GRAPHICS_REGISTER_FLAGS_TEXTURE_GATHER": ("hipGraphicsRegisterFlagsTextureGather", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_OCCUPANCY_DEFAULT": ("hipOccupancyDefault", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_OCCUPANCY_DISABLE_CACHING_OVERRIDE": ("hipOccupancyDisableCachingOverride", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_FUNC_CACHE_PREFER_NONE": ("hipFuncCachePreferNone", CONV_CACHE, API_DRIVER), + "CU_FUNC_CACHE_PREFER_SHARED": ("hipFuncCachePreferShared", CONV_CACHE, API_DRIVER), + "CU_FUNC_CACHE_PREFER_L1": ("hipFuncCachePreferL1", CONV_CACHE, API_DRIVER), + "CU_FUNC_CACHE_PREFER_EQUAL": ("hipFuncCachePreferEqual", CONV_CACHE, API_DRIVER), + "CU_IPC_MEM_LAZY_ENABLE_PEER_ACCESS": ("hipIpcMemLazyEnablePeerAccess", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CUDA_IPC_HANDLE_SIZE": ("HIP_IPC_HANDLE_SIZE", CONV_TYPE, API_DRIVER), + "CU_JIT_CACHE_OPTION_NONE": ("hipJitCacheModeOptionNone", CONV_JIT, API_DRIVER, HIP_UNSUPPORTED), + "CU_JIT_CACHE_OPTION_CG": ("hipJitCacheModeOptionCG", CONV_JIT, API_DRIVER, HIP_UNSUPPORTED), + "CU_JIT_CACHE_OPTION_CA": ("hipJitCacheModeOptionCA", CONV_JIT, API_DRIVER, HIP_UNSUPPORTED), + "CU_PREFER_PTX": ("hipJitFallbackPreferPtx", CONV_JIT, API_DRIVER, HIP_UNSUPPORTED), + "CU_PREFER_BINARY": ("hipJitFallbackPreferBinary", CONV_JIT, API_DRIVER, HIP_UNSUPPORTED), + "CU_JIT_MAX_REGISTERS": ("hipJitOptionMaxRegisters", CONV_JIT, API_DRIVER), + "CU_JIT_THREADS_PER_BLOCK": ("hipJitOptionThreadsPerBlock", CONV_JIT, API_DRIVER), + "CU_JIT_WALL_TIME": ("hipJitOptionWallTime", CONV_JIT, API_DRIVER), + "CU_JIT_INFO_LOG_BUFFER": ("hipJitOptionInfoLogBuffer", CONV_JIT, API_DRIVER), + "CU_JIT_INFO_LOG_BUFFER_SIZE_BYTES": ("hipJitOptionInfoLogBufferSizeBytes", CONV_JIT, API_DRIVER), + "CU_JIT_ERROR_LOG_BUFFER": ("hipJitOptionErrorLogBuffer", CONV_JIT, API_DRIVER), + "CU_JIT_ERROR_LOG_BUFFER_SIZE_BYTES": ("hipJitOptionErrorLogBufferSizeBytes", CONV_JIT, API_DRIVER), + "CU_JIT_OPTIMIZATION_LEVEL": ("hipJitOptionOptimizationLevel", CONV_JIT, API_DRIVER), + "CU_JIT_TARGET_FROM_CUCONTEXT": ("hipJitOptionTargetFromContext", CONV_JIT, API_DRIVER), + "CU_JIT_TARGET": ("hipJitOptionTarget", CONV_JIT, API_DRIVER), + "CU_JIT_FALLBACK_STRATEGY": ("hipJitOptionFallbackStrategy", CONV_JIT, API_DRIVER), + "CU_JIT_GENERATE_DEBUG_INFO": ("hipJitOptionGenerateDebugInfo", CONV_JIT, API_DRIVER), + "CU_JIT_LOG_VERBOSE": ("hipJitOptionLogVerbose", CONV_JIT, API_DRIVER), + "CU_JIT_GENERATE_LINE_INFO": ("hipJitOptionGenerateLineInfo", CONV_JIT, API_DRIVER), + "CU_JIT_CACHE_MODE": ("hipJitOptionCacheMode", CONV_JIT, API_DRIVER), + "CU_JIT_NEW_SM3X_OPT": ("hipJitOptionSm3xOpt", CONV_JIT, API_DRIVER), + "CU_JIT_FAST_COMPILE": ("hipJitOptionFastCompile", CONV_JIT, API_DRIVER), + "CU_JIT_NUM_OPTIONS": ("hipJitOptionNumOptions", CONV_JIT, API_DRIVER), + "CU_TARGET_COMPUTE_10": ("hipJitTargetCompute10", CONV_JIT, API_DRIVER, HIP_UNSUPPORTED), + "CU_TARGET_COMPUTE_11": ("hipJitTargetCompute11", CONV_JIT, API_DRIVER, HIP_UNSUPPORTED), + "CU_TARGET_COMPUTE_12": ("hipJitTargetCompute12", CONV_JIT, API_DRIVER, HIP_UNSUPPORTED), + "CU_TARGET_COMPUTE_13": ("hipJitTargetCompute13", CONV_JIT, API_DRIVER, HIP_UNSUPPORTED), + "CU_TARGET_COMPUTE_20": ("hipJitTargetCompute20", CONV_JIT, API_DRIVER, HIP_UNSUPPORTED), + "CU_TARGET_COMPUTE_21": ("hipJitTargetCompute21", CONV_JIT, API_DRIVER, HIP_UNSUPPORTED), + "CU_TARGET_COMPUTE_30": ("hipJitTargetCompute30", CONV_JIT, API_DRIVER, HIP_UNSUPPORTED), + "CU_TARGET_COMPUTE_32": ("hipJitTargetCompute32", CONV_JIT, API_DRIVER, HIP_UNSUPPORTED), + "CU_TARGET_COMPUTE_35": ("hipJitTargetCompute35", CONV_JIT, API_DRIVER, HIP_UNSUPPORTED), + "CU_TARGET_COMPUTE_37": ("hipJitTargetCompute37", CONV_JIT, API_DRIVER, HIP_UNSUPPORTED), + "CU_TARGET_COMPUTE_50": ("hipJitTargetCompute50", CONV_JIT, API_DRIVER, HIP_UNSUPPORTED), + "CU_TARGET_COMPUTE_52": ("hipJitTargetCompute52", CONV_JIT, API_DRIVER, HIP_UNSUPPORTED), + "CU_TARGET_COMPUTE_53": ("hipJitTargetCompute53", CONV_JIT, API_DRIVER, HIP_UNSUPPORTED), + "CU_TARGET_COMPUTE_60": ("hipJitTargetCompute60", CONV_JIT, API_DRIVER, HIP_UNSUPPORTED), + "CU_TARGET_COMPUTE_61": ("hipJitTargetCompute61", CONV_JIT, API_DRIVER, HIP_UNSUPPORTED), + "CU_TARGET_COMPUTE_62": ("hipJitTargetCompute62", CONV_JIT, API_DRIVER, HIP_UNSUPPORTED), + "CU_JIT_INPUT_CUBIN": ("hipJitInputTypeBin", CONV_JIT, API_DRIVER, HIP_UNSUPPORTED), + "CU_JIT_INPUT_PTX": ("hipJitInputTypePtx", CONV_JIT, API_DRIVER, HIP_UNSUPPORTED), + "CU_JIT_INPUT_FATBINARY": ("hipJitInputTypeFatBinary", CONV_JIT, API_DRIVER, HIP_UNSUPPORTED), + "CU_JIT_INPUT_OBJECT": ("hipJitInputTypeObject", CONV_JIT, API_DRIVER, HIP_UNSUPPORTED), + "CU_JIT_INPUT_LIBRARY": ("hipJitInputTypeLibrary", CONV_JIT, API_DRIVER, HIP_UNSUPPORTED), + "CU_JIT_NUM_INPUT_TYPES": ("hipJitInputTypeNumInputTypes", CONV_JIT, API_DRIVER, HIP_UNSUPPORTED), + "CU_LIMIT_STACK_SIZE": ("hipLimitStackSize", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_LIMIT_PRINTF_FIFO_SIZE": ("hipLimitPrintfFifoSize", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_LIMIT_MALLOC_HEAP_SIZE": ("hipLimitMallocHeapSize", CONV_TYPE, API_DRIVER), + "CU_LIMIT_DEV_RUNTIME_SYNC_DEPTH": ("hipLimitDevRuntimeSyncDepth", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_LIMIT_DEV_RUNTIME_PENDING_LAUNCH_COUNT": ("hipLimitDevRuntimePendingLaunchCount", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_LIMIT_STACK_SIZE": ("hipLimitStackSize", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_MEM_ATTACH_GLOBAL": ("hipMemAttachGlobal", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_MEM_ATTACH_HOST": ("hipMemAttachHost", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_MEM_ATTACH_SINGLE": ("hipMemAttachSingle", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_MEMORYTYPE_HOST": ("hipMemTypeHost", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_MEMORYTYPE_DEVICE": ("hipMemTypeDevice", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_MEMORYTYPE_ARRAY": ("hipMemTypeArray", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_MEMORYTYPE_UNIFIED": ("hipMemTypeUnified", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_RESOURCE_TYPE_ARRAY": ("hipResourceTypeArray", CONV_TEX, API_DRIVER, HIP_UNSUPPORTED), + "CU_RESOURCE_TYPE_MIPMAPPED_ARRAY": ("hipResourceTypeMipmappedArray", CONV_TEX, API_DRIVER, HIP_UNSUPPORTED), + "CU_RESOURCE_TYPE_LINEAR": ("hipResourceTypeLinear", CONV_TEX, API_DRIVER, HIP_UNSUPPORTED), + "CU_RESOURCE_TYPE_PITCH2D": ("hipResourceTypePitch2D", CONV_TEX, API_DRIVER, HIP_UNSUPPORTED), + "CU_RES_VIEW_FORMAT_NONE": ("hipResViewFormatNone", CONV_TEX, API_DRIVER), + "CU_RES_VIEW_FORMAT_UINT_1X8": ("hipResViewFormatUnsignedChar1", CONV_TEX, API_DRIVER), + "CU_RES_VIEW_FORMAT_UINT_2X8": ("hipResViewFormatUnsignedChar2", CONV_TEX, API_DRIVER), + "CU_RES_VIEW_FORMAT_UINT_4X8": ("hipResViewFormatUnsignedChar4", CONV_TEX, API_DRIVER), + "CU_RES_VIEW_FORMAT_SINT_1X8": ("hipResViewFormatSignedChar1", CONV_TEX, API_DRIVER), + "CU_RES_VIEW_FORMAT_SINT_2X8": ("hipResViewFormatSignedChar2", CONV_TEX, API_DRIVER), + "CU_RES_VIEW_FORMAT_SINT_4X8": ("hipResViewFormatSignedChar4", CONV_TEX, API_DRIVER), + "CU_RES_VIEW_FORMAT_UINT_1X16": ("hipResViewFormatUnsignedShort1", CONV_TEX, API_DRIVER), + "CU_RES_VIEW_FORMAT_UINT_2X16": ("hipResViewFormatUnsignedShort2", CONV_TEX, API_DRIVER), + "CU_RES_VIEW_FORMAT_UINT_4X16": ("hipResViewFormatUnsignedShort4", CONV_TEX, API_DRIVER), + "CU_RES_VIEW_FORMAT_SINT_1X16": ("hipResViewFormatSignedShort1", CONV_TEX, API_DRIVER), + "CU_RES_VIEW_FORMAT_SINT_2X16": ("hipResViewFormatSignedShort2", CONV_TEX, API_DRIVER), + "CU_RES_VIEW_FORMAT_SINT_4X16": ("hipResViewFormatSignedShort4", CONV_TEX, API_DRIVER), + "CU_RES_VIEW_FORMAT_UINT_1X32": ("hipResViewFormatUnsignedInt1", CONV_TEX, API_DRIVER), + "CU_RES_VIEW_FORMAT_UINT_2X32": ("hipResViewFormatUnsignedInt2", CONV_TEX, API_DRIVER), + "CU_RES_VIEW_FORMAT_UINT_4X32": ("hipResViewFormatUnsignedInt4", CONV_TEX, API_DRIVER), + "CU_RES_VIEW_FORMAT_SINT_1X32": ("hipResViewFormatSignedInt1", CONV_TEX, API_DRIVER), + "CU_RES_VIEW_FORMAT_SINT_2X32": ("hipResViewFormatSignedInt2", CONV_TEX, API_DRIVER), + "CU_RES_VIEW_FORMAT_SINT_4X32": ("hipResViewFormatSignedInt4", CONV_TEX, API_DRIVER), + "CU_RES_VIEW_FORMAT_FLOAT_1X16": ("hipResViewFormatHalf1", CONV_TEX, API_DRIVER), + "CU_RES_VIEW_FORMAT_FLOAT_2X16": ("hipResViewFormatHalf2", CONV_TEX, API_DRIVER), + "CU_RES_VIEW_FORMAT_FLOAT_4X16": ("hipResViewFormatHalf4", CONV_TEX, API_DRIVER), + "CU_RES_VIEW_FORMAT_FLOAT_1X32": ("hipResViewFormatFloat1", CONV_TEX, API_DRIVER), + "CU_RES_VIEW_FORMAT_FLOAT_2X32": ("hipResViewFormatFloat2", CONV_TEX, API_DRIVER), + "CU_RES_VIEW_FORMAT_FLOAT_4X32": ("hipResViewFormatFloat4", CONV_TEX, API_DRIVER), + "CU_RES_VIEW_FORMAT_UNSIGNED_BC1": ("hipResViewFormatUnsignedBlockCompressed1", CONV_TEX, API_DRIVER), + "CU_RES_VIEW_FORMAT_UNSIGNED_BC2": ("hipResViewFormatUnsignedBlockCompressed2", CONV_TEX, API_DRIVER), + "CU_RES_VIEW_FORMAT_UNSIGNED_BC3": ("hipResViewFormatUnsignedBlockCompressed3", CONV_TEX, API_DRIVER), + "CU_RES_VIEW_FORMAT_UNSIGNED_BC4": ("hipResViewFormatUnsignedBlockCompressed4", CONV_TEX, API_DRIVER), + "CU_RES_VIEW_FORMAT_SIGNED_BC4": ("hipResViewFormatSignedBlockCompressed4", CONV_TEX, API_DRIVER), + "CU_RES_VIEW_FORMAT_UNSIGNED_BC5": ("hipResViewFormatUnsignedBlockCompressed5", CONV_TEX, API_DRIVER), + "CU_RES_VIEW_FORMAT_SIGNED_BC5": ("hipResViewFormatSignedBlockCompressed5", CONV_TEX, API_DRIVER), + "CU_RES_VIEW_FORMAT_UNSIGNED_BC6H": ("hipResViewFormatUnsignedBlockCompressed6H", CONV_TEX, API_DRIVER), + "CU_RES_VIEW_FORMAT_SIGNED_BC6H": ("hipResViewFormatSignedBlockCompressed6H", CONV_TEX, API_DRIVER), + "CU_RES_VIEW_FORMAT_UNSIGNED_BC7": ("hipResViewFormatUnsignedBlockCompressed7", CONV_TEX, API_DRIVER), + "CU_SHARED_MEM_CONFIG_DEFAULT_BANK_SIZE": ("hipSharedMemBankSizeDefault", CONV_TYPE, API_DRIVER), + "CU_SHARED_MEM_CONFIG_FOUR_BYTE_BANK_SIZE": ("hipSharedMemBankSizeFourByte", CONV_TYPE, API_DRIVER), + "CU_SHARED_MEM_CONFIG_EIGHT_BYTE_BANK_SIZE": ("hipSharedMemBankSizeEightByte", CONV_TYPE, API_DRIVER), + "CU_STREAM_DEFAULT": ("hipStreamDefault", CONV_TYPE, API_DRIVER), + "CU_STREAM_NON_BLOCKING": ("hipStreamNonBlocking", CONV_TYPE, API_DRIVER), + "CU_STREAM_WAIT_VALUE_GEQ": ("hipStreamWaitValueGeq", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_STREAM_WAIT_VALUE_EQ": ("hipStreamWaitValueEq", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_STREAM_WAIT_VALUE_AND": ("hipStreamWaitValueAnd", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_STREAM_WAIT_VALUE_FLUSH": ("hipStreamWaitValueFlush", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_STREAM_WRITE_VALUE_DEFAULT": ("hipStreamWriteValueDefault", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_STREAM_WRITE_VALUE_NO_MEMORY_BARRIER": ("hipStreamWriteValueNoMemoryBarrier", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_STREAM_MEM_OP_WAIT_VALUE_32": ("hipStreamBatchMemOpWaitValue32", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_STREAM_MEM_OP_WRITE_VALUE_32": ("hipStreamBatchMemOpWriteValue32", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_STREAM_MEM_OP_FLUSH_REMOTE_WRITES": ("hipStreamBatchMemOpFlushRemoteWrites", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "cuGetErrorName": ("hipGetErrorName___", CONV_ERROR, API_DRIVER, HIP_UNSUPPORTED), + "cuGetErrorString": ("hipGetErrorString___", CONV_ERROR, API_DRIVER, HIP_UNSUPPORTED), + "cuInit": ("hipInit", CONV_INIT, API_DRIVER), + "cuDriverGetVersion": ("hipDriverGetVersion", CONV_VERSION, API_DRIVER), + "cuCtxCreate_v2": ("hipCtxCreate", CONV_CONTEXT, API_DRIVER), + "cuCtxDestroy_v2": ("hipCtxDestroy", CONV_CONTEXT, API_DRIVER), + "cuCtxGetApiVersion": ("hipCtxGetApiVersion", CONV_CONTEXT, API_DRIVER), + "cuCtxGetCacheConfig": ("hipCtxGetCacheConfig", CONV_CONTEXT, API_DRIVER), + "cuCtxGetCurrent": ("hipCtxGetCurrent", CONV_CONTEXT, API_DRIVER), + "cuCtxGetDevice": ("hipCtxGetDevice", CONV_CONTEXT, API_DRIVER), + "cuCtxGetFlags": ("hipCtxGetFlags", CONV_CONTEXT, API_DRIVER), + "cuCtxGetLimit": ("hipCtxGetLimit", CONV_CONTEXT, API_DRIVER, HIP_UNSUPPORTED), + "cuCtxGetSharedMemConfig": ("hipCtxGetSharedMemConfig", CONV_CONTEXT, API_DRIVER), + "cuCtxGetStreamPriorityRange": ("hipCtxGetStreamPriorityRange", CONV_CONTEXT, API_DRIVER, HIP_UNSUPPORTED), + "cuCtxPopCurrent_v2": ("hipCtxPopCurrent", CONV_CONTEXT, API_DRIVER), + "cuCtxPushCurrent_v2": ("hipCtxPushCurrent", CONV_CONTEXT, API_DRIVER), + "cuCtxSetCacheConfig": ("hipCtxSetCacheConfig", CONV_CONTEXT, API_DRIVER), + "cuCtxSetCurrent": ("hipCtxSetCurrent", CONV_CONTEXT, API_DRIVER), + "cuCtxSetLimit": ("hipCtxSetLimit", CONV_CONTEXT, API_DRIVER, HIP_UNSUPPORTED), + "cuCtxSetSharedMemConfig": ("hipCtxSetSharedMemConfig", CONV_CONTEXT, API_DRIVER), + "cuCtxSynchronize": ("hipCtxSynchronize", CONV_CONTEXT, API_DRIVER), + "cuCtxAttach": ("hipCtxAttach", CONV_CONTEXT, API_DRIVER, HIP_UNSUPPORTED), + "cuCtxDetach": ("hipCtxDetach", CONV_CONTEXT, API_DRIVER, HIP_UNSUPPORTED), + "cuCtxEnablePeerAccess": ("hipCtxEnablePeerAccess", CONV_PEER, API_DRIVER), + "cuCtxDisablePeerAccess": ("hipCtxDisablePeerAccess", CONV_PEER, API_DRIVER), + "cuDeviceCanAccessPeer": ("hipDeviceCanAccessPeer", CONV_PEER, API_DRIVER), + "cuDeviceGetP2PAttribute": ("hipDeviceGetP2PAttribute", CONV_PEER, API_DRIVER, HIP_UNSUPPORTED), + "cuDevicePrimaryCtxGetState": ("hipDevicePrimaryCtxGetState", CONV_CONTEXT, API_DRIVER), + "cuDevicePrimaryCtxRelease": ("hipDevicePrimaryCtxRelease", CONV_CONTEXT, API_DRIVER), + "cuDevicePrimaryCtxReset": ("hipDevicePrimaryCtxReset", CONV_CONTEXT, API_DRIVER), + "cuDevicePrimaryCtxRetain": ("hipDevicePrimaryCtxRetain", CONV_CONTEXT, API_DRIVER), + "cuDevicePrimaryCtxSetFlags": ("hipDevicePrimaryCtxSetFlags", CONV_CONTEXT, API_DRIVER), + "cuDeviceGet": ("hipGetDevice", CONV_DEVICE, API_DRIVER), + "cuDeviceGetName": ("hipDeviceGetName", CONV_DEVICE, API_DRIVER), + "cuDeviceGetCount": ("hipGetDeviceCount", CONV_DEVICE, API_DRIVER), + "cuDeviceGetAttribute": ("hipDeviceGetAttribute", CONV_DEVICE, API_DRIVER), + "cuDeviceGetPCIBusId": ("hipDeviceGetPCIBusId", CONV_DEVICE, API_DRIVER), + "cuDeviceGetByPCIBusId": ("hipDeviceGetByPCIBusId", CONV_DEVICE, API_DRIVER), + "cuDeviceTotalMem_v2": ("hipDeviceTotalMem", CONV_DEVICE, API_DRIVER), + "cuDeviceComputeCapability": ("hipDeviceComputeCapability", CONV_DEVICE, API_DRIVER), + "cuDeviceGetProperties": ("hipGetDeviceProperties", CONV_DEVICE, API_DRIVER), + "cuLinkAddData": ("hipLinkAddData", CONV_MODULE, API_DRIVER, HIP_UNSUPPORTED), + "cuLinkAddFile": ("hipLinkAddFile", CONV_MODULE, API_DRIVER, HIP_UNSUPPORTED), + "cuLinkComplete": ("hipLinkComplete", CONV_MODULE, API_DRIVER, HIP_UNSUPPORTED), + "cuLinkCreate": ("hipLinkCreate", CONV_MODULE, API_DRIVER, HIP_UNSUPPORTED), + "cuLinkDestroy": ("hipLinkDestroy", CONV_MODULE, API_DRIVER, HIP_UNSUPPORTED), + "cuModuleGetFunction": ("hipModuleGetFunction", CONV_MODULE, API_DRIVER), + "cuModuleGetGlobal_v2": ("hipModuleGetGlobal", CONV_MODULE, API_DRIVER), + "cuModuleGetSurfRef": ("hipModuleGetSurfRef", CONV_MODULE, API_DRIVER, HIP_UNSUPPORTED), + "cuModuleGetTexRef": ("hipModuleGetTexRef", CONV_MODULE, API_DRIVER), + "cuModuleLoad": ("hipModuleLoad", CONV_MODULE, API_DRIVER), + "cuModuleLoadData": ("hipModuleLoadData", CONV_MODULE, API_DRIVER), + "cuModuleLoadDataEx": ("hipModuleLoadDataEx", CONV_MODULE, API_DRIVER), + "cuModuleLoadFatBinary": ("hipModuleLoadFatBinary", CONV_MODULE, API_DRIVER, HIP_UNSUPPORTED), + "cuModuleUnload": ("hipModuleUnload", CONV_MODULE, API_DRIVER), + "CU_DEVICE_P2P_ATTRIBUTE_PERFORMANCE_RANK": ("hipDeviceP2PAttributePerformanceRank", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_P2P_ATTRIBUTE_ACCESS_SUPPORTED": ("hipDeviceP2PAttributeAccessSupported", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_DEVICE_P2P_ATTRIBUTE_NATIVE_ATOMIC_SUPPORTED": ("hipDeviceP2PAttributeNativeAtomicSupported", CONV_TYPE, API_DRIVER, HIP_UNSUPPORTED), + "CU_EVENT_DEFAULT": ("hipEventDefault", CONV_EVENT, API_DRIVER), + "CU_EVENT_BLOCKING_SYNC": ("hipEventBlockingSync", CONV_EVENT, API_DRIVER), + "CU_EVENT_DISABLE_TIMING": ("hipEventDisableTiming", CONV_EVENT, API_DRIVER), + "CU_EVENT_INTERPROCESS": ("hipEventInterprocess", CONV_EVENT, API_DRIVER), + "cuEventCreate": ("hipEventCreate", CONV_EVENT, API_DRIVER), + "cuEventDestroy_v2": ("hipEventDestroy", CONV_EVENT, API_DRIVER), + "cuEventElapsedTime": ("hipEventElapsedTime", CONV_EVENT, API_DRIVER), + "cuEventQuery": ("hipEventQuery", CONV_EVENT, API_DRIVER), + "cuEventRecord": ("hipEventRecord", CONV_EVENT, API_DRIVER), + "cuEventSynchronize": ("hipEventSynchronize", CONV_EVENT, API_DRIVER), + "cuFuncGetAttribute": ("hipFuncGetAttribute", CONV_MODULE, API_DRIVER, HIP_UNSUPPORTED), + "cuFuncSetCacheConfig": ("hipFuncSetCacheConfig", CONV_MODULE, API_DRIVER), + "cuFuncSetSharedMemConfig": ("hipFuncSetSharedMemConfig", CONV_MODULE, API_DRIVER, HIP_UNSUPPORTED), + "cuLaunchKernel": ("hipModuleLaunchKernel", CONV_MODULE, API_DRIVER), + "cuFuncSetBlockShape": ("hipFuncSetBlockShape", CONV_MODULE, API_DRIVER, HIP_UNSUPPORTED), + "cuFuncSetSharedSize": ("hipFuncSetSharedSize", CONV_MODULE, API_DRIVER, HIP_UNSUPPORTED), + "cuLaunch": ("hipLaunch", CONV_MODULE, API_DRIVER, HIP_UNSUPPORTED), + "cuLaunchGrid": ("hipLaunchGrid", CONV_MODULE, API_DRIVER, HIP_UNSUPPORTED), + "cuLaunchGridAsync": ("hipLaunchGridAsync", CONV_MODULE, API_DRIVER, HIP_UNSUPPORTED), + "cuParamSetf": ("hipParamSetf", CONV_MODULE, API_DRIVER, HIP_UNSUPPORTED), + "cuParamSeti": ("hipParamSeti", CONV_MODULE, API_DRIVER, HIP_UNSUPPORTED), + "cuParamSetSize": ("hipParamSetSize", CONV_MODULE, API_DRIVER, HIP_UNSUPPORTED), + "cuParamSetSize": ("hipParamSetSize", CONV_MODULE, API_DRIVER, HIP_UNSUPPORTED), + "cuParamSetv": ("hipParamSetv", CONV_MODULE, API_DRIVER, HIP_UNSUPPORTED), + "cuOccupancyMaxActiveBlocksPerMultiprocessor": ("hipOccupancyMaxActiveBlocksPerMultiprocessor", CONV_OCCUPANCY, API_DRIVER), + "cuOccupancyMaxActiveBlocksPerMultiprocessorWithFlags": ("hipOccupancyMaxActiveBlocksPerMultiprocessorWithFlags", CONV_OCCUPANCY, API_DRIVER, HIP_UNSUPPORTED), + "cuOccupancyMaxPotentialBlockSize": ("hipOccupancyMaxPotentialBlockSize", CONV_OCCUPANCY, API_DRIVER), + "cuOccupancyMaxPotentialBlockSizeWithFlags": ("hipOccupancyMaxPotentialBlockSizeWithFlags", CONV_OCCUPANCY, API_DRIVER, HIP_UNSUPPORTED), + "cuStreamAddCallback": ("hipStreamAddCallback", CONV_STREAM, API_DRIVER), + "cuStreamAttachMemAsync": ("hipStreamAttachMemAsync", CONV_STREAM, API_DRIVER, HIP_UNSUPPORTED), + "cuStreamCreate": ("hipStreamCreate__", CONV_STREAM, API_DRIVER, HIP_UNSUPPORTED), + "cuStreamCreateWithPriority": ("hipStreamCreateWithPriority", CONV_STREAM, API_DRIVER, HIP_UNSUPPORTED), + "cuStreamDestroy_v2": ("hipStreamDestroy", CONV_STREAM, API_DRIVER), + "cuStreamGetFlags": ("hipStreamGetFlags", CONV_STREAM, API_DRIVER), + "cuStreamGetPriority": ("hipStreamGetPriority", CONV_STREAM, API_DRIVER, HIP_UNSUPPORTED), + "cuStreamQuery": ("hipStreamQuery", CONV_STREAM, API_DRIVER), + "cuStreamSynchronize": ("hipStreamSynchronize", CONV_STREAM, API_DRIVER), + "cuStreamWaitEvent": ("hipStreamWaitEvent", CONV_STREAM, API_DRIVER), + "cuStreamWaitValue32": ("hipStreamWaitValue32", CONV_STREAM, API_DRIVER, HIP_UNSUPPORTED), + "cuStreamWriteValue32": ("hipStreamWriteValue32", CONV_STREAM, API_DRIVER, HIP_UNSUPPORTED), + "cuStreamBatchMemOp": ("hipStreamBatchMemOp", CONV_STREAM, API_DRIVER, HIP_UNSUPPORTED), + "cuArray3DCreate": ("hipArray3DCreate", CONV_MEM, API_DRIVER), + "cuArray3DGetDescriptor": ("hipArray3DGetDescriptor", CONV_MEM, API_DRIVER, HIP_UNSUPPORTED), + "cuArrayCreate": ("hipArrayCreate", CONV_MEM, API_DRIVER, HIP_UNSUPPORTED), + "cuArrayDestroy": ("hipArrayDestroy", CONV_MEM, API_DRIVER, HIP_UNSUPPORTED), + "cuArrayGetDescriptor": ("hipArrayGetDescriptor", CONV_MEM, API_DRIVER, HIP_UNSUPPORTED), + "cuIpcCloseMemHandle": ("hipIpcCloseMemHandle", CONV_MEM, API_DRIVER, HIP_UNSUPPORTED), + "cuIpcGetEventHandle": ("hipIpcGetEventHandle", CONV_MEM, API_DRIVER, HIP_UNSUPPORTED), + "cuIpcGetMemHandle": ("hipIpcGetMemHandle", CONV_MEM, API_DRIVER, HIP_UNSUPPORTED), + "cuIpcOpenEventHandle": ("hipIpcOpenEventHandle", CONV_MEM, API_DRIVER, HIP_UNSUPPORTED), + "cuIpcOpenMemHandle": ("hipIpcOpenMemHandle", CONV_MEM, API_DRIVER, HIP_UNSUPPORTED), + "cuMemAlloc_v2": ("hipMalloc", CONV_MEM, API_DRIVER), + "cuMemAllocHost": ("hipMemAllocHost", CONV_MEM, API_DRIVER, HIP_UNSUPPORTED), + "cuMemAllocManaged": ("hipMemAllocManaged", CONV_MEM, API_DRIVER, HIP_UNSUPPORTED), + "cuMemAllocPitch": ("hipMemAllocPitch__", CONV_MEM, API_DRIVER, HIP_UNSUPPORTED), + "cuMemcpy": ("hipMemcpy__", CONV_MEM, API_DRIVER, HIP_UNSUPPORTED), + "cuMemcpy2D": ("hipMemcpy2D__", CONV_MEM, API_DRIVER, HIP_UNSUPPORTED), + "cuMemcpy2DAsync": ("hipMemcpy2DAsync__", CONV_MEM, API_DRIVER, HIP_UNSUPPORTED), + "cuMemcpy2DUnaligned": ("hipMemcpy2DUnaligned", CONV_MEM, API_DRIVER, HIP_UNSUPPORTED), + "cuMemcpy3D": ("hipMemcpy3D__", CONV_MEM, API_DRIVER, HIP_UNSUPPORTED), + "cuMemcpy3DAsync": ("hipMemcpy3DAsync__", CONV_MEM, API_DRIVER, HIP_UNSUPPORTED), + "cuMemcpy3DPeer": ("hipMemcpy3DPeer__", CONV_MEM, API_DRIVER, HIP_UNSUPPORTED), + "cuMemcpy3DPeerAsync": ("hipMemcpy3DPeerAsync__", CONV_MEM, API_DRIVER, HIP_UNSUPPORTED), + "cuMemcpyAsync": ("hipMemcpyAsync__", CONV_MEM, API_DRIVER, HIP_UNSUPPORTED), + "cuMemcpyAtoA": ("hipMemcpyAtoA", CONV_MEM, API_DRIVER, HIP_UNSUPPORTED), + "cuMemcpyAtoD": ("hipMemcpyAtoD", CONV_MEM, API_DRIVER, HIP_UNSUPPORTED), + "cuMemcpyAtoH": ("hipMemcpyAtoH", CONV_MEM, API_DRIVER, HIP_UNSUPPORTED), + "cuMemcpyAtoHAsync": ("hipMemcpyAtoHAsync", CONV_MEM, API_DRIVER, HIP_UNSUPPORTED), + "cuMemcpyDtoA": ("hipMemcpyDtoA", CONV_MEM, API_DRIVER, HIP_UNSUPPORTED), + "cuMemcpyDtoD_v2": ("hipMemcpyDtoD", CONV_MEM, API_DRIVER), + "cuMemcpyDtoDAsync_v2": ("hipMemcpyDtoDAsync", CONV_MEM, API_DRIVER), + "cuMemcpyDtoH_v2": ("hipMemcpyDtoH", CONV_MEM, API_DRIVER), + "cuMemcpyDtoHAsync_v2": ("hipMemcpyDtoHAsync", CONV_MEM, API_DRIVER), + "cuMemcpyHtoA": ("hipMemcpyHtoA", CONV_MEM, API_DRIVER, HIP_UNSUPPORTED), + "cuMemcpyHtoAAsync": ("hipMemcpyHtoAAsync", CONV_MEM, API_DRIVER, HIP_UNSUPPORTED), + "cuMemcpyHtoD_v2": ("hipMemcpyHtoD", CONV_MEM, API_DRIVER), + "cuMemcpyHtoDAsync_v2": ("hipMemcpyHtoDAsync", CONV_MEM, API_DRIVER), + "cuMemcpyPeerAsync": ("hipMemcpyPeerAsync__", CONV_MEM, API_DRIVER, HIP_UNSUPPORTED), + "cuMemcpyPeer": ("hipMemcpyPeer__", CONV_MEM, API_DRIVER, HIP_UNSUPPORTED), + "cuMemFree_v2": ("hipFree", CONV_MEM, API_DRIVER), + "cuMemFreeHost": ("hipHostFree", CONV_MEM, API_DRIVER), + "cuMemGetAddressRange": ("hipMemGetAddressRange", CONV_MEM, API_DRIVER, HIP_UNSUPPORTED), + "cuMemGetInfo_v2": ("hipMemGetInfo", CONV_MEM, API_DRIVER), + "cuMemHostAlloc": ("hipHostMalloc", CONV_MEM, API_DRIVER), + "cuMemHostGetDevicePointer": ("hipMemHostGetDevicePointer", CONV_MEM, API_DRIVER, HIP_UNSUPPORTED), + "cuMemHostGetFlags": ("hipMemHostGetFlags", CONV_MEM, API_DRIVER, HIP_UNSUPPORTED), + "cuMemHostRegister_v2": ("hipHostRegister", CONV_MEM, API_DRIVER), + "cuMemHostUnregister": ("hipHostUnregister", CONV_MEM, API_DRIVER), + "cuMemsetD16_v2": ("hipMemsetD16", CONV_MEM, API_DRIVER, HIP_UNSUPPORTED), + "cuMemsetD16Async": ("hipMemsetD16Async", CONV_MEM, API_DRIVER, HIP_UNSUPPORTED), + "cuMemsetD2D16_v2": ("hipMemsetD2D16", CONV_MEM, API_DRIVER, HIP_UNSUPPORTED), + "cuMemsetD2D16Async": ("hipMemsetD2D16Async", CONV_MEM, API_DRIVER, HIP_UNSUPPORTED), + "cuMemsetD2D32_v2": ("hipMemsetD2D32", CONV_MEM, API_DRIVER, HIP_UNSUPPORTED), + "cuMemsetD2D32Async": ("hipMemsetD2D32Async", CONV_MEM, API_DRIVER, HIP_UNSUPPORTED), + "cuMemsetD2D8_v2": ("hipMemsetD2D8", CONV_MEM, API_DRIVER, HIP_UNSUPPORTED), + "cuMemsetD2D8Async": ("hipMemsetD2D8Async", CONV_MEM, API_DRIVER, HIP_UNSUPPORTED), + "cuMemsetD32_v2": ("hipMemset", CONV_MEM, API_DRIVER), + "cuMemsetD32Async": ("hipMemsetAsync", CONV_MEM, API_DRIVER), + "cuMemsetD8_v2": ("hipMemsetD8", CONV_MEM, API_DRIVER, HIP_UNSUPPORTED), + "cuMemsetD8Async": ("hipMemsetD8Async", CONV_MEM, API_DRIVER, HIP_UNSUPPORTED), + "cuMipmappedArrayCreate": ("hipMipmappedArrayCreate", CONV_MEM, API_DRIVER, HIP_UNSUPPORTED), + "cuMipmappedArrayDestroy": ("hipMipmappedArrayDestroy", CONV_MEM, API_DRIVER, HIP_UNSUPPORTED), + "cuMipmappedArrayGetLevel": ("hipMipmappedArrayGetLevel", CONV_MEM, API_DRIVER, HIP_UNSUPPORTED), + "cuMemPrefetchAsync": ("hipMemPrefetchAsync__", CONV_MEM, API_DRIVER, HIP_UNSUPPORTED), + "cuMemAdvise": ("hipMemAdvise", CONV_MEM, API_DRIVER, HIP_UNSUPPORTED), + "cuMemRangeGetAttribute": ("hipMemRangeGetAttribute", CONV_MEM, API_DRIVER, HIP_UNSUPPORTED), + "cuMemRangeGetAttributes": ("hipMemRangeGetAttributes", CONV_MEM, API_DRIVER, HIP_UNSUPPORTED), + "cuPointerGetAttribute": ("hipPointerGetAttribute", CONV_MEM, API_DRIVER, HIP_UNSUPPORTED), + "cuPointerGetAttributes": ("hipPointerGetAttributes", CONV_MEM, API_DRIVER, HIP_UNSUPPORTED), + "cuPointerSetAttribute": ("hipPointerSetAttribute", CONV_MEM, API_DRIVER, HIP_UNSUPPORTED), + "CU_TR_FILTER_MODE_POINT": ("hipFilterModePoint", CONV_TEX, API_DRIVER), + "CU_TR_FILTER_MODE_LINEAR": ("hipFilterModeLinear", CONV_TEX, API_DRIVER, HIP_UNSUPPORTED), + "cuTexRefGetAddress": ("hipTexRefGetAddress", CONV_TEX, API_DRIVER, HIP_UNSUPPORTED), + "cuTexRefGetAddressMode": ("hipTexRefGetAddressMode", CONV_TEX, API_DRIVER, HIP_UNSUPPORTED), + "cuTexRefGetArray": ("hipTexRefGetArray", CONV_TEX, API_DRIVER, HIP_UNSUPPORTED), + "cuTexRefGetBorderColor": ("hipTexRefGetBorderColor", CONV_TEX, API_DRIVER, HIP_UNSUPPORTED), + "cuTexRefGetFilterMode": ("hipTexRefGetFilterMode", CONV_TEX, API_DRIVER, HIP_UNSUPPORTED), + "cuTexRefGetFlags": ("hipTexRefGetFlags", CONV_TEX, API_DRIVER, HIP_UNSUPPORTED), + "cuTexRefGetFormat": ("hipTexRefGetFormat", CONV_TEX, API_DRIVER, HIP_UNSUPPORTED), + "cuTexRefGetMaxAnisotropy": ("hipTexRefGetMaxAnisotropy", CONV_TEX, API_DRIVER, HIP_UNSUPPORTED), + "cuTexRefGetMipmapFilterMode": ("hipTexRefGetMipmapFilterMode", CONV_TEX, API_DRIVER, HIP_UNSUPPORTED), + "cuTexRefGetMipmapLevelBias": ("hipTexRefGetMipmapLevelBias", CONV_TEX, API_DRIVER, HIP_UNSUPPORTED), + "cuTexRefGetMipmapLevelClamp": ("hipTexRefGetMipmapLevelClamp", CONV_TEX, API_DRIVER, HIP_UNSUPPORTED), + "cuTexRefGetMipmappedArray": ("hipTexRefGetMipmappedArray", CONV_TEX, API_DRIVER, HIP_UNSUPPORTED), + "cuTexRefSetAddress": ("hipTexRefSetAddress", CONV_TEX, API_DRIVER, HIP_UNSUPPORTED), + "cuTexRefSetAddress2D": ("hipTexRefSetAddress2D", CONV_TEX, API_DRIVER, HIP_UNSUPPORTED), + "cuTexRefSetAddressMode": ("hipTexRefSetAddressMode", CONV_TEX, API_DRIVER), + "cuTexRefSetArray": ("hipTexRefSetArray", CONV_TEX, API_DRIVER), + "cuTexRefSetBorderColor": ("hipTexRefSetBorderColor", CONV_TEX, API_DRIVER, HIP_UNSUPPORTED), + "cuTexRefSetFilterMode": ("hipTexRefSetFilterMode", CONV_TEX, API_DRIVER), + "cuTexRefSetFlags": ("hipTexRefSetFlags", CONV_TEX, API_DRIVER), + "cuTexRefSetFormat": ("hipTexRefSetFormat", CONV_TEX, API_DRIVER), + "cuTexRefSetMaxAnisotropy": ("hipTexRefSetMaxAnisotropy", CONV_TEX, API_DRIVER, HIP_UNSUPPORTED), + "cuTexRefSetMipmapFilterMode": ("hipTexRefSetMipmapFilterMode", CONV_TEX, API_DRIVER, HIP_UNSUPPORTED), + "cuTexRefSetMipmapLevelBias": ("hipTexRefSetMipmapLevelBias", CONV_TEX, API_DRIVER, HIP_UNSUPPORTED), + "cuTexRefSetMipmapLevelClamp": ("hipTexRefSetMipmapLevelClamp", CONV_TEX, API_DRIVER, HIP_UNSUPPORTED), + "cuTexRefSetMipmappedArray": ("hipTexRefSetMipmappedArray", CONV_TEX, API_DRIVER, HIP_UNSUPPORTED), + "cuTexRefCreate": ("hipTexRefCreate", CONV_TEX, API_DRIVER, HIP_UNSUPPORTED), + "cuTexRefDestroy": ("hipTexRefDestroy", CONV_TEX, API_DRIVER, HIP_UNSUPPORTED), + "cuSurfRefGetArray": ("hipSurfRefGetArray", CONV_SURFACE, API_DRIVER, HIP_UNSUPPORTED), + "cuSurfRefSetArray": ("hipSurfRefSetArray", CONV_SURFACE, API_DRIVER, HIP_UNSUPPORTED), + "cuTexObjectCreate": ("hipTexObjectCreate", CONV_TEX, API_DRIVER, HIP_UNSUPPORTED), + "cuTexObjectDestroy": ("hipTexObjectDestroy", CONV_TEX, API_DRIVER, HIP_UNSUPPORTED), + "cuTexObjectGetResourceDesc": ("hipTexObjectGetResourceDesc", CONV_TEX, API_DRIVER, HIP_UNSUPPORTED), + "cuTexObjectGetResourceViewDesc": ("hipTexObjectGetResourceViewDesc", CONV_TEX, API_DRIVER, HIP_UNSUPPORTED), + "cuTexObjectGetTextureDesc": ("hipTexObjectGetTextureDesc", CONV_TEX, API_DRIVER, HIP_UNSUPPORTED), + "cuSurfObjectCreate": ("hipSurfObjectCreate", CONV_TEX, API_DRIVER, HIP_UNSUPPORTED), + "cuSurfObjectDestroy": ("hipSurfObjectDestroy", CONV_TEX, API_DRIVER, HIP_UNSUPPORTED), + "cuSurfObjectGetResourceDesc": ("hipSurfObjectGetResourceDesc", CONV_TEX, API_DRIVER, HIP_UNSUPPORTED), + "cuGraphicsMapResources": ("hipGraphicsMapResources", CONV_GRAPHICS, API_DRIVER, HIP_UNSUPPORTED), + "cuGraphicsResourceGetMappedMipmappedArray": ("hipGraphicsResourceGetMappedMipmappedArray", CONV_GRAPHICS, API_DRIVER, HIP_UNSUPPORTED), + "cuGraphicsResourceGetMappedPointer": ("hipGraphicsResourceGetMappedPointer", CONV_GRAPHICS, API_DRIVER, HIP_UNSUPPORTED), + "cuGraphicsResourceSetMapFlags": ("hipGraphicsResourceSetMapFlags", CONV_GRAPHICS, API_DRIVER, HIP_UNSUPPORTED), + "cuGraphicsSubResourceGetMappedArray": ("hipGraphicsSubResourceGetMappedArray", CONV_GRAPHICS, API_DRIVER, HIP_UNSUPPORTED), + "cuGraphicsUnmapResources": ("hipGraphicsUnmapResources", CONV_GRAPHICS, API_DRIVER, HIP_UNSUPPORTED), + "cuGraphicsUnregisterResource": ("hipGraphicsUnregisterResource", CONV_GRAPHICS, API_DRIVER, HIP_UNSUPPORTED), + "cuProfilerInitialize": ("hipProfilerInitialize", CONV_OTHER, API_DRIVER, HIP_UNSUPPORTED), + "cuProfilerStart": ("hipProfilerStart", CONV_OTHER, API_DRIVER), + "cuProfilerStop": ("hipProfilerStop", CONV_OTHER, API_DRIVER), + "CU_GL_DEVICE_LIST_ALL": ("HIP_GL_DEVICE_LIST_ALL", CONV_GL, API_DRIVER, HIP_UNSUPPORTED), + "CU_GL_DEVICE_LIST_CURRENT_FRAME": ("HIP_GL_DEVICE_LIST_CURRENT_FRAME", CONV_GL, API_DRIVER, HIP_UNSUPPORTED), + "CU_GL_DEVICE_LIST_NEXT_FRAME": ("HIP_GL_DEVICE_LIST_NEXT_FRAME", CONV_GL, API_DRIVER, HIP_UNSUPPORTED), + "cuGLGetDevices": ("hipGLGetDevices", CONV_GL, API_DRIVER, HIP_UNSUPPORTED), + "cuGraphicsGLRegisterBuffer": ("hipGraphicsGLRegisterBuffer", CONV_GL, API_DRIVER, HIP_UNSUPPORTED), + "cuGraphicsGLRegisterImage": ("hipGraphicsGLRegisterImage", CONV_GL, API_DRIVER, HIP_UNSUPPORTED), + "cuWGLGetDevice": ("hipWGLGetDevice", CONV_GL, API_DRIVER, HIP_UNSUPPORTED), + "CU_GL_MAP_RESOURCE_FLAGS_NONE": ("HIP_GL_MAP_RESOURCE_FLAGS_NONE", CONV_GL, API_DRIVER, HIP_UNSUPPORTED), + "CU_GL_MAP_RESOURCE_FLAGS_READ_ONLY": ("HIP_GL_MAP_RESOURCE_FLAGS_READ_ONLY", CONV_GL, API_DRIVER, HIP_UNSUPPORTED), + "CU_GL_MAP_RESOURCE_FLAGS_WRITE_DISCARD": ("HIP_GL_MAP_RESOURCE_FLAGS_WRITE_DISCARD", CONV_GL, API_DRIVER, HIP_UNSUPPORTED), + "cuGLCtxCreate": ("hipGLCtxCreate", CONV_GL, API_DRIVER, HIP_UNSUPPORTED), + "cuGLInit": ("hipGLInit", CONV_GL, API_DRIVER, HIP_UNSUPPORTED), + "cuGLMapBufferObject": ("hipGLMapBufferObject", CONV_GL, API_DRIVER, HIP_UNSUPPORTED), + "cuGLMapBufferObjectAsync": ("hipGLMapBufferObjectAsync", CONV_GL, API_DRIVER, HIP_UNSUPPORTED), + "cuGLRegisterBufferObject": ("hipGLRegisterBufferObject", CONV_GL, API_DRIVER, HIP_UNSUPPORTED), + "cuGLSetBufferObjectMapFlags": ("hipGLSetBufferObjectMapFlags", CONV_GL, API_DRIVER, HIP_UNSUPPORTED), + "cuGLUnmapBufferObject": ("hipGLUnmapBufferObject", CONV_GL, API_DRIVER, HIP_UNSUPPORTED), + "cuGLUnmapBufferObjectAsync": ("hipGLUnmapBufferObjectAsync", CONV_GL, API_DRIVER, HIP_UNSUPPORTED), + "cuGLUnregisterBufferObject": ("hipGLUnregisterBufferObject", CONV_GL, API_DRIVER, HIP_UNSUPPORTED), + "CU_D3D9_DEVICE_LIST_ALL": ("HIP_D3D9_DEVICE_LIST_ALL", CONV_D3D9, API_DRIVER, HIP_UNSUPPORTED), + "CU_D3D9_DEVICE_LIST_CURRENT_FRAME": ("HIP_D3D9_DEVICE_LIST_CURRENT_FRAME", CONV_D3D9, API_DRIVER, HIP_UNSUPPORTED), + "CU_D3D9_DEVICE_LIST_NEXT_FRAME": ("HIP_D3D9_DEVICE_LIST_NEXT_FRAME", CONV_D3D9, API_DRIVER, HIP_UNSUPPORTED), + "cuD3D9CtxCreate": ("hipD3D9CtxCreate", CONV_D3D9, API_DRIVER, HIP_UNSUPPORTED), + "cuD3D9CtxCreateOnDevice": ("hipD3D9CtxCreateOnDevice", CONV_D3D9, API_DRIVER, HIP_UNSUPPORTED), + "cuD3D9GetDevice": ("hipD3D9GetDevice", CONV_D3D9, API_DRIVER, HIP_UNSUPPORTED), + "cuD3D9GetDevices": ("hipD3D9GetDevices", CONV_D3D9, API_DRIVER, HIP_UNSUPPORTED), + "cuD3D9GetDirect3DDevice": ("hipD3D9GetDirect3DDevice", CONV_D3D9, API_DRIVER, HIP_UNSUPPORTED), + "cuGraphicsD3D9RegisterResource": ("hipGraphicsD3D9RegisterResource", CONV_D3D9, API_DRIVER, HIP_UNSUPPORTED), + "CU_D3D9_MAPRESOURCE_FLAGS_NONE": ("HIP_D3D9_MAPRESOURCE_FLAGS_NONE", CONV_D3D9, API_DRIVER, HIP_UNSUPPORTED), + "CU_D3D9_MAPRESOURCE_FLAGS_READONLY": ("HIP_D3D9_MAPRESOURCE_FLAGS_READONLY", CONV_D3D9, API_DRIVER, HIP_UNSUPPORTED), + "CU_D3D9_MAPRESOURCE_FLAGS_WRITEDISCARD": ("HIP_D3D9_MAPRESOURCE_FLAGS_WRITEDISCARD", CONV_D3D9, API_DRIVER, HIP_UNSUPPORTED), + "CU_D3D9_REGISTER_FLAGS_NONE": ("HIP_D3D9_REGISTER_FLAGS_NONE", CONV_D3D9, API_DRIVER, HIP_UNSUPPORTED), + "CU_D3D9_REGISTER_FLAGS_ARRAY": ("HIP_D3D9_REGISTER_FLAGS_ARRAY", CONV_D3D9, API_DRIVER, HIP_UNSUPPORTED), + "cuD3D9MapResources": ("hipD3D9MapResources", CONV_D3D9, API_DRIVER, HIP_UNSUPPORTED), + "cuD3D9RegisterResource": ("hipD3D9RegisterResource", CONV_D3D9, API_DRIVER, HIP_UNSUPPORTED), + "cuD3D9ResourceGetMappedArray": ("hipD3D9ResourceGetMappedArray", CONV_D3D9, API_DRIVER, HIP_UNSUPPORTED), + "cuD3D9ResourceGetMappedPitch": ("hipD3D9ResourceGetMappedPitch", CONV_D3D9, API_DRIVER, HIP_UNSUPPORTED), + "cuD3D9ResourceGetMappedPointer": ("hipD3D9ResourceGetMappedPointer", CONV_D3D9, API_DRIVER, HIP_UNSUPPORTED), + "cuD3D9ResourceGetMappedSize": ("hipD3D9ResourceGetMappedSize", CONV_D3D9, API_DRIVER, HIP_UNSUPPORTED), + "cuD3D9ResourceGetSurfaceDimensions": ("hipD3D9ResourceGetSurfaceDimensions", CONV_D3D9, API_DRIVER, HIP_UNSUPPORTED), + "cuD3D9ResourceSetMapFlags": ("hipD3D9ResourceSetMapFlags", CONV_D3D9, API_DRIVER, HIP_UNSUPPORTED), + "cuD3D9UnmapResources": ("hipD3D9UnmapResources", CONV_D3D9, API_DRIVER, HIP_UNSUPPORTED), + "cuD3D9UnregisterResource": ("hipD3D9UnregisterResource", CONV_D3D9, API_DRIVER, HIP_UNSUPPORTED), + "CU_D3D10_DEVICE_LIST_ALL": ("HIP_D3D10_DEVICE_LIST_ALL", CONV_D3D10, API_DRIVER, HIP_UNSUPPORTED), + "CU_D3D10_DEVICE_LIST_CURRENT_FRAME": ("HIP_D3D10_DEVICE_LIST_CURRENT_FRAME", CONV_D3D10, API_DRIVER, HIP_UNSUPPORTED), + "CU_D3D10_DEVICE_LIST_NEXT_FRAME": ("HIP_D3D10_DEVICE_LIST_NEXT_FRAME", CONV_D3D10, API_DRIVER, HIP_UNSUPPORTED), + "cuD3D10GetDevice": ("hipD3D10GetDevice", CONV_D3D10, API_DRIVER, HIP_UNSUPPORTED), + "cuD3D10GetDevices": ("hipD3D10GetDevices", CONV_D3D10, API_DRIVER, HIP_UNSUPPORTED), + "cuGraphicsD3D10RegisterResource": ("hipGraphicsD3D10RegisterResource", CONV_D3D10, API_DRIVER, HIP_UNSUPPORTED), + "CU_D3D10_MAPRESOURCE_FLAGS_NONE": ("HIP_D3D10_MAPRESOURCE_FLAGS_NONE", CONV_D3D10, API_DRIVER, HIP_UNSUPPORTED), + "CU_D3D10_MAPRESOURCE_FLAGS_READONLY": ("HIP_D3D10_MAPRESOURCE_FLAGS_READONLY", CONV_D3D10, API_DRIVER, HIP_UNSUPPORTED), + "CU_D3D10_MAPRESOURCE_FLAGS_WRITEDISCARD": ("HIP_D3D10_MAPRESOURCE_FLAGS_WRITEDISCARD", CONV_D3D10, API_DRIVER, HIP_UNSUPPORTED), + "CU_D3D10_REGISTER_FLAGS_NONE": ("HIP_D3D10_REGISTER_FLAGS_NONE", CONV_D3D10, API_DRIVER, HIP_UNSUPPORTED), + "CU_D3D10_REGISTER_FLAGS_ARRAY": ("HIP_D3D10_REGISTER_FLAGS_ARRAY", CONV_D3D10, API_DRIVER, HIP_UNSUPPORTED), + "cuD3D10CtxCreate": ("hipD3D10CtxCreate", CONV_D3D10, API_DRIVER, HIP_UNSUPPORTED), + "cuD3D10CtxCreateOnDevice": ("hipD3D10CtxCreateOnDevice", CONV_D3D10, API_DRIVER, HIP_UNSUPPORTED), + "cuD3D10GetDirect3DDevice": ("hipD3D10GetDirect3DDevice", CONV_D3D10, API_DRIVER, HIP_UNSUPPORTED), + "cuD3D10MapResources": ("hipD3D10MapResources", CONV_D3D10, API_DRIVER, HIP_UNSUPPORTED), + "cuD3D10RegisterResource": ("hipD3D10RegisterResource", CONV_D3D10, API_DRIVER, HIP_UNSUPPORTED), + "cuD3D10ResourceGetMappedArray": ("hipD3D10ResourceGetMappedArray", CONV_D3D10, API_DRIVER, HIP_UNSUPPORTED), + "cuD3D10ResourceGetMappedPitch": ("hipD3D10ResourceGetMappedPitch", CONV_D3D10, API_DRIVER, HIP_UNSUPPORTED), + "cuD3D10ResourceGetMappedPointer": ("hipD3D10ResourceGetMappedPointer", CONV_D3D10, API_DRIVER, HIP_UNSUPPORTED), + "cuD3D10ResourceGetMappedSize": ("hipD3D10ResourceGetMappedSize", CONV_D3D10, API_DRIVER, HIP_UNSUPPORTED), + "cuD3D10ResourceGetSurfaceDimensions": ("hipD3D10ResourceGetSurfaceDimensions", CONV_D3D10, API_DRIVER, HIP_UNSUPPORTED), + "cuD310ResourceSetMapFlags": ("hipD3D10ResourceSetMapFlags", CONV_D3D10, API_DRIVER, HIP_UNSUPPORTED), + "cuD3D10UnmapResources": ("hipD3D10UnmapResources", CONV_D3D10, API_DRIVER, HIP_UNSUPPORTED), + "cuD3D10UnregisterResource": ("hipD3D10UnregisterResource", CONV_D3D10, API_DRIVER, HIP_UNSUPPORTED), + "CU_D3D11_DEVICE_LIST_ALL": ("HIP_D3D11_DEVICE_LIST_ALL", CONV_D3D11, API_DRIVER, HIP_UNSUPPORTED), + "CU_D3D11_DEVICE_LIST_CURRENT_FRAME": ("HIP_D3D11_DEVICE_LIST_CURRENT_FRAME", CONV_D3D11, API_DRIVER, HIP_UNSUPPORTED), + "CU_D3D11_DEVICE_LIST_NEXT_FRAME": ("HIP_D3D11_DEVICE_LIST_NEXT_FRAME", CONV_D3D11, API_DRIVER, HIP_UNSUPPORTED), + "cuD3D11GetDevice": ("hipD3D11GetDevice", CONV_D3D11, API_DRIVER, HIP_UNSUPPORTED), + "cuD3D11GetDevices": ("hipD3D11GetDevices", CONV_D3D11, API_DRIVER, HIP_UNSUPPORTED), + "cuGraphicsD3D11RegisterResource": ("hipGraphicsD3D11RegisterResource", CONV_D3D11, API_DRIVER, HIP_UNSUPPORTED), + "cuD3D11CtxCreate": ("hipD3D11CtxCreate", CONV_D3D11, API_DRIVER, HIP_UNSUPPORTED), + "cuD3D11CtxCreateOnDevice": ("hipD3D11CtxCreateOnDevice", CONV_D3D11, API_DRIVER, HIP_UNSUPPORTED), + "cuD3D11GetDirect3DDevice": ("hipD3D11GetDirect3DDevice", CONV_D3D11, API_DRIVER, HIP_UNSUPPORTED), + "cuGraphicsVDPAURegisterOutputSurface": ("hipGraphicsVDPAURegisterOutputSurface", CONV_VDPAU, API_DRIVER, HIP_UNSUPPORTED), + "cuGraphicsVDPAURegisterVideoSurface": ("hipGraphicsVDPAURegisterVideoSurface", CONV_VDPAU, API_DRIVER, HIP_UNSUPPORTED), + "cuVDPAUGetDevice": ("hipVDPAUGetDevice", CONV_VDPAU, API_DRIVER, HIP_UNSUPPORTED), + "cuVDPAUCtxCreate": ("hipVDPAUCtxCreate", CONV_VDPAU, API_DRIVER, HIP_UNSUPPORTED), + "cuEGLStreamConsumerAcquireFrame": ("hipEGLStreamConsumerAcquireFrame", CONV_EGL, API_DRIVER, HIP_UNSUPPORTED), + "cuEGLStreamConsumerConnect": ("hipEGLStreamConsumerConnect", CONV_EGL, API_DRIVER, HIP_UNSUPPORTED), + "cuEGLStreamConsumerConnectWithFlags": ("hipEGLStreamConsumerConnectWithFlags", CONV_EGL, API_DRIVER, HIP_UNSUPPORTED), + "cuEGLStreamConsumerDisconnect": ("hipEGLStreamConsumerDisconnect", CONV_EGL, API_DRIVER, HIP_UNSUPPORTED), + "cuEGLStreamConsumerReleaseFrame": ("hipEGLStreamConsumerReleaseFrame", CONV_EGL, API_DRIVER, HIP_UNSUPPORTED), + "cuEGLStreamProducerConnect": ("hipEGLStreamProducerConnect", CONV_EGL, API_DRIVER, HIP_UNSUPPORTED), + "cuEGLStreamProducerDisconnect": ("hipEGLStreamProducerDisconnect", CONV_EGL, API_DRIVER, HIP_UNSUPPORTED), + "cuEGLStreamProducerPresentFrame": ("hipEGLStreamProducerPresentFrame", CONV_EGL, API_DRIVER, HIP_UNSUPPORTED), + "cuEGLStreamProducerReturnFrame": ("hipEGLStreamProducerReturnFrame", CONV_EGL, API_DRIVER, HIP_UNSUPPORTED), + "cuGraphicsEGLRegisterImage": ("hipGraphicsEGLRegisterImage", CONV_EGL, API_DRIVER, HIP_UNSUPPORTED), + "cuGraphicsResourceGetMappedEglFrame": ("hipGraphicsResourceGetMappedEglFrame", CONV_EGL, API_DRIVER, HIP_UNSUPPORTED), + "cudaDataType_t": ("hipDataType_t", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaDataType": ("hipDataType_t", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "CUDA_R_16F": ("hipR16F", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "CUDA_C_16F": ("hipC16F", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "CUDA_R_32F": ("hipR32F", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "CUDA_C_32F": ("hipC32F", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "CUDA_R_64F": ("hipR64F", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "CUDA_C_64F": ("hipC64F", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "CUDA_R_8I": ("hipR8I", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "CUDA_C_8I": ("hipC8I", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "CUDA_R_8U": ("hipR8U", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "CUDA_C_8U": ("hipC8U", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "CUDA_R_32I": ("hipR32I", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "CUDA_C_32I": ("hipC32I", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "CUDA_R_32U": ("hipR32U", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "CUDA_C_32U": ("hipC32U", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "MAJOR_VERSION": ("hipLibraryMajorVersion", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "MINOR_VERSION": ("hipLibraryMinorVersion", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "PATCH_LEVEL": ("hipLibraryPatchVersion", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaMemAttachGlobal": ("hipMemAttachGlobal", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaMemAttachHost": ("hipMemAttachHost", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaMemAttachSingle": ("hipMemAttachSingle", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaOccupancyDefault": ("hipOccupancyDefault", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaOccupancyDisableCachingOverride": ("hipOccupancyDisableCachingOverride", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaGetLastError": ("hipGetLastError", CONV_ERROR, API_RUNTIME), + "cudaPeekAtLastError": ("hipPeekAtLastError", CONV_ERROR, API_RUNTIME), + "cudaGetErrorName": ("hipGetErrorName", CONV_ERROR, API_RUNTIME), + "cudaGetErrorString": ("hipGetErrorString", CONV_ERROR, API_RUNTIME), + "cudaMemcpy3DParms": ("hipMemcpy3DParms", CONV_MEM, API_RUNTIME), + "cudaMemcpy3DPeerParms": ("hipMemcpy3DPeerParms", CONV_MEM, API_RUNTIME, HIP_UNSUPPORTED), + "cudaMemcpy": ("hipMemcpy", CONV_MEM, API_RUNTIME), + "cudaMemcpyToArray": ("hipMemcpyToArray", CONV_MEM, API_RUNTIME), + "cudaMemcpyToSymbol": ("hipMemcpyToSymbol", CONV_MEM, API_RUNTIME), + "cudaMemcpyToSymbolAsync": ("hipMemcpyToSymbolAsync", CONV_MEM, API_RUNTIME), + "cudaMemcpyAsync": ("hipMemcpyAsync", CONV_MEM, API_RUNTIME), + "cudaMemcpy2D": ("hipMemcpy2D", CONV_MEM, API_RUNTIME), + "cudaMemcpy2DAsync": ("hipMemcpy2DAsync", CONV_MEM, API_RUNTIME), + "cudaMemcpy2DToArray": ("hipMemcpy2DToArray", CONV_MEM, API_RUNTIME), + "cudaMemcpy2DArrayToArray": ("hipMemcpy2DArrayToArray", CONV_MEM, API_RUNTIME, HIP_UNSUPPORTED), + "cudaMemcpy2DFromArray": ("hipMemcpy2DFromArray", CONV_MEM, API_RUNTIME, HIP_UNSUPPORTED), + "cudaMemcpy2DFromArrayAsync": ("hipMemcpy2DFromArrayAsync", CONV_MEM, API_RUNTIME, HIP_UNSUPPORTED), + "cudaMemcpy2DToArrayAsync": ("hipMemcpy2DToArrayAsync", CONV_MEM, API_RUNTIME, HIP_UNSUPPORTED), + "cudaMemcpy3D": ("hipMemcpy3D", CONV_MEM, API_RUNTIME), + "cudaMemcpy3DAsync": ("hipMemcpy3DAsync", CONV_MEM, API_RUNTIME, HIP_UNSUPPORTED), + "cudaMemcpy3DPeer": ("hipMemcpy3DPeer", CONV_MEM, API_RUNTIME, HIP_UNSUPPORTED), + "cudaMemcpy3DPeerAsync": ("hipMemcpy3DPeerAsync", CONV_MEM, API_RUNTIME, HIP_UNSUPPORTED), + "cudaMemcpyArrayToArray": ("hipMemcpyArrayToArray", CONV_MEM, API_RUNTIME, HIP_UNSUPPORTED), + "cudaMemcpyFromArrayAsync": ("hipMemcpyFromArrayAsync", CONV_MEM, API_RUNTIME, HIP_UNSUPPORTED), + "cudaMemcpyFromSymbol": ("hipMemcpyFromSymbol", CONV_MEM, API_RUNTIME), + "cudaMemcpyFromSymbolAsync": ("hipMemcpyFromSymbolAsync", CONV_MEM, API_RUNTIME), + "cudaMemAdvise": ("hipMemAdvise", CONV_MEM, API_RUNTIME, HIP_UNSUPPORTED), + "cudaMemRangeGetAttribute": ("hipMemRangeGetAttribute", CONV_MEM, API_RUNTIME, HIP_UNSUPPORTED), + "cudaMemRangeGetAttributes": ("hipMemRangeGetAttributes", CONV_MEM, API_RUNTIME, HIP_UNSUPPORTED), + "cudaMemAdviseSetReadMostly": ("hipMemAdviseSetReadMostly", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaMemAdviseUnsetReadMostly": ("hipMemAdviseUnsetReadMostly", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaMemAdviseSetPreferredLocation": ("hipMemAdviseSetPreferredLocation", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaMemAdviseUnsetPreferredLocation": ("hipMemAdviseUnsetPreferredLocation", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaMemAdviseSetAccessedBy": ("hipMemAdviseSetAccessedBy", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaMemAdviseUnsetAccessedBy": ("hipMemAdviseUnsetAccessedBy", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaMemRangeAttributeReadMostly": ("hipMemRangeAttributeReadMostly", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaMemRangeAttributePreferredLocation": ("hipMemRangeAttributePreferredLocation", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaMemRangeAttributeAccessedBy": ("hipMemRangeAttributeAccessedBy", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaMemRangeAttributeLastPrefetchLocation": ("hipMemRangeAttributeLastPrefetchLocation", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaMemcpyHostToHost": ("hipMemcpyHostToHost", CONV_MEM, API_RUNTIME), + "cudaMemcpyHostToDevice": ("hipMemcpyHostToDevice", CONV_MEM, API_RUNTIME), + "cudaMemcpyDeviceToHost": ("hipMemcpyDeviceToHost", CONV_MEM, API_RUNTIME), + "cudaMemcpyDeviceToDevice": ("hipMemcpyDeviceToDevice", CONV_MEM, API_RUNTIME), + "cudaMemcpyDefault": ("hipMemcpyDefault", CONV_MEM, API_RUNTIME), + "cudaMemset": ("hipMemset", CONV_MEM, API_RUNTIME), + "cudaMemsetAsync": ("hipMemsetAsync", CONV_MEM, API_RUNTIME), + "cudaMemset2D": ("hipMemset2D", CONV_MEM, API_RUNTIME), + "cudaMemset2DAsync": ("hipMemset2DAsync", CONV_MEM, API_RUNTIME, HIP_UNSUPPORTED), + "cudaMemset3D": ("hipMemset3D", CONV_MEM, API_RUNTIME, HIP_UNSUPPORTED), + "cudaMemset3DAsync": ("hipMemset3DAsync", CONV_MEM, API_RUNTIME, HIP_UNSUPPORTED), + "cudaMemGetInfo": ("hipMemGetInfo", CONV_MEM, API_RUNTIME), + "cudaArrayGetInfo": ("hipArrayGetInfo", CONV_MEM, API_RUNTIME, HIP_UNSUPPORTED), + "cudaFreeMipmappedArray": ("hipFreeMipmappedArray", CONV_MEM, API_RUNTIME, HIP_UNSUPPORTED), + "cudaGetMipmappedArrayLevel": ("hipGetMipmappedArrayLevel", CONV_MEM, API_RUNTIME, HIP_UNSUPPORTED), + "cudaGetSymbolAddress": ("hipGetSymbolAddress", CONV_MEM, API_RUNTIME, HIP_UNSUPPORTED), + "cudaGetSymbolSize": ("hipGetSymbolSize", CONV_MEM, API_RUNTIME, HIP_UNSUPPORTED), + "cudaMemPrefetchAsync": ("hipMemPrefetchAsync", CONV_MEM, API_RUNTIME, HIP_UNSUPPORTED), + "cudaMalloc": ("hipMalloc", CONV_MEM, API_RUNTIME), + "cudaMallocHost": ("hipHostMalloc", CONV_MEM, API_RUNTIME), + "cudaMallocArray": ("hipMallocArray", CONV_MEM, API_RUNTIME), + "cudaMalloc3D": ("hipMalloc3D", CONV_MEM, API_RUNTIME), + "cudaMalloc3DArray": ("hipMalloc3DArray", CONV_MEM, API_RUNTIME), + "cudaMallocManaged": ("hipMallocManaged", CONV_MEM, API_RUNTIME, HIP_UNSUPPORTED), + "cudaMallocMipmappedArray": ("hipMallocMipmappedArray", CONV_MEM, API_RUNTIME, HIP_UNSUPPORTED), + "cudaMallocPitch": ("hipMallocPitch", CONV_MEM, API_RUNTIME), + "cudaFree": ("hipFree", CONV_MEM, API_RUNTIME), + "cudaFreeHost": ("hipHostFree", CONV_MEM, API_RUNTIME), + "cudaFreeArray": ("hipFreeArray", CONV_MEM, API_RUNTIME), + "cudaHostRegister": ("hipHostRegister", CONV_MEM, API_RUNTIME), + "cudaHostUnregister": ("hipHostUnregister", CONV_MEM, API_RUNTIME), + "cudaHostAlloc": ("hipHostMalloc", CONV_MEM, API_RUNTIME), + "cudaMemoryTypeHost": ("hipMemoryTypeHost", CONV_MEM, API_RUNTIME), + "cudaMemoryTypeDevice": ("hipMemoryTypeDevice", CONV_MEM, API_RUNTIME), + "make_cudaExtent": ("make_hipExtent", CONV_MEM, API_RUNTIME), + "make_cudaPitchedPtr": ("make_hipPitchedPtr", CONV_MEM, API_RUNTIME), + "make_cudaPos": ("make_hipPos", CONV_MEM, API_RUNTIME), + "cudaHostAllocDefault": ("hipHostMallocDefault", CONV_MEM, API_RUNTIME), + "cudaHostAllocPortable": ("hipHostMallocPortable", CONV_MEM, API_RUNTIME), + "cudaHostAllocMapped": ("hipHostMallocMapped", CONV_MEM, API_RUNTIME), + "cudaHostAllocWriteCombined": ("hipHostMallocWriteCombined", CONV_MEM, API_RUNTIME), + "cudaHostGetFlags": ("hipHostGetFlags", CONV_MEM, API_RUNTIME), + "cudaHostRegisterDefault": ("hipHostRegisterDefault", CONV_MEM, API_RUNTIME), + "cudaHostRegisterPortable": ("hipHostRegisterPortable", CONV_MEM, API_RUNTIME), + "cudaHostRegisterMapped": ("hipHostRegisterMapped", CONV_MEM, API_RUNTIME), + "cudaHostRegisterIoMemory": ("hipHostRegisterIoMemory", CONV_MEM, API_RUNTIME), + # "warpSize": ("hipWarpSize", CONV_SPECIAL_FUNC, API_RUNTIME), (HIP actually uses warpSize...) + "cudaEventCreate": ("hipEventCreate", CONV_EVENT, API_RUNTIME), + "cudaEventCreateWithFlags": ("hipEventCreateWithFlags", CONV_EVENT, API_RUNTIME), + "cudaEventDestroy": ("hipEventDestroy", CONV_EVENT, API_RUNTIME), + "cudaEventRecord": ("hipEventRecord", CONV_EVENT, API_RUNTIME), + "cudaEventElapsedTime": ("hipEventElapsedTime", CONV_EVENT, API_RUNTIME), + "cudaEventSynchronize": ("hipEventSynchronize", CONV_EVENT, API_RUNTIME), + "cudaEventQuery": ("hipEventQuery", CONV_EVENT, API_RUNTIME), + "cudaEventDefault": ("hipEventDefault", CONV_EVENT, API_RUNTIME), + "cudaEventBlockingSync": ("hipEventBlockingSync", CONV_EVENT, API_RUNTIME), + "cudaEventDisableTiming": ("hipEventDisableTiming", CONV_EVENT, API_RUNTIME), + "cudaEventInterprocess": ("hipEventInterprocess", CONV_EVENT, API_RUNTIME), + "cudaStreamCreate": ("hipStreamCreate", CONV_STREAM, API_RUNTIME), + "cudaStreamCreateWithFlags": ("hipStreamCreateWithFlags", CONV_STREAM, API_RUNTIME), + "cudaStreamCreateWithPriority": ("hipStreamCreateWithPriority", CONV_STREAM, API_RUNTIME, HIP_UNSUPPORTED), + "cudaStreamDestroy": ("hipStreamDestroy", CONV_STREAM, API_RUNTIME), + "cudaStreamWaitEvent": ("hipStreamWaitEvent", CONV_STREAM, API_RUNTIME), + "cudaStreamSynchronize": ("hipStreamSynchronize", CONV_STREAM, API_RUNTIME), + "cudaStreamGetFlags": ("hipStreamGetFlags", CONV_STREAM, API_RUNTIME), + "cudaStreamQuery": ("hipStreamQuery", CONV_STREAM, API_RUNTIME), + "cudaStreamAddCallback": ("hipStreamAddCallback", CONV_STREAM, API_RUNTIME), + "cudaStreamAttachMemAsync": ("hipStreamAttachMemAsync", CONV_STREAM, API_RUNTIME, HIP_UNSUPPORTED), + "cudaStreamGetPriority": ("hipStreamGetPriority", CONV_STREAM, API_RUNTIME, HIP_UNSUPPORTED), + "cudaStreamDefault": ("hipStreamDefault", CONV_TYPE, API_RUNTIME), + "cudaStreamNonBlocking": ("hipStreamNonBlocking", CONV_TYPE, API_RUNTIME), + "cudaDeviceSynchronize": ("hipDeviceSynchronize", CONV_DEVICE, API_RUNTIME), + "cudaDeviceReset": ("hipDeviceReset", CONV_DEVICE, API_RUNTIME), + "cudaSetDevice": ("hipSetDevice", CONV_DEVICE, API_RUNTIME), + "cudaGetDevice": ("hipGetDevice", CONV_DEVICE, API_RUNTIME), + "cudaGetDeviceCount": ("hipGetDeviceCount", CONV_DEVICE, API_RUNTIME), + "cudaChooseDevice": ("hipChooseDevice", CONV_DEVICE, API_RUNTIME), + "cudaThreadExit": ("hipDeviceReset", CONV_THREAD, API_RUNTIME), + "cudaThreadGetCacheConfig": ("hipDeviceGetCacheConfig", CONV_THREAD, API_RUNTIME), + "cudaThreadGetLimit": ("hipThreadGetLimit", CONV_THREAD, API_RUNTIME, HIP_UNSUPPORTED), + "cudaThreadSetCacheConfig": ("hipDeviceSetCacheConfig", CONV_THREAD, API_RUNTIME), + "cudaThreadSetLimit": ("hipThreadSetLimit", CONV_THREAD, API_RUNTIME, HIP_UNSUPPORTED), + "cudaThreadSynchronize": ("hipDeviceSynchronize", CONV_THREAD, API_RUNTIME), + "cudaDeviceGetAttribute": ("hipDeviceGetAttribute", CONV_DEVICE, API_RUNTIME), + "cudaDevAttrMaxThreadsPerBlock": ("hipDeviceAttributeMaxThreadsPerBlock", CONV_TYPE, API_RUNTIME), + "cudaDevAttrMaxBlockDimX": ("hipDeviceAttributeMaxBlockDimX", CONV_TYPE, API_RUNTIME), + "cudaDevAttrMaxBlockDimY": ("hipDeviceAttributeMaxBlockDimY", CONV_TYPE, API_RUNTIME), + "cudaDevAttrMaxBlockDimZ": ("hipDeviceAttributeMaxBlockDimZ", CONV_TYPE, API_RUNTIME), + "cudaDevAttrMaxGridDimX": ("hipDeviceAttributeMaxGridDimX", CONV_TYPE, API_RUNTIME), + "cudaDevAttrMaxGridDimY": ("hipDeviceAttributeMaxGridDimY", CONV_TYPE, API_RUNTIME), + "cudaDevAttrMaxGridDimZ": ("hipDeviceAttributeMaxGridDimZ", CONV_TYPE, API_RUNTIME), + "cudaDevAttrMaxSharedMemoryPerBlock": ("hipDeviceAttributeMaxSharedMemoryPerBlock", CONV_TYPE, API_RUNTIME), + "cudaDevAttrTotalConstantMemory": ("hipDeviceAttributeTotalConstantMemory", CONV_TYPE, API_RUNTIME), + "cudaDevAttrWarpSize": ("hipDeviceAttributeWarpSize", CONV_TYPE, API_RUNTIME), + "cudaDevAttrMaxPitch": ("hipDeviceAttributeMaxPitch", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaDevAttrMaxRegistersPerBlock": ("hipDeviceAttributeMaxRegistersPerBlock", CONV_TYPE, API_RUNTIME), + "cudaDevAttrClockRate": ("hipDeviceAttributeClockRate", CONV_TYPE, API_RUNTIME), + "cudaDevAttrTextureAlignment": ("hipDeviceAttributeTextureAlignment", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaDevAttrGpuOverlap": ("hipDeviceAttributeGpuOverlap", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaDevAttrMultiProcessorCount": ("hipDeviceAttributeMultiprocessorCount", CONV_TYPE, API_RUNTIME), + "cudaDevAttrKernelExecTimeout": ("hipDeviceAttributeKernelExecTimeout", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaDevAttrIntegrated": ("hipDeviceAttributeIntegrated", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaDevAttrCanMapHostMemory": ("hipDeviceAttributeCanMapHostMemory", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaDevAttrComputeMode": ("hipDeviceAttributeComputeMode", CONV_TYPE, API_RUNTIME), + "cudaDevAttrMaxTexture1DWidth": ("hipDeviceAttributeMaxTexture1DWidth", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaDevAttrMaxTexture2DWidth": ("hipDeviceAttributeMaxTexture2DWidth", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaDevAttrMaxTexture2DHeight": ("hipDeviceAttributeMaxTexture2DHeight", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaDevAttrMaxTexture3DWidth": ("hipDeviceAttributeMaxTexture3DWidth", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaDevAttrMaxTexture3DHeight": ("hipDeviceAttributeMaxTexture3DHeight", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaDevAttrMaxTexture3DDepth": ("hipDeviceAttributeMaxTexture3DDepth", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaDevAttrMaxTexture2DLayeredWidth": ("hipDeviceAttributeMaxTexture2DLayeredWidth", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaDevAttrMaxTexture2DLayeredHeight": ("hipDeviceAttributeMaxTexture2DLayeredHeight", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaDevAttrMaxTexture2DLayeredLayers": ("hipDeviceAttributeMaxTexture2DLayeredLayers", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaDevAttrSurfaceAlignment": ("hipDeviceAttributeSurfaceAlignment", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaDevAttrConcurrentKernels": ("hipDeviceAttributeConcurrentKernels", CONV_TYPE, API_RUNTIME), + "cudaDevAttrEccEnabled": ("hipDeviceAttributeEccEnabled", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaDevAttrPciBusId": ("hipDeviceAttributePciBusId", CONV_TYPE, API_RUNTIME), + "cudaDevAttrPciDeviceId": ("hipDeviceAttributePciDeviceId", CONV_TYPE, API_RUNTIME), + "cudaDevAttrTccDriver": ("hipDeviceAttributeTccDriver", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaDevAttrMemoryClockRate": ("hipDeviceAttributeMemoryClockRate", CONV_TYPE, API_RUNTIME), + "cudaDevAttrGlobalMemoryBusWidth": ("hipDeviceAttributeMemoryBusWidth", CONV_TYPE, API_RUNTIME), + "cudaDevAttrL2CacheSize": ("hipDeviceAttributeL2CacheSize", CONV_TYPE, API_RUNTIME), + "cudaDevAttrMaxThreadsPerMultiProcessor": ("hipDeviceAttributeMaxThreadsPerMultiProcessor", CONV_TYPE, API_RUNTIME), + "cudaDevAttrAsyncEngineCount": ("hipDeviceAttributeAsyncEngineCount", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaDevAttrUnifiedAddressing": ("hipDeviceAttributeUnifiedAddressing", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaDevAttrMaxTexture1DLayeredWidth": ("hipDeviceAttributeMaxTexture1DLayeredWidth", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaDevAttrMaxTexture1DLayeredLayers": ("hipDeviceAttributeMaxTexture1DLayeredLayers", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaDevAttrMaxTexture2DGatherWidth": ("hipDeviceAttributeMaxTexture2DGatherWidth", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaDevAttrMaxTexture2DGatherHeight": ("hipDeviceAttributeMaxTexture2DGatherHeight", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaDevAttrMaxTexture3DWidthAlt": ("hipDeviceAttributeMaxTexture3DWidthAlternate", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaDevAttrMaxTexture3DHeightAlt": ("hipDeviceAttributeMaxTexture3DHeightAlternate", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaDevAttrMaxTexture3DDepthAlt": ("hipDeviceAttributeMaxTexture3DDepthAlternate", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaDevAttrPciDomainId": ("hipDeviceAttributePciDomainId", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaDevAttrTexturePitchAlignment": ("hipDeviceAttributeTexturePitchAlignment", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaDevAttrMaxTextureCubemapWidth": ("hipDeviceAttributeMaxTextureCubemapWidth", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaDevAttrMaxTextureCubemapLayeredWidth": ("hipDeviceAttributeMaxTextureCubemapLayeredWidth", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaDevAttrMaxTextureCubemapLayeredLayers": ("hipDeviceAttributeMaxTextureCubemapLayeredLayers", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaDevAttrMaxSurface1DWidth": ("hipDeviceAttributeMaxSurface1DWidth", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaDevAttrMaxSurface2DWidth": ("hipDeviceAttributeMaxSurface2DWidth", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaDevAttrMaxSurface2DHeight": ("hipDeviceAttributeMaxSurface2DHeight", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaDevAttrMaxSurface3DWidth": ("hipDeviceAttributeMaxSurface3DWidth", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaDevAttrMaxSurface3DHeight": ("hipDeviceAttributeMaxSurface3DHeight", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaDevAttrMaxSurface3DDepth": ("hipDeviceAttributeMaxSurface3DDepth", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaDevAttrMaxSurface1DLayeredWidth": ("hipDeviceAttributeMaxSurface1DLayeredWidth", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaDevAttrMaxSurface1DLayeredLayers": ("hipDeviceAttributeMaxSurface1DLayeredLayers", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaDevAttrMaxSurface2DLayeredWidth": ("hipDeviceAttributeMaxSurface2DLayeredWidth", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaDevAttrMaxSurface2DLayeredHeight": ("hipDeviceAttributeMaxSurface2DLayeredHeight", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaDevAttrMaxSurface2DLayeredLayers": ("hipDeviceAttributeMaxSurface2DLayeredLayers", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaDevAttrMaxSurfaceCubemapWidth": ("hipDeviceAttributeMaxSurfaceCubemapWidth", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaDevAttrMaxSurfaceCubemapLayeredWidth": ("hipDeviceAttributeMaxSurfaceCubemapLayeredWidth", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaDevAttrMaxSurfaceCubemapLayeredLayers": ("hipDeviceAttributeMaxSurfaceCubemapLayeredLayers", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaDevAttrMaxTexture1DLinearWidth": ("hipDeviceAttributeMaxTexture1DLinearWidth", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaDevAttrMaxTexture2DLinearWidth": ("hipDeviceAttributeMaxTexture2DLinearWidth", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaDevAttrMaxTexture2DLinearHeight": ("hipDeviceAttributeMaxTexture2DLinearHeight", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaDevAttrMaxTexture2DLinearPitch": ("hipDeviceAttributeMaxTexture2DLinearPitch", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaDevAttrMaxTexture2DMipmappedWidth": ("hipDeviceAttributeMaxTexture2DMipmappedWidth", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaDevAttrMaxTexture2DMipmappedHeight": ("hipDeviceAttributeMaxTexture2DMipmappedHeight", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaDevAttrComputeCapabilityMajor": ("hipDeviceAttributeComputeCapabilityMajor", CONV_TYPE, API_RUNTIME), + "cudaDevAttrComputeCapabilityMinor": ("hipDeviceAttributeComputeCapabilityMinor", CONV_TYPE, API_RUNTIME), + "cudaDevAttrMaxTexture1DMipmappedWidth": ("hipDeviceAttributeMaxTexture1DMipmappedWidth", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaDevAttrStreamPrioritiesSupported": ("hipDeviceAttributeStreamPrioritiesSupported", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaDevAttrGlobalL1CacheSupported": ("hipDeviceAttributeGlobalL1CacheSupported", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaDevAttrLocalL1CacheSupported": ("hipDeviceAttributeLocalL1CacheSupported", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaDevAttrMaxSharedMemoryPerMultiprocessor": ("hipDeviceAttributeMaxSharedMemoryPerMultiprocessor", CONV_TYPE, API_RUNTIME), + "cudaDevAttrMaxRegistersPerMultiprocessor": ("hipDeviceAttributeMaxRegistersPerMultiprocessor", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaDevAttrManagedMemory": ("hipDeviceAttributeManagedMemory", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaDevAttrIsMultiGpuBoard": ("hipDeviceAttributeIsMultiGpuBoard", CONV_TYPE, API_RUNTIME), + "cudaDevAttrMultiGpuBoardGroupID": ("hipDeviceAttributeMultiGpuBoardGroupID", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaDevAttrHostNativeAtomicSupported": ("hipDeviceAttributeHostNativeAtomicSupported", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaDevAttrSingleToDoublePrecisionPerfRatio": ("hipDeviceAttributeSingleToDoublePrecisionPerfRatio", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaDevAttrPageableMemoryAccess": ("hipDeviceAttributePageableMemoryAccess", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaDevAttrConcurrentManagedAccess": ("hipDeviceAttributeConcurrentManagedAccess", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaDevAttrComputePreemptionSupported": ("hipDeviceAttributeComputePreemptionSupported", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaDevAttrCanUseHostPointerForRegisteredMem": ("hipDeviceAttributeCanUseHostPointerForRegisteredMem", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaPointerGetAttributes": ("hipPointerGetAttributes", CONV_MEM, API_RUNTIME), + "cudaHostGetDevicePointer": ("hipHostGetDevicePointer", CONV_MEM, API_RUNTIME), + "cudaGetDeviceProperties": ("hipGetDeviceProperties", CONV_DEVICE, API_RUNTIME), + "cudaDeviceGetPCIBusId": ("hipDeviceGetPCIBusId", CONV_DEVICE, API_RUNTIME), + "cudaDeviceGetByPCIBusId": ("hipDeviceGetByPCIBusId", CONV_DEVICE, API_RUNTIME), + "cudaDeviceGetStreamPriorityRange": ("hipDeviceGetStreamPriorityRange", CONV_DEVICE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaSetValidDevices": ("hipSetValidDevices", CONV_DEVICE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaDevP2PAttrPerformanceRank": ("hipDeviceP2PAttributePerformanceRank", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaDevP2PAttrAccessSupported": ("hipDeviceP2PAttributeAccessSupported", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaDevP2PAttrNativeAtomicSupported": ("hipDeviceP2PAttributeNativeAtomicSupported", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaDeviceGetP2PAttribute": ("hipDeviceGetP2PAttribute", CONV_DEVICE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaComputeModeDefault": ("hipComputeModeDefault", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaComputeModeExclusive": ("hipComputeModeExclusive", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaComputeModeProhibited": ("hipComputeModeProhibited", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaComputeModeExclusiveProcess": ("hipComputeModeExclusiveProcess", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaGetDeviceFlags": ("hipGetDeviceFlags", CONV_DEVICE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaSetDeviceFlags": ("hipSetDeviceFlags", CONV_DEVICE, API_RUNTIME), + "cudaDeviceScheduleAuto": ("hipDeviceScheduleAuto", CONV_TYPE, API_RUNTIME), + "cudaDeviceScheduleSpin": ("hipDeviceScheduleSpin", CONV_TYPE, API_RUNTIME), + "cudaDeviceScheduleYield": ("hipDeviceScheduleYield", CONV_TYPE, API_RUNTIME), + "cudaDeviceBlockingSync": ("hipDeviceScheduleBlockingSync", CONV_TYPE, API_RUNTIME), + "cudaDeviceScheduleBlockingSync": ("hipDeviceScheduleBlockingSync", CONV_TYPE, API_RUNTIME), + "cudaDeviceScheduleMask": ("hipDeviceScheduleMask", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaDeviceMapHost": ("hipDeviceMapHost", CONV_TYPE, API_RUNTIME), + "cudaDeviceLmemResizeToMax": ("hipDeviceLmemResizeToMax", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaDeviceMask": ("hipDeviceMask", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaDeviceSetCacheConfig": ("hipDeviceSetCacheConfig", CONV_CACHE, API_RUNTIME), + "cudaDeviceGetCacheConfig": ("hipDeviceGetCacheConfig", CONV_CACHE, API_RUNTIME), + "cudaFuncSetCacheConfig": ("hipFuncSetCacheConfig", CONV_CACHE, API_RUNTIME), + "cudaFuncCachePreferNone": ("hipFuncCachePreferNone", CONV_CACHE, API_RUNTIME), + "cudaFuncCachePreferShared": ("hipFuncCachePreferShared", CONV_CACHE, API_RUNTIME), + "cudaFuncCachePreferL1": ("hipFuncCachePreferL1", CONV_CACHE, API_RUNTIME), + "cudaFuncCachePreferEqual": ("hipFuncCachePreferEqual", CONV_CACHE, API_RUNTIME), + "cudaFuncGetAttributes": ("hipFuncGetAttributes", CONV_EXEC, API_RUNTIME, HIP_UNSUPPORTED), + "cudaFuncSetSharedMemConfig": ("hipFuncSetSharedMemConfig", CONV_EXEC, API_RUNTIME, HIP_UNSUPPORTED), + "cudaGetParameterBuffer": ("hipGetParameterBuffer", CONV_EXEC, API_RUNTIME, HIP_UNSUPPORTED), + "cudaSetDoubleForDevice": ("hipSetDoubleForDevice", CONV_EXEC, API_RUNTIME, HIP_UNSUPPORTED), + "cudaSetDoubleForHost": ("hipSetDoubleForHost", CONV_EXEC, API_RUNTIME, HIP_UNSUPPORTED), + "cudaConfigureCall": ("hipConfigureCall", CONV_EXEC, API_RUNTIME, HIP_UNSUPPORTED), + "cudaLaunch": ("hipLaunch", CONV_EXEC, API_RUNTIME, HIP_UNSUPPORTED), + "cudaSetupArgument": ("hipSetupArgument", CONV_EXEC, API_RUNTIME, HIP_UNSUPPORTED), + "cudaDriverGetVersion": ("hipDriverGetVersion", CONV_VERSION, API_RUNTIME), + "cudaRuntimeGetVersion": ("hipRuntimeGetVersion", CONV_VERSION, API_RUNTIME, HIP_UNSUPPORTED), + "cudaOccupancyMaxPotentialBlockSize": ("hipOccupancyMaxPotentialBlockSize", CONV_OCCUPANCY, API_RUNTIME), + "cudaOccupancyMaxPotentialBlockSizeWithFlags": ("hipOccupancyMaxPotentialBlockSizeWithFlags", CONV_OCCUPANCY, API_RUNTIME, HIP_UNSUPPORTED), + "cudaOccupancyMaxActiveBlocksPerMultiprocessor": ("hipOccupancyMaxActiveBlocksPerMultiprocessor", CONV_OCCUPANCY, API_RUNTIME), + "cudaOccupancyMaxActiveBlocksPerMultiprocessorWithFlags": ("hipOccupancyMaxActiveBlocksPerMultiprocessorWithFlags", CONV_OCCUPANCY, API_RUNTIME, HIP_UNSUPPORTED), + "cudaOccupancyMaxPotentialBlockSizeVariableSMem": ("hipOccupancyMaxPotentialBlockSizeVariableSMem", CONV_OCCUPANCY, API_RUNTIME, HIP_UNSUPPORTED), + "cudaOccupancyMaxPotentialBlockSizeVariableSMemWithFlags": ("hipOccupancyMaxPotentialBlockSizeVariableSMemWithFlags", CONV_OCCUPANCY, API_RUNTIME, HIP_UNSUPPORTED), + "cudaDeviceCanAccessPeer": ("hipDeviceCanAccessPeer", CONV_PEER, API_RUNTIME), + "cudaDeviceDisablePeerAccess": ("hipDeviceDisablePeerAccess", CONV_PEER, API_RUNTIME), + "cudaDeviceEnablePeerAccess": ("hipDeviceEnablePeerAccess", CONV_PEER, API_RUNTIME), + "cudaMemcpyPeerAsync": ("hipMemcpyPeerAsync", CONV_MEM, API_RUNTIME), + "cudaMemcpyPeer": ("hipMemcpyPeer", CONV_MEM, API_RUNTIME), + "cudaIpcMemLazyEnablePeerAccess": ("hipIpcMemLazyEnablePeerAccess", CONV_TYPE, API_RUNTIME), + "cudaDeviceSetSharedMemConfig": ("hipDeviceSetSharedMemConfig", CONV_DEVICE, API_RUNTIME), + "cudaDeviceGetSharedMemConfig": ("hipDeviceGetSharedMemConfig", CONV_DEVICE, API_RUNTIME), + "cudaSharedMemBankSizeDefault": ("hipSharedMemBankSizeDefault", CONV_TYPE, API_RUNTIME), + "cudaSharedMemBankSizeFourByte": ("hipSharedMemBankSizeFourByte", CONV_TYPE, API_RUNTIME), + "cudaSharedMemBankSizeEightByte": ("hipSharedMemBankSizeEightByte", CONV_TYPE, API_RUNTIME), + "cudaLimitStackSize": ("hipLimitStackSize", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaLimitPrintfFifoSize": ("hipLimitPrintfFifoSize", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaLimitMallocHeapSize": ("hipLimitMallocHeapSize", CONV_TYPE, API_RUNTIME), + "cudaLimitDevRuntimeSyncDepth": ("hipLimitDevRuntimeSyncDepth", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaLimitDevRuntimePendingLaunchCount": ("hipLimitDevRuntimePendingLaunchCount", CONV_TYPE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaDeviceGetLimit": ("hipDeviceGetLimit", CONV_DEVICE, API_RUNTIME), + "cudaProfilerInitialize": ("hipProfilerInitialize", CONV_OTHER, API_RUNTIME, HIP_UNSUPPORTED), + "cudaProfilerStart": ("hipProfilerStart", CONV_OTHER, API_RUNTIME), + "cudaProfilerStop": ("hipProfilerStop", CONV_OTHER, API_RUNTIME), + "cudaKeyValuePair": ("hipKeyValuePair", CONV_OTHER, API_RUNTIME, HIP_UNSUPPORTED), + "cudaCSV": ("hipCSV", CONV_OTHER, API_RUNTIME, HIP_UNSUPPORTED), + "cudaReadModeElementType": ("hipReadModeElementType", CONV_TEX, API_RUNTIME), + "cudaReadModeNormalizedFloat": ("hipReadModeNormalizedFloat", CONV_TEX, API_RUNTIME), + "cudaFilterModePoint": ("hipFilterModePoint", CONV_TEX, API_RUNTIME), + "cudaFilterModeLinear": ("hipFilterModeLinear", CONV_TEX, API_RUNTIME), + "cudaBindTexture": ("hipBindTexture", CONV_TEX, API_RUNTIME), + "cudaUnbindTexture": ("hipUnbindTexture", CONV_TEX, API_RUNTIME), + "cudaBindTexture2D": ("hipBindTexture2D", CONV_TEX, API_RUNTIME), + "cudaBindTextureToArray": ("hipBindTextureToArray", CONV_TEX, API_RUNTIME), + "cudaBindTextureToMipmappedArray": ("hipBindTextureToMipmappedArray", CONV_TEX, API_RUNTIME), + "cudaGetTextureAlignmentOffset": ("hipGetTextureAlignmentOffset", CONV_TEX, API_RUNTIME), + "cudaGetTextureReference": ("hipGetTextureReference", CONV_TEX, API_RUNTIME), + "cudaChannelFormatKindSigned": ("hipChannelFormatKindSigned", CONV_TEX, API_RUNTIME), + "cudaChannelFormatKindUnsigned": ("hipChannelFormatKindUnsigned", CONV_TEX, API_RUNTIME), + "cudaChannelFormatKindFloat": ("hipChannelFormatKindFloat", CONV_TEX, API_RUNTIME), + "cudaChannelFormatKindNone": ("hipChannelFormatKindNone", CONV_TEX, API_RUNTIME), + "cudaCreateChannelDesc": ("hipCreateChannelDesc", CONV_TEX, API_RUNTIME), + "cudaGetChannelDesc": ("hipGetChannelDesc", CONV_TEX, API_RUNTIME), + "cudaResourceTypeArray": ("hipResourceTypeArray", CONV_TEX, API_RUNTIME), + "cudaResourceTypeMipmappedArray": ("hipResourceTypeMipmappedArray", CONV_TEX, API_RUNTIME), + "cudaResourceTypeLinear": ("hipResourceTypeLinear", CONV_TEX, API_RUNTIME), + "cudaResourceTypePitch2D": ("hipResourceTypePitch2D", CONV_TEX, API_RUNTIME), + "cudaResViewFormatNone": ("hipResViewFormatNone", CONV_TEX, API_RUNTIME), + "cudaResViewFormatUnsignedChar1": ("hipResViewFormatUnsignedChar1", CONV_TEX, API_RUNTIME), + "cudaResViewFormatUnsignedChar2": ("hipResViewFormatUnsignedChar2", CONV_TEX, API_RUNTIME), + "cudaResViewFormatUnsignedChar4": ("hipResViewFormatUnsignedChar4", CONV_TEX, API_RUNTIME), + "cudaResViewFormatSignedChar1": ("hipResViewFormatSignedChar1", CONV_TEX, API_RUNTIME), + "cudaResViewFormatSignedChar2": ("hipResViewFormatSignedChar2", CONV_TEX, API_RUNTIME), + "cudaResViewFormatSignedChar4": ("hipResViewFormatSignedChar4", CONV_TEX, API_RUNTIME), + "cudaResViewFormatUnsignedShort1": ("hipResViewFormatUnsignedShort1", CONV_TEX, API_RUNTIME), + "cudaResViewFormatUnsignedShort2": ("hipResViewFormatUnsignedShort2", CONV_TEX, API_RUNTIME), + "cudaResViewFormatUnsignedShort4": ("hipResViewFormatUnsignedShort4", CONV_TEX, API_RUNTIME), + "cudaResViewFormatSignedShort1": ("hipResViewFormatSignedShort1", CONV_TEX, API_RUNTIME), + "cudaResViewFormatSignedShort2": ("hipResViewFormatSignedShort2", CONV_TEX, API_RUNTIME), + "cudaResViewFormatSignedShort4": ("hipResViewFormatSignedShort4", CONV_TEX, API_RUNTIME), + "cudaResViewFormatUnsignedInt1": ("hipResViewFormatUnsignedInt1", CONV_TEX, API_RUNTIME), + "cudaResViewFormatUnsignedInt2": ("hipResViewFormatUnsignedInt2", CONV_TEX, API_RUNTIME), + "cudaResViewFormatUnsignedInt4": ("hipResViewFormatUnsignedInt4", CONV_TEX, API_RUNTIME), + "cudaResViewFormatSignedInt1": ("hipResViewFormatSignedInt1", CONV_TEX, API_RUNTIME), + "cudaResViewFormatSignedInt2": ("hipResViewFormatSignedInt2", CONV_TEX, API_RUNTIME), + "cudaResViewFormatSignedInt4": ("hipResViewFormatSignedInt4", CONV_TEX, API_RUNTIME), + "cudaResViewFormatHalf1": ("hipResViewFormatHalf1", CONV_TEX, API_RUNTIME), + "cudaResViewFormatHalf2": ("hipResViewFormatHalf2", CONV_TEX, API_RUNTIME), + "cudaResViewFormatHalf4": ("hipResViewFormatHalf4", CONV_TEX, API_RUNTIME), + "cudaResViewFormatFloat1": ("hipResViewFormatFloat1", CONV_TEX, API_RUNTIME), + "cudaResViewFormatFloat2": ("hipResViewFormatFloat2", CONV_TEX, API_RUNTIME), + "cudaResViewFormatFloat4": ("hipResViewFormatFloat4", CONV_TEX, API_RUNTIME), + "cudaResViewFormatUnsignedBlockCompressed1": ("hipResViewFormatUnsignedBlockCompressed1", CONV_TEX, API_RUNTIME), + "cudaResViewFormatUnsignedBlockCompressed2": ("hipResViewFormatUnsignedBlockCompressed2", CONV_TEX, API_RUNTIME), + "cudaResViewFormatUnsignedBlockCompressed3": ("hipResViewFormatUnsignedBlockCompressed3", CONV_TEX, API_RUNTIME), + "cudaResViewFormatUnsignedBlockCompressed4": ("hipResViewFormatUnsignedBlockCompressed4", CONV_TEX, API_RUNTIME), + "cudaResViewFormatSignedBlockCompressed4": ("hipResViewFormatSignedBlockCompressed4", CONV_TEX, API_RUNTIME), + "cudaResViewFormatUnsignedBlockCompressed5": ("hipResViewFormatUnsignedBlockCompressed5", CONV_TEX, API_RUNTIME), + "cudaResViewFormatSignedBlockCompressed5": ("hipResViewFormatSignedBlockCompressed5", CONV_TEX, API_RUNTIME), + "cudaResViewFormatUnsignedBlockCompressed6H": ("hipResViewFormatUnsignedBlockCompressed6H", CONV_TEX, API_RUNTIME), + "cudaResViewFormatSignedBlockCompressed6H": ("hipResViewFormatSignedBlockCompressed6H", CONV_TEX, API_RUNTIME), + "cudaResViewFormatUnsignedBlockCompressed7": ("hipResViewFormatUnsignedBlockCompressed7", CONV_TEX, API_RUNTIME), + "cudaAddressModeWrap": ("hipAddressModeWrap", CONV_TEX, API_RUNTIME), + "cudaAddressModeClamp": ("hipAddressModeClamp", CONV_TEX, API_RUNTIME), + "cudaAddressModeMirror": ("hipAddressModeMirror", CONV_TEX, API_RUNTIME), + "cudaAddressModeBorder": ("hipAddressModeBorder", CONV_TEX, API_RUNTIME), + "cudaCreateTextureObject": ("hipCreateTextureObject", CONV_TEX, API_RUNTIME), + "cudaDestroyTextureObject": ("hipDestroyTextureObject", CONV_TEX, API_RUNTIME), + "cudaGetTextureObjectResourceDesc": ("hipGetTextureObjectResourceDesc", CONV_TEX, API_RUNTIME), + "cudaGetTextureObjectResourceViewDesc": ("hipGetTextureObjectResourceViewDesc", CONV_TEX, API_RUNTIME), + "cudaGetTextureObjectTextureDesc": ("hipGetTextureObjectTextureDesc", CONV_TEX, API_RUNTIME), + "cudaBindSurfaceToArray": ("hipBindSurfaceToArray", CONV_SURFACE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaGetSurfaceReference": ("hipGetSurfaceReference", CONV_SURFACE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaBoundaryModeZero": ("hipBoundaryModeZero", CONV_SURFACE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaBoundaryModeClamp": ("hipBoundaryModeClamp", CONV_SURFACE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaBoundaryModeTrap": ("hipBoundaryModeTrap", CONV_SURFACE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaFormatModeForced": ("hipFormatModeForced", CONV_SURFACE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaFormatModeAuto": ("hipFormatModeAuto", CONV_SURFACE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaCreateSurfaceObject": ("hipCreateSurfaceObject", CONV_SURFACE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaDestroySurfaceObject": ("hipDestroySurfaceObject", CONV_SURFACE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaGetSurfaceObjectResourceDesc": ("hipGetSurfaceObjectResourceDesc", CONV_SURFACE, API_RUNTIME, HIP_UNSUPPORTED), + "cudaIpcCloseMemHandle": ("hipIpcCloseMemHandle", CONV_DEVICE, API_RUNTIME), + "cudaIpcGetEventHandle": ("hipIpcGetEventHandle", CONV_DEVICE, API_RUNTIME), + "cudaIpcGetMemHandle": ("hipIpcGetMemHandle", CONV_DEVICE, API_RUNTIME), + "cudaIpcOpenEventHandle": ("hipIpcOpenEventHandle", CONV_DEVICE, API_RUNTIME), + "cudaIpcOpenMemHandle": ("hipIpcOpenMemHandle", CONV_DEVICE, API_RUNTIME), + "cudaGLGetDevices": ("hipGLGetDevices", CONV_GL, API_RUNTIME, HIP_UNSUPPORTED), + "cudaGraphicsGLRegisterBuffer": ("hipGraphicsGLRegisterBuffer", CONV_GL, API_RUNTIME, HIP_UNSUPPORTED), + "cudaGraphicsGLRegisterImage": ("hipGraphicsGLRegisterImage", CONV_GL, API_RUNTIME, HIP_UNSUPPORTED), + "cudaWGLGetDevice": ("hipWGLGetDevice", CONV_GL, API_RUNTIME, HIP_UNSUPPORTED), + "cudaGraphicsMapResources": ("hipGraphicsMapResources", CONV_GRAPHICS, API_RUNTIME, HIP_UNSUPPORTED), + "cudaGraphicsResourceGetMappedMipmappedArray": ("hipGraphicsResourceGetMappedMipmappedArray", CONV_GRAPHICS, API_RUNTIME, HIP_UNSUPPORTED), + "cudaGraphicsResourceGetMappedPointer": ("hipGraphicsResourceGetMappedPointer", CONV_GRAPHICS, API_RUNTIME, HIP_UNSUPPORTED), + "cudaGraphicsResourceSetMapFlags": ("hipGraphicsResourceSetMapFlags", CONV_GRAPHICS, API_RUNTIME, HIP_UNSUPPORTED), + "cudaGraphicsSubResourceGetMappedArray": ("hipGraphicsSubResourceGetMappedArray", CONV_GRAPHICS, API_RUNTIME, HIP_UNSUPPORTED), + "cudaGraphicsUnmapResources": ("hipGraphicsUnmapResources", CONV_GRAPHICS, API_RUNTIME, HIP_UNSUPPORTED), + "cudaGraphicsUnregisterResource": ("hipGraphicsUnregisterResource", CONV_GRAPHICS, API_RUNTIME, HIP_UNSUPPORTED), + "cudaGraphicsCubeFacePositiveX": ("hipGraphicsCubeFacePositiveX", CONV_GRAPHICS, API_RUNTIME, HIP_UNSUPPORTED), + "cudaGraphicsCubeFaceNegativeX": ("hipGraphicsCubeFaceNegativeX", CONV_GRAPHICS, API_RUNTIME, HIP_UNSUPPORTED), + "cudaGraphicsCubeFacePositiveY": ("hipGraphicsCubeFacePositiveY", CONV_GRAPHICS, API_RUNTIME, HIP_UNSUPPORTED), + "cudaGraphicsCubeFaceNegativeY": ("hipGraphicsCubeFaceNegativeY", CONV_GRAPHICS, API_RUNTIME, HIP_UNSUPPORTED), + "cudaGraphicsCubeFacePositiveZ": ("hipGraphicsCubeFacePositiveZ", CONV_GRAPHICS, API_RUNTIME, HIP_UNSUPPORTED), + "cudaGraphicsCubeFaceNegativeZ": ("hipGraphicsCubeFaceNegativeZ", CONV_GRAPHICS, API_RUNTIME, HIP_UNSUPPORTED), + "cudaGraphicsMapFlagsNone": ("hipGraphicsMapFlagsNone", CONV_GRAPHICS, API_RUNTIME, HIP_UNSUPPORTED), + "cudaGraphicsMapFlagsReadOnly": ("hipGraphicsMapFlagsReadOnly", CONV_GRAPHICS, API_RUNTIME, HIP_UNSUPPORTED), + "cudaGraphicsMapFlagsWriteDiscard": ("hipGraphicsMapFlagsWriteDiscard", CONV_GRAPHICS, API_RUNTIME, HIP_UNSUPPORTED), + "cudaGraphicsRegisterFlagsNone": ("hipGraphicsRegisterFlagsNone", CONV_GRAPHICS, API_RUNTIME, HIP_UNSUPPORTED), + "cudaGraphicsRegisterFlagsReadOnly": ("hipGraphicsRegisterFlagsReadOnly", CONV_GRAPHICS, API_RUNTIME, HIP_UNSUPPORTED), + "cudaGraphicsRegisterFlagsWriteDiscard": ("hipGraphicsRegisterFlagsWriteDiscard", CONV_GRAPHICS, API_RUNTIME, HIP_UNSUPPORTED), + "cudaGraphicsRegisterFlagsSurfaceLoadStore": ("hipGraphicsRegisterFlagsSurfaceLoadStore", CONV_GRAPHICS, API_RUNTIME, HIP_UNSUPPORTED), + "cudaGraphicsRegisterFlagsTextureGather": ("hipGraphicsRegisterFlagsTextureGather", CONV_GRAPHICS, API_RUNTIME, HIP_UNSUPPORTED), + "cudaGLDeviceListAll": ("HIP_GL_DEVICE_LIST_ALL", CONV_GL, API_RUNTIME, HIP_UNSUPPORTED), + "cudaGLDeviceListCurrentFrame": ("HIP_GL_DEVICE_LIST_CURRENT_FRAME", CONV_GL, API_RUNTIME, HIP_UNSUPPORTED), + "cudaGLDeviceListNextFrame": ("HIP_GL_DEVICE_LIST_NEXT_FRAME", CONV_GL, API_RUNTIME, HIP_UNSUPPORTED), + "cudaGLGetDevices": ("hipGLGetDevices", CONV_GL, API_RUNTIME, HIP_UNSUPPORTED), + "cudaGraphicsGLRegisterBuffer": ("hipGraphicsGLRegisterBuffer", CONV_GL, API_RUNTIME, HIP_UNSUPPORTED), + "cudaGraphicsGLRegisterImage": ("hipGraphicsGLRegisterImage", CONV_GL, API_RUNTIME, HIP_UNSUPPORTED), + "cudaWGLGetDevice": ("hipWGLGetDevice", CONV_GL, API_RUNTIME, HIP_UNSUPPORTED), + "cudaGLMapFlagsNone": ("HIP_GL_MAP_RESOURCE_FLAGS_NONE", CONV_GL, API_RUNTIME, HIP_UNSUPPORTED), + "cudaGLMapFlagsReadOnly": ("HIP_GL_MAP_RESOURCE_FLAGS_READ_ONLY", CONV_GL, API_RUNTIME, HIP_UNSUPPORTED), + "cudaGLMapFlagsWriteDiscard": ("HIP_GL_MAP_RESOURCE_FLAGS_WRITE_DISCARD", CONV_GL, API_RUNTIME, HIP_UNSUPPORTED), + "cudaGLMapBufferObject": ("hipGLMapBufferObject__", CONV_GL, API_RUNTIME, HIP_UNSUPPORTED), + "cudaGLMapBufferObjectAsync": ("hipGLMapBufferObjectAsync__", CONV_GL, API_RUNTIME, HIP_UNSUPPORTED), + "cudaGLRegisterBufferObject": ("hipGLRegisterBufferObject", CONV_GL, API_RUNTIME, HIP_UNSUPPORTED), + "cudaGLSetBufferObjectMapFlags": ("hipGLSetBufferObjectMapFlags", CONV_GL, API_RUNTIME, HIP_UNSUPPORTED), + "cudaGLSetGLDevice": ("hipGLSetGLDevice", CONV_GL, API_RUNTIME, HIP_UNSUPPORTED), + "cudaGLUnmapBufferObject": ("hipGLUnmapBufferObject", CONV_GL, API_RUNTIME, HIP_UNSUPPORTED), + "cudaGLUnmapBufferObjectAsync": ("hipGLUnmapBufferObjectAsync", CONV_GL, API_RUNTIME, HIP_UNSUPPORTED), + "cudaGLUnregisterBufferObject": ("hipGLUnregisterBufferObject", CONV_GL, API_RUNTIME, HIP_UNSUPPORTED), + "cudaD3D9DeviceListAll": ("HIP_D3D9_DEVICE_LIST_ALL", CONV_D3D9, API_RUNTIME, HIP_UNSUPPORTED), + "cudaD3D9DeviceListCurrentFrame": ("HIP_D3D9_DEVICE_LIST_CURRENT_FRAME", CONV_D3D9, API_RUNTIME, HIP_UNSUPPORTED), + "cudaD3D9DeviceListNextFrame": ("HIP_D3D9_DEVICE_LIST_NEXT_FRAME", CONV_D3D9, API_RUNTIME, HIP_UNSUPPORTED), + "cudaD3D9GetDevice": ("hipD3D9GetDevice", CONV_D3D9, API_RUNTIME, HIP_UNSUPPORTED), + "cudaD3D9GetDevices": ("hipD3D9GetDevices", CONV_D3D9, API_RUNTIME, HIP_UNSUPPORTED), + "cudaD3D9GetDirect3DDevice": ("hipD3D9GetDirect3DDevice", CONV_D3D9, API_RUNTIME, HIP_UNSUPPORTED), + "cudaD3D9SetDirect3DDevice": ("hipD3D9SetDirect3DDevice", CONV_D3D9, API_RUNTIME, HIP_UNSUPPORTED), + "cudaGraphicsD3D9RegisterResource": ("hipGraphicsD3D9RegisterResource", CONV_D3D9, API_RUNTIME, HIP_UNSUPPORTED), + "cudaD3D9MapFlags": ("hipD3D9MapFlags", CONV_D3D9, API_RUNTIME, HIP_UNSUPPORTED), + "cudaD3D9MapFlagsNone": ("HIP_D3D9_MAPRESOURCE_FLAGS_NONE", CONV_D3D9, API_RUNTIME, HIP_UNSUPPORTED), + "cudaD3D9MapFlagsReadOnly": ("HIP_D3D9_MAPRESOURCE_FLAGS_READONLY", CONV_D3D9, API_RUNTIME, HIP_UNSUPPORTED), + "cudaD3D9MapFlagsWriteDiscard": ("HIP_D3D9_MAPRESOURCE_FLAGS_WRITEDISCARD", CONV_D3D9, API_RUNTIME, HIP_UNSUPPORTED), + "cudaD3D9RegisterFlagsNone": ("HIP_D3D9_REGISTER_FLAGS_NONE", CONV_D3D9, API_RUNTIME, HIP_UNSUPPORTED), + "cudaD3D9RegisterFlagsArray": ("HIP_D3D9_REGISTER_FLAGS_ARRAY", CONV_D3D9, API_RUNTIME, HIP_UNSUPPORTED), + "cudaD3D9MapResources": ("hipD3D9MapResources", CONV_D3D9, API_RUNTIME, HIP_UNSUPPORTED), + "cudaD3D9RegisterResource": ("hipD3D9RegisterResource", CONV_D3D9, API_RUNTIME, HIP_UNSUPPORTED), + "cudaD3D9ResourceGetMappedArray": ("hipD3D9ResourceGetMappedArray", CONV_D3D9, API_RUNTIME, HIP_UNSUPPORTED), + "cudaD3D9ResourceGetMappedPitch": ("hipD3D9ResourceGetMappedPitch", CONV_D3D9, API_RUNTIME, HIP_UNSUPPORTED), + "cudaD3D9ResourceGetMappedPointer": ("hipD3D9ResourceGetMappedPointer", CONV_D3D9, API_RUNTIME, HIP_UNSUPPORTED), + "cudaD3D9ResourceGetMappedSize": ("hipD3D9ResourceGetMappedSize", CONV_D3D9, API_RUNTIME, HIP_UNSUPPORTED), + "cudaD3D9ResourceGetSurfaceDimensions": ("hipD3D9ResourceGetSurfaceDimensions", CONV_D3D9, API_RUNTIME, HIP_UNSUPPORTED), + "cudaD3D9ResourceSetMapFlags": ("hipD3D9ResourceSetMapFlags", CONV_D3D9, API_RUNTIME, HIP_UNSUPPORTED), + "cudaD3D9UnmapResources": ("hipD3D9UnmapResources", CONV_D3D9, API_RUNTIME, HIP_UNSUPPORTED), + "cudaD3D9UnregisterResource": ("hipD3D9UnregisterResource", CONV_D3D9, API_RUNTIME, HIP_UNSUPPORTED), + "cudaD3D10DeviceListAll": ("HIP_D3D10_DEVICE_LIST_ALL", CONV_D3D10, API_RUNTIME, HIP_UNSUPPORTED), + "cudaD3D10DeviceListCurrentFrame": ("HIP_D3D10_DEVICE_LIST_CURRENT_FRAME", CONV_D3D10, API_RUNTIME, HIP_UNSUPPORTED), + "cudaD3D10DeviceListNextFrame": ("HIP_D3D10_DEVICE_LIST_NEXT_FRAME", CONV_D3D10, API_RUNTIME, HIP_UNSUPPORTED), + "cudaD3D10GetDevice": ("hipD3D10GetDevice", CONV_D3D10, API_RUNTIME, HIP_UNSUPPORTED), + "cudaD3D10GetDevices": ("hipD3D10GetDevices", CONV_D3D10, API_RUNTIME, HIP_UNSUPPORTED), + "cudaGraphicsD3D10RegisterResource": ("hipGraphicsD3D10RegisterResource", CONV_D3D10, API_RUNTIME, HIP_UNSUPPORTED), + "cudaD3D10MapFlagsNone": ("HIP_D3D10_MAPRESOURCE_FLAGS_NONE", CONV_D3D10, API_RUNTIME, HIP_UNSUPPORTED), + "cudaD3D10MapFlagsReadOnly": ("HIP_D3D10_MAPRESOURCE_FLAGS_READONLY", CONV_D3D10, API_RUNTIME, HIP_UNSUPPORTED), + "cudaD3D10MapFlagsWriteDiscard": ("HIP_D3D10_MAPRESOURCE_FLAGS_WRITEDISCARD", CONV_D3D10, API_RUNTIME, HIP_UNSUPPORTED), + "cudaD3D10RegisterFlagsNone": ("HIP_D3D10_REGISTER_FLAGS_NONE", CONV_D3D10, API_RUNTIME, HIP_UNSUPPORTED), + "cudaD3D10RegisterFlagsArray": ("HIP_D3D10_REGISTER_FLAGS_ARRAY", CONV_D3D10, API_RUNTIME, HIP_UNSUPPORTED), + "cudaD3D10GetDirect3DDevice": ("hipD3D10GetDirect3DDevice", CONV_D3D10, API_RUNTIME, HIP_UNSUPPORTED), + "cudaD3D10MapResources": ("hipD3D10MapResources", CONV_D3D10, API_RUNTIME, HIP_UNSUPPORTED), + "cudaD3D10RegisterResource": ("hipD3D10RegisterResource", CONV_D3D10, API_RUNTIME, HIP_UNSUPPORTED), + "cudaD3D10ResourceGetMappedArray": ("hipD3D10ResourceGetMappedArray", CONV_D3D10, API_RUNTIME, HIP_UNSUPPORTED), + "cudaD3D10ResourceGetMappedPitch": ("hipD3D10ResourceGetMappedPitch", CONV_D3D10, API_RUNTIME, HIP_UNSUPPORTED), + "cudaD3D10ResourceGetMappedPointer": ("hipD3D10ResourceGetMappedPointer", CONV_D3D10, API_RUNTIME, HIP_UNSUPPORTED), + "cudaD3D10ResourceGetMappedSize": ("hipD3D10ResourceGetMappedSize", CONV_D3D10, API_RUNTIME, HIP_UNSUPPORTED), + "cudaD3D10ResourceGetSurfaceDimensions": ("hipD3D10ResourceGetSurfaceDimensions", CONV_D3D10, API_RUNTIME, HIP_UNSUPPORTED), + "cudaD3D10ResourceSetMapFlags": ("hipD3D10ResourceSetMapFlags", CONV_D3D10, API_RUNTIME, HIP_UNSUPPORTED), + "cudaD3D10SetDirect3DDevice": ("hipD3D10SetDirect3DDevice", CONV_D3D10, API_RUNTIME, HIP_UNSUPPORTED), + "cudaD3D10UnmapResources": ("hipD3D10UnmapResources", CONV_D3D10, API_RUNTIME, HIP_UNSUPPORTED), + "cudaD3D10UnregisterResource": ("hipD3D10UnregisterResource", CONV_D3D10, API_RUNTIME, HIP_UNSUPPORTED), + "cudaD3D11DeviceListAll": ("HIP_D3D11_DEVICE_LIST_ALL", CONV_D3D11, API_RUNTIME, HIP_UNSUPPORTED), + "cudaD3D11DeviceListCurrentFrame": ("HIP_D3D11_DEVICE_LIST_CURRENT_FRAME", CONV_D3D11, API_RUNTIME, HIP_UNSUPPORTED), + "cudaD3D11DeviceListNextFrame": ("HIP_D3D11_DEVICE_LIST_NEXT_FRAME", CONV_D3D11, API_RUNTIME, HIP_UNSUPPORTED), + "cudaD3D11GetDevice": ("hipD3D11GetDevice", CONV_D3D11, API_RUNTIME, HIP_UNSUPPORTED), + "cudaD3D11GetDevices": ("hipD3D11GetDevices", CONV_D3D11, API_RUNTIME, HIP_UNSUPPORTED), + "cudaGraphicsD3D11RegisterResource": ("hipGraphicsD3D11RegisterResource", CONV_D3D11, API_RUNTIME, HIP_UNSUPPORTED), + "cudaD3D11GetDevice": ("hipD3D11GetDevice", CONV_D3D11, API_RUNTIME, HIP_UNSUPPORTED), + "cudaD3D11GetDevices": ("hipD3D11GetDevices", CONV_D3D11, API_RUNTIME, HIP_UNSUPPORTED), + "cudaGraphicsD3D11RegisterResource": ("hipGraphicsD3D11RegisterResource", CONV_D3D11, API_RUNTIME, HIP_UNSUPPORTED), + "cudaGraphicsVDPAURegisterOutputSurface": ("hipGraphicsVDPAURegisterOutputSurface", CONV_VDPAU, API_RUNTIME, HIP_UNSUPPORTED), + "cudaGraphicsVDPAURegisterVideoSurface": ("hipGraphicsVDPAURegisterVideoSurface", CONV_VDPAU, API_RUNTIME, HIP_UNSUPPORTED), + "cudaVDPAUGetDevice": ("hipVDPAUGetDevice", CONV_VDPAU, API_RUNTIME, HIP_UNSUPPORTED), + "cudaVDPAUSetVDPAUDevice": ("hipVDPAUSetDevice", CONV_VDPAU, API_RUNTIME, HIP_UNSUPPORTED), + "cudaEGLStreamConsumerAcquireFrame": ("hipEGLStreamConsumerAcquireFrame", CONV_EGL, API_RUNTIME, HIP_UNSUPPORTED), + "cudaEGLStreamConsumerConnect": ("hipEGLStreamConsumerConnect", CONV_EGL, API_RUNTIME, HIP_UNSUPPORTED), + "cudaEGLStreamConsumerConnectWithFlags": ("hipEGLStreamConsumerConnectWithFlags", CONV_EGL, API_RUNTIME, HIP_UNSUPPORTED), + "cudaEGLStreamConsumerReleaseFrame": ("hipEGLStreamConsumerReleaseFrame", CONV_EGL, API_RUNTIME, HIP_UNSUPPORTED), + "cudaEGLStreamProducerConnect": ("hipEGLStreamProducerConnect", CONV_EGL, API_RUNTIME, HIP_UNSUPPORTED), + "cudaEGLStreamProducerDisconnect": ("hipEGLStreamProducerDisconnect", CONV_EGL, API_RUNTIME, HIP_UNSUPPORTED), + "cudaEGLStreamProducerPresentFrame": ("hipEGLStreamProducerPresentFrame", CONV_EGL, API_RUNTIME, HIP_UNSUPPORTED), + "cudaEGLStreamProducerReturnFrame": ("hipEGLStreamProducerReturnFrame", CONV_EGL, API_RUNTIME, HIP_UNSUPPORTED), + "cudaGraphicsEGLRegisterImage": ("hipGraphicsEGLRegisterImage", CONV_EGL, API_RUNTIME, HIP_UNSUPPORTED), + "cudaGraphicsResourceGetMappedEglFrame": ("hipGraphicsResourceGetMappedEglFrame", CONV_EGL, API_RUNTIME, HIP_UNSUPPORTED), + "cublasInit": ("hipblasInit", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasShutdown": ("hipblasShutdown", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasGetVersion": ("hipblasGetVersion", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasGetError": ("hipblasGetError", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasAlloc": ("hipblasAlloc", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasFree": ("hipblasFree", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasSetKernelStream": ("hipblasSetKernelStream", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasGetAtomicsMode": ("hipblasGetAtomicsMode", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasSetAtomicsMode": ("hipblasSetAtomicsMode", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasGetMathMode": ("hipblasGetMathMode", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasSetMathMode": ("hipblasSetMathMode", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "CUBLAS_OP_N": ("HIPBLAS_OP_N", CONV_NUMERIC_LITERAL, API_BLAS), + "CUBLAS_OP_T": ("HIPBLAS_OP_T", CONV_NUMERIC_LITERAL, API_BLAS), + "CUBLAS_OP_C": ("HIPBLAS_OP_C", CONV_NUMERIC_LITERAL, API_BLAS), + "CUBLAS_STATUS_SUCCESS": ("HIPBLAS_STATUS_SUCCESS", CONV_NUMERIC_LITERAL, API_BLAS), + "CUBLAS_STATUS_NOT_INITIALIZED": ("HIPBLAS_STATUS_NOT_INITIALIZED", CONV_NUMERIC_LITERAL, API_BLAS), + "CUBLAS_STATUS_ALLOC_FAILED": ("HIPBLAS_STATUS_ALLOC_FAILED", CONV_NUMERIC_LITERAL, API_BLAS), + "CUBLAS_STATUS_INVALID_VALUE": ("HIPBLAS_STATUS_INVALID_VALUE", CONV_NUMERIC_LITERAL, API_BLAS), + "CUBLAS_STATUS_MAPPING_ERROR": ("HIPBLAS_STATUS_MAPPING_ERROR", CONV_NUMERIC_LITERAL, API_BLAS), + "CUBLAS_STATUS_EXECUTION_FAILED": ("HIPBLAS_STATUS_EXECUTION_FAILED", CONV_NUMERIC_LITERAL, API_BLAS), + "CUBLAS_STATUS_INTERNAL_ERROR": ("HIPBLAS_STATUS_INTERNAL_ERROR", CONV_NUMERIC_LITERAL, API_BLAS), + "CUBLAS_STATUS_NOT_SUPPORTED": ("HIPBLAS_STATUS_INTERNAL_ERROR", CONV_NUMERIC_LITERAL, API_BLAS), + "CUBLAS_STATUS_ARCH_MISMATCH": ("HIPBLAS_STATUS_ARCH_MISMATCH", CONV_NUMERIC_LITERAL, API_BLAS), + "CUBLAS_FILL_MODE_LOWER": ("HIPBLAS_FILL_MODE_LOWER", CONV_NUMERIC_LITERAL, API_BLAS), + "CUBLAS_FILL_MODE_UPPER": ("HIPBLAS_FILL_MODE_UPPER", CONV_NUMERIC_LITERAL, API_BLAS), + "CUBLAS_DIAG_NON_UNIT": ("HIPBLAS_DIAG_NON_UNIT", CONV_NUMERIC_LITERAL, API_BLAS), + "CUBLAS_DIAG_UNIT": ("HIPBLAS_DIAG_UNIT", CONV_NUMERIC_LITERAL, API_BLAS), + "CUBLAS_SIDE_LEFT": ("HIPBLAS_SIDE_LEFT", CONV_NUMERIC_LITERAL, API_BLAS), + "CUBLAS_SIDE_RIGHT": ("HIPBLAS_SIDE_RIGHT", CONV_NUMERIC_LITERAL, API_BLAS), + "CUBLAS_POINTER_MODE_HOST": ("HIPBLAS_POINTER_MODE_HOST", CONV_NUMERIC_LITERAL, API_BLAS), + "CUBLAS_POINTER_MODE_DEVICE": ("HIPBLAS_POINTER_MODE_DEVICE", CONV_NUMERIC_LITERAL, API_BLAS), + "CUBLAS_ATOMICS_NOT_ALLOWED": ("HIPBLAS_ATOMICS_NOT_ALLOWED", CONV_NUMERIC_LITERAL, API_BLAS, HIP_UNSUPPORTED), + "CUBLAS_ATOMICS_ALLOWED": ("HIPBLAS_ATOMICS_ALLOWED", CONV_NUMERIC_LITERAL, API_BLAS, HIP_UNSUPPORTED), + "CUBLAS_DATA_FLOAT": ("HIPBLAS_DATA_FLOAT", CONV_NUMERIC_LITERAL, API_BLAS, HIP_UNSUPPORTED), + "CUBLAS_DATA_DOUBLE": ("HIPBLAS_DATA_DOUBLE", CONV_NUMERIC_LITERAL, API_BLAS, HIP_UNSUPPORTED), + "CUBLAS_DATA_HALF": ("HIPBLAS_DATA_HALF", CONV_NUMERIC_LITERAL, API_BLAS, HIP_UNSUPPORTED), + "CUBLAS_DATA_INT8": ("HIPBLAS_DATA_INT8", CONV_NUMERIC_LITERAL, API_BLAS, HIP_UNSUPPORTED), + "cublasCreate": ("hipblasCreate", CONV_MATH_FUNC, API_BLAS), + "cublasDestroy": ("hipblasDestroy", CONV_MATH_FUNC, API_BLAS), + "cublasSetVector": ("hipblasSetVector", CONV_MATH_FUNC, API_BLAS), + "cublasGetVector": ("hipblasGetVector", CONV_MATH_FUNC, API_BLAS), + "cublasSetVectorAsync": ("hipblasSetVectorAsync", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasGetVectorAsync": ("hipblasGetVectorAsync", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasSetMatrix": ("hipblasSetMatrix", CONV_MATH_FUNC, API_BLAS), + "cublasGetMatrix": ("hipblasGetMatrix", CONV_MATH_FUNC, API_BLAS), + "cublasGetMatrixAsync": ("hipblasGetMatrixAsync", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasSetMatrixAsync": ("hipblasSetMatrixAsync", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasXerbla": ("hipblasXerbla", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasSnrm2": ("hipblasSnrm2", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasDnrm2": ("hipblasDnrm2", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasScnrm2": ("hipblasScnrm2", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasDznrm2": ("hipblasDznrm2", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasNrm2Ex": ("hipblasNrm2Ex", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasSdot": ("hipblasSdot", CONV_MATH_FUNC, API_BLAS), + "cublasSdotBatched": ("hipblasSdotBatched", CONV_MATH_FUNC, API_BLAS), + "cublasDdot": ("hipblasDdot", CONV_MATH_FUNC, API_BLAS), + "cublasDdotBatched": ("hipblasDdotBatched", CONV_MATH_FUNC, API_BLAS), + "cublasCdotu": ("hipblasCdotu", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasCdotc": ("hipblasCdotc", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZdotu": ("hipblasZdotu", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZdotc": ("hipblasZdotc", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasSscal": ("hipblasSscal", CONV_MATH_FUNC, API_BLAS), + "cublasSscalBatched": ("hipblasSscalBatched", CONV_MATH_FUNC, API_BLAS), + "cublasDscal": ("hipblasDscal", CONV_MATH_FUNC, API_BLAS), + "cublasDscalBatched": ("hipblasDscalBatched", CONV_MATH_FUNC, API_BLAS), + "cublasCscal": ("hipblasCscal", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasCsscal": ("hipblasCsscal", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZscal": ("hipblasZscal", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZdscal": ("hipblasZdscal", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasSaxpy": ("hipblasSaxpy", CONV_MATH_FUNC, API_BLAS), + "cublasSaxpyBatched": ("hipblasSaxpyBatched", CONV_MATH_FUNC, API_BLAS), + "cublasDaxpy": ("hipblasDaxpy", CONV_MATH_FUNC, API_BLAS), + "cublasCaxpy": ("hipblasCaxpy", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZaxpy": ("hipblasZaxpy", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasScopy": ("hipblasScopy", CONV_MATH_FUNC, API_BLAS), + "cublasScopyBatched": ("hipblasScopyBatched", CONV_MATH_FUNC, API_BLAS), + "cublasDcopy": ("hipblasDcopy", CONV_MATH_FUNC, API_BLAS), + "cublasDcopyBatched": ("hipblasDcopyBatched", CONV_MATH_FUNC, API_BLAS), + "cublasCcopy": ("hipblasCcopy", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZcopy": ("hipblasZcopy", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasSswap": ("hipblasSswap", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasDswap": ("hipblasDswap", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasCswap": ("hipblasCswap", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZswap": ("hipblasZswap", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasIsamax": ("hipblasIsamax", CONV_MATH_FUNC, API_BLAS), + "cublasIdamax": ("hipblasIdamax", CONV_MATH_FUNC, API_BLAS), + "cublasIcamax": ("hipblasIcamax", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasIzamax": ("hipblasIzamax", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasIsamin": ("hipblasIsamin", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasIdamin": ("hipblasIdamin", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasIcamin": ("hipblasIcamin", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasIzamin": ("hipblasIzamin", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasSasum": ("hipblasSasum", CONV_MATH_FUNC, API_BLAS), + "cublasSasumBatched": ("hipblasSasumBatched", CONV_MATH_FUNC, API_BLAS), + "cublasDasum": ("hipblasDasum", CONV_MATH_FUNC, API_BLAS), + "cublasDasumBatched": ("hipblasDasumBatched", CONV_MATH_FUNC, API_BLAS), + "cublasScasum": ("hipblasScasum", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasDzasum": ("hipblasDzasum", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasSrot": ("hipblasSrot", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasDrot": ("hipblasDrot", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasCrot": ("hipblasCrot", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasCsrot": ("hipblasCsrot", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZrot": ("hipblasZrot", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZdrot": ("hipblasZdrot", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasSrotg": ("hipblasSrotg", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasDrotg": ("hipblasDrotg", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasCrotg": ("hipblasCrotg", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZrotg": ("hipblasZrotg", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasSrotm": ("hipblasSrotm", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasDrotm": ("hipblasDrotm", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasSrotmg": ("hipblasSrotmg", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasDrotmg": ("hipblasDrotmg", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasSgemv": ("hipblasSgemv", CONV_MATH_FUNC, API_BLAS), + "cublasSgemvBatched": ("hipblasSgemvBatched", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasDgemv": ("hipblasDgemv", CONV_MATH_FUNC, API_BLAS), + "cublasCgemv": ("hipblasCgemv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZgemv": ("hipblasZgemv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasSgbmv": ("hipblasSgbmv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasDgbmv": ("hipblasDgbmv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasCgbmv": ("hipblasCgbmv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZgbmv": ("hipblasZgbmv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasStrmv": ("hipblasStrmv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasDtrmv": ("hipblasDtrmv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasCtrmv": ("hipblasCtrmv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZtrmv": ("hipblasZtrmv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasStbmv": ("hipblasStbmv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasDtbmv": ("hipblasDtbmv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasCtbmv": ("hipblasCtbmv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZtbmv": ("hipblasZtbmv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasStpmv": ("hipblasStpmv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasDtpmv": ("hipblasDtpmv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasCtpmv": ("hipblasCtpmv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZtpmv": ("hipblasZtpmv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasStrsv": ("hipblasStrsv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasDtrsv": ("hipblasDtrsv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasCtrsv": ("hipblasCtrsv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZtrsv": ("hipblasZtrsv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasStpsv": ("hipblasStpsv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasDtpsv": ("hipblasDtpsv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasCtpsv": ("hipblasCtpsv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZtpsv": ("hipblasZtpsv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasStbsv": ("hipblasStbsv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasDtbsv": ("hipblasDtbsv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasCtbsv": ("hipblasCtbsv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZtbsv": ("hipblasZtbsv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasSsymv": ("hipblasSsymv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasDsymv": ("hipblasDsymv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasCsymv": ("hipblasCsymv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZsymv": ("hipblasZsymv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasChemv": ("hipblasChemv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZhemv": ("hipblasZhemv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasSsbmv": ("hipblasSsbmv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasDsbmv": ("hpiblasDsbmv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasChbmv": ("hipblasChbmv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZhbmv": ("hipblasZhbmv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasSspmv": ("hipblasSspmv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasDspmv": ("hipblasDspmv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasChpmv": ("hipblasChpmv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZhpmv": ("hipblasZhpmv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasSger": ("hipblasSger", CONV_MATH_FUNC, API_BLAS), + "cublasDger": ("hipblasDger", CONV_MATH_FUNC, API_BLAS), + "cublasCgeru": ("hipblasCgeru", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasCgerc": ("hipblasCgerc", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZgeru": ("hipblasZgeru", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZgerc": ("hipblasZgerc", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasSsyr": ("hipblasSsyr", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasDsyr": ("hipblasDsyr", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasCher": ("hipblasCher", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZher": ("hipblasZher", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasSspr": ("hipblasSspr", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasDspr": ("hipblasDspr", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasChpr": ("hipblasChpr", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZhpr": ("hipblasZhpr", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasSsyr2": ("hipblasSsyr2", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasDsyr2": ("hipblasDsyr2", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasCher2": ("hipblasCher2", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZher2": ("hipblasZher2", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasSspr2": ("hipblasSspr2", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasDspr2": ("hipblasDspr2", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasChpr2": ("hipblasChpr2", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZhpr2": ("hipblasZhpr2", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasSgemm": ("hipblasSgemm", CONV_MATH_FUNC, API_BLAS), + "cublasDgemm": ("hipblasDgemm", CONV_MATH_FUNC, API_BLAS), + "cublasCgemm": ("hipblasCgemm", CONV_MATH_FUNC, API_BLAS), + "cublasZgemm": ("hipblasZgemm", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasHgemm": ("hipblasHgemm", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasSgemmBatched": ("hipblasSgemmBatched", CONV_MATH_FUNC, API_BLAS), + "cublasDgemmBatched": ("hipblasDgemmBatched", CONV_MATH_FUNC, API_BLAS), + "cublasHgemmBatched": ("hipblasHgemmBatched", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasSgemmStridedBatched": ("hipblasSgemmStridedBatched", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasDgemmStridedBatched": ("hipblasDgemmStridedBatched", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasCgemmBatched": ("hipblasCgemmBatched", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasCgemm3mBatched": ("hipblasCgemm3mBatched", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZgemmBatched": ("hipblasZgemmBatched", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasCgemmStridedBatched": ("hipblasCgemmStridedBatched", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasCgemm3mStridedBatched": ("hipblasCgemm3mStridedBatched", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZgemmStridedBatched": ("hipblasZgemmStridedBatched", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasHgemmStridedBatched": ("hipblasHgemmStridedBatched", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasSsyrk": ("hipblasSsyrk", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasDsyrk": ("hipblasDsyrk", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasCsyrk": ("hipblasCsyrk", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZsyrk": ("hipblasZsyrk", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasCherk": ("hipblasCherk", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZherk": ("hipblasZherk", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasSsyr2k": ("hipblasSsyr2k", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasDsyr2k": ("hipblasDsyr2k", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasCsyr2k": ("hipblasCsyr2k", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZsyr2k": ("hipblasZsyr2k", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasSsyrkx": ("hipblasSsyrkx", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasDsyrkx": ("hipblasDsyrkx", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasCsyrkx": ("hipblasCsyrkx", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZsyrkx": ("hipblasZsyrkx", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasCher2k": ("hipblasCher2k", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZher2k": ("hipblasZher2k", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasCherkx": ("hipblasCherkx", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZherkx": ("hipblasZherkx", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasSsymm": ("hipblasSsymm", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasDsymm": ("hipblasDsymm", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasCsymm": ("hipblasCsymm", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZsymm": ("hipblasZsymm", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasChemm": ("hipblasChemm", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZhemm": ("hipblasZhemm", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasStrsm": ("hipblasStrsm", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasDtrsm": ("hipblasDtrsm", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasCtrsm": ("hipblasCtrsm", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZtrsm": ("hipblasZtrsm", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasStrsmBatched": ("hipblasStrsmBatched", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasDtrsmBatched": ("hipblasDtrsmBatched", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasCtrsmBatched": ("hipblasCtrsmBatched", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZtrsmBatched": ("hipblasZtrsmBatched", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasStrmm": ("hipblasStrmm", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasDtrmm": ("hipblasDtrmm", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasCtrmm": ("hipblasCtrmm", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZtrmm": ("hipblasZtrmm", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasSgeam": ("hipblasSgeam", CONV_MATH_FUNC, API_BLAS), + "cublasDgeam": ("hipblasDgeam", CONV_MATH_FUNC, API_BLAS), + "cublasCgeam": ("hipblasCgeam", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZgeam": ("hipblasZgeam", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasSgetrfBatched": ("hipblasSgetrfBatched", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasDgetrfBatched": ("hipblasDgetrfBatched", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasCgetrfBatched": ("hipblasCgetrfBatched", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZgetrfBatched": ("hipblasZgetrfBatched", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasSgetriBatched": ("hipblasSgetriBatched", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasDgetriBatched": ("hipblasDgetriBatched", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasCgetriBatched": ("hipblasCgetriBatched", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZgetriBatched": ("hipblasZgetriBatched", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasSgetrsBatched": ("hipblasSgetrsBatched", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasDgetrsBatched": ("hipblasDgetrsBatched", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasCgetrsBatched": ("hipblasCgetrsBatched", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZgetrsBatched": ("hipblasZgetrsBatched", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasStrsmBatched": ("hipblasStrsmBatched", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasDtrsmBatched": ("hipblasDtrsmBatched", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasCtrsmBatched": ("hipblasCtrsmBatched", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZtrsmBatched": ("hipblasZtrsmBatched", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasSmatinvBatched": ("hipblasSmatinvBatched", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasDmatinvBatched": ("hipblasDmatinvBatched", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasCmatinvBatched": ("hipblasCmatinvBatched", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZmatinvBatched": ("hipblasZmatinvBatched", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasSgeqrfBatched": ("hipblasSgeqrfBatched", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasDgeqrfBatched": ("hipblasDgeqrfBatched", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasCgeqrfBatched": ("hipblasCgeqrfBatched", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZgeqrfBatched": ("hipblasZgeqrfBatched", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasSgelsBatched": ("hipblasSgelsBatched", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasDgelsBatched": ("hipblasDgelsBatched", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasCgelsBatched": ("hipblasCgelsBatched", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZgelsBatched": ("hipblasZgelsBatched", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasSdgmm": ("hipblasSdgmm", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasDdgmm": ("hipblasDdgmm", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasCdgmm": ("hipblasCdgmm", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZdgmm": ("hipblasZdgmm", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasStpttr": ("hipblasStpttr", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasDtpttr": ("hipblasDtpttr", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasCtpttr": ("hipblasCtpttr", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZtpttr": ("hipblasZtpttr", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasStrttp": ("hipblasStrttp", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasDtrttp": ("hipblasDtrttp", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasCtrttp": ("hipblasCtrttp", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZtrttp": ("hipblasZtrttp", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasCreate_v2": ("hipblasCreate", CONV_MATH_FUNC, API_BLAS), + "cublasDestroy_v2": ("hipblasDestroy", CONV_MATH_FUNC, API_BLAS), + "cublasGetVersion_v2": ("hipblasGetVersion", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasSetStream": ("hipblasSetStream", CONV_MATH_FUNC, API_BLAS), + "cublasGetStream": ("hipblasGetStream", CONV_MATH_FUNC, API_BLAS), + "cublasSetStream_v2": ("hipblasSetStream", CONV_MATH_FUNC, API_BLAS), + "cublasGetStream_v2": ("hipblasGetStream", CONV_MATH_FUNC, API_BLAS), + "cublasGetPointerMode_v2": ("hipblasGetPointerMode", CONV_MATH_FUNC, API_BLAS), + "cublasSetPointerMode_v2": ("hipblasSetPointerMode", CONV_MATH_FUNC, API_BLAS), + "cublasSgemv_v2": ("hipblasSgemv", CONV_MATH_FUNC, API_BLAS), + "cublasDgemv_v2": ("hipblasDgemv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasCgemv_v2": ("hipblasCgemv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZgemv_v2": ("hipblasZgemv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasSgbmv_v2": ("hipblasSgbmv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasDgbmv_v2": ("hipblasDgbmv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasCgbmv_v2": ("hipblasCgbmv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZgbmv_v2": ("hipblasZgbmv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasStrmv_v2": ("hipblasStrmv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasDtrmv_v2": ("hipblasDtrmv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasCtrmv_v2": ("hipblasCtrmv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZtrmv_v2": ("hipblasZtrmv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasStbmv_v2": ("hipblasStbmv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasDtbmv_v2": ("hipblasDtbmv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasCtbmv_v2": ("hipblasCtbmv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZtbmv_v2": ("hipblasZtbmv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasStpmv_v2": ("hipblasStpmv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasDtpmv_v2": ("hipblasDtpmv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasCtpmv_v2": ("hipblasCtpmv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZtpmv_v2": ("hipblasZtpmv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasStrsv_v2": ("hipblasStrsv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasDtrsv_v2": ("hipblasDtrsv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasCtrsv_v2": ("hipblasCtrsv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZtrsv_v2": ("hipblasZtrsv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasStpsv_v2": ("hipblasStpsv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasDtpsv_v2": ("hipblasDtpsv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasCtpsv_v2": ("hipblasCtpsv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZtpsv_v2": ("hipblasZtpsv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasStbsv_v2": ("hipblasStbsv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasDtbsv_v2": ("hipblasDtbsv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasCtbsv_v2": ("hipblasCtbsv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZtbsv_v2": ("hipblasZtbsv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasSsymv_v2": ("hipblasSsymv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasDsymv_v2": ("hipblasDsymv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasCsymv_v2": ("hipblasCsymv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZsymv_v2": ("hipblasZsymv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasChemv_v2": ("hipblasChemv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZhemv_v2": ("hipblasZhemv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasSsbmv_v2": ("hipblasSsbmv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasDsbmv_v2": ("hpiblasDsbmv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasChbmv_v2": ("hipblasChbmv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZhbmv_v2": ("hipblasZhbmv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasSspmv_v2": ("hipblasSspmv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasDspmv_v2": ("hipblasDspmv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasChpmv_v2": ("hipblasChpmv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZhpmv_v2": ("hipblasZhpmv", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasSger_v2": ("hipblasSger", CONV_MATH_FUNC, API_BLAS), + "cublasDger_v2": ("hipblasDger", CONV_MATH_FUNC, API_BLAS), + "cublasCgeru_v2": ("hipblasCgeru", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasCgerc_v2": ("hipblasCgerc", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZgeru_v2": ("hipblasZgeru", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZgerc_v2": ("hipblasZgerc", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasSsyr_v2": ("hipblasSsyr", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasDsyr_v2": ("hipblasDsyr", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasCsyr_v2": ("hipblasCsyr", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZsyr_v2": ("hipblasZsyr", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasCher_v2": ("hipblasCher", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZher_v2": ("hipblasZher", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasSspr_v2": ("hipblasSspr", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasDspr_v2": ("hipblasDspr", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasChpr_v2": ("hipblasChpr", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZhpr_v2": ("hipblasZhpr", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasSsyr2_v2": ("hipblasSsyr2", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasDsyr2_v2": ("hipblasDsyr2", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasCsyr2_v2": ("hipblasCsyr2", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZsyr2_v2": ("hipblasZsyr2", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasCher2_v2": ("hipblasCher2", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZher2_v2": ("hipblasZher2", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasSspr2_v2": ("hipblasSspr2", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasDspr2_v2": ("hipblasDspr2", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasChpr2_v2": ("hipblasChpr2", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZhpr2_v2": ("hipblasZhpr2", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasSgemm_v2": ("hipblasSgemm", CONV_MATH_FUNC, API_BLAS), + "cublasDgemm_v2": ("hipblasDgemm", CONV_MATH_FUNC, API_BLAS), + "cublasCgemm_v2": ("hipblasCgemm", CONV_MATH_FUNC, API_BLAS), + "cublasCgemm3m": ("hipblasCgemm3m", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasCgemm3mEx": ("hipblasCgemm3mEx", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZgemm_v2": ("hipblasZgemm", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZgemm3m": ("hipblasZgemm3m", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasSgemmEx": ("hipblasSgemmEx", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasGemmEx": ("hipblasGemmEx", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasCgemmEx": ("hipblasCgemmEx", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasUint8gemmBias": ("hipblasUint8gemmBias", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasSsyrk_v2": ("hipblasSsyrk", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasDsyrk_v2": ("hipblasDsyrk", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasCsyrk_v2": ("hipblasCsyrk", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZsyrk_v2": ("hipblasZsyrk", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasCsyrkEx": ("hipblasCsyrkEx", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasCsyrk3mEx": ("hipblasCsyrk3mEx", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasCherk_v2": ("hipblasCherk", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasCherkEx": ("hipblasCherkEx", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasCherk3mEx": ("hipblasCherk3mEx", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZherk_v2": ("hipblasZherk", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasSsyr2k_v2": ("hipblasSsyr2k", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasDsyr2k_v2": ("hipblasDsyr2k", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasCsyr2k_v2": ("hipblasCsyr2k", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZsyr2k_v2": ("hipblasZsyr2k", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasCher2k_v2": ("hipblasCher2k", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZher2k_v2": ("hipblasZher2k", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasSsymm_v2": ("hipblasSsymm", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasDsymm_v2": ("hipblasDsymm", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasCsymm_v2": ("hipblasCsymm", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZsymm_v2": ("hipblasZsymm", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasChemm_v2": ("hipblasChemm", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZhemm_v2": ("hipblasZhemm", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasStrsm_v2": ("hipblasStrsm", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasDtrsm_v2": ("hipblasDtrsm", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasCtrsm_v2": ("hipblasCtrsm", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZtrsm_v2": ("hipblasZtrsm", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasStrmm_v2": ("hipblasStrmm", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasDtrmm_v2": ("hipblasDtrmm", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasCtrmm_v2": ("hipblasCtrmm", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZtrmm_v2": ("hipblasZtrmm", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasSnrm2_v2": ("hipblasSnrm2", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasDnrm2_v2": ("hipblasDnrm2", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasScnrm2_v2": ("hipblasScnrm2", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasDznrm2_v2": ("hipblasDznrm2", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasDotEx": ("hipblasDotEx", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasDotcEx": ("hipblasDotcEx", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasSdot_v2": ("hipblasSdot", CONV_MATH_FUNC, API_BLAS), + "cublasDdot_v2": ("hipblasDdot", CONV_MATH_FUNC, API_BLAS), + "cublasCdotu_v2": ("hipblasCdotu", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasCdotc_v2": ("hipblasCdotc", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZdotu_v2": ("hipblasZdotu", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZdotc_v2": ("hipblasZdotc", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasScalEx": ("hipblasScalEx", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasSscal_v2": ("hipblasSscal", CONV_MATH_FUNC, API_BLAS), + "cublasDscal_v2": ("hipblasDscal", CONV_MATH_FUNC, API_BLAS), + "cublasCscal_v2": ("hipblasCscal", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasCsscal_v2": ("hipblasCsscal", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZscal_v2": ("hipblasZscal", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZdscal_v2": ("hipblasZdscal", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasAxpyEx": ("hipblasAxpyEx", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasSaxpy_v2": ("hipblasSaxpy", CONV_MATH_FUNC, API_BLAS), + "cublasDaxpy_v2": ("hipblasDaxpy", CONV_MATH_FUNC, API_BLAS), + "cublasCaxpy_v2": ("hipblasCaxpy", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZaxpy_v2": ("hipblasZaxpy", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasScopy_v2": ("hipblasScopy", CONV_MATH_FUNC, API_BLAS), + "cublasDcopy_v2": ("hipblasDcopy", CONV_MATH_FUNC, API_BLAS), + "cublasCcopy_v2": ("hipblasCcopy", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZcopy_v2": ("hipblasZcopy", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasSswap_v2": ("hipblasSswap", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasDswap_v2": ("hipblasDswap", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasCswap_v2": ("hipblasCswap", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZswap_v2": ("hipblasZswap", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasIsamax_v2": ("hipblasIsamax", CONV_MATH_FUNC, API_BLAS), + "cublasIdamax_v2": ("hipblasIdamax", CONV_MATH_FUNC, API_BLAS), + "cublasIcamax_v2": ("hipblasIcamax", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasIzamax_v2": ("hipblasIzamax", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasIsamin_v2": ("hipblasIsamin", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasIdamin_v2": ("hipblasIdamin", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasIcamin_v2": ("hipblasIcamin", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasIzamin_v2": ("hipblasIzamin", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasSasum_v2": ("hipblasSasum", CONV_MATH_FUNC, API_BLAS), + "cublasDasum_v2": ("hipblasDasum", CONV_MATH_FUNC, API_BLAS), + "cublasScasum_v2": ("hipblasScasum", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasDzasum_v2": ("hipblasDzasum", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasSrot_v2": ("hipblasSrot", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasDrot_v2": ("hipblasDrot", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasCrot_v2": ("hipblasCrot", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasCsrot_v2": ("hipblasCsrot", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZrot_v2": ("hipblasZrot", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZdrot_v2": ("hipblasZdrot", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasSrotg_v2": ("hipblasSrotg", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasDrotg_v2": ("hipblasDrotg", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasCrotg_v2": ("hipblasCrotg", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasZrotg_v2": ("hipblasZrotg", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasSrotm_v2": ("hipblasSrotm", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasDrotm_v2": ("hipblasDrotm", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasSrotmg_v2": ("hipblasSrotmg", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "cublasDrotmg_v2": ("hipblasDrotmg", CONV_MATH_FUNC, API_BLAS, HIP_UNSUPPORTED), + "CURAND_STATUS_SUCCESS": ("HIPRNG_STATUS_SUCCESS", CONV_NUMERIC_LITERAL, API_RAND), + "curand_STATUS_VERSION_MISMATCH": ("hiprng_STATUS_VERSION_MISMATCH", CONV_NUMERIC_LITERAL, API_RAND), + "curand_STATUS_NOT_INITIALIZED": ("hiprng_STATUS_NOT_INITIALIZED", CONV_NUMERIC_LITERAL, API_RAND), + "curand_STATUS_ALLOCATION_FAILED": ("hiprng_STATUS_ALLOCATION_FAILED", CONV_NUMERIC_LITERAL, API_RAND), + "curand_STATUS_TYPE_ERROR": ("hiprng_STATUS_TYPE_ERROR", CONV_NUMERIC_LITERAL, API_RAND), + "curand_STATUS_OUT_OF_RANGE": ("hiprng_STATUS_OUT_OF_RANGE", CONV_NUMERIC_LITERAL, API_RAND), + "curand_STATUS_LENGTH_NOT_MULTIPLE": ("hiprng_STATUS_LENGTH_NOT_MULTIPLE", CONV_NUMERIC_LITERAL, API_RAND), + "curand_STATUS_DOUBLE_PRECISION_REQUIRED": ("hiprng_STATUS_DOUBLE_PRECISION_REQUIRED", CONV_NUMERIC_LITERAL, API_RAND), + "curand_STATUS_LAUNCH_FAILURE": ("hiprng_STATUS_LAUNCH_FAILURE", CONV_NUMERIC_LITERAL, API_RAND), + "curand_STATUS_PREEXISTING_FAILURE": ("hiprng_STATUS_PREEXISTING_FAILURE", CONV_NUMERIC_LITERAL, API_RAND), + "curand_STATUS_INITIALIZATION_FAILED": ("hiprng_STATUS_INITIALIZATION_FAILED", CONV_NUMERIC_LITERAL, API_RAND), + "curand_STATUS_ARCH_MISMATCH": ("hiprng_STATUS_ARCH_MISMATCH", CONV_NUMERIC_LITERAL, API_RAND), + "curand_STATUS_INTERNAL_ERROR": ("hiprng_STATUS_INTERNAL_ERROR", CONV_NUMERIC_LITERAL, API_RAND), + "curand_RNG_TEST": ("hiprng_RNG_TEST", CONV_NUMERIC_LITERAL, API_RAND), + "mtgp32dc_params_fast_11213": ("mtgp32_params_fast_11213", CONV_NUMERIC_LITERAL, API_RAND), + "curand_RNG_PSEUDO_DEFAULT": ("hiprng_RNG_PSEUDO_DEFAULT", CONV_NUMERIC_LITERAL, API_RAND), + "curand_RNG_PSEUDO_XORWOW": ("hiprng_RNG_PSEUDO_XORWOW", CONV_NUMERIC_LITERAL, API_RAND), + "curand_RNG_PSEUDO_MRG32K3A": ("hiprng_RNG_PSEUDO_MRG32K3A", CONV_NUMERIC_LITERAL, API_RAND), + "curand_RNG_PSEUDO_MTGP32": ("hiprng_RNG_PSEUDO_MTGP32", CONV_NUMERIC_LITERAL, API_RAND), + "curand_RNG_PSEUDO_MT19937": ("hiprng_RNG_PSEUDO_MT19937", CONV_NUMERIC_LITERAL, API_RAND), + "curand_RNG_PSEUDO_PHILOX4_32_10": ("hiprng_RNG_PSEUDO_PHILOX4_32_10", CONV_NUMERIC_LITERAL, API_RAND), + "curand_RNG_QUASI_DEFAULT": ("hiprng_RNG_QUASI_DEFAULT", CONV_NUMERIC_LITERAL, API_RAND), + "curand_RNG_QUASI_SOBOL32": ("hiprng_RNG_QUASI_SOBOL32", CONV_NUMERIC_LITERAL, API_RAND), + "curand_RNG_QUASI_SCRAMBLED_SOBOL32": ("hiprng_RNG_QUASI_SCRAMBLED_SOBOL32", CONV_NUMERIC_LITERAL, API_RAND), + "curand_RNG_QUASI_SOBOL64": ("hiprng_RNG_QUASI_SOBOL64", CONV_NUMERIC_LITERAL, API_RAND), + "curand_RNG_QUASI_SCRAMBLED_SOBOL64": ("hiprng_RNG_QUASI_SCRAMBLED_SOBOL64", CONV_NUMERIC_LITERAL, API_RAND), + "curand_ORDERING_PSEUDO_BEST": ("hiprng_ORDERING_PSEUDO_BEST", CONV_NUMERIC_LITERAL, API_RAND, HIP_UNSUPPORTED), + "curand_ORDERING_PSEUDO_DEFAULT": ("hiprng_ORDERING_PSEUDO_DEFAULT", CONV_NUMERIC_LITERAL, API_RAND, HIP_UNSUPPORTED), + "curand_ORDERING_PSEUDO_SEEDED": ("hiprng_ORDERING_PSEUDO_SEEDED", CONV_NUMERIC_LITERAL, API_RAND, HIP_UNSUPPORTED), + "curand_ORDERING_QUASI_DEFAULT": ("hiprng_ORDERING_QUASI_DEFAULT", CONV_NUMERIC_LITERAL, API_RAND, HIP_UNSUPPORTED), + "curand_DIRECTION_VECTORS_32_JOEKUO6": ("hiprng_DIRECTION_VECTORS_32_JOEKUO6", CONV_NUMERIC_LITERAL, API_RAND, HIP_UNSUPPORTED), + "curand_SCRAMBLED_DIRECTION_VECTORS_32_JOEKUO6": ("hiprng_SCRAMBLED_DIRECTION_VECTORS_32_JOEKUO6", CONV_NUMERIC_LITERAL, API_RAND, HIP_UNSUPPORTED), + "curand_DIRECTION_VECTORS_64_JOEKUO6": ("hiprng_DIRECTION_VECTORS_64_JOEKUO6", CONV_NUMERIC_LITERAL, API_RAND, HIP_UNSUPPORTED), + "curand_SCRAMBLED_DIRECTION_VECTORS_64_JOEKUO6": ("hiprng_SCRAMBLED_DIRECTION_VECTORS_64_JOEKUO6", CONV_NUMERIC_LITERAL, API_RAND, HIP_UNSUPPORTED), + "curand_CHOOSE_BEST": ("hiprng_CHOOSE_BEST", CONV_NUMERIC_LITERAL, API_RAND, HIP_UNSUPPORTED), + "curand_ITR": ("hiprng_ITR", CONV_NUMERIC_LITERAL, API_RAND, HIP_UNSUPPORTED), + "curand_KNUTH": ("hiprng_KNUTH", CONV_NUMERIC_LITERAL, API_RAND, HIP_UNSUPPORTED), + "curand_HITR": ("hiprng_HITR", CONV_NUMERIC_LITERAL, API_RAND, HIP_UNSUPPORTED), + "curand_M1": ("hiprng_M1", CONV_NUMERIC_LITERAL, API_RAND, HIP_UNSUPPORTED), + "curand_M2": ("hiprng_M2", CONV_NUMERIC_LITERAL, API_RAND, HIP_UNSUPPORTED), + "curand_BINARY_SEARCH": ("hiprng_BINARY_SEARCH", CONV_NUMERIC_LITERAL, API_RAND, HIP_UNSUPPORTED), + "curand_DISCRETE_GAUSS": ("hiprng_DISCRETE_GAUSS", CONV_NUMERIC_LITERAL, API_RAND, HIP_UNSUPPORTED), + "curand_REJECTION": ("hiprng_REJECTION", CONV_NUMERIC_LITERAL, API_RAND, HIP_UNSUPPORTED), + "curand_DEVICE_API": ("hiprng_DEVICE_API", CONV_NUMERIC_LITERAL, API_RAND, HIP_UNSUPPORTED), + "curand_FAST_REJECTION": ("hiprng_FAST_REJECTION", CONV_NUMERIC_LITERAL, API_RAND, HIP_UNSUPPORTED), + "curand_3RD": ("hiprng_3RD", CONV_NUMERIC_LITERAL, API_RAND, HIP_UNSUPPORTED), + "curand_DEFINITION": ("hiprng_DEFINITION", CONV_NUMERIC_LITERAL, API_RAND, HIP_UNSUPPORTED), + "curand_POISSON": ("hiprng_POISSON", CONV_NUMERIC_LITERAL, API_RAND, HIP_UNSUPPORTED), + "curandCreateGenerator": ("hiprngCreateGenerator", CONV_MATH_FUNC, API_RAND), + "curandCreateGeneratorHost": ("hiprngCreateGeneratorHost", CONV_MATH_FUNC, API_RAND), + "curandCreatePoissonDistribution": ("hiprngCreatePoissonDistribution", CONV_MATH_FUNC, API_RAND), + "curandDestroyDistribution": ("hiprngDestroyDistribution", CONV_MATH_FUNC, API_RAND), + "curandDestroyGenerator": ("hiprngDestroyGenerator", CONV_MATH_FUNC, API_RAND), + "curandGenerate": ("hiprngGenerate", CONV_MATH_FUNC, API_RAND), + "curandGenerateLogNormal": ("hiprngGenerateLogNormal", CONV_MATH_FUNC, API_RAND), + "curandGenerateLogNormalDouble": ("hiprngGenerateLogNormalDouble", CONV_MATH_FUNC, API_RAND), + "curandGenerateLongLong": ("hiprngGenerateLongLong", CONV_MATH_FUNC, API_RAND, HIP_UNSUPPORTED), + "curandGenerateNormal": ("hiprngGenerateNormal", CONV_MATH_FUNC, API_RAND), + "curandGenerateNormalDouble": ("hiprngGenerateNormalDouble", CONV_MATH_FUNC, API_RAND), + "curandGeneratePoisson": ("hiprngGeneratePoisson", CONV_MATH_FUNC, API_RAND), + "curandGenerateSeeds": ("hiprngGenerateSeeds", CONV_MATH_FUNC, API_RAND), + "curandGenerateUniform": ("hiprngGenerateUniform", CONV_MATH_FUNC, API_RAND), + "curandGenerateUniformDouble": ("hiprngGenerateUniformDouble", CONV_MATH_FUNC, API_RAND), + "curandGetDirectionVectors32": ("hiprngGetDirectionVectors32", CONV_MATH_FUNC, API_RAND, HIP_UNSUPPORTED), + "curandGetDirectionVectors64": ("hiprngGetDirectionVectors64", CONV_MATH_FUNC, API_RAND, HIP_UNSUPPORTED), + "curandGetProperty": ("hiprngGetProperty", CONV_MATH_FUNC, API_RAND, HIP_UNSUPPORTED), + "curandGetScrambleConstants32": ("hiprngGetScrambleConstants32", CONV_MATH_FUNC, API_RAND, HIP_UNSUPPORTED), + "curandGetScrambleConstants64": ("hiprngGetScrambleConstants64", CONV_MATH_FUNC, API_RAND, HIP_UNSUPPORTED), + "curandGetVersion": ("hiprngGetVersion", CONV_MATH_FUNC, API_RAND), + "curandSetGeneratorOffset": ("hiprngSetGeneratorOffset", CONV_MATH_FUNC, API_RAND), + "curandSetGeneratorOrdering": ("hiprngSetGeneratorOrdering", CONV_MATH_FUNC, API_RAND, HIP_UNSUPPORTED), + "curandSetPseudoRandomGeneratorSeed": ("hiprngSetPseudoRandomGeneratorSeed", CONV_MATH_FUNC, API_RAND), + "curandSetQuasiRandomGeneratorDimensions": ("hiprngSetQuasiRandomGeneratorDimensions", CONV_MATH_FUNC, API_RAND), + "curandSetStream": ("hiprngSetStream", CONV_MATH_FUNC, API_RAND), + "curand": ("hiprng", CONV_DEVICE_FUNC, API_RAND), + "curand_init": ("hiprng_init", CONV_DEVICE_FUNC, API_RAND), + "curand_log_normal": ("hiprng_log_normal", CONV_DEVICE_FUNC, API_RAND), + "curand_log_normal_double": ("hiprng_log_normal_double", CONV_DEVICE_FUNC, API_RAND), + "curand_log_normal2": ("hiprng_log_normal2", CONV_DEVICE_FUNC, API_RAND), + "curand_log_normal2_double": ("hiprng_log_normal2_double", CONV_DEVICE_FUNC, API_RAND), + "curand_log_normal4": ("hiprng_log_normal4", CONV_DEVICE_FUNC, API_RAND), + "curand_log_normal4_double": ("hiprng_log_normal4_double", CONV_DEVICE_FUNC, API_RAND), + "curand_mtgp32_single": ("hiprng_mtgp32_single", CONV_DEVICE_FUNC, API_RAND, HIP_UNSUPPORTED), + "curand_mtgp32_single_specific": ("hiprng_mtgp32_single_specific", CONV_DEVICE_FUNC, API_RAND, HIP_UNSUPPORTED), + "curand_mtgp32_specific": ("hiprng_mtgp32_specific", CONV_DEVICE_FUNC, API_RAND, HIP_UNSUPPORTED), + "curand_normal": ("hiprng_normal", CONV_DEVICE_FUNC, API_RAND), + "curandMakeMTGP32Constants": ("hiprngMakeMTGP32Constants", CONV_DEVICE_FUNC, API_RAND), + "curandMakeMTGP32KernelState": ("hiprngMakeMTGP32KernelState", CONV_DEVICE_FUNC, API_RAND), + "curand_normal_double": ("hiprng_normal_double", CONV_DEVICE_FUNC, API_RAND), + "curand_normal2": ("hiprng_normal2", CONV_DEVICE_FUNC, API_RAND), + "curand_normal2_double": ("hiprng_normal2_double", CONV_DEVICE_FUNC, API_RAND), + "curand_normal4": ("hiprng_normal4", CONV_DEVICE_FUNC, API_RAND), + "curand_normal4_double": ("hiprng_normal4_double", CONV_DEVICE_FUNC, API_RAND), + "curand_uniform": ("hiprng_uniform", CONV_DEVICE_FUNC, API_RAND), + "curand_uniform_double": ("hiprng_uniform_double", CONV_DEVICE_FUNC, API_RAND), + "curand_uniform2_double": ("hiprng_uniform2_double", CONV_DEVICE_FUNC, API_RAND), + "curand_uniform4": ("hiprng_uniform4", CONV_DEVICE_FUNC, API_RAND), + "curand_uniform4_double": ("hiprng_uniform4_double", CONV_DEVICE_FUNC, API_RAND), + "curand_discrete": ("hiprng_discrete", CONV_DEVICE_FUNC, API_RAND), + "curand_discrete4": ("hiprng_discrete4", CONV_DEVICE_FUNC, API_RAND), + "curand_poisson": ("hiprng_poisson", CONV_DEVICE_FUNC, API_RAND), + "curand_poisson4": ("hiprng_poisson4", CONV_DEVICE_FUNC, API_RAND), + "curand_Philox4x32_10": ("hiprng_Philox4x32_10", CONV_DEVICE_FUNC, API_RAND, HIP_UNSUPPORTED) +} + +CUDA_SPARSE_MAP = { + "cusparseStatus_t": ("hipsparseStatus_t", CONV_MATH_FUNC, API_SPARSE), + "cusparseHandle_t": ("hipsparseHandle_t", CONV_MATH_FUNC, API_SPARSE), + "cusparseOperation_t": ("hcsparseOperation_t", CONV_TYPE, API_SPARSE), + "cusparseCreate": ("hipsparseCreate", CONV_MATH_FUNC, API_SPARSE), + "cusparseDestroy": ("hipsparseDestroy", CONV_MATH_FUNC, API_SPARSE), + "CUSPARSE_STATUS_SUCCESS": ("HIPSPARSE_STATUS_SUCCESS", CONV_NUMERIC_LITERAL, API_SPARSE), + "CUSPARSE_STATUS_NOT_INITIALIZED": ("HIPSPARSE_STATUS_NOT_INITIALIZED", CONV_NUMERIC_LITERAL, API_SPARSE), + "CUSPARSE_STATUS_ALLOC_FAILED": ("HIPSPARSE_STATUS_ALLOC_FAILED", CONV_NUMERIC_LITERAL, API_SPARSE), + "CUSPARSE_STATUS_INVALID_VALUE": ("HIPSPARSE_STATUS_INVALID_VALUE", CONV_NUMERIC_LITERAL, API_SPARSE), + "CUSPARSE_STATUS_MAPPING_ERROR": ("HIPSPARSE_STATUS_MAPPING_ERROR", CONV_NUMERIC_LITERAL, API_SPARSE), + "CUSPARSE_STATUS_EXECUTION_FAILED": ("HIPSPARSE_STATUS_EXECUTION_FAILED", CONV_NUMERIC_LITERAL, API_SPARSE), + "CUSPARSE_STATUS_INTERNAL_ERROR": ("HIPSPARSE_STATUS_INTERNAL_ERROR", CONV_NUMERIC_LITERAL, API_SPARSE), + "CUSPARSE_STATUS_MATRIX_TYPE_NOT_SUPPORTED": ("HIPSPARSE_STATUS_MATRIX_TYPE_NOT_SUPPORTED", CONV_NUMERIC_LITERAL, API_SPARSE), + "CUSPARSE_STATUS_ARCH_MISMATCH": ("HIPSPARSE_STATUS_ARCH_MISMATCH", CONV_NUMERIC_LITERAL, API_SPARSE), +} + +PYTORCH_SPECIFIC_MAPPINGS = { + "cudaHostAllocator": ("hipHostAllocator", API_PYTORCH), + "cudaUVAAllocator": ("hipUVAAllocator", API_PYTORCH), + "cudaDeviceAllocator": ("hipDeviceAllocator", API_PYTORCH), + "define MAX_NUM_BLOCKS 200": ("define MAX_NUM_BLOCKS 64", API_PYTORCH), +} + +CUDA_TO_HIP_MAPPINGS = [CUDA_TYPE_NAME_MAP, CUDA_IDENTIFIER_MAP, + CUDA_INCLUDE_MAP, CUDA_SPARSE_MAP, PYTORCH_SPECIFIC_MAPPINGS] diff --git a/tools/amd_build/pyHIPIFY/hipify-python.py b/tools/amd_build/pyHIPIFY/hipify-python.py new file mode 100755 index 0000000000000..bd38e26949492 --- /dev/null +++ b/tools/amd_build/pyHIPIFY/hipify-python.py @@ -0,0 +1,975 @@ +#!/usr/bin/python +""" The Python Hipify script. +## +# Copyright (c) 2015-2016 Advanced Micro Devices, Inc. All rights reserved. +# 2017-2018 Advanced Micro Devices, Inc. and +# Facebook Inc. All rights reserved. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +""" + +import argparse +import constants +import re +import shutil +import sys +import os +import yaml + +from functools import reduce +from enum import Enum +from cuda_to_hip_mappings import CUDA_TO_HIP_MAPPINGS + + +def openf(filename, mode): + if sys.version_info[0] == 3: + return open(filename, mode, errors='ignore') + else: + return open(filename, mode) + +# Color coding for printing + + +class bcolors: + HEADER = '\033[95m' + OKBLUE = '\033[94m' + OKGREEN = '\033[92m' + WARNING = '\033[93m' + FAIL = '\033[91m' + ENDC = '\033[0m' + BOLD = '\033[1m' + UNDERLINE = '\033[4m' + + +class disablefuncmode(Enum): + """ How to disable functions + 0 - Remove the function entirely (includes the signature). + 1 - Stub the function and return an empty object based off the type. + 2 - Add !defined(__HIP_PLATFORM_HCC__) preprocessors around the function. + This macro is defined by HIP if the compiler used is hcc. + 3 - Add !defined(__HIP_DEVICE_COMPILE__) preprocessors around the function. + This macro is defined by HIP if either hcc or nvcc are used in the device path. + 4 - Stub the function and throw an exception at runtime. + 5 - Stub the function and throw an assert(0). + 6 - Stub the function and keep an empty body. + """ + REMOVE = 0 + STUB = 1 + HCC_MACRO = 2 + DEVICE_MACRO = 3 + EXCEPTION = 4 + ASSERT = 5 + EMPTYBODY = 6 + + +def update_progress_bar(total, progress): + """ + Displays and updates a console progress bar. + """ + barLength, status = 20, "" + progress = float(progress) / float(total) + if progress >= 1.: + progress, status = 1, "\r\n" + + # Number of blocks to display. Used to visualize progress. + block = int(round(barLength * progress)) + text = "\r[{}] {:.0f}% {}".format( + "#" * block + "-" * (barLength - block), round(progress * 100, 0), + status) + + # Send the progress to stdout. + sys.stderr.write(text) + + # Send the buffered text to stdout! + sys.stderr.flush() + + +def filename_ends_with_extension(filename, extensions): + """Helper method to see if filename ends with certain extension""" + return reduce(lambda result, ext: filename.endswith("." + ext) or result, extensions, False) + + +def inside_included_directories(dirpath, rootpath, include_dirs): + """Helper method to see if filename within included directories""" + return reduce(lambda result, included_directory: re.match(r'{0}\b'.format(os.path.join(rootpath, included_directory)), dirpath) or result, include_dirs, None) + + +def walk_over_directory(rootpath, extensions, show_detailed=False, include_dirs=None): + """ + Recursively walk over directory and call preprocessor on selected files. + + Arguments) + extensions - A plist of file extensions ['cu', 'cuh', ..] + + include_dirs - Directories under the rootpath that should be included in the walk. + + show_detailed - Show a detailed summary of the transpilation process. + """ + + # Default argument for excluded directories. + if include_dirs is None: + include_dirs = [] + + # Compute the total number of files to be traversed. + total_files = 0 + for (dirpath, _dirnames, filenames) in os.walk(rootpath): + if inside_included_directories(dirpath, rootpath, include_dirs): + for filename in filenames: + total_files += filename_ends_with_extension(filename, extensions) + + current_file = 0 + + # Preprocessing statistics. + stats = {"unsupported_calls": [], "kernel_launches": []} + + # Begin traversing the files. + for (dirpath, _dirnames, filenames) in os.walk(rootpath, topdown=True): + # Check if file ends with a valid extensions + if not inside_included_directories(dirpath, rootpath, include_dirs): + continue + + for filename in filenames: + if filename_ends_with_extension(filename, extensions): + # Construct the file's full path + filepath = os.sep.join([dirpath, filename]) + + # Execute the preprocessor on the specified file. + preprocessor(filepath, stats) + + # Update the progress + print(os.path.join(dirpath, filename)) + update_progress_bar(total_files, current_file) + + current_file += 1 + + print(bcolors.OKGREEN + "Successfully preprocessed all matching files." + bcolors.ENDC) + + # Show detailed summary + if show_detailed: + compute_stats(stats) + + +def compute_stats(stats): + unsupported_calls = set(cuda_call for (cuda_call, _filepath) in stats["unsupported_calls"]) + + # Print the number of unsupported calls + print("Total number of unsupported CUDA function calls: {0:d}".format(len(unsupported_calls))) + + # Print the list of unsupported calls + print(", ".join(unsupported_calls)) + + # Print the number of kernel launches + print("\nTotal number of replaced kernel launches: {0:d}".format(len(stats["kernel_launches"]))) + + +def processKernelLaunches(string, stats): + """ Replace the CUDA style Kernel launches with the HIP style kernel launches.""" + # Concat the namespace with the kernel names. (Find cleaner way of doing this later). + string = re.sub(r'([ ]+)(detail?)::[ ]+\\\n[ ]+', lambda inp: "{0}{1}::".format(inp.group(1), inp.group(2)), string) + + def grab_method_and_template(in_kernel): + # The positions for relevant kernel components. + pos = { + "kernel_launch": {"start": in_kernel["start"], "end": in_kernel["end"]}, + "kernel_name": {"start": -1, "end": -1}, + "template": {"start": -1, "end": -1} + } + + # Count for balancing template + count = {"<>": 0} + + # Status for whether we are parsing a certain item. + START = 0 + AT_TEMPLATE = 1 + AFTER_TEMPLATE = 2 + AT_KERNEL_NAME = 3 + + status = START + + # Parse the string character by character + for i in range(pos["kernel_launch"]["start"] - 1, -1, -1): + char = string[i] + + # Handle Templating Arguments + if status == START or status == AT_TEMPLATE: + if char == ">": + if status == START: + status = AT_TEMPLATE + pos["template"]["end"] = i + count["<>"] += 1 + + if char == "<": + count["<>"] -= 1 + if count["<>"] == 0 and (status == AT_TEMPLATE): + pos["template"]["start"] = i + status = AFTER_TEMPLATE + + # Handle Kernel Name + if status != AT_TEMPLATE: + if string[i] == "(" or string[i] == ")" or string[i] == "_" or string[i].isalnum() or string[i] == ":": + if status != AT_KERNEL_NAME: + status = AT_KERNEL_NAME + pos["kernel_name"]["end"] = i + + # Case: Kernel name starts the string. + if i == 0: + pos["kernel_name"]["start"] = 0 + + # Finished + return [(pos["kernel_name"]), (pos["template"]), (pos["kernel_launch"])] + + else: + # Potential ending point if we're already traversing a kernel's name. + if status == AT_KERNEL_NAME: + pos["kernel_name"]["start"] = i + + # Finished + return [(pos["kernel_name"]), (pos["template"]), (pos["kernel_launch"])] + + def find_kernel_bounds(string): + """Finds the starting and ending points for all kernel launches in the string.""" + kernel_end = 0 + kernel_positions = [] + + # Continue until we cannot find any more kernels anymore. + while string.find("<<<", kernel_end) != -1: + # Get kernel starting position (starting from the previous ending point) + kernel_start = string.find("<<<", kernel_end) + + # Get kernel ending position (adjust end point past the >>>) + kernel_end = string.find(">>>", kernel_start) + 3 + if kernel_end <= 0: + raise InputError("no kernel end found") + + # Add to list of traversed kernels + kernel_positions.append({"start": kernel_start, "end": kernel_end, + "group": string[kernel_start: kernel_end]}) + + return kernel_positions + + # Grab positional ranges of all kernel launchces + get_kernel_positions = [k for k in find_kernel_bounds(string)] + output_string = string + + # Replace each CUDA kernel with a HIP kernel. + for kernel in get_kernel_positions: + # Get kernel components + params = grab_method_and_template(kernel) + + # Find parenthesis after kernel launch + parenthesis = string.find("(", kernel["end"]) + + # Extract cuda kernel + cuda_kernel = string[params[0]["start"]:parenthesis + 1] + + # Keep number of kernel launch params consistent (grid dims, group dims, stream, dynamic shared size) + num_klp = len(extract_arguments(0, kernel["group"].replace("<<<", "(").replace(">>>", ")"))) + + # Transform cuda kernel to hip kernel + hip_kernel = "hipLaunchKernelGGL(" + cuda_kernel[0:-1].replace(">>>", + ", 0" * (4 - num_klp) + ">>>").replace("<<<", ", ").replace(">>>", ", ") + + # Replace cuda kernel with hip kernel + output_string = output_string.replace(cuda_kernel, hip_kernel) + + # Update the statistics + stats["kernel_launches"].append(hip_kernel) + + return output_string + + +def find_parenthesis_end(input_string, start): + inside_parenthesis = False + parens = 0 + pos = start + p_start, p_end = -1, -1 + + while pos < len(input_string): + if input_string[pos] == "(": + if inside_parenthesis is False: + inside_parenthesis = True + parens = 1 + p_start = pos + else: + parens += 1 + elif input_string[pos] == ")" and inside_parenthesis: + parens -= 1 + + if parens == 0: + p_end = pos + return p_start, p_end + + pos += 1 + return None, None + + +def disable_asserts(input_string): + """ Disables regular assert statements + e.g. "assert(....)" -> "/*assert(....)*/" + """ + output_string = input_string + asserts = list(re.finditer(r"\bassert[ ]*\(", input_string)) + for assert_item in asserts: + p_start, p_end = find_parenthesis_end(input_string, assert_item.end() - 1) + start = assert_item.start() + output_string = output_string.replace(input_string[start:p_end + 1], "") + return output_string + + +def disable_function(input_string, function, replace_style): + """ Finds and disables a function in a particular file. + + If type(function) == List + function - The signature of the function to disable. + e.g. ["bool", "overlappingIndices", "(const Tensor& t)"] + disables function -> "bool overlappingIndices(const Tensor& t)" + + If type(function) == String + function - Disables the function by name only. + e.g. "overlappingIndices" + + replace_style - The style to use when stubbing functions. + """ +# void (*)(hcrngStateMtgp32 *, int, float *, double, double) + info = { + "function_start": -1, + "function_end": -1, + "bracket_count": 0 + } + + STARTED = 0 + INSIDE_FUNCTION = 1 + BRACKET_COMPLETE = 2 + + STATE = STARTED + + if type(function) == list: + # Extract components from function signature. + func_info = { + "return_type": function[0].strip(), + "function_name": function[1].strip(), + "function_args": function[2].strip() + } + + # Create function string to search for + function_string = "{0}{1}{2}".format( + func_info["return_type"], + func_info["function_name"], + func_info["function_args"] + ) + + # Find the starting position for the function + info["function_start"] = input_string.find(function_string) + else: + # Automatically detect signature. + the_match = re.search(r"(((.*) (\*)?)({0})(\([^{{)]*\)))\s*{{".format(function.replace("(", "\(").replace(")", "\)")), input_string) + if the_match is None: + return input_string + + func_info = { + "return_type": the_match.group(2).strip(), + "function_name": the_match.group(5).strip(), + "function_args": the_match.group(6).strip(), + } + + # Find the starting position for the function + info["function_start"] = the_match.start() + function_string = the_match.group(1) + + # The function can't be found anymore. + if info["function_start"] == -1: + return input_string + + # Find function block start. + pos = info["function_start"] + len(function_string) - 1 + while pos < len(input_string) and STATE != BRACKET_COMPLETE: + if input_string[pos] == "{": + if STATE != INSIDE_FUNCTION: + STATE = INSIDE_FUNCTION + info["bracket_count"] = 1 + else: + info["bracket_count"] += 1 + elif input_string[pos] == "}": + info["bracket_count"] -= 1 + + if info["bracket_count"] == 0 and STATE == INSIDE_FUNCTION: + STATE = BRACKET_COMPLETE + info["function_end"] = pos + + pos += 1 + + # Never found the function end. Corrupted file! + if STATE != BRACKET_COMPLETE: + return input_string + + # Preprocess the source by removing the function. + function_body = input_string[info["function_start"]:info["function_end"] + 1] + + # Remove the entire function body + if replace_style == disablefuncmode.REMOVE: + output_string = input_string.replace(function_body, "") + + # Stub the function based off its return type. + elif replace_style == disablefuncmode.STUB: + # void return type + if func_info["return_type"] == "void" or func_info["return_type"] == "static void": + stub = "{0}{{\n}}".format(function_string) + # pointer return type + elif "*" in func_info["return_type"]: + stub = "{0}{{\nreturn {1};\n}}".format(function_string, "NULL") # nullptr + else: + stub = "{0}{{\n{1} stub_var;\nreturn stub_var;\n}}".format(function_string, func_info["return_type"]) + + output_string = input_string.replace(function_body, stub) + + # Add HIP Preprocessors. + elif replace_style == disablefuncmode.HCC_MACRO: + output_string = input_string.replace( + function_body, + "#if !defined(__HIP_PLATFORM_HCC__)\n{0}\n#endif".format(function_body)) + + # Add HIP Preprocessors. + elif replace_style == disablefuncmode.DEVICE_MACRO: + output_string = input_string.replace( + function_body, + "#if !defined(__HIP_DEVICE_COMPILE__)\n{0}\n#endif".format(function_body)) + + # Throw an exception at runtime. + elif replace_style == disablefuncmode.EXCEPTION: + stub = "{0}{{\n{1};\n}}".format( + function_string, + 'throw std::runtime_error("The function {0} is not implemented.")'.format( + function_string.replace("\n", " "))) + output_string = input_string.replace(function_body, stub) + + elif replace_style == disablefuncmode.ASSERT: + stub = "{0}{{\n{1};\n}}".format( + function_string, + 'assert(0)') + output_string = input_string.replace(function_body, stub) + + elif replace_style == disablefuncmode.EMPTY: + stub = "{0}{{\n;\n}}".format(function_string) + output_string = input_string.replace(function_body, stub) + return output_string + + +def preprocessor(filepath, stats): + """ Executes the CUDA -> HIP conversion on the specified file. """ + with openf(filepath, "r+") as fileobj: + output_source = fileobj.read() + + # Perform type, method, constant replacements + for mapping in CUDA_TO_HIP_MAPPINGS: + for cuda_type, value in mapping.items(): + # Extract relevant information + hip_type = value[0] + meta_data = value[1:] + + if output_source.find(cuda_type) > -1: + # Check if supported + if constants.HIP_UNSUPPORTED in meta_data: + stats["unsupported_calls"].append((cuda_type, filepath)) + + if cuda_type in output_source: + output_source = re.sub(r'\b({0})\b'.format(cuda_type), lambda x: hip_type, output_source) + + # Perform Kernel Launch Replacements + output_source = processKernelLaunches(output_source, stats) + + # Disable asserts + if not filepath.endswith("THCGeneral.h.in"): + output_source = disable_asserts(output_source) + + # Overwrite file contents + fileobj.seek(0) + fileobj.write(output_source) + fileobj.truncate() + fileobj.flush() + + # Flush to disk + os.fsync(fileobj) + + +def file_specific_replacement(filepath, search_string, replace_string, strict=False): + with openf(filepath, "r+") as f: + contents = f.read() + if strict: + contents = re.sub(r'\b({0})\b'.format(search_string), lambda x: replace_string, contents) + else: + contents = contents.replace(search_string, replace_string) + f.seek(0) + f.write(contents) + f.truncate() + + +def file_add_header(filepath, header): + with openf(filepath, "r+") as f: + contents = f.read() + if header[0] != "<" and header[-1] != ">": + header = '"{0}"'.format(header) + contents = ('#include {0} \n'.format(header)) + contents + f.seek(0) + f.write(contents) + f.truncate() + + +def fix_static_global_kernels(in_txt): + """Static global kernels in HIP results in a compilation error.""" + in_txt = in_txt.replace(" __global__ static", "__global__") + return in_txt + + +def get_kernel_template_params(the_file, KernelDictionary): + """Scan for __global__ kernel definitions then extract its argument types, and static cast as necessary""" + # Read the kernel file. + with openf(the_file, "r") as f: + # Extract all kernels with their templates inside of the file + string = f.read() + + get_kernel_definitions = [k for k in re.finditer( + r"(template[ ]*<(.*)>\n.*\n?)?__global__ void[\n| ](\w+(\(.*\))?)\(", string)] + + # Create new launch syntax + for kernel in get_kernel_definitions: + template_arguments = kernel.group(2).split(",") if kernel.group(2) else "" + template_arguments = [x.replace("template", "").replace("typename", "").strip() for x in template_arguments] + kernel_name = kernel.group(3) + + # Kernel starting / ending positions + arguments_start = kernel.end() + argument_start_pos = arguments_start + current_position = arguments_start + 1 + + # Search for final parenthesis + arguments = [] + closures = {"(": 1, "<": 0} + while current_position < len(string): + if string[current_position] == "(": + closures["("] += 1 + elif string[current_position] == ")": + closures["("] -= 1 + elif string[current_position] == "<": + closures["<"] += 1 + elif string[current_position] == ">": + closures["<"] -= 1 + + # Finished all arguments + if closures["("] == 0 and closures["<"] == 0: + # Add final argument + arguments.append({"start": argument_start_pos, "end": current_position}) + break + + # Finished current argument + if closures["("] == 1 and closures["<"] == 0 and string[current_position] == ",": + arguments.append({"start": argument_start_pos, "end": current_position}) + argument_start_pos = current_position + 1 + + current_position += 1 + + # Grab range of arguments + arguments_string = [string[arg["start"]: arg["end"]] for arg in arguments] + + argument_types = [None] * len(arguments_string) + for arg_idx, arg in enumerate(arguments_string): + for i in range(len(arg) - 1, -1, -1): + if arg[i] == "*" or arg[i] == " ": + argument_types[arg_idx] = re.sub(' +', ' ', arg[0:i + 1].replace("\n", "").strip()) + break + if len(template_arguments) == 1 and template_arguments[0].strip() in ["Dtype", "T"]: + # Updates kernel + kernel_with_template = "{0}".format(kernel_name) + else: + kernel_with_template = kernel_name + formatted_args = {} + for idx, arg_type in enumerate(argument_types): + formatted_args[idx] = arg_type + + KernelDictionary[kernel_name] = {"kernel_with_template": kernel_with_template, "arg_types": formatted_args} + + # Extract generated kernels + # curandStateMtgp32 *state, int size, T *result, ARG1 + for kernel in re.finditer(r"GENERATE_KERNEL([1-9])\((.*)\)", string): + kernel_gen_type = int(kernel.group(1)) + kernel_name = kernel.group(2).split(",")[0] + kernel_params = kernel.group(2).split(",")[1:] + + if kernel_gen_type == 1: + kernel_args = {1: "int", 2: "{0} *".format(kernel_params[0]), 3: kernel_params[1]} + + if kernel_gen_type == 2: + kernel_args = {1: "int", 2: "{0} *".format(kernel_params[0]), 3: kernel_params[1], 4: kernel_params[2]} + + # Argument at position 1 should be int + KernelDictionary[kernel_name] = {"kernel_with_template": kernel_name, "arg_types": kernel_args} + + +def disable_unsupported_function_call(function, input_string, replacement): + """Disables calls to an unsupported HIP function""" + # Prepare output string + output_string = input_string + + # Find all calls to the function + calls = re.finditer(r"\b{0}\b".format(function), input_string) + + # Do replacements + for call in calls: + start = call.start() + end = call.end() + + pos = end + started_arguments = False + bracket_count = 0 + while pos < len(input_string): + if input_string[pos] == "(": + if started_arguments is False: + started_arguments = True + bracket_count = 1 + else: + bracket_count += 1 + elif input_string[pos] == ")" and started_arguments: + bracket_count -= 1 + + if bracket_count == 0 and started_arguments: + # Finished! + break + pos += 1 + + function_call = input_string[start:pos + 1] + output_string = output_string.replace(function_call, replacement) + + return output_string + + +def disable_module(input_file): + """Disable a module entirely except for header includes.""" + with openf(input_file, "r+") as f: + txt = f.read() + last = list(re.finditer(r"#include .*\n", txt))[-1] + end = last.end() + + disabled = "{0}#if !defined(__HIP_PLATFORM_HCC__)\n{1}\n#endif".format(txt[0:end], txt[end:]) + + f.seek(0) + f.write(disabled) + f.truncate() + +def extract_arguments(start, string): + """ Return the list of arguments in the upcoming function parameter closure + This function needs a string that contains function arguments fully encapsulated within opening and closing parantheses. + Eg: + string (input): '(blocks, threads, 0, THCState_getCurrentStream(state))' + arguments (output): '[{'start': 1, 'end': 7}, {'start': 8, 'end': 16}, {'start': 17, 'end': 19}, {'start': 20, 'end': 53}]' + """ + + arguments = [] + closures = { + "<": 0, + "(": 0 + } + current_position = start + argument_start_pos = current_position + 1 + + # Search for final parenthesis + while current_position < len(string): + if string[current_position] == "(": + closures["("] += 1 + elif string[current_position] == ")": + closures["("] -= 1 + elif string[current_position] == "<": + closures["<"] += 1 + elif string[current_position] == ">" and string[current_position - 1] != "-": + closures["<"] -= 1 + + # Finished all arguments + if closures["("] == 0 and closures["<"] == 0: + # Add final argument + arguments.append({"start": argument_start_pos, "end": current_position}) + break + + # Finished current argument + if closures["("] == 1 and closures["<"] == 0 and string[current_position] == ",": + arguments.append({"start": argument_start_pos, "end": current_position}) + argument_start_pos = current_position + 1 + + current_position += 1 + + return arguments + +# Add static_cast to ensure that the type of kernel arguments matches that in the corresponding kernel definition + +def add_static_casts(directory, extensions, KernelTemplateParams): + """Added necessary static casts to kernel launches to match kernel argument type to corresponding kernel definition + Eg. + old_kernel_launch: ' createBatchGemmBuffer, grid, block, 0, THCState_getCurrentStream(state), + (const real**)d_result, THCTensor_(data)(state, ra__), + ra__->stride[0], num_batches' + new_kernel_launch: ' createBatchGemmBuffer, grid, block, 0, THCState_getCurrentStream(state), + (const real**)d_result, THCTensor_(data)(state, ra__), + static_cast(ra__->stride[0]), static_cast(num_batches)' + """ + # Add static_casts<> to all kernel launches. + for (dirpath, _dirnames, filenames) in os.walk(directory): + for filename in filenames: + if filename_ends_with_extension(filename, extensions): + filepath = os.sep.join([dirpath, filename]) + with openf(filepath, "r+") as fileobj: + input_source = fileobj.read() + new_output_source = input_source + for kernel in re.finditer("hipLaunchKernelGGL\(", input_source): + arguments = extract_arguments(kernel.end() - 1, input_source) + + # Check if we have templating + static_cast information + argument_strings = [input_source[arg["start"]:arg["end"]] for arg in arguments] + original_kernel_name_with_template = argument_strings[0].strip() + kernel_name = original_kernel_name_with_template.split("<")[0].strip() + ignore = ["upscale"] + if kernel_name in KernelTemplateParams and kernel_name not in ignore: + # Add template to the kernel + # Add static_casts to relevant arguments + kernel_name_with_template = KernelTemplateParams[kernel_name]["kernel_with_template"] + argument_types = KernelTemplateParams[kernel_name]["arg_types"] + + old_kernel_launch = input_source[arguments[0]["start"]:arguments[-1]["end"]] + new_kernel_launch = old_kernel_launch + + kernel_params = argument_strings[5:] + for arg_idx, arg in enumerate(kernel_params): + if arg_idx in argument_types: + the_type = argument_types[arg_idx] + the_arg = arg.replace("\n", "").replace("\\", "").strip() + if the_type in ["int", "const int", "int64_t", "THCIndex_t *", "const int *", "ptrdiff_t", "long", "const int64_t*", "int64_t *", "double"]: + static_argument = "static_cast<{0}>({1})".format(the_type, the_arg) + + def replace_arg(match): + return match.group(1) + static_argument + match.group(3) + # Update to static_cast, account for cases where argument is at start/end of string + new_kernel_launch = re.sub(r'(^|\W)({0})(\W|$)'.format(re.escape(the_arg)), replace_arg, new_kernel_launch) + + # Add template type + if "THCUNN" in filepath.split("/") and "generic" not in filepath.split("/"): + kernel_name_with_template = kernel_name_with_template.replace("", "") + new_kernel_launch = re.sub(r'\b{0}\b'.format(original_kernel_name_with_template), + lambda x: kernel_name_with_template, new_kernel_launch) + + # Replace Launch + new_output_source = new_output_source.replace(old_kernel_launch, new_kernel_launch) + + # Overwrite file contents + fileobj.seek(0) + fileobj.write(new_output_source) + fileobj.truncate() + fileobj.flush() + + # Flush to disk + os.fsync(fileobj) + + +def main(): + """Example invocation + + python hipify.py --project-directory /home/myproject/ --extensions cu cuh h cpp --output-directory /home/gains/ + """ + + parser = argparse.ArgumentParser( + description="The Python Hipify Script.") + + parser.add_argument( + '--project-directory', + type=str, + default=os.getcwd(), + help="The root of the project.", + required=False) + + parser.add_argument( + '--show-detailed', + type=bool, + default=False, + help="Show detailed summary of the hipification process.", + required=False) + + parser.add_argument( + '--extensions', + nargs='+', + default=["cu", "cuh", "c", "cpp", "h", "in", "hpp"], + help="The extensions for files to run the Hipify script over.", + required=False) + + parser.add_argument( + '--output-directory', + type=str, + default="", + help="The directory to store the hipified project.", + required=False) + + parser.add_argument( + '--include-dirs', + nargs='+', + default=[], + help="The directories under the root that should be included.", + required=False) + + parser.add_argument( + '--yaml-settings', + type=str, + default="", + help="The yaml file storing information for disabled functions and modules.", + required=False) + + parser.add_argument( + '--add-static-casts', + type=bool, + default=False, + help="Whether to automatically add static_casts to kernel arguments.", + required=False) + + args = parser.parse_args() + + # Verify the project directory exists. + if not os.path.exists(args.project_directory): + print("The project folder specified does not exist.") + sys.exit(1) + + # If no output directory, provide a default one. + if args.output_directory is "": + args.project_directory.rstrip("/") + args.output_directory = args.project_directory + "_amd" + + # Make sure output directory does not exist. + if not os.path.exists(args.output_directory): + print("The output folder already exists.") + sys.exit(2) + + # Copy from project directory to output directory if not done already. + if not os.path.exists(args.output_directory): + shutil.copytree(args.project_directory, args.output_directory) + + # Extract all of the kernel parameter and template type information. + if args.add_static_casts: + KernelTemplateParams = {} + for (dirpath, _dirnames, filenames) in os.walk(args.output_directory): + for filename in filenames: + if filename_ends_with_extension(filename, args.extensions) and inside_included_directories(dirpath, args.output_directory, args.include_dirs): + the_file = os.sep.join([dirpath, filename]) + + # Store param information inside KernelTemplateParams + get_kernel_template_params(the_file, KernelTemplateParams) + + # Open YAML file with disable information. + if args.yaml_settings != "": + with openf(args.yaml_settings, "r") as f: + yaml_data = yaml.load(f) + + # Disable functions in certain files according to YAML description + for disable_info in yaml_data["disabled_functions"]: + filepath = os.path.join(args.output_directory, disable_info["path"]) + if "functions" in disable_info: + functions = disable_info["functions"] + else: + functions = disable_info.get("functions", []) + + if "non_hip_functions" in disable_info: + non_hip_functions = disable_info["non_hip_functions"] + else: + non_hip_functions = disable_info.get("non_hip_functions", []) + + if "non_device_functions" in disable_info: + not_on_device_functions = disable_info["non_device_functions"] + else: + not_on_device_functions = disable_info.get("non_device_functions", []) + + with openf(filepath, "r+") as f: + txt = f.read() + for func in functions: + # TODO - Find fix assertions in HIP for device code. + txt = disable_function(txt, func, disablefuncmode.ASSERT) + + for func in non_hip_functions: + # Disable this function on HIP stack + txt = disable_function(txt, func, disablefuncmode.HCC_MACRO) + + for func in not_on_device_functions: + # Disable this function when compiling on Device + txt = disable_function(txt, func, disablefuncmode.DEVICE_MACRO) + + f.seek(0) + f.write(txt) + f.truncate() + + # Disable modules + disable_modules = yaml_data["disabled_modules"] + for module in disable_modules: + disable_module(os.path.join(args.output_directory, module)) + + # Disable unsupported HIP functions + for disable in yaml_data["disable_unsupported_hip_calls"]: + filepath = os.path.join(args.output_directory, disable["path"]) + if "functions" in disable: + functions = disable["functions"] + else: + functions = disable.get("functions", []) + + if "constants" in disable: + constants = disable["constants"] + else: + constants = disable.get("constants", []) + + if "s_constants" in disable: + s_constants = disable["s_constants"] + else: + s_constants = disable.get("s_constants", []) + + if not os.path.exists(filepath): + print("\n" + bcolors.WARNING + "YAML Warning: File {0} does not exist.".format(filepath) + bcolors.ENDC) + continue + + with openf(filepath, "r+") as f: + txt = f.read() + + # Disable HIP Functions + for func in functions: + txt = disable_unsupported_function_call(func, txt, functions[func]) + + # Disable Constants w\ Boundary. + for const in constants: + txt = re.sub(r"\b{0}\b".format(const), constants[const], txt) + + # Disable Constants + for s_const in s_constants: + txt = txt.replace(s_const, s_constants[s_const]) + + # Save Changes + f.seek(0) + f.write(txt) + f.truncate() + + # Start Preprocessor + walk_over_directory( + args.output_directory, + extensions=args.extensions, + show_detailed=args.show_detailed, + include_dirs=args.include_dirs) + + if args.add_static_casts: + # Execute the Clang Tool to Automatically add static casts + add_static_casts(args.output_directory, args.extensions, KernelTemplateParams) + + +if __name__ == '__main__': + main() diff --git a/tox.ini b/tox.ini index ba01f28a2296b..8324d229e75d3 100644 --- a/tox.ini +++ b/tox.ini @@ -1,4 +1,4 @@ [flake8] max-line-length = 120 ignore = E305,E402,E721,E741,F401,F403,F405,F821,F841,F999 -exclude = docs/src,venv,third_party,caffe2,scripts,docs/caffe2 +exclude = docs/src,venv,third_party,caffe2,scripts,docs/caffe2,tools/amd_build/pyHIPIFY From 00aeb0b84b503c81c2d87585321090b958af6af2 Mon Sep 17 00:00:00 2001 From: Christian Puhrsch Date: Tue, 10 Jul 2018 18:03:00 -0700 Subject: [PATCH 10/36] Privatize values for vec256 (#9321) Summary: Helps prevent calling functions of the base case on float/double/int subclasses that aren't supported. Pull Request resolved: https://github.com/pytorch/pytorch/pull/9321 Reviewed By: colesbury Differential Revision: D8793627 Pulled By: cpuhrsch fbshipit-source-id: 7fde779ecd4b890dda406f3d1306b58bab40efe2 --- aten/src/ATen/cpu/vec256/vec256_base.h | 32 +++++++++++++-------- aten/src/ATen/cpu/vec256/vec256_double.h | 5 +++- aten/src/ATen/cpu/vec256/vec256_float.h | 5 +++- aten/src/ATen/cpu/vec256/vec256_int.h | 8 ++++++ aten/src/ATen/native/cpu/UnaryOpsKernel.cpp | 4 +-- 5 files changed, 38 insertions(+), 16 deletions(-) diff --git a/aten/src/ATen/cpu/vec256/vec256_base.h b/aten/src/ATen/cpu/vec256/vec256_base.h index abdf01d900a3e..7e8eb45eb2011 100644 --- a/aten/src/ATen/cpu/vec256/vec256_base.h +++ b/aten/src/ATen/cpu/vec256/vec256_base.h @@ -23,8 +23,10 @@ namespace { // emulates vectorized types template struct Vec256 { - static constexpr int size = 32 / sizeof(T); +private: T values[32 / sizeof(T)] = {0}; +public: + static constexpr int size = 32 / sizeof(T); Vec256() {} Vec256(T val) { for (int i = 0; i != size; i++) { @@ -37,9 +39,9 @@ struct Vec256 { Vec256 vec; for (int64_t i = 0; i < size; i++) { if (mask & 0x01) { - vec.values[i] = b[i]; + vec[i] = b[i]; } else { - vec.values[i] = a[i]; + vec[i] = a[i]; } mask = mask >> 1; } @@ -49,9 +51,9 @@ struct Vec256 { Vec256 vec; for (int64_t i = 0; i < size; i++) { if (i < count) { - vec.values[i] = b.values[i]; + vec[i] = b[i]; } else { - vec.values[i] = a.values[i]; + vec[i] = a[i]; } } return vec; @@ -69,17 +71,23 @@ struct Vec256 { void store(void* ptr, int count = size) const { std::memcpy(ptr, values, count * sizeof(T)); } + const T& operator[](int idx) const { + return values[idx]; + } + T& operator[](int idx) { + return values[idx]; + } Vec256 map(T (*f)(T)) const { Vec256 ret; for (int64_t i = 0; i != size; i++) { - ret.values[i] = f(values[i]); + ret[i] = f(values[i]); } return ret; } Vec256 abs() const { Vec256 ret; for (int64_t i = 0; i < size; i++) { - ret.values[i] = values[i] < 0 ? -values[i] : values[i]; + ret[i] = values[i] < 0 ? -values[i] : values[i]; } return ret; } @@ -160,7 +168,7 @@ struct Vec256 { template Vec256 operator+(const Vec256 &a, const Vec256 &b) { Vec256 c = Vec256(); for (int i = 0; i != Vec256::size; i++) { - c.values[i] = a.values[i] + b.values[i]; + c[i] = a[i] + b[i]; } return c; } @@ -168,7 +176,7 @@ template Vec256 operator+(const Vec256 &a, const Vec256 &b) { template Vec256 operator-(const Vec256 &a, const Vec256 &b) { Vec256 c = Vec256(); for (int i = 0; i != Vec256::size; i++) { - c.values[i] = a.values[i] - b.values[i]; + c[i] = a[i] - b[i]; } return c; } @@ -176,7 +184,7 @@ template Vec256 operator-(const Vec256 &a, const Vec256 &b) { template Vec256 operator*(const Vec256 &a, const Vec256 &b) { Vec256 c = Vec256(); for (int i = 0; i != Vec256::size; i++) { - c.values[i] = a.values[i] * b.values[i]; + c[i] = a[i] * b[i]; } return c; } @@ -184,7 +192,7 @@ template Vec256 operator*(const Vec256 &a, const Vec256 &b) { template Vec256 operator/(const Vec256 &a, const Vec256 &b) __ubsan_ignore_float_divide_by_zero__ { Vec256 c = Vec256(); for (int i = 0; i != Vec256::size; i++) { - c.values[i] = a.values[i] / b.values[i]; + c[i] = a[i] / b[i]; } return c; } @@ -192,7 +200,7 @@ template Vec256 operator/(const Vec256 &a, const Vec256 &b) _ template Vec256 max(const Vec256 &a, const Vec256 &b) { Vec256 c = Vec256(); for (int i = 0; i != Vec256::size; i++) { - c.values[i] = std::max(a.values[i], b.values[i]); + c[i] = std::max(a[i], b[i]); } return c; } diff --git a/aten/src/ATen/cpu/vec256/vec256_double.h b/aten/src/ATen/cpu/vec256/vec256_double.h index 60e2be37a4c1d..eae62c6a38d85 100644 --- a/aten/src/ATen/cpu/vec256/vec256_double.h +++ b/aten/src/ATen/cpu/vec256/vec256_double.h @@ -13,9 +13,10 @@ namespace { #if defined(__AVX__) && !defined(_MSC_VER) template <> class Vec256 { +private: + __m256d values; public: static constexpr int size = 4; - __m256d values; Vec256() {} Vec256(__m256d v) : values(v) {} Vec256(double val) { @@ -61,6 +62,8 @@ template <> class Vec256 { std::memcpy(ptr, tmp_values, count * sizeof(double)); } } + const double& operator[](int idx) const = delete; + double& operator[](int idx) = delete; Vec256 map(double (*f)(double)) const { __at_align32__ double tmp[4]; store(tmp); diff --git a/aten/src/ATen/cpu/vec256/vec256_float.h b/aten/src/ATen/cpu/vec256/vec256_float.h index 4851318203809..4b4c37fa17ec9 100644 --- a/aten/src/ATen/cpu/vec256/vec256_float.h +++ b/aten/src/ATen/cpu/vec256/vec256_float.h @@ -13,9 +13,10 @@ namespace { #if defined(__AVX__) && !defined(_MSC_VER) template <> class Vec256 { +private: + __m256 values; public: static constexpr int64_t size = 8; - __m256 values; Vec256() {} Vec256(__m256 v) : values(v) {} Vec256(float val) { @@ -66,6 +67,8 @@ template <> class Vec256 { std::memcpy(ptr, tmp_values, count * sizeof(float)); } } + const float& operator[](int idx) const = delete; + float& operator[](int idx) = delete; Vec256 map(float (*f)(float)) const { __at_align32__ float tmp[8]; store(tmp); diff --git a/aten/src/ATen/cpu/vec256/vec256_int.h b/aten/src/ATen/cpu/vec256/vec256_int.h index 4c2d88f1cf646..19a0a9328a0d5 100644 --- a/aten/src/ATen/cpu/vec256/vec256_int.h +++ b/aten/src/ATen/cpu/vec256/vec256_int.h @@ -10,7 +10,9 @@ namespace { #ifdef __AVX2__ struct Vec256i { +protected: __m256i values; +public: Vec256i() {} Vec256i(__m256i v) : values(v) {} operator __m256i() const { @@ -69,6 +71,8 @@ struct Vec256 : public Vec256i { std::memcpy(ptr, tmp_values, count * sizeof(int64_t)); } } + const int64_t& operator[](int idx) const = delete; + int64_t& operator[](int idx) = delete; Vec256 abs() const { auto zero = _mm256_set1_epi64x(0); auto is_larger = _mm256_cmpgt_epi64(zero, values); @@ -126,6 +130,8 @@ struct Vec256 : public Vec256i { std::memcpy(ptr, tmp_values, count * sizeof(int32_t)); } } + const int32_t& operator[](int idx) const = delete; + int32_t& operator[](int idx) = delete; Vec256 abs() const { return _mm256_abs_epi32(values); } @@ -230,6 +236,8 @@ struct Vec256 : public Vec256i { std::memcpy(ptr, tmp_values, count * sizeof(int16_t)); } } + const int16_t& operator[](int idx) const = delete; + int16_t& operator[](int idx) = delete; Vec256 abs() const { return _mm256_abs_epi16(values); } diff --git a/aten/src/ATen/native/cpu/UnaryOpsKernel.cpp b/aten/src/ATen/native/cpu/UnaryOpsKernel.cpp index e34d7ad161c9b..11e505f130006 100644 --- a/aten/src/ATen/native/cpu/UnaryOpsKernel.cpp +++ b/aten/src/ATen/native/cpu/UnaryOpsKernel.cpp @@ -30,8 +30,8 @@ int64_t _sigmoid(float* x, float* y, int64_t size) { ret = ret.neg(); ret2 = ret2.neg(); #if defined(__AVX2__) && !defined(_MSC_VER) - ret.values = exp256_ps(ret.values); - ret2.values = exp256_ps(ret2.values); + ret = exp256_ps(ret); + ret2 = exp256_ps(ret2); #else ret = ret.exp(); ret2 = ret2.exp(); From fb9f9c9ba2bf58791943e6c899340c1260bcd313 Mon Sep 17 00:00:00 2001 From: Huamin Li Date: Tue, 10 Jul 2018 18:49:18 -0700 Subject: [PATCH 11/36] Implement Sinh and Cosh (#9213) Summary: Pull Request resolved: https://github.com/pytorch/pytorch/pull/9213 Closes https://github.com/pytorch/pytorch/pull/9213 Added hyperbolic trig functions Sinh and Cosh Reviewed By: BIT-silence Differential Revision: D8752566 fbshipit-source-id: 5a58336a5153ec804404b9ac7b10b5662ede3cb7 --- caffe2/operators/cosh_op.cc | 115 ++++++++++++++++++ caffe2/operators/cosh_op.cu | 60 +++++++++ caffe2/operators/cosh_op.h | 34 ++++++ caffe2/operators/sinh_op.cc | 115 ++++++++++++++++++ caffe2/operators/sinh_op.cu | 60 +++++++++ caffe2/operators/sinh_op.h | 34 ++++++ .../operator_test/hyperbolic_ops_test.py | 8 ++ caffe2/utils/math.h | 4 + caffe2/utils/math_cpu.cc | 24 ++++ caffe2/utils/math_gpu.cu | 2 + 10 files changed, 456 insertions(+) create mode 100644 caffe2/operators/cosh_op.cc create mode 100644 caffe2/operators/cosh_op.cu create mode 100644 caffe2/operators/cosh_op.h create mode 100644 caffe2/operators/sinh_op.cc create mode 100644 caffe2/operators/sinh_op.cu create mode 100644 caffe2/operators/sinh_op.h diff --git a/caffe2/operators/cosh_op.cc b/caffe2/operators/cosh_op.cc new file mode 100644 index 0000000000000..7eb88ac573882 --- /dev/null +++ b/caffe2/operators/cosh_op.cc @@ -0,0 +1,115 @@ +#include "caffe2/operators/cosh_op.h" + +#include +#include + +namespace caffe2 { + +template <> +template +bool CoshGradientFunctor::Forward( + const std::vector& /* dY_dims */, + const std::vector& X_dims, + const T* dY, + const T* X, + T* dX, + CPUContext* /* context */) const { + const int size = std::accumulate( + X_dims.cbegin(), X_dims.cend(), 1, std::multiplies()); + ConstEigenVectorArrayMap dY_arr(dY, size); + ConstEigenVectorArrayMap X_arr(X, size); + EigenVectorMap(dX, size) = dY_arr * (X_arr.exp() - (-X_arr).exp()) / 2; + return true; +} + +REGISTER_CPU_OPERATOR( + Cosh, + UnaryElementwiseOp< + TensorTypes, + CPUContext, + CoshFunctor>); +REGISTER_CPU_OPERATOR( + CoshGradient, + BinaryElementwiseOp< + TensorTypes, + CPUContext, + CoshGradientFunctor>); + +OPERATOR_SCHEMA(Cosh) + .NumInputs(1) + .NumOutputs(1) + .IdenticalTypeAndShape() + .SetDoc(R"DOC( +Calculates the hyperbolic cosine of the given input tensor, element-wise. + +Github Links: + +- https://github.com/pytorch/pytorch/blob/master/caffe2/operators/cosh_op.cc + + +
+ + Example + +**Code** + +``` + +workspace.ResetWorkspace() + +op = core.CreateOperator( + "Cosh", + ["X"], + ["Y"] +) + +workspace.FeedBlob("X", np.random.rand(5).astype(np.float32)) +print("X:", workspace.FetchBlob("X")) +workspace.RunOperatorOnce(op) +print("Y:", workspace.FetchBlob("Y")) + +``` + +**Result** + +``` + +X: [0.66423494 0.32074615 0.81523746 0.90423071 0.39275789] +Y: [1.22883528 1.05188156 1.35112322 1.43744212 1.07812598] + +``` + +
+ +)DOC") + .Input(0, "input", "Input tensor") + .Output( + 0, + "output", + "The hyperbolic cosine values of the input tensor, computed " + "element-wise") + .InheritOnnxSchema("Cosh"); + +OPERATOR_SCHEMA(CoshGradient) + .NumInputs(2) + .NumOutputs(1) + .IdenticalTypeAndShape(); + +namespace { + +class GetCoshGradient : public GradientMakerBase { + using GradientMakerBase::GradientMakerBase; + std::vector GetGradientDefs() override { + return SingleGradientDef( + "CoshGradient", + "", + std::vector{GO(0), I(0)}, + std::vector{GI(0)}); + } +}; + +} // namespace + +REGISTER_GRADIENT(Cosh, GetCoshGradient); + +} // namespace caffe2 diff --git a/caffe2/operators/cosh_op.cu b/caffe2/operators/cosh_op.cu new file mode 100644 index 0000000000000..ac50284a7d723 --- /dev/null +++ b/caffe2/operators/cosh_op.cu @@ -0,0 +1,60 @@ +#include "caffe2/operators/cosh_op.h" + +#include +#include + +#include "caffe2/core/context_gpu.h" + +namespace caffe2 { + +namespace { + +__global__ void CoshGradientCUDAKernel( + const int N, + const float* dY, + const float* X, + float* dX) { + CUDA_1D_KERNEL_LOOP(i, N) { +#if __CUDA_ARCH__ >= 350 + dX[i] = __ldg(dY + i) * sinhf(__ldg(X + i)); +#else + dX[i] = dY[i] * sinhf(X[i]); +#endif + } +} + +} // namespace + +template <> +template +bool CoshGradientFunctor::Forward( + const std::vector& /* dY_dims */, + const std::vector& X_dims, + const T* dY, + const T* X, + T* dX, + CUDAContext* context) const { + const int size = std::accumulate( + X_dims.cbegin(), X_dims.cend(), 1, std::multiplies()); + CoshGradientCUDAKernel<<< + CAFFE_GET_BLOCKS(size), + CAFFE_CUDA_NUM_THREADS, + 0, + context->cuda_stream()>>>(size, dY, X, dX); + return true; +} + +REGISTER_CUDA_OPERATOR( + Cosh, + UnaryElementwiseOp< + TensorTypes, + CUDAContext, + CoshFunctor>); +REGISTER_CUDA_OPERATOR( + CoshGradient, + BinaryElementwiseOp< + TensorTypes, + CUDAContext, + CoshGradientFunctor>); + +} // namespace caffe2 diff --git a/caffe2/operators/cosh_op.h b/caffe2/operators/cosh_op.h new file mode 100644 index 0000000000000..201faa27aaf00 --- /dev/null +++ b/caffe2/operators/cosh_op.h @@ -0,0 +1,34 @@ +#ifndef CAFFE2_OPERATORS_COSH_OP_H_ +#define CAFFE2_OPERATORS_COSH_OP_H_ + +#include + +#include "caffe2/operators/elementwise_ops.h" +#include "caffe2/utils/math.h" + +namespace caffe2 { + +template +struct CoshFunctor { + template + bool operator()(const int N, const T* X, T* Y, Context* context) const { + math::Cosh(N, X, Y, context); + return true; + } +}; + +template +struct CoshGradientFunctor { + template + bool Forward( + const std::vector& dY_dims, + const std::vector& X_dims, + const T* dY, + const T* X, + T* dX, + Context* context) const; +}; + +} // namespace caffe2 + +#endif // CAFFE2_OPERATORS_COSH_OP_H_ diff --git a/caffe2/operators/sinh_op.cc b/caffe2/operators/sinh_op.cc new file mode 100644 index 0000000000000..dcf94aeddeba1 --- /dev/null +++ b/caffe2/operators/sinh_op.cc @@ -0,0 +1,115 @@ +#include "caffe2/operators/sinh_op.h" + +#include +#include + +namespace caffe2 { + +template <> +template +bool SinhGradientFunctor::Forward( + const std::vector& /* dY_dims */, + const std::vector& X_dims, + const T* dY, + const T* X, + T* dX, + CPUContext* /* context */) const { + const int size = std::accumulate( + X_dims.cbegin(), X_dims.cend(), 1, std::multiplies()); + ConstEigenVectorArrayMap dY_arr(dY, size); + ConstEigenVectorArrayMap X_arr(X, size); + EigenVectorMap(dX, size) = dY_arr * (X_arr.exp() + (-X_arr).exp()) / 2; + return true; +} + +REGISTER_CPU_OPERATOR( + Sinh, + UnaryElementwiseOp< + TensorTypes, + CPUContext, + SinhFunctor>); +REGISTER_CPU_OPERATOR( + SinhGradient, + BinaryElementwiseOp< + TensorTypes, + CPUContext, + SinhGradientFunctor>); + +OPERATOR_SCHEMA(Sinh) + .NumInputs(1) + .NumOutputs(1) + .IdenticalTypeAndShape() + .SetDoc(R"DOC( +Calculates the hyperbolic sine of the given input tensor, element-wise. + +Github Links: + +- https://github.com/pytorch/pytorch/blob/master/caffe2/operators/sinh_op.cc + + +
+ + Example + +**Code** + +``` + +workspace.ResetWorkspace() + +op = core.CreateOperator( + "Sinh", + ["X"], + ["Y"] +) + +workspace.FeedBlob("X", np.random.rand(5).astype(np.float32)) +print("X:", workspace.FetchBlob("X")) +workspace.RunOperatorOnce(op) +print("Y:", workspace.FetchBlob("Y")) + +``` + +**Result** + +``` + +X: [0.98907769 0.52907848 0.03216429 0.94983935 0.47881418] +Y: [1.15841695 0.5541099 0.03216984 1.09924557 0.49732079] + +``` + +
+ +)DOC") + .Input(0, "input", "Input tensor") + .Output( + 0, + "output", + "The hyperbolic sine values of the input tensor, computed " + "element-wise") + .InheritOnnxSchema("Sinh"); + +OPERATOR_SCHEMA(SinhGradient) + .NumInputs(2) + .NumOutputs(1) + .IdenticalTypeAndShape(); + +namespace { + +class GetSinhGradient : public GradientMakerBase { + using GradientMakerBase::GradientMakerBase; + std::vector GetGradientDefs() override { + return SingleGradientDef( + "SinhGradient", + "", + std::vector{GO(0), I(0)}, + std::vector{GI(0)}); + } +}; + +} // namespace + +REGISTER_GRADIENT(Sinh, GetSinhGradient); + +} // namespace caffe2 diff --git a/caffe2/operators/sinh_op.cu b/caffe2/operators/sinh_op.cu new file mode 100644 index 0000000000000..3dc8e0ceddd84 --- /dev/null +++ b/caffe2/operators/sinh_op.cu @@ -0,0 +1,60 @@ +#include "caffe2/operators/sinh_op.h" + +#include +#include + +#include "caffe2/core/context_gpu.h" + +namespace caffe2 { + +namespace { + +__global__ void SinhGradientCUDAKernel( + const int N, + const float* dY, + const float* X, + float* dX) { + CUDA_1D_KERNEL_LOOP(i, N) { +#if __CUDA_ARCH__ >= 350 + dX[i] = __ldg(dY + i) * coshf(__ldg(X + i)); +#else + dX[i] = dY[i] * coshf(X[i]); +#endif + } +} + +} // namespace + +template <> +template +bool SinhGradientFunctor::Forward( + const std::vector& /* dY_dims */, + const std::vector& X_dims, + const T* dY, + const T* X, + T* dX, + CUDAContext* context) const { + const int size = std::accumulate( + X_dims.cbegin(), X_dims.cend(), 1, std::multiplies()); + SinhGradientCUDAKernel<<< + CAFFE_GET_BLOCKS(size), + CAFFE_CUDA_NUM_THREADS, + 0, + context->cuda_stream()>>>(size, dY, X, dX); + return true; +} + +REGISTER_CUDA_OPERATOR( + Sinh, + UnaryElementwiseOp< + TensorTypes, + CUDAContext, + SinhFunctor>); +REGISTER_CUDA_OPERATOR( + SinhGradient, + BinaryElementwiseOp< + TensorTypes, + CUDAContext, + SinhGradientFunctor>); + +} // namespace caffe2 diff --git a/caffe2/operators/sinh_op.h b/caffe2/operators/sinh_op.h new file mode 100644 index 0000000000000..62e867b0a13af --- /dev/null +++ b/caffe2/operators/sinh_op.h @@ -0,0 +1,34 @@ +#ifndef CAFFE2_OPERATORS_SINH_OP_H_ +#define CAFFE2_OPERATORS_SINH_OP_H_ + +#include + +#include "caffe2/operators/elementwise_ops.h" +#include "caffe2/utils/math.h" + +namespace caffe2 { + +template +struct SinhFunctor { + template + bool operator()(const int N, const T* X, T* Y, Context* context) const { + math::Sinh(N, X, Y, context); + return true; + } +}; + +template +struct SinhGradientFunctor { + template + bool Forward( + const std::vector& dY_dims, + const std::vector& X_dims, + const T* dY, + const T* X, + T* dX, + Context* context) const; +}; + +} // namespace caffe2 + +#endif // CAFFE2_OPERATORS_SINH_OP_H_ diff --git a/caffe2/python/operator_test/hyperbolic_ops_test.py b/caffe2/python/operator_test/hyperbolic_ops_test.py index 269399b8305d9..b7018af181361 100644 --- a/caffe2/python/operator_test/hyperbolic_ops_test.py +++ b/caffe2/python/operator_test/hyperbolic_ops_test.py @@ -29,3 +29,11 @@ def ref(X): @given(X=hu.tensor(dtype=np.float32), in_place=st.booleans(), **hu.gcs) def test_tanh(self, X, in_place, gc, dc): self._test_hyperbolic_op("Tanh", np.tanh, X, in_place, gc, dc) + + @given(X=hu.tensor(dtype=np.float32), **hu.gcs) + def test_sinh(self, X, gc, dc): + self._test_hyperbolic_op("Sinh", np.sinh, X, False, gc, dc) + + @given(X=hu.tensor(dtype=np.float32), **hu.gcs) + def test_cosh(self, X, gc, dc): + self._test_hyperbolic_op("Cosh", np.cosh, X, False, gc, dc) diff --git a/caffe2/utils/math.h b/caffe2/utils/math.h index 9a9bdad5b7bba..fe1da18647464 100644 --- a/caffe2/utils/math.h +++ b/caffe2/utils/math.h @@ -72,6 +72,10 @@ void Tan(const int N, const T* x, T* y, Context* context); template void Atan(const int N, const T* x, T* y, Context* context); template +void Sinh(const int N, const T* x, T* y, Context* context); +template +void Cosh(const int N, const T* x, T* y, Context* context); +template void SinCos(const int N, const T* x, T* ys, T* yc, Context* context); template void Abs(const int N, const T* x, T* y, Context* context); diff --git a/caffe2/utils/math_cpu.cc b/caffe2/utils/math_cpu.cc index 8430cc91b89b5..feb44a762c3bb 100644 --- a/caffe2/utils/math_cpu.cc +++ b/caffe2/utils/math_cpu.cc @@ -552,6 +552,10 @@ DELEGATE_SIMPLE_UNARY_FUNCTION(float, Tan, vsTan) DELEGATE_SIMPLE_UNARY_FUNCTION(double, Tan, vdTan) DELEGATE_SIMPLE_UNARY_FUNCTION(float, Atan, vsAtan) DELEGATE_SIMPLE_UNARY_FUNCTION(double, Atan, vdAtan) +DELEGATE_SIMPLE_UNARY_FUNCTION(float, Sinh, vsSinh) +DELEGATE_SIMPLE_UNARY_FUNCTION(double, Sinh, vdSinh) +DELEGATE_SIMPLE_UNARY_FUNCTION(float, Cosh, vsCosh) +DELEGATE_SIMPLE_UNARY_FUNCTION(double, Cosh, vdCosh) DELEGATE_SIMPLE_UNARY_FUNCTION(float, Abs, vsAbs) DELEGATE_SIMPLE_UNARY_FUNCTION(double, Abs, vdAbs) DELEGATE_SIMPLE_UNARY_FUNCTION(float, Sqr, vsSqr) @@ -650,6 +654,26 @@ DELEGATE_CBRT_FUNCTION(double) DELEGATE_POWX_FUNCTION(float) #undef DELEGATE_POWX_FUNCTION +#define DELEGATE_SINH_FUNCTION(T) \ + template <> \ + void Sinh(const int N, const T* X, T* Y, CPUContext*) { \ + ConstEigenVectorArrayMap X_arr(X, N); \ + EigenVectorMap(Y, N) = (X_arr.exp() - (-X_arr).exp()) / 2; \ + } +DELEGATE_SINH_FUNCTION(float) +DELEGATE_SINH_FUNCTION(double) +#undef DELEGATE_SINH_FUNCTION + +#define DELEGATE_COSH_FUNCTION(T) \ + template <> \ + void Cosh(const int N, const T* X, T* Y, CPUContext*) { \ + ConstEigenVectorArrayMap X_arr(X, N); \ + EigenVectorMap(Y, N) = (X_arr.exp() + (-X_arr).exp()) / 2; \ + } +DELEGATE_COSH_FUNCTION(float) +DELEGATE_COSH_FUNCTION(double) +#undef DELEGATE_COSH_FUNCTION + #endif // CAFFE2_USE_MKL #define DELEGATE_NEG_FUNCTION(T) \ diff --git a/caffe2/utils/math_gpu.cu b/caffe2/utils/math_gpu.cu index 1f2f721363406..17e941c975864 100644 --- a/caffe2/utils/math_gpu.cu +++ b/caffe2/utils/math_gpu.cu @@ -329,6 +329,8 @@ DELEGATE_SIMPLE_CUDA_UNARY_FUNCTION(float, Sin, sinf) DELEGATE_SIMPLE_CUDA_UNARY_FUNCTION(float, Asin, asinf) DELEGATE_SIMPLE_CUDA_UNARY_FUNCTION(float, Tan, tanf) DELEGATE_SIMPLE_CUDA_UNARY_FUNCTION(float, Atan, atanf) +DELEGATE_SIMPLE_CUDA_UNARY_FUNCTION(float, Sinh, sinhf) +DELEGATE_SIMPLE_CUDA_UNARY_FUNCTION(float, Cosh, coshf) DELEGATE_SIMPLE_CUDA_UNARY_FUNCTION(float, Abs, fabsf) DELEGATE_SIMPLE_CUDA_UNARY_FUNCTION(float, Sqr, utils::Square) DELEGATE_SIMPLE_CUDA_UNARY_FUNCTION(float, Sqrt, sqrtf) From 04a7fc1dc4173a2571c1a9c3829b82955523b91d Mon Sep 17 00:00:00 2001 From: Lu Fang Date: Tue, 10 Jul 2018 22:36:29 -0700 Subject: [PATCH 12/36] Add Upsample support in C2 onnx backend for opset 1 Summary: Pull Request resolved: https://github.com/pytorch/pytorch/pull/9327 Reviewed By: ailzhang Differential Revision: D8798462 Pulled By: houseroad fbshipit-source-id: d7d1127a853de6a7bb8fdef146f283487e1e5569 --- caffe2/onnx/backend.cc | 36 ++++++++++++++++++----------------- caffe2/python/onnx/backend.py | 13 +++++++------ 2 files changed, 26 insertions(+), 23 deletions(-) diff --git a/caffe2/onnx/backend.cc b/caffe2/onnx/backend.cc index a74005904e1da..de44ab67cf6c0 100644 --- a/caffe2/onnx/backend.cc +++ b/caffe2/onnx/backend.cc @@ -910,24 +910,26 @@ Caffe2Ops Caffe2Backend::CreateMatMul(OnnxNode* onnx_node, int opset_version) { Caffe2Ops Caffe2Backend::CreateUpsample(OnnxNode* onnx_node, int opset_version) { auto& attributes = onnx_node->attributes; - auto scales = attributes.get<::google::protobuf::RepeatedField>("scales"); - if (scales.size() != 4) { - CAFFE_THROW("The scales argument should have size 4"); - } else if (!AlmostEqual(scales.Get(0), 1) || !AlmostEqual(scales.Get(1), 1)) { - CAFFE_THROW("The first two elements in the scales argument must be 1"); - } attributes.remove("mode"); - attributes.remove("scales"); - auto c2_op = CommonOnnxNodeToCaffe2Ops(onnx_node, opset_version); - auto* op = c2_op.ops.Mutable(0); - auto* c2_height = op->add_arg(); - c2_height->set_name("height_scale"); - c2_height->set_f(scales.Get(2)); - auto* c2_width = op->add_arg(); - c2_width->set_name("width_scale"); - c2_width->set_f(scales.Get(3)); - - return c2_op; + if (opset_version >= 7) { + const auto& scales = attributes.get<::google::protobuf::RepeatedField>("scales"); + if (scales.size() != 4) { + CAFFE_THROW("The scales argument should have size 4"); + } else if (!AlmostEqual(scales.Get(0), 1) || !AlmostEqual(scales.Get(1), 1)) { + CAFFE_THROW("The first two elements in the scales argument must be 1"); + } + attributes.remove("scales"); + auto c2_op = CommonOnnxNodeToCaffe2Ops(onnx_node, opset_version); + auto* op = c2_op.ops.Mutable(0); + auto* c2_height = op->add_arg(); + c2_height->set_name("height_scale"); + c2_height->set_f(scales.Get(2)); + auto* c2_width = op->add_arg(); + c2_width->set_name("width_scale"); + c2_width->set_f(scales.Get(3)); + return c2_op; + } + return CommonOnnxNodeToCaffe2Ops(onnx_node, opset_version); } Caffe2Ops Caffe2Backend::CreateDropout(OnnxNode* onnx_node, int opset_version) { diff --git a/caffe2/python/onnx/backend.py b/caffe2/python/onnx/backend.py index 508dde2b26e00..3d7e76a7176d3 100644 --- a/caffe2/python/onnx/backend.py +++ b/caffe2/python/onnx/backend.py @@ -381,12 +381,13 @@ def _make_rnn_direction(cls, input_blob, B, W, R, initial_states_and_names, sequ @classmethod def _create_upsample(cls, init_model, pred_model, n, opset_version): c2_op = cls._common_onnx_node_to_caffe2_op(init_model, pred_model, n, opset_version) - if len(n.attrs['scales']) != 4: - raise ValueError("The scales argument should have size 4") - elif not (np.isclose(n.attrs['scales'][0], 1) and np.isclose(n.attrs['scales'][1], 1)): - raise ValueError("The first two elements in the scales argument must be 1") - c2_op.arg.extend([caffe2.python.utils.MakeArgument('height_scale', n.attrs['scales'][2])]) - c2_op.arg.extend([caffe2.python.utils.MakeArgument('width_scale', n.attrs['scales'][3])]) + if opset_version >= 7: + if len(n.attrs['scales']) != 4: + raise ValueError("The scales argument should have size 4") + elif not (np.isclose(n.attrs['scales'][0], 1) and np.isclose(n.attrs['scales'][1], 1)): + raise ValueError("The first two elements in the scales argument must be 1") + c2_op.arg.extend([caffe2.python.utils.MakeArgument('height_scale', n.attrs['scales'][2])]) + c2_op.arg.extend([caffe2.python.utils.MakeArgument('width_scale', n.attrs['scales'][3])]) return c2_op From b2a74d17adc99e024190b3a18aa1071f889bd3bc Mon Sep 17 00:00:00 2001 From: Thomas Viehmann Date: Wed, 11 Jul 2018 07:27:21 -0700 Subject: [PATCH 13/36] document torch.utils.dlpack (#9343) Summary: dlpacks deserve documentation. :) I wonder whether it might make sense to merge the various small torch.utils pages (and include a link for the larger ones, e.g. data) to enhance the structure in the docs. Pull Request resolved: https://github.com/pytorch/pytorch/pull/9343 Differential Revision: D8801227 Pulled By: soumith fbshipit-source-id: 2980d271971743b86f052bec5a2cb4d146a90d9b --- docs/source/dlpack.rst | 8 ++++++++ docs/source/index.rst | 1 + torch/utils/dlpack.py | 23 +++++++++++++++++++++++ 3 files changed, 32 insertions(+) create mode 100644 docs/source/dlpack.rst diff --git a/docs/source/dlpack.rst b/docs/source/dlpack.rst new file mode 100644 index 0000000000000..869285de792d1 --- /dev/null +++ b/docs/source/dlpack.rst @@ -0,0 +1,8 @@ +torch.utils.dlpack +================== + +.. currentmodule:: torch.utils.dlpack + +.. autofunction:: from_dlpack +.. autofunction:: to_dlpack + diff --git a/docs/source/index.rst b/docs/source/index.rst index 1ad4f9d679c92..ea6eb3c935329 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -38,6 +38,7 @@ PyTorch is an optimized tensor library for deep learning using GPUs and CPUs. checkpoint cpp_extension data + dlpack ffi model_zoo onnx diff --git a/torch/utils/dlpack.py b/torch/utils/dlpack.py index c33be352b3ecd..7d66cc3f7194a 100644 --- a/torch/utils/dlpack.py +++ b/torch/utils/dlpack.py @@ -2,3 +2,26 @@ from torch._C import _from_dlpack as from_dlpack from torch._C import _to_dlpack as to_dlpack + +torch._C._add_docstr(from_dlpack, r"""from_dlpack(dlpack) -> Tensor + +Decodes a DLPack to a tensor. + +Arguments:: + dlpack - a PyCapsule object with the dltensor + +The tensor will share the memory with the object represented +in the dlpack. +Note that each dlpack can only be consumed once. +""") + +torch._C._add_docstr(to_dlpack, r"""to_dlpack(tensor) -> PyCapsule + +Returns a DLPack representing the tensor. + +Arguments:: + tensor - a tensor to be exported + +The dlpack shares the tensors memory. +Note that each dlpack can only be consumed once. +""") From 01cffaa7e8426655f94b893dcd18defc6c62ca04 Mon Sep 17 00:00:00 2001 From: Zachary DeVito Date: Wed, 11 Jul 2018 10:09:32 -0700 Subject: [PATCH 14/36] fix extra output in generate_code.py (#9339) Summary: operator.cpp is not generated. removing the line prevents generate_code.py from always thinking it is out of date and running. Pull Request resolved: https://github.com/pytorch/pytorch/pull/9339 Reviewed By: ezyang Differential Revision: D8798689 Pulled By: zdevito fbshipit-source-id: f25a2e215fec29aa51571e6a31771f0f91e7a213 --- tools/setup_helpers/generate_code.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/setup_helpers/generate_code.py b/tools/setup_helpers/generate_code.py index 33daa663ca0d4..4d3db46699b3b 100644 --- a/tools/setup_helpers/generate_code.py +++ b/tools/setup_helpers/generate_code.py @@ -41,7 +41,6 @@ def all_generator_source(): 'torch/csrc/autograd/generated/VariableType.cpp', 'torch/csrc/autograd/generated/VariableType.h', 'torch/csrc/jit/generated/register_aten_ops.cpp', - 'torch/csrc/jit/generated/operator.cpp', ] From 748a90d05b1b43d30512878a6ac45c9f6ca2225f Mon Sep 17 00:00:00 2001 From: Viswanath Sivakumar Date: Wed, 11 Jul 2018 10:15:53 -0700 Subject: [PATCH 15/36] BBoxTransform op: Add support for rotated boxes (#8952) Summary: Pull Request resolved: https://github.com/pytorch/pytorch/pull/8952 Closes https://github.com/pytorch/pytorch/pull/8952 Based on RRPN paper: https://arxiv.org/abs/1703.01086 Reviewed By: pjh5 Differential Revision: D8598547 fbshipit-source-id: 3699379df9bf45ed5bdd395175a0e26a77e079f7 --- caffe2/operators/bbox_transform_op.cc | 40 +++-- caffe2/operators/bbox_transform_op.h | 6 +- .../generate_proposals_op_util_boxes.h | 141 +++++++++++++++++- .../generate_proposals_op_util_boxes_test.cc | 31 ++++ .../operator_test/bbox_transform_test.py | 131 ++++++++++++---- .../python/operator_test/boolean_mask_test.py | 20 ++- 6 files changed, 320 insertions(+), 49 deletions(-) diff --git a/caffe2/operators/bbox_transform_op.cc b/caffe2/operators/bbox_transform_op.cc index 369db13815c84..6572fb56ab3f1 100644 --- a/caffe2/operators/bbox_transform_op.cc +++ b/caffe2/operators/bbox_transform_op.cc @@ -37,6 +37,11 @@ Transform proposal bounding boxes to target bounding box using bounding box " see bbox_transform() in boxes.py " "Set to true to match the detectron code, set to false for backward" " compatibility") + .Arg( + "rotated", + "bool (default false). If true, then boxes (rois and deltas) include " + "angle info to handle rotation. The format will be " + "[ctr_x, ctr_y, width, height, angle (in degrees)].") .Input( 0, "rois", @@ -44,12 +49,15 @@ Transform proposal bounding boxes to target bounding box using bounding box "Size (M, 4), format [x1, y1, x2, y2], or" "Size (M, 5), format [batch_index, x1, y1, x2, y2]. " "If proposals from multiple images in a batch are present, they " - "should be grouped sequentially and in incremental order.") + "should be grouped sequentially and in incremental order." + "For rotated boxes, this would have an additional angle (in degrees) " + "in the format [, ctr_x, ctr_y, w, h, angle].") .Input( 1, "deltas", "bounding box translations and scales," - "size (M, 4*K), format [dx, dy, dw, dh], K = # classes") + "size (M, 4*K), format [dx, dy, dw, dh], K = # classes. " + "For rotated boxes, size (M, 5*K, format [dx, dy, dw, dh, da].") .Input( 2, "im_info", @@ -59,7 +67,9 @@ Transform proposal bounding boxes to target bounding box using bounding box 0, "box_out", "Pixel coordinates of the transformed bounding boxes," - "Size (M, 4*K), format [x1, y1, x2, y2]") + "Size (M, 4*K), format [x1, y1, x2, y2]. " + "For rotated boxes, size (M, 5*K), " + "format [ctr_x, ctr_y, w, h, angle].") .Output( 1, "roi_batch_splits", @@ -76,14 +86,15 @@ bool BBoxTransformOp::RunOnDevice() { const auto& iminfo_in = Input(2); auto* box_out = Output(0); + const int box_dim = rotated_ ? 5 : 4; const int N = roi_in.dim32(0); CAFFE_ENFORCE_EQ(roi_in.ndim(), 2); - CAFFE_ENFORCE(roi_in.dim32(1) == 4 || roi_in.dim32(1) == 5); + CAFFE_ENFORCE(roi_in.dim32(1) == box_dim || roi_in.dim32(1) == box_dim + 1); CAFFE_ENFORCE_EQ(delta_in.ndim(), 2); CAFFE_ENFORCE_EQ(delta_in.dim32(0), N); - CAFFE_ENFORCE_EQ(delta_in.dim32(1) % 4, 0); - const int num_classes = delta_in.dim32(1) / 4; + CAFFE_ENFORCE_EQ(delta_in.dim32(1) % box_dim, 0); + const int num_classes = delta_in.dim32(1) / box_dim; CAFFE_ENFORCE_EQ(iminfo_in.ndim(), 2); CAFFE_ENFORCE_EQ(iminfo_in.dim32(1), 3); @@ -98,7 +109,7 @@ bool BBoxTransformOp::RunOnDevice() { // Count the number of RoIs per batch vector num_rois_per_batch(batch_size, 0); - if (roi_in.dim32(1) == 4) { + if (roi_in.dim32(1) == box_dim) { CAFFE_ENFORCE_EQ(batch_size, 1); num_rois_per_batch[0] = N; } else { @@ -129,18 +140,23 @@ bool BBoxTransformOp::RunOnDevice() { int img_h = int(cur_iminfo(0) / scale_before + 0.5); int img_w = int(cur_iminfo(1) / scale_before + 0.5); - const auto& cur_boxes = - boxes0.rightCols(4).block(offset, 0, num_rois, 4) / scale_before; + EArrXXf cur_boxes = + boxes0.rightCols(box_dim).block(offset, 0, num_rois, box_dim); + // Do not apply scale for angle in rotated boxes + cur_boxes.leftCols(4) /= scale_before; for (int k = 0; k < num_classes; k++) { - const auto& cur_deltas = deltas0.block(offset, k * 4, num_rois, 4); + const auto& cur_deltas = + deltas0.block(offset, k * box_dim, num_rois, box_dim); const auto& trans_boxes = utils::bbox_transform( cur_boxes, cur_deltas, weights_, utils::BBOX_XFORM_CLIP_DEFAULT, correct_transform_coords_); - const auto& clip_boxes = utils::clip_boxes(trans_boxes, img_h, img_w); - new_boxes.block(offset, k * 4, num_rois, 4) = clip_boxes * scale_after; + EArrXXf clip_boxes = utils::clip_boxes(trans_boxes, img_h, img_w); + // Do not apply scale for angle in rotated boxes + clip_boxes.leftCols(4) *= scale_after; + new_boxes.block(offset, k * box_dim, num_rois, box_dim) = clip_boxes; } offset += num_rois; diff --git a/caffe2/operators/bbox_transform_op.h b/caffe2/operators/bbox_transform_op.h index 68986cbc2f7bc..e7d5e476c38c5 100644 --- a/caffe2/operators/bbox_transform_op.h +++ b/caffe2/operators/bbox_transform_op.h @@ -22,7 +22,8 @@ class BBoxTransformOp final : public Operator { OperatorBase::GetSingleArgument("apply_scale", true)), correct_transform_coords_(OperatorBase::GetSingleArgument( "correct_transform_coords", - false)) { + false)), + rotated_(OperatorBase::GetSingleArgument("rotated", false)) { CAFFE_ENFORCE_EQ( weights_.size(), 4, @@ -44,6 +45,9 @@ class BBoxTransformOp final : public Operator { // Set to true to match the detectron code, set to false for backward // compatibility bool correct_transform_coords_{false}; + // Set for RRPN case to handle rotated boxes. Inputs should be in format + // [ctr_x, ctr_y, width, height, angle (in degrees)]. + bool rotated_{false}; }; } // namespace caffe2 diff --git a/caffe2/operators/generate_proposals_op_util_boxes.h b/caffe2/operators/generate_proposals_op_util_boxes.h index 660e1ade722ce..633e9630eb7b9 100644 --- a/caffe2/operators/generate_proposals_op_util_boxes.h +++ b/caffe2/operators/generate_proposals_op_util_boxes.h @@ -13,6 +13,7 @@ namespace utils { // Default value for minimum bounding box width and height after bounding box // transformation (bbox_transform()) in log-space const float BBOX_XFORM_CLIP_DEFAULT = log(1000.0 / 16.0); +const float PI = 3.14159265358979323846; // Forward transform that maps proposal boxes to ground-truth boxes using // bounding-box regression deltas. @@ -21,7 +22,7 @@ const float BBOX_XFORM_CLIP_DEFAULT = log(1000.0 / 16.0); // deltas: bounding box translations and scales // size (M, 4), format [dx; dy; dw; dh] // dx, dy: scale-invariant translation of the center of the bounding box -// dw, dh: log-space sclaing of the width and height of the bounding box +// dw, dh: log-space scaling of the width and height of the bounding box // weights: weights [wx, wy, ww, wh] for the deltas // bbox_xform_clip: minimum bounding box width and height in log-space after // transofmration @@ -33,7 +34,7 @@ const float BBOX_XFORM_CLIP_DEFAULT = log(1000.0 / 16.0); // segmentation" Appendix C for more details // reference: detectron/lib/utils/boxes.py bbox_transform() template -EArrXXt bbox_transform( +EArrXXt bbox_transform_upright( const Eigen::ArrayBase& boxes, const Eigen::ArrayBase& deltas, const std::vector& weights = @@ -84,12 +85,100 @@ EArrXXt bbox_transform( return pred_boxes; } +// Like bbox_transform_upright, but works on rotated boxes. +// boxes: pixel coordinates of the bounding boxes +// size (M, 5), format [ctr_x; ctr_y; width; height; angle (in degrees)] +// deltas: bounding box translations and scales +// size (M, 5), format [dx; dy; dw; dh; da] +// dx, dy: scale-invariant translation of the center of the bounding box +// dw, dh: log-space scaling of the width and height of the bounding box +// da: delta for angle in radians +// return: pixel coordinates of the bounding boxes +// size (M, 5), format [ctr_x; ctr_y; width; height; angle (in degrees)] +template +EArrXXt bbox_transform_rotated( + const Eigen::ArrayBase& boxes, + const Eigen::ArrayBase& deltas, + const std::vector& weights = + std::vector{1.0, 1.0, 1.0, 1.0}, + const float bbox_xform_clip = BBOX_XFORM_CLIP_DEFAULT) { + using T = typename Derived1::Scalar; + using EArrXX = EArrXXt; + using EArrX = EArrXt; + + if (boxes.rows() == 0) { + return EArrXX::Zero(T(0), deltas.cols()); + } + + CAFFE_ENFORCE_EQ(boxes.rows(), deltas.rows()); + CAFFE_ENFORCE_EQ(boxes.cols(), 5); + CAFFE_ENFORCE_EQ(deltas.cols(), 5); + + const auto& ctr_x = boxes.col(0); + const auto& ctr_y = boxes.col(1); + const auto& widths = boxes.col(2); + const auto& heights = boxes.col(3); + const auto& angles = boxes.col(4); + + auto dx = deltas.col(0).template cast() / weights[0]; + auto dy = deltas.col(1).template cast() / weights[1]; + auto dw = + (deltas.col(2).template cast() / weights[2]).cwiseMin(bbox_xform_clip); + auto dh = + (deltas.col(3).template cast() / weights[3]).cwiseMin(bbox_xform_clip); + // Convert back to degrees + auto da = deltas.col(4).template cast() * 180.0 / PI; + + EArrXX pred_boxes = EArrXX::Zero(deltas.rows(), deltas.cols()); + // new ctr_x + pred_boxes.col(0) = dx * widths + ctr_x; + // new ctr_y + pred_boxes.col(1) = dy * heights + ctr_y; + // new width + pred_boxes.col(2) = dw.exp() * widths; + // new height + pred_boxes.col(3) = dh.exp() * heights; + // new angle + pred_boxes.col(4) = da + angles; + // TODO (viswanath): Normalize angle + + return pred_boxes; +} + +template +EArrXXt bbox_transform( + const Eigen::ArrayBase& boxes, + const Eigen::ArrayBase& deltas, + const std::vector& weights = + std::vector{1.0, 1.0, 1.0, 1.0}, + const float bbox_xform_clip = BBOX_XFORM_CLIP_DEFAULT, + const bool correct_transform_coords = false) { + CAFFE_ENFORCE(boxes.cols() == 4 || boxes.cols() == 5); + if (boxes.cols() == 4) { + // Upright boxes + return bbox_transform_upright( + boxes, deltas, weights, bbox_xform_clip, correct_transform_coords); + } else { + // Rotated boxes with angle info + return bbox_transform_rotated(boxes, deltas, weights, bbox_xform_clip); + } +} + // Clip boxes to image boundaries // boxes: pixel coordinates of bounding box, size (M * 4) +// +// For rotated boxes with angle support (M * 5), we don't clip and just +// return early. It's tricky to make the entire rectangular box fit within the +// image and still be able to not leave out pixels of interest. +// We rely on upstream ops like RoIAlignRotated safely handling such cases. template EArrXXt clip_boxes(const Eigen::ArrayBase& boxes, int height, int width) { - CAFFE_ENFORCE_EQ(boxes.cols(), 4); + CAFFE_ENFORCE(boxes.cols() == 4 || boxes.cols() == 5); + if (boxes.cols() == 5) { + // No clipping for rotated boxes. + return boxes; + } EArrXXt ret(boxes.rows(), boxes.cols()); @@ -110,7 +199,7 @@ clip_boxes(const Eigen::ArrayBase& boxes, int height, int width) { // im_info: [height, width, img_scale] // return: row indices for 'boxes' template -std::vector filter_boxes( +std::vector filter_boxes_upright( const Eigen::ArrayBase& boxes, double min_size, const Eigen::Array3f& im_info) { @@ -133,6 +222,50 @@ std::vector filter_boxes( return GetArrayIndices(keep); } +// Similar to filter_boxes_upright but works for rotated boxes. +// boxes: pixel coordinates of the bounding boxes +// size (M, 5), format [ctr_x; ctr_y; width; height; angle (in degrees)] +// im_info: [height, width, img_scale] +// return: row indices for 'boxes' +template +std::vector filter_boxes_rotated( + const Eigen::ArrayBase& boxes, + double min_size, + const Eigen::Array3f& im_info) { + CAFFE_ENFORCE_EQ(boxes.cols(), 5); + + // Scale min_size to match image scale + min_size *= im_info[2]; + + using T = typename Derived::Scalar; + using EArrX = EArrXt; + + const auto& x_ctr = boxes.col(0); + const auto& y_ctr = boxes.col(1); + const auto& ws = boxes.col(2); + const auto& hs = boxes.col(3); + + EArrXb keep = (ws >= min_size) && (hs >= min_size) && + (x_ctr < T(im_info[1])) && (y_ctr < T(im_info[0])); + + return GetArrayIndices(keep); +} + +template +std::vector filter_boxes( + const Eigen::ArrayBase& boxes, + double min_size, + const Eigen::Array3f& im_info) { + CAFFE_ENFORCE(boxes.cols() == 4 || boxes.cols() == 5); + if (boxes.cols() == 4) { + // Upright boxes + return filter_boxes_upright(boxes, min_size, im_info); + } else { + // Rotated boxes with angle info + return filter_boxes_rotated(boxes, min_size, im_info); + } +} + } // namespace utils } // namespace caffe2 diff --git a/caffe2/operators/generate_proposals_op_util_boxes_test.cc b/caffe2/operators/generate_proposals_op_util_boxes_test.cc index 3ba38929b6b78..fe6f4206a7764 100644 --- a/caffe2/operators/generate_proposals_op_util_boxes_test.cc +++ b/caffe2/operators/generate_proposals_op_util_boxes_test.cc @@ -35,4 +35,35 @@ TEST(UtilsBoxesTest, TestBboxTransformRandom) { EXPECT_NEAR((result.matrix() - result_gt).norm(), 0.0, 1e-4); } +TEST(UtilsBoxesTest, TestBboxTransformRotated) { + using EMatXf = Eigen::MatrixXf; + + EMatXf bbox(5, 5); + bbox << 214.986, 88.4628, 78.7317, 135.104, 0.0, 199.553, 55.4367, 60.6142, + 101.169, 45.0, 187.829, 207.427, 0012.11, 15.1967, 90.0, 235.777, 209.518, + 122.828, 45.5215, -60.0, 79.6505, 150.914, 113.838, 117.777, 170.0; + + EMatXf deltas(5, 5); + // 0.174533 radians -> 10 degrees + deltas << 0.47861834, 0.13992102, 0.14961673, 0.71495209, 0.0, 0.29915856, + -0.35664671, 0.89018666, 0.70815367, 0.174533, -0.03852064, 0.44466892, + 0.49492538, 0.71409376, 0.174533, 0.28052918, 0.02184832, 0.65289006, + 1.05060139, 0.174533, -0.38172557, -0.08533806, -0.60335309, 0.79052375, + 0.174533; + + EMatXf result_gt(5, 5); + result_gt << 252.668, 107.367, 91.4381, 276.165, 0.0, 217.686, 19.3551, + 147.631, 205.397, 55.0, 187.363, 214.185, 19.865, 31.0368, 100.0, 270.234, + 210.513, 235.963, 130.163, -50.0, 36.1956, 140.863, 62.2665, 259.645, + 180.0; + + const float BBOX_XFORM_CLIP = log(1000.0 / 16.0); + auto result = utils::bbox_transform( + bbox.array(), + deltas.array(), + std::vector{1.0, 1.0, 1.0, 1.0}, + BBOX_XFORM_CLIP); + EXPECT_NEAR((result.matrix() - result_gt).norm(), 0.0, 1e-2); +} + } // namespace caffe2 diff --git a/caffe2/python/operator_test/bbox_transform_test.py b/caffe2/python/operator_test/bbox_transform_test.py index 7fe1ae7abe46b..aaf6c0eb11ae2 100644 --- a/caffe2/python/operator_test/bbox_transform_test.py +++ b/caffe2/python/operator_test/bbox_transform_test.py @@ -58,8 +58,9 @@ def bbox_transform(boxes, deltas, weights=(1.0, 1.0, 1.0, 1.0)): def clip_tiled_boxes(boxes, im_shape): """Clip boxes to image boundaries. im_shape is [height, width] and boxes has shape (N, 4 * num_tiled_boxes).""" - assert boxes.shape[1] % 4 == 0, \ - 'boxes.shape[1] is {:d}, but must be divisible by 4.'.format( + assert ( + boxes.shape[1] % 4 == 0 + ), "boxes.shape[1] is {:d}, but must be divisible by 4.".format( boxes.shape[1] ) # x1 >= 0 @@ -80,48 +81,112 @@ def generate_rois(roi_counts, im_dims): if num_rois == 0: continue # [batch_idx, x1, y1, x2, y2] - rois = np.random.uniform( - 0, im_dims[i], size=(roi_counts[i], 5) - ).astype(np.float32) + rois = np.random.uniform(0, im_dims[i], size=(roi_counts[i], 5)).astype( + np.float32 + ) rois[:, 0] = i # batch_idx # Swap (x1, x2) if x1 > x2 - rois[:, 1], rois[:, 3] = np.minimum(rois[:, 1], rois[:, 3]), \ - np.maximum(rois[:, 1], rois[:, 3]) + rois[:, 1], rois[:, 3] = ( + np.minimum(rois[:, 1], rois[:, 3]), + np.maximum(rois[:, 1], rois[:, 3]), + ) # Swap (y1, y2) if y1 > y2 - rois[:, 2], rois[:, 4] = np.minimum(rois[:, 2], rois[:, 4]), \ - np.maximum(rois[:, 2], rois[:, 4]) + rois[:, 2], rois[:, 4] = ( + np.minimum(rois[:, 2], rois[:, 4]), + np.maximum(rois[:, 2], rois[:, 4]), + ) all_rois.append(rois) if len(all_rois) > 0: return np.vstack(all_rois) return np.empty((0, 5)).astype(np.float32) +def bbox_transform_rotated(boxes, deltas, weights=(1.0, 1.0, 1.0, 1.0)): + """ + Similar to bbox_transform but for rotated boxes with angle info. + """ + if boxes.shape[0] == 0: + return np.zeros((0, deltas.shape[1]), dtype=deltas.dtype) + + boxes = boxes.astype(deltas.dtype, copy=False) + + ctr_x = boxes[:, 0] + ctr_y = boxes[:, 1] + widths = boxes[:, 2] + heights = boxes[:, 3] + angles = boxes[:, 4] + + wx, wy, ww, wh = weights + dx = deltas[:, 0::5] / wx + dy = deltas[:, 1::5] / wy + dw = deltas[:, 2::5] / ww + dh = deltas[:, 3::5] / wh + da = deltas[:, 4::5] * 180.0 / np.pi + + # Prevent sending too large values into np.exp() + BBOX_XFORM_CLIP = np.log(1000. / 16.) + dw = np.minimum(dw, BBOX_XFORM_CLIP) + dh = np.minimum(dh, BBOX_XFORM_CLIP) + + pred_boxes = np.zeros(deltas.shape, dtype=deltas.dtype) + pred_boxes[:, 0::5] = dx * widths[:, np.newaxis] + ctr_x[:, np.newaxis] + pred_boxes[:, 1::5] = dy * heights[:, np.newaxis] + ctr_y[:, np.newaxis] + pred_boxes[:, 2::5] = np.exp(dw) * widths[:, np.newaxis] + pred_boxes[:, 3::5] = np.exp(dh) * heights[:, np.newaxis] + pred_boxes[:, 4::5] = da + angles[:, np.newaxis] + + # TODO (viswanath): Normalize angles + return pred_boxes + + +def generate_rois_rotated(roi_counts, im_dims): + rois = generate_rois(roi_counts, im_dims) + # [batch_id, ctr_x, ctr_y, w, h, angle] + rotated_rois = np.empty((rois.shape[0], 6)).astype(np.float32) + rotated_rois[:, 0] = rois[:, 0] # batch_id + rotated_rois[:, 1] = (rois[:, 1] + rois[:, 3]) / 2. # ctr_x = (x1 + x2) / 2 + rotated_rois[:, 2] = (rois[:, 2] + rois[:, 4]) / 2. # ctr_y = (y1 + y2) / 2 + rotated_rois[:, 3] = rois[:, 3] - rois[:, 1] + 1.0 # w = x2 - x1 + 1 + rotated_rois[:, 4] = rois[:, 4] - rois[:, 2] + 1.0 # h = y2 - y1 + 1 + rotated_rois[:, 5] = np.random.uniform(0.0, 360.0) # angle in degrees + return rotated_rois + + class TestBBoxTransformOp(hu.HypothesisTestCase): @given( num_rois=st.integers(1, 10), num_classes=st.integers(1, 10), im_dim=st.integers(100, 600), skip_batch_id=st.booleans(), + rotated=st.booleans(), **hu.gcs_cpu_only ) def test_bbox_transform( - self, num_rois, num_classes, im_dim, skip_batch_id, gc, dc + self, num_rois, num_classes, im_dim, skip_batch_id, rotated, gc, dc ): """ Test with all rois belonging to a single image per run. """ - rois = generate_rois([num_rois], [im_dim]) + rois = ( + generate_rois_rotated([num_rois], [im_dim]) + if rotated + else generate_rois([num_rois], [im_dim]) + ) + box_dim = 5 if rotated else 4 if skip_batch_id: - rois = rois[:, 1:5] - deltas = np.random.randn(num_rois, 4 * num_classes).astype(np.float32) - im_info = np.array([im_dim, im_dim, - 1.0]).astype(np.float32).reshape(1, 3) + rois = rois[:, 1:] + deltas = np.random.randn(num_rois, box_dim * num_classes).astype(np.float32) + im_info = np.array([im_dim, im_dim, 1.0]).astype(np.float32).reshape(1, 3) def bbox_transform_ref(rois, deltas, im_info): - boxes = rois if rois.shape[1] == 4 else rois[:, 1:5] - box_out = bbox_transform(boxes, deltas) - im_shape = im_info[0, 0:2] - box_out = clip_tiled_boxes(box_out, im_shape) + boxes = rois if rois.shape[1] == box_dim else rois[:, 1:] + if rotated: + box_out = bbox_transform_rotated(boxes, deltas) + # No clipping for rotated boxes + else: + box_out = bbox_transform(boxes, deltas) + im_shape = im_info[0, 0:2] + box_out = clip_tiled_boxes(box_out, im_shape) return [box_out] op = core.CreateOperator( @@ -130,6 +195,7 @@ def bbox_transform_ref(rois, deltas, im_info): ["box_out"], apply_scale=False, correct_transform_coords=True, + rotated=rotated, ) self.assertReferenceChecks( @@ -142,17 +208,23 @@ def bbox_transform_ref(rois, deltas, im_info): @given( roi_counts=st.lists(st.integers(0, 5), min_size=1, max_size=10), num_classes=st.integers(1, 10), + rotated=st.booleans(), **hu.gcs_cpu_only ) - def test_bbox_transform_batch(self, roi_counts, num_classes, gc, dc): + def test_bbox_transform_batch(self, roi_counts, num_classes, rotated, gc, dc): """ Test with rois for multiple images in a batch """ batch_size = len(roi_counts) total_rois = sum(roi_counts) im_dims = np.random.randint(100, 600, batch_size) - rois = generate_rois(roi_counts, im_dims) - deltas = np.random.randn(total_rois, 4 * num_classes).astype(np.float32) + rois = ( + generate_rois_rotated(roi_counts, im_dims) + if rotated + else generate_rois(roi_counts, im_dims) + ) + box_dim = 5 if rotated else 4 + deltas = np.random.randn(total_rois, box_dim * num_classes).astype(np.float32) im_info = np.zeros((batch_size, 3)).astype(np.float32) im_info[:, 0] = im_dims im_info[:, 1] = im_dims @@ -164,11 +236,15 @@ def bbox_transform_ref(rois, deltas, im_info): for i, num_rois in enumerate(roi_counts): if num_rois == 0: continue - cur_boxes = rois[offset:offset + num_rois, 1:5] - cur_deltas = deltas[offset:offset + num_rois] - cur_box_out = bbox_transform(cur_boxes, cur_deltas) - im_shape = im_info[i, 0:2] - cur_box_out = clip_tiled_boxes(cur_box_out, im_shape) + cur_boxes = rois[offset : offset + num_rois, 1:] + cur_deltas = deltas[offset : offset + num_rois] + if rotated: + cur_box_out = bbox_transform_rotated(cur_boxes, cur_deltas) + # No clipping for rotated boxes + else: + cur_box_out = bbox_transform(cur_boxes, cur_deltas) + im_shape = im_info[i, 0:2] + cur_box_out = clip_tiled_boxes(cur_box_out, im_shape) box_out.append(cur_box_out) offset += num_rois @@ -184,6 +260,7 @@ def bbox_transform_ref(rois, deltas, im_info): ["box_out", "roi_batch_splits"], apply_scale=False, correct_transform_coords=True, + rotated=rotated, ) self.assertReferenceChecks( diff --git a/caffe2/python/operator_test/boolean_mask_test.py b/caffe2/python/operator_test/boolean_mask_test.py index 51f457fdb73d9..638248d60bafe 100644 --- a/caffe2/python/operator_test/boolean_mask_test.py +++ b/caffe2/python/operator_test/boolean_mask_test.py @@ -122,7 +122,9 @@ def ref(x, centers): self.assertReferenceChecks(gc, op, [x, centers], ref) self.assertDeviceChecks(dc, op, [x, centers], [0]) - threshold = 0.4 if dtype == np.float16 else 0.005 + # Gradient check with np.float16 is found to be flakey, disable for now + # with high threshold (to repro, set threshold to 0.4). + threshold = 1.0 if dtype == np.float16 else 0.005 self.assertGradientChecks(gc, op, [x, centers], 0, [0], threshold=threshold) @@ -171,7 +173,9 @@ def ref(x): self.assertReferenceChecks(gc, op, [x], ref) self.assertDeviceChecks(dc, op, [x], [0]) - threshold = 0.4 if dtype == np.float16 else 0.005 + # Gradient check with np.float16 is found to be flakey, disable for now + # with high threshold (to repro, set threshold to 0.4). + threshold = 1.0 if dtype == np.float16 else 0.005 stepsize = 0.1 if dtype == np.float16 else 0.05 self.assertGradientChecks(gc, op, [x], 0, [0], threshold=threshold, stepsize=stepsize) @@ -222,7 +226,9 @@ def ref(z, l): self.assertReferenceChecks(gc, op, [x, lengths], ref) self.assertDeviceChecks(dc, op, [x, lengths], [0]) - threshold = 0.4 if dtype == np.float16 else 0.005 + # Gradient check with np.float16 is found to be flakey, disable for now + # with high threshold (to repro, set threshold to 0.4). + threshold = 1.0 if dtype == np.float16 else 0.005 self.assertGradientChecks(gc, op, [x, lengths], 0, [0], threshold=threshold) @@ -274,7 +280,9 @@ def ref(z, c): self.assertReferenceChecks(gc, op, [x, centers], ref) self.assertDeviceChecks(dc, op, [x, centers], [0]) - threshold = 0.4 if dtype == np.float16 else 0.005 + # Gradient check with np.float16 is found to be flakey, disable for now + # with high threshold (to repro, set threshold to 0.4). + threshold = 1.0 if dtype == np.float16 else 0.005 self.assertGradientChecks(gc, op, [x, centers], 0, [0], threshold=threshold) @@ -335,7 +343,9 @@ def ref(z): self.assertReferenceChecks(gc, op, [x], ref) self.assertDeviceChecks(dc, op, [x], [0]) - threshold = 0.4 if dtype == np.float16 else 0.005 + # Gradient check with np.float16 is found to be flakey, disable for now + # with high threshold (to repro, set threshold to 0.4). + threshold = 1.0 if dtype == np.float16 else 0.005 stepsize = 0.1 if dtype == np.float16 else 0.05 self.assertGradientChecks(gc, op, [x], 0, [0], threshold=threshold, stepsize=stepsize) From 05559b40716d4161fadabff6130805f07172ef83 Mon Sep 17 00:00:00 2001 From: Richard Zou Date: Wed, 11 Jul 2018 10:20:13 -0700 Subject: [PATCH 16/36] Accumulate MSELoss reduce=True into accreal instead of real (#9287) Summary: THNN was accumulating the result of reduction loss functions into real instead of accreal. This was causing precision issues with MSELoss. This patch only fixes MSELoss. Some of the other losses exhibit bad precision as well (because they accumulate into real instead of accreal) and require more investigation. I will open an issue for those (#9286) Fixes #8710 cc li-roy SsnL Pull Request resolved: https://github.com/pytorch/pytorch/pull/9287 Reviewed By: SsnL Differential Revision: D8775708 Pulled By: zou3519 fbshipit-source-id: d1a1f159deee0cb90fd8e81e63b246115eea8e9e --- aten/src/THNN/generic/MSECriterion.c | 6 +++--- test/common_nn.py | 4 ++++ test/test_nn.py | 9 +++++++++ 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/aten/src/THNN/generic/MSECriterion.c b/aten/src/THNN/generic/MSECriterion.c index e236c8ea61c6d..b7c6e07d0d039 100644 --- a/aten/src/THNN/generic/MSECriterion.c +++ b/aten/src/THNN/generic/MSECriterion.c @@ -14,17 +14,17 @@ void THNN_(MSECriterion_updateOutput)( if (reduction != Reduction::None) { THTensor_(resize1d)(output, 1); - real sum = 0; + accreal sum = 0; TH_TENSOR_APPLY2(real, input, real, target, - real z = (*input_data - *target_data); + accreal z = (*input_data - *target_data); sum += z*z; ); if (reduction == Reduction::ElementwiseMean) sum /= THTensor_(nElement)(input); - THTensor_(set1d)(output, 0, sum); + THTensor_(set1d)(output, 0, (real)sum); return; } diff --git a/test/common_nn.py b/test/common_nn.py index ba161b39f0b2e..6172f4b15adc3 100644 --- a/test/common_nn.py +++ b/test/common_nn.py @@ -1087,6 +1087,7 @@ class CriterionTest(TestBase): def __init__(self, *args, **kwargs): super(CriterionTest, self).__init__(*args, **kwargs) self.should_test_cuda = kwargs.get('test_cuda', True) + self.check_forward_only = kwargs.get('check_forward_only', True) def _get_target(self): return self._get_arg('target', True) @@ -1109,6 +1110,9 @@ def __call__(self, test_case): expected_out = expected_out.item() test_case.assertEqual(out, expected_out) + if self.check_forward_only: + return + test_case.check_criterion_jacobian(module, input, target) self._do_extra_tests(test_case, module, input, target) diff --git a/test/test_nn.py b/test/test_nn.py index c2661c68654c4..f20c11fb3f1dc 100644 --- a/test/test_nn.py +++ b/test/test_nn.py @@ -5940,6 +5940,15 @@ def forward(self, *args): check_sum_reduction=True, desc='scalar' ), + dict( + module_name='MSELoss', + input_fn=lambda: torch.ones(5, 68, 64, 64, dtype=torch.float) / 10, + target_fn=lambda: torch.zeros(5, 68, 64, 64, dtype=torch.float), + reference_fn=lambda i, t, m: ((i - t).abs().pow(2).sum() / + (i.numel() if get_reduction(m) == 'elementwise_mean' else 1)), + check_forward_only=True, + desc='prec', + ), dict( module_name='BCELoss', constructor_args_fn=lambda: (torch.rand(()),), From b9f575fc33168d5867bdb990887c466e6669fcf9 Mon Sep 17 00:00:00 2001 From: Adam Paszke Date: Wed, 11 Jul 2018 10:22:00 -0700 Subject: [PATCH 17/36] Remove legacy code from the JIT (#9323) Summary: In particular, get rid of backward tracing and CppOp. Pull Request resolved: https://github.com/pytorch/pytorch/pull/9323 Reviewed By: ezyang Differential Revision: D8795935 Pulled By: apaszke fbshipit-source-id: fb7a7eeee41902da35f2a8efd77262ca60fd6bbe --- setup.py | 1 - test/expect/TestJit.test_assign_traces.expect | 8 - test/test_jit.py | 43 +-- tools/autograd/templates/Functions.h | 1 + torch/CMakeLists.txt | 1 - torch/csrc/autograd/function.cpp | 77 ---- torch/csrc/autograd/function.h | 16 - torch/csrc/autograd/functions/init.cpp | 4 - torch/csrc/autograd/functions/special.cpp | 348 ------------------ torch/csrc/autograd/functions/special.h | 103 ------ torch/csrc/jit/README.md | 22 -- torch/csrc/jit/export.cpp | 9 +- torch/csrc/jit/graph_executor.cpp | 1 + torch/csrc/jit/import.cpp | 1 - torch/csrc/jit/interned_strings.h | 1 - torch/csrc/jit/interpreter.cpp | 8 - torch/csrc/jit/interpreter.h | 2 - torch/csrc/jit/ir.cpp | 13 - torch/csrc/jit/ir.h | 30 -- .../common_subexpression_elimination.cpp | 1 - .../csrc/jit/passes/dead_code_elimination.cpp | 4 +- torch/csrc/jit/passes/lower_tuples.cpp | 2 +- torch/csrc/jit/passes/onnx.cpp | 35 +- torch/csrc/jit/python_interpreter.cpp | 2 - torch/csrc/jit/python_ir.cpp | 3 - torch/csrc/jit/python_tracer.cpp | 21 +- torch/csrc/jit/register_prim_ops.cpp | 22 -- torch/csrc/jit/script/compiler.cpp | 4 +- torch/csrc/jit/test_jit.cpp | 3 +- torch/csrc/jit/tracer.cpp | 97 ----- torch/csrc/jit/tracer.h | 42 +-- torch/csrc/jit/tracer_state.cpp | 34 +- torch/csrc/jit/tracer_state.h | 33 +- torch/csrc/jit/type.cpp | 6 - torch/csrc/jit/type.h | 33 -- torch/jit/__init__.py | 22 +- 36 files changed, 48 insertions(+), 1005 deletions(-) delete mode 100644 test/expect/TestJit.test_assign_traces.expect delete mode 100644 torch/csrc/autograd/functions/special.cpp delete mode 100644 torch/csrc/autograd/functions/special.h diff --git a/setup.py b/setup.py index 7c4bfac6c9d39..25bbc1c7f0f8e 100644 --- a/setup.py +++ b/setup.py @@ -825,7 +825,6 @@ def run(self): "torch/csrc/autograd/functions/basic_ops.cpp", "torch/csrc/autograd/functions/tensor.cpp", "torch/csrc/autograd/functions/accumulate_grad.cpp", - "torch/csrc/autograd/functions/special.cpp", "torch/csrc/autograd/functions/utils.cpp", "torch/csrc/autograd/functions/init.cpp", "torch/csrc/nn/THNN.cpp", diff --git a/test/expect/TestJit.test_assign_traces.expect b/test/expect/TestJit.test_assign_traces.expect deleted file mode 100644 index 5be283a8a78c5..0000000000000 --- a/test/expect/TestJit.test_assign_traces.expect +++ /dev/null @@ -1,8 +0,0 @@ -graph(%0 : Double(10, 10) - -------- stage 1 -------- - %1 : Double(10, 10!)) { - %2 : Double(10, 10) = ^MyFn()(%0) - ---------------- stage 1 ---------------- - %3 : Double(10, 10) = aten::mul(%2, %1) - return (%2, %3); -} diff --git a/test/test_jit.py b/test/test_jit.py index 06ccd7a0f38e3..c13f2d6e80b5a 100644 --- a/test/test_jit.py +++ b/test/test_jit.py @@ -72,11 +72,11 @@ def LSTMCell(input, hidden, w_ih, w_hh, b_ih=None, b_hh=None): ingate, forgetgate, cellgate, outgate = gates.chunk(4, 1) ingate = torch.sigmoid(ingate) forgetgate = torch.sigmoid(forgetgate) - cellgate = F.tanh(cellgate) + cellgate = torch.tanh(cellgate) outgate = torch.sigmoid(outgate) cy = (forgetgate * cx) + (ingate * cellgate) - hy = outgate * F.tanh(cy) + hy = outgate * torch.tanh(cy) return hy, cy @@ -297,7 +297,7 @@ def f(x, y): out = torch.sigmoid(out) return out - trace, z = torch.jit.get_trace_graph(f, (x, y), nderivs=0) + trace, z = torch.jit.get_trace_graph(f, (x, y)) self.assertExpectedGraph(trace) self.assertExportImport(trace, (x, y)) @@ -541,7 +541,7 @@ def fn(x, y): z = (x + y) * (x + y) * (x + y) + t return z - trace, _ = torch.jit.get_trace_graph(fn, (x, y), nderivs=0) + trace, _ = torch.jit.get_trace_graph(fn, (x, y)) self.run_pass('cse', trace) self.assertExpectedGraph(trace) self.assertExportImport(trace, (x, y)) @@ -553,7 +553,7 @@ def test_scalar(self): def fn(x, y): return x - y - trace, _ = torch.jit.get_trace_graph(fn, (x, y), nderivs=0) + trace, _ = torch.jit.get_trace_graph(fn, (x, y)) def test_shape_analysis_broadcast(self): def broadcast(a, b): @@ -579,27 +579,6 @@ def doit(x, y): ge = self.checkTrace(doit, (x, y)) self.assertExpectedGraph(ge.graph_for(x, y)) - def test_assign_traces(self): - """Check that output Variables are assigned traces before they are saved.""" - @traceable - class MyFn(Function): - @staticmethod - def forward(ctx, a): - out = a * 2 - ctx.save_for_backward(out) - return out - - @staticmethod - def backward(ctx, grad_a): - a, = ctx.saved_tensors - return a * grad_a - - x = torch.randn(10, 10, requires_grad=True) - trace, out = torch.jit.get_trace_graph(MyFn.apply, x, nderivs=1) - out.sum().backward() - self.run_pass('dce', trace) - self.assertExpectedGraph(trace) - # TODO: update verify to work with GraphExecutors @unittest.skip("verify needs to be updated to work with GraphExecutors") def test_verify(self): @@ -632,7 +611,7 @@ def backward(self, grad_output): x = torch.tensor([0.], requires_grad=True) with self.assertRaisesRegex(RuntimeError, "MyLegacyFn"): - torch.jit.get_trace_graph(lambda x: MyLegacyFn()(x), (x,), nderivs=0) + torch.jit.get_trace_graph(lambda x: MyLegacyFn()(x), (x,)) def test_inplace_transplant(self): x = torch.tensor([0.], requires_grad=True) @@ -643,7 +622,7 @@ def fn(x): y.add_(3) return y - trace, _ = torch.jit.get_trace_graph(fn, (x,), nderivs=0) + trace, _ = torch.jit.get_trace_graph(fn, (x,)) self.assertExpectedGraph(trace) self.assertExportImport(trace, (x,)) @@ -676,7 +655,7 @@ def fn(x): y = RegularFn.apply(y) return y - trace, _ = torch.jit.get_trace_graph(fn, (x,), nderivs=0) + trace, _ = torch.jit.get_trace_graph(fn, (x,)) self.run_pass('dce', trace) ops = [n for n in trace.graph().nodes()] for op in ops: @@ -864,7 +843,7 @@ def f(x): out.copy_(x) return out - trace, z = torch.jit.get_trace_graph(f, (x, ), nderivs=0) + trace, z = torch.jit.get_trace_graph(f, (x, )) self.run_pass('dce', trace) self.assertExpectedGraph(trace) self.assertExportImport(trace, (x,)) @@ -880,13 +859,13 @@ def forward(self, x): return x * self.a + self.b m = MyModule() - trace, _ = torch.jit.get_trace_graph(m, (torch.randn(2, 2),), nderivs=0) + trace, _ = torch.jit.get_trace_graph(m, (torch.randn(2, 2),)) self.assertEqual(len(list(trace.graph().inputs())), 2) self.assertExpectedGraph(trace) def test_nested_inplace(self): x = torch.randn(2, 2) - trace, _ = torch.jit.get_trace_graph(lambda x: F.threshold(x, 0, 0, inplace=True), (x,), nderivs=0) + trace, _ = torch.jit.get_trace_graph(lambda x: F.threshold(x, 0, 0, inplace=True), (x,)) self.assertExpectedGraph(trace) self.assertExportImport(trace, (x,)) diff --git a/tools/autograd/templates/Functions.h b/tools/autograd/templates/Functions.h index 6532a5f317d9f..7f3e5f9c05509 100644 --- a/tools/autograd/templates/Functions.h +++ b/tools/autograd/templates/Functions.h @@ -8,6 +8,7 @@ #include "torch/csrc/autograd/function.h" #include "torch/csrc/autograd/variable.h" #include "torch/csrc/autograd/saved_variable.h" +#include "torch/csrc/utils/functional.h" namespace torch { namespace autograd { namespace generated { diff --git a/torch/CMakeLists.txt b/torch/CMakeLists.txt index cd8d5cefebc8e..25be2397e4706 100644 --- a/torch/CMakeLists.txt +++ b/torch/CMakeLists.txt @@ -201,7 +201,6 @@ set(TORCH_SRCS ${TORCH_SRC_DIR}/csrc/autograd/function.cpp ${TORCH_SRC_DIR}/csrc/autograd/input_buffer.cpp ${TORCH_SRC_DIR}/csrc/autograd/functions/utils.cpp - ${TORCH_SRC_DIR}/csrc/autograd/functions/special.cpp ${TORCH_SRC_DIR}/csrc/autograd/functions/basic_ops.cpp ${TORCH_SRC_DIR}/csrc/autograd/functions/accumulate_grad.cpp ${TORCH_SRC_DIR}/csrc/autograd/functions/tensor.cpp diff --git a/torch/csrc/autograd/function.cpp b/torch/csrc/autograd/function.cpp index 1edd55720d81e..af5e410686c7f 100644 --- a/torch/csrc/autograd/function.cpp +++ b/torch/csrc/autograd/function.cpp @@ -1,7 +1,6 @@ #include "torch/csrc/autograd/function.h" #include "torch/csrc/autograd/engine.h" -#include "torch/csrc/autograd/functions/special.h" #include "torch/csrc/autograd/variable.h" #include "torch/csrc/jit/ir.h" @@ -24,82 +23,6 @@ auto Function::name() const -> std::string { return at::demangle(typeid(*this).name()); } -// This function is analogous to make_trace which operates on PythonOp, but this -// function instead works for C++ implemented autograd Functions, which don't -// actually have any backing Python class. We still need to trace them! -variable_list Function::traced_apply(variable_list inputs) { - using namespace torch::jit; - // Traceable Functions are completely transparent to the JIT. - if (is_traceable()) { - return apply(inputs); - } - auto state = tracer::getTracingState(inputs); - auto state_lock = state->lock(); - - // Insert a CppOp in the trace. - auto& graph = state->graph; - auto* this_node = graph->createCppOp(get_shared_ptr()); - jit::tracer::recordSourceLocation(this_node); - for (auto& input: inputs) { - this_node->addInput(tracer::getValueTrace(state, input)); - } - graph->appendNode(this_node); - - // Finally apply this Function. - state_lock.unlock(); - variable_list outputs = apply(inputs); - state_lock.lock(); - - // Set up output traces. - int num_outputs = outputs.size(); - for (int i = 0; i < num_outputs; ++i) { - auto& output = outputs[i]; - auto sel = this_node->addOutput(); - // TODO: At the moment, C++ does not track shared storage. It - // should. Update this when that happens. - if (output.defined()) { - sel->inferTypeFrom(output.data()); - tracer::setValueTrace(state, output, sel); - } - } - - if (!passes_state_transparently()) { - auto this_eval = dynamic_cast(this); - // Evals consume handle from a context edge of forward node - if (this_eval) - this_node->addInput(this_eval->forward_ctx_select); - // There's no point in wrapping functions in Eval, if we know they already are - // part of another Eval subgraph. This is both a small optimization, and - // it allows us to not implement saved_variables() in many functions. - const bool should_trace_backward = tracing_state_->in_eval_subgraph; - if (!should_trace_backward) { - auto saved_vars = saved_variables(); - if (!saved_vars) - throw std::runtime_error("saved_variables() needed but not implemented in " + name()); - variable_list bw_subgraph_inputs(inputs); - for (auto& saved_var : *saved_vars) { - bw_subgraph_inputs.emplace_back(saved_var.unpack(get_shared_ptr())); - } - tracer::nontraceableBackwardSubgraph(bw_subgraph_inputs, outputs); - } - bool has_backwards_eval = !should_trace_backward || this_eval; - if (has_backwards_eval) - set_up_context_edge(this_node, inputs, outputs); - } - return outputs; -} - -void Function::set_up_context_edge( - jit::Node* this_node, - const variable_list& inputs, - const variable_list& outputs) { - auto ctx_select = this_node->addOutput(); - ctx_select->setType(jit::HandleType::get()); - auto backward_eval = Eval::getBackwardEval(inputs, outputs); - if (backward_eval) - backward_eval->forward_ctx_select = ctx_select; -} - AnomalyMetadata* Function::metadata() noexcept { if (!anomaly_metadata_) { anomaly_metadata_ = Engine::get_default_engine().make_anomaly_metadata(); diff --git a/torch/csrc/autograd/function.h b/torch/csrc/autograd/function.h index 0753ef9192fba..f610fd2326454 100644 --- a/torch/csrc/autograd/function.h +++ b/torch/csrc/autograd/function.h @@ -8,7 +8,6 @@ #include "torch/csrc/autograd/saved_variable.h" #include "torch/csrc/autograd/type_and_shape.h" #include "torch/csrc/autograd/variable.h" -#include "torch/csrc/jit/tracer.h" #include "torch/csrc/utils/auto_unique_ptr.h" #include "torch/csrc/utils/python_stub.h" #include "torch/csrc/utils/variadic.h" @@ -117,9 +116,6 @@ struct Function : std::enable_shared_from_this { /// function call. variable_list operator()(const variable_list& inputs) { profiler::RecordFunction rec(this); - if (jit::tracer::isTracingVar(inputs)) { - return traced_apply(inputs); - } return apply(inputs); } @@ -225,11 +221,6 @@ struct Function : std::enable_shared_from_this { }); } - jit::tracer::FunctionTracingState& tracing_state() noexcept { - // Dereferencing will create the `TracingState` if the pointer is empty. - return *tracing_state_; - } - /// Returns the `PyObject` stored for this `Function` (for Python /// interaction). PyObject* pyobj() const noexcept { @@ -245,12 +236,6 @@ struct Function : std::enable_shared_from_this { /// If none exist, creates a new empty one. AnomalyMetadata* metadata() noexcept; - /// Create a context edge for the JIT. - static void set_up_context_edge( - jit::Node* this_node, - const variable_list& inputs, - const variable_list& outputs); - // Hook API //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -341,7 +326,6 @@ struct Function : std::enable_shared_from_this { std::unique_ptr anomaly_metadata_ = nullptr; std::vector> pre_hooks_; std::vector> post_hooks_; - auto_unique_ptr tracing_state_; at::SmallVector input_metadata_; }; diff --git a/torch/csrc/autograd/functions/init.cpp b/torch/csrc/autograd/functions/init.cpp index b2512e1199c41..5b4523a3a2513 100644 --- a/torch/csrc/autograd/functions/init.cpp +++ b/torch/csrc/autograd/functions/init.cpp @@ -2,7 +2,6 @@ #include "accumulate_grad.h" #include "basic_ops.h" #include "tensor.h" -#include "special.h" #include "torch/csrc/autograd/functions/pybind.h" #include "torch/csrc/autograd/python_cpp_function.h" #include "torch/csrc/autograd/generated/python_functions.h" @@ -95,9 +94,6 @@ void THPAutograd_initFunctions() static PyTypeObject DelayedErrorClass; addClass(module, DelayedErrorClass, "DelayedError"); - static PyTypeObject EvalClass; - addClass(module, EvalClass, "Eval"); - static PyTypeObject CopyBackwardsClass; addClass(module, CopyBackwardsClass, "CopyBackwards"); diff --git a/torch/csrc/autograd/functions/special.cpp b/torch/csrc/autograd/functions/special.cpp deleted file mode 100644 index 88ac969122b78..0000000000000 --- a/torch/csrc/autograd/functions/special.cpp +++ /dev/null @@ -1,348 +0,0 @@ -#include "torch/csrc/autograd/functions/special.h" - -#include "torch/csrc/assertions.h" -#include "torch/csrc/autograd/engine.h" -#include "torch/csrc/autograd/edge.h" -#include "torch/csrc/autograd/function.h" - -#include -#include -#include -#include -#include -#include // for swap - -namespace torch { namespace autograd { - -// Used when an output has multiple uses (there's only one entry -// in next_edges per output). -struct Replicate : public Function { - Replicate(const at::Type& type, at::IntList shape) : Function() { - add_input_metadata(type, shape); - } - - virtual variable_list apply(const variable_list& inputs) { - TORCH_ASSERT(inputs.size() == 1); - return variable_list(num_outputs(), inputs[0]); - } -}; - -// Note [Null-edge pruning] -// Evals have a problem with null edges appearing in the graph, because there's -// no way to tell the identity of the input (i.e. each nullptr might have been -// a different input, all of them might have been a single input, etc.). -// However, null edges are generally quite useless, so we can safely prune them, -// by removing them from next_edges of Eval node and never allocating -// placeholders for them. This is a bit annoying because backward subgraphs may -// have many less outputs than forward graph had inputs, but I don't think there's -// a way around it. It's a tiny perf optimization too :) - -// There's some subtlety involved in computing backwards of Eval functions, -// because sometimes we need to inherit placeholders. There are two situations -// in which it can happen: -// 1. One of the nodes in subgraph saved a Variable, that has a grad_fn that was -// moved into the interior of the subgraph. Thus, if we were to traverse the -// graph from an output created when using this Variable, we would end up in -// one of the placeholders. We don't want this to happen, so we'll inherit it -// and include the whole subgraph saved grad_fn in this Eval node too (they -// will be shared, which is ok, because they're immutable at this point). -// 2. One of the nodes in subgraph saved a Variable, that has a grad_fn that -// points to a node outside of the subgraph (it's grad_fn of one of subgraph's -// inputs). In this situation, the previous subgraph must have had a placeholder -// for this input, and we should inherit it as well. -// INVARIANT: all outputs are relevant. -auto Eval::getSubgraph(const variable_list& inputs, const variable_list& outputs, - const placeholder_list& inherited_placeholders) -> Subgraph { - Subgraph subgraph; - std::unordered_set> extra_placeholders; - - // Prepare a set of all edges that shouldn't be followed during the search - edge_set input_edges; - input_edges.reserve(inputs.size()); - for (auto & input : inputs) { - if (!input.defined()) continue; - input_edges.emplace(input.gradient_edge()); - } - - // This is used to stop the search in situation 2 and find the corresponding placeholders. - std::unordered_map> inherited_edges; - inherited_edges.reserve(inherited_placeholders.size()); - for (auto & placeholder : inherited_placeholders) { - input_edges.emplace(placeholder->next_edge); - inherited_edges.emplace(placeholder->next_edge, placeholder); - } - - // Regular DFS data structures - std::unordered_set seen; - std::vector queue; - for (auto & output : outputs) { - auto ptr = output.grad_fn().get(); - bool unseen = seen.emplace(ptr).second; - if (unseen) - queue.emplace_back(ptr); - } - - while (!queue.empty()) { - auto fn = queue.back(); queue.pop_back(); - JIT_ASSERT(fn); - fn->tracing_state().in_eval_subgraph = true; - const auto num_outputs = fn->num_outputs(); - for (size_t i = 0; i < num_outputs; ++i) { - const auto& edge = fn->next_edge(i); - if (!edge.function) continue; // See Note [Null-edge pruning] - // Edge belongs to subgraph boundary. Register that and don't search along it. - if (input_edges.count(edge) > 0) { - subgraph.boundary.begins.emplace(fn->get_shared_ptr(), i); - subgraph.boundary.ends.emplace(edge); - auto it = inherited_edges.find(edge); - // Situation 2. If that edge is actually pointing to an earlier stage subgraph, - // we'll also need to inherit its placeholder. - if (it != inherited_edges.end()) { - extra_placeholders.emplace(it->second); - } - continue; - } - // Situation 1. If we end up in a placeholder, we need to inherit it. - if (auto placeholder = std::dynamic_pointer_cast(edge.function)) { - extra_placeholders.emplace(placeholder); - subgraph.boundary.ends.emplace(placeholder->next_edge); - continue; - } - bool unseen = seen.emplace(edge.function.get()).second; - if (unseen) - queue.emplace_back(edge.function.get()); - } - } - - // Initially fill placeholders with those that we'll need to inherit. - for (auto & placeholder : extra_placeholders) - placeholders.emplace_back(placeholder); - return subgraph; -} - -bool Eval::trySimpleEval(const variable_list& inputs, const variable_list& outputs, - const placeholder_list& inherited_placeholders) { - using bitset_type = uint64_t; - constexpr size_t max_outputs = sizeof(bitset_type) * 8; - - if (inherited_placeholders.size() != 0) return false; - - auto& grad_fn = outputs[0].grad_fn(); - if (static_cast(grad_fn->num_inputs()) >= max_outputs) return false; - if (static_cast(grad_fn->num_inputs()) != outputs.size()) return false; - - // Check that all outputs have the same grad_fn and cover all its inputs - bitset_type output_nrs = 0; - bitset_type expected_bitset = ((1 << grad_fn->num_inputs()) - 1); - for (auto & output : outputs) { - if (output.grad_fn() != grad_fn) return false; - output_nrs |= (1 << output.output_nr()); - } - if (output_nrs != expected_bitset) return false; - - // Check that grad_fn's next_edges match the inputs exactly. - auto num_inputs = inputs.size(); - if (num_inputs != grad_fn->num_outputs()) return false; - for (size_t i = 0; i < num_inputs; ++i) { - const auto& next_grad_edge = grad_fn->next_edge(i); - // Unfortunately, null edge pruning (see Note [Null-edge pruning]) applies - // to autograd functions which would otherwise be eligible for the - // SimpleEval optimization. This makes everything more complicated, so for - // now we just don't attempt the optimization in this case. To fix it - // properly, we'd need to filter grad_fn's output edges and outputs of - // apply in Eval::apply. The check below tests if null edge pruning - // occurred. - if (!inputs[i].defined() || !next_grad_edge.is_valid()) return false; - if (next_grad_edge != inputs[i].gradient_edge()) return false; - } - - // Success! We still need to set up placeholders for next stages and to drop - // references to the graph. - std::swap(next_edges_, grad_fn->next_edges()); - grad_fn->next_edges().reserve(num_inputs); - placeholders.reserve(num_inputs); - for (const auto& input : next_edges_) { - auto placeholder = std::make_shared(input); - grad_fn->add_next_edge({placeholder, 0}); - placeholders.emplace_back(std::move(placeholder)); - } - simple_graph = grad_fn; - grad_fn->tracing_state().in_eval_subgraph = true; - return true; -} - - -// Here, a _relevant_ output is one that has a grad_fn (is not a leaf and is not -// volatile) and is not one of the inputs (can happen because of passthrough). -variable_list Eval::filterRelevantOutputs(const variable_list& inputs, const variable_list& outputs) { - variable_list relevant_outputs; - relevant_outputs.reserve(outputs.size()); - edge_set ignored_grad_fns; - ignored_grad_fns.reserve(inputs.size()); - for (auto& input : inputs) { - if (!input.defined()) continue; - ignored_grad_fns.insert(input.gradient_edge()); - } - for (auto& output : outputs) { - if (!output.defined()) continue; - if (!output.grad_fn()) continue; - if (ignored_grad_fns.count(output.gradient_edge()) > 0) continue; - relevant_outputs.emplace_back(output); - } - return relevant_outputs; -} - -auto Eval::computeInputOrder(const variable_list& inputs, const placeholder_list& inherited_placeholders) -> edge_order { - edge_order input_order; - int idx = 0; - for (auto & input : inputs) { - if (!input.defined()) continue; - input_order.emplace(input.gradient_edge(), idx++); - } - for (auto & placeholder : inherited_placeholders) - input_order.emplace(placeholder->next_edge, idx++); - return input_order; -} - -bool Eval::replaceSubgraph(const variable_list& inputs, const variable_list& _outputs, - const placeholder_list& inherited_placeholders) { - // _outputs has a prefix deliberately, because it's unlikely that anything else - // than relevant_outputs will be needed inside this function. - // TODO: it would be useful to unpack inputs to their grad_fn/grad_accumulators to avoid - // all these ternary operators in functions above - variable_list relevant_outputs = filterRelevantOutputs(inputs, _outputs); - - if (relevant_outputs.size() == 0) - return false; - - if (!trySimpleEval(inputs, relevant_outputs, inherited_placeholders)) { - roots.reserve(relevant_outputs.size()); - for (auto & output : relevant_outputs) - roots.push_back(output.gradient_edge()); - - auto subgraph = getSubgraph(inputs, relevant_outputs, inherited_placeholders); - - // Prepare output placeholder nodes for each end. - std::unordered_map> ends_to_outputs; - for (auto & placeholder : placeholders) { - ends_to_outputs[placeholder->next_edge] = placeholder; - } - for (auto & end : subgraph.boundary.ends) { - if (ends_to_outputs.count(end) == 0) { - placeholders.emplace_back(std::make_shared(end)); - ends_to_outputs[end] = placeholders.back(); - } - } - - // Replace begins with pointers to output nodes. - // This detaches the subgraph from the full backward graph. - for (auto& begin : subgraph.boundary.begins) { - const auto& edge = begin.function->next_edge(begin.input_nr); - - begin.function->set_next_edge( - begin.input_nr, Edge(ends_to_outputs.at(edge), 0)); - } - - // Replace subgraph with this node. - next_edges_.insert(next_edges_.begin(), subgraph.boundary.ends.begin(), subgraph.boundary.ends.end()); - - // Ensure placeholders and inputs are sorted in the same way. - edge_order input_order = computeInputOrder(inputs, inherited_placeholders); - std::sort(next_edges_.begin(), next_edges_.end(), [&input_order](const Edge &a, const Edge &b) { - return input_order.at(a) < input_order.at(b); - }); - std::sort(placeholders.begin(), placeholders.end(), [&input_order](const std::shared_ptr &a, const std::shared_ptr &b) { - return input_order.at(a->next_edge) < input_order.at(b->next_edge); - }); - } - - // Rebase outputs. - auto this_shared = shared_from_this(); - std::unordered_set repeated_outputs; - // NB: every output can be in 3 states: - // - unique so far - only the else of second if is taken - // - repeated first time - first if + first branch of second if - // - repeated many times - first branch of second if only - for (auto & output : relevant_outputs) { - // This output is already rebased. This happens when there - // the same Variable has been returned multiple times, and - // is repeated in this list. - if (output.grad_fn_unsafe() == this) { - auto replicate = std::make_shared(output.type(), output.sizes()); - replicate->add_next_edge({this_shared, output.output_nr()}); - output.set_gradient_edge({std::move(replicate), 0}); - repeated_outputs.emplace(&output); - } - // NOTE: this check should be fairly cheap, and the set shouldn't - // perform any allocations until we actually see repeated outputs. - if (repeated_outputs.count(&output) > 0) { - auto & replicate = output.grad_fn(); - auto input_nr = add_input_metadata(output.type(), output.sizes()); - replicate->add_next_edge({this_shared, input_nr}); - } else { - autograd::create_gradient_edge(output, this_shared); - } - } - - return true; -} - -variable_list Eval::apply(const variable_list& inputs) { - variable_list outputs; - if (simple_graph) { - outputs = (*simple_graph)(inputs); - } else { - auto& engine = Engine::get_default_engine(); - auto exec_data = filterRoots(inputs); - auto next_edges = fmap( - placeholders, - [](const std::shared_ptr& o) { return Edge(o, 0); }); - outputs = engine.execute(exec_data.first, exec_data.second, true, true, next_edges); - } - - auto bw_eval = newEval(); - bw_eval->replaceSubgraph(inputs, outputs, placeholders); - - // This will prevent Function::traced_apply from marking the backward subgraph as non-traceable. - // This node already does it (backward of non-traceable backward is implicitly non-traceable), - // and it passes more information (backward Eval may inherit placeholders) than - // Function::traced_apply has available. - tracing_state_->in_eval_subgraph = true; - - return outputs; -} - -// TODO: once we clean up the stochastic function mess it should be possible to ignore -// nullptr inputs in the Engine (it implies that the Variables is 0, so the jacobian vector -// product will be all zero too). -std::pair Eval::filterRoots(const variable_list& inputs) { - variable_list filtered_inputs; - edge_list filtered_roots; - auto num_inputs = inputs.size(); - if (roots.size() != num_inputs) - throw std::logic_error("inputs.size() != roots.size()"); - filtered_inputs.reserve(num_inputs); - filtered_roots.reserve(num_inputs); - for (size_t i = 0; i < num_inputs; ++i) { - // This check is the sole reason why this function is needed. The problem - // with larger Evals is that they might trigger computation of nodes that - // would normally be ignored. For example, consider a subgraph with multiple - // outputs and a backprop from a Variable that's derived from only one of - // them. This line prevents us from unnecessarily executing, and thus recording, - // nodes in the trace which are unrelated to this Variable. - // - // If we didn't filter out roots that only get nullptr outputs, we would then - // pass nullptr inputs to roots that are executable. Then, the engine would - // discover them and would unnecessarily run a computation that doesn't contribute - // to the overall grad and would complicate the trace. - // If the node gets only nullptr inputs, it's guaranteed that - // the grad of its output w.r.t. anything is 0, so it is sound to just - // skip the computation entirely. - if (!inputs[i].defined()) continue; - filtered_inputs.emplace_back(inputs[i]); - filtered_roots.emplace_back(roots[i]); - } - return std::make_pair(std::move(filtered_roots), std::move(filtered_inputs)); -} - -}} // namespace torch::autograd diff --git a/torch/csrc/autograd/functions/special.h b/torch/csrc/autograd/functions/special.h deleted file mode 100644 index 273b139e23878..0000000000000 --- a/torch/csrc/autograd/functions/special.h +++ /dev/null @@ -1,103 +0,0 @@ -#pragma once - -#include "torch/csrc/autograd/function.h" -#include "torch/csrc/autograd/variable.h" -#include "torch/csrc/autograd/engine.h" - -#include -#include -#include -#include -#include -#include - -namespace torch { namespace autograd { - -struct EvalOutput : Function { - explicit EvalOutput(const Edge& next_edge_) - : Function(), next_edge(next_edge_) { - add_input_metadata(undefined_input()); - } - - virtual variable_list apply(const variable_list& inputs) override { - throw std::logic_error("EvalOutput::apply() called"); - } - - Edge next_edge; -}; - -struct Eval : Function { - using edge_set = std::unordered_set; - using edge_order = std::unordered_map; - using placeholder_list = std::vector>; - - // This struct has only one member, but it's useful to e.g. add a set of all - // nodes when debugging this stuff, so I'm leaving it as is. - struct Subgraph { - struct Boundary { - // All nodes from within the subgraph that connect to the outside. - // These are the places that will need to be patched to point to placeholders. - // Contains pairs of (fn, offset into next_edges). - edge_set begins; - // All nodes that are not in the subgraph, but are in the union of - // next_edges of all nodes from the subgraph. These are the places that - // will be modeled by placeholders. - // Contains pairs of (fn, input_nr) and is equivalent to next_edges - // of an Eval node that will replace the subgraph. - edge_set ends; - }; - - Boundary boundary; - }; - - virtual ~Eval() {} - - virtual inline bool is_traceable() final { return traceable; } - - virtual variable_list apply(const variable_list& inputs) override; - - bool replaceSubgraph( - const variable_list& inputs, - const variable_list& outputs, - const placeholder_list& inherited_placeholders = placeholder_list()); - - static variable_list filterRelevantOutputs(const variable_list& inputs, const variable_list& outputs); - edge_order computeInputOrder(const variable_list& inputs, const placeholder_list& inherited_placeholders); - - static std::shared_ptr getBackwardEval(const variable_list& inputs, const variable_list& outputs) { - auto relevant_outputs = filterRelevantOutputs(inputs, outputs); - if (relevant_outputs.size() == 0) - return nullptr; - return std::dynamic_pointer_cast(relevant_outputs[0].grad_fn()); - } - - virtual std::shared_ptr newEval() { - return std::make_shared(); - } - - // Roots are empty if simple_graph is not nullptr. - // simple_graph is an optimization of first backward stage - in this case - // all Eval subgraphs contain only a single gradient function, and the - // graph search on creation + call to the engine in apply can be elided - edge_list roots; - std::shared_ptr simple_graph; - - placeholder_list placeholders; - jit::Value* forward_ctx_select = nullptr; - bool traceable = false; - -private: - std::pair filterRoots(const variable_list& inputs); - - Subgraph getSubgraph( - const variable_list& inputs, - const variable_list& outputs, - const placeholder_list& inherited_placeholders); - - bool trySimpleEval( - const variable_list& inputs, - const variable_list& outputs, - const placeholder_list& inherited_placeholders); -}; - -}} // namespace torch::autograd diff --git a/torch/csrc/jit/README.md b/torch/csrc/jit/README.md index 789491994818c..02b4be87c02b2 100644 --- a/torch/csrc/jit/README.md +++ b/torch/csrc/jit/README.md @@ -70,25 +70,3 @@ other well-known functions which are specific to PyTorch. * **input**: 1 - ∞ (same as inputs of Subgraph) * **output**: 1 - ∞ (same as outputs of Subgraph) - -* **Eval** (renders as `CppOp[N5torch8autograd4EvalE]`) - - An Eval node takes some inputs, and an autograd closure `Handle`. It applies - those inputs to the autograd closure, and returns the results of having - executed the closure. An Eval node is primarily used to implement backwards - operations for black box forward operations: because the backwards computation - of a black box forwards is not known until we actually execute the forward - operation, we have to run the forward computation, giving us an autograd - closure to compute backwards, and then run it later when we actually - execute backwards. - - * **input**: -
-
Input1, Input2, ...
-
Any number of inputs, which will be passed as inputs to the - autograd closure
-
Handle
-
An autograd closure (opaquely represented with type `Handle` in our - IR) which specifies how to execute the operation.)
-
- * **output**: 1 - ∞ (same as outputs of autograd closure) diff --git a/torch/csrc/jit/export.cpp b/torch/csrc/jit/export.cpp index aed47f3474d8a..f1283da1f44b8 100644 --- a/torch/csrc/jit/export.cpp +++ b/torch/csrc/jit/export.cpp @@ -337,17 +337,12 @@ void validateGraph(const std::shared_ptr& graph, onnx::OperatorExportType // Macro'ed so we get a marginally better line number on failed export #define FAIL_EXPORT(name) \ throw std::runtime_error(std::string("ONNX export failed: ") + name + "\n\nGraph we tried to export:\n" + graph->toString()); - IR_IF(node, CppOp) - auto cpp_node = static_cast(value); - FAIL_EXPORT( - "Couldn't export C++ operator " + cpp_node->name() + - "\n\nDefined at:\n" + getNodeStackTraceString(node)) - IR_ELSEIF(PythonOp) + IR_IF(node, PythonOp) auto py_node = static_cast(value); FAIL_EXPORT( "Couldn't export Python operator " + py_node->name() + "\n\nDefined at:\n" + getNodeStackTraceString(node)) - IR_ELSE() + IR_ELSE() // Special error messages for certain types of operators if (node->kind() == aten::expand) { FAIL_EXPORT( diff --git a/torch/csrc/jit/graph_executor.cpp b/torch/csrc/jit/graph_executor.cpp index 6602fa6da97f7..e2e46b639d287 100644 --- a/torch/csrc/jit/graph_executor.cpp +++ b/torch/csrc/jit/graph_executor.cpp @@ -5,6 +5,7 @@ #include "torch/csrc/jit/autodiff.h" #include "torch/csrc/jit/interpreter.h" #include "torch/csrc/jit/ir.h" +#include "torch/csrc/jit/tracer.h" #include "torch/csrc/jit/passes/batch_mm.h" #include "torch/csrc/jit/passes/common_subexpression_elimination.h" #include "torch/csrc/jit/passes/create_autodiff_subgraphs.h" diff --git a/torch/csrc/jit/import.cpp b/torch/csrc/jit/import.cpp index 797ab2b3b9306..75eca1e2d062f 100644 --- a/torch/csrc/jit/import.cpp +++ b/torch/csrc/jit/import.cpp @@ -431,7 +431,6 @@ void buildBlock(const Graph_& graph_, Block* block, } for (auto & node_ : graph_.nodes) { - TORCH_ASSERT(node_.op_type != "CppOp"); TORCH_ASSERT(node_.op_type != "PythonOp"); auto node = block->owningGraph()->create(Symbol::fromDomainAndUnqualString(node_.domain, node_.op_type), diff --git a/torch/csrc/jit/interned_strings.h b/torch/csrc/jit/interned_strings.h index b3a4d70d7d1d9..a4a73eb8f2484 100644 --- a/torch/csrc/jit/interned_strings.h +++ b/torch/csrc/jit/interned_strings.h @@ -18,7 +18,6 @@ _(namespaces, scope) \ _(namespaces, namespaces) \ _(prim, Assign) \ _(prim, Constant) \ -_(prim, CppOp) \ _(prim, Drop) \ _(prim, Eval) \ _(prim, Expand) /* onnx */ \ diff --git a/torch/csrc/jit/interpreter.cpp b/torch/csrc/jit/interpreter.cpp index d582f80a6fb2e..1fb82c9035952 100644 --- a/torch/csrc/jit/interpreter.cpp +++ b/torch/csrc/jit/interpreter.cpp @@ -2,7 +2,6 @@ #include "torch/csrc/autograd/edge.h" #include "torch/csrc/autograd/function.h" -#include "torch/csrc/autograd/functions/special.h" #include "torch/csrc/autograd/profiler.h" #include "torch/csrc/autograd/variable.h" #include "torch/csrc/jit/fusion_compiler.h" @@ -365,13 +364,6 @@ struct ContainerTensor : public at::TensorImpl { } }; -bool hasHandleOutput(Node * n) { - if(n->outputs().size() == 0) - return false; - auto & last = n->outputs().back(); - return last->isHandle() && last->uses().size() > 0; // don't bother creating a handle if it is never used -} - // We need some lists for inputs and outputs. To keep all the memory // contiguous we allocate a single vector and use offsets into the vector // which are stored in the ListHandle struct diff --git a/torch/csrc/jit/interpreter.h b/torch/csrc/jit/interpreter.h index b6c9238e15cc9..0bd8a2891a18b 100644 --- a/torch/csrc/jit/interpreter.h +++ b/torch/csrc/jit/interpreter.h @@ -55,6 +55,4 @@ struct InterpreterState { std::shared_ptr pImpl; }; -bool hasHandleOutput(Node * n); - }} diff --git a/torch/csrc/jit/ir.cpp b/torch/csrc/jit/ir.cpp index fe9bf75fc23f5..a340ddec6fc23 100644 --- a/torch/csrc/jit/ir.cpp +++ b/torch/csrc/jit/ir.cpp @@ -14,7 +14,6 @@ namespace torch { namespace jit { // Sigh, see https://stackoverflow.com/questions/8016780/undefined-reference-to-static-constexpr-char -constexpr Symbol CppOp::Kind; constexpr Symbol PythonOp::Kind; constexpr int max_tensor_display_size = 10; @@ -40,10 +39,6 @@ std::ostream& operator<<(std::ostream & out, const at::ArrayRef & nodes) { return out; } -std::string CppOp::name() const { - return fn->name(); -} - struct const_value_list_with_types { const std::vector& values; bool use_newlines; @@ -169,8 +164,6 @@ std::ostream& printNode(std::ostream & out, size_t level, const Node * n, std::v IR_IFM_CONST(n,PythonOp) out << "^" << value->name(); value->writeScalars(out); - IR_ELSEIFM_CONST(CppOp) - out << "CppOp[" << value->name() << "]"; IR_ELSE() if(n->hasAttribute(attr::Subgraph) && groups) { out << n->kind().toQualString() << "_" << groups->size(); @@ -289,10 +282,6 @@ void Node::lint() const { JIT_ASSERT(std::find(ALL_OF(input->uses_), Use(const_cast(this), i)) != input->uses_.end()); JIT_ASSERT(stage_ >= input->stage_); JIT_ASSERT(graph_->all_nodes.count(this) == 1); - // Handle invariant - if (i != inputs_.size() - 1) { - JIT_ASSERT(input->type()->kind() != TypeKind::HandleType); - } i++; } } @@ -334,8 +323,6 @@ void Node::lint() const { } JIT_ASSERT(n_scalars == value->scalar_args.size()); JIT_ASSERT(n_tensors == inputs_.size()); - IR_ELSEIFM_CONST(CppOp) - // TODO: add invariants IR_ELSEIF(Eval) // TODO: add invariants // TODO: It's not good for these ops to be top-level, it makes cases longer. diff --git a/torch/csrc/jit/ir.h b/torch/csrc/jit/ir.h index bcd73c84d8598..815a7862550f6 100644 --- a/torch/csrc/jit/ir.h +++ b/torch/csrc/jit/ir.h @@ -189,9 +189,6 @@ struct Value { JIT_ASSERT(type_ != nullptr); return type_; } - bool isHandle() const { - return type()->kind() == TypeKind::HandleType; - } bool isTensor() const { return type()->kind() == TypeKind::TensorType; } @@ -978,7 +975,6 @@ friend struct Block; THPObjectPtr&& pyobj, const std::string& cconv, pyobj_list&& scalar_args); - Node * createCppOp(const std::shared_ptr & fn); // clone n, making a new node in _this_ graph. // use node_map to translate inputs of n to inputs of the cloned node // if copy_blocks is false, it will not recursively clone the nested blocks @@ -1310,32 +1306,6 @@ inline Node* Graph::createPythonOp( std::move(scalar_args)); } -// A Cpp operator is an operator which dispatches directly to an autograd function. -// TODO: These are not executable without reentrant engine. -struct CppOp : public Node { - static constexpr Symbol Kind = prim::CppOp; - CppOp(Graph * g) - : Node(g,prim::CppOp) {} - std::shared_ptr fn; - std::string name() const; - CppOp* init(std::shared_ptr fn) { - JIT_ASSERT(fn); - this->fn = std::move(fn); - return this; - } - virtual Node * allocNewInstance(Graph * g) override { - return new CppOp(g); - } - virtual void cloneFrom(Node * other_) override { - Node::cloneFrom(other_); - auto other = other_->cast(); - this->fn = other->fn; - } -}; -inline Node * Graph::createCppOp(const std::shared_ptr & fn) { - auto op = new CppOp(this); - return op->init(fn); -} inline graph_node_list_iterator Node::iterator() { return graph_node_list_iterator(this, 0); diff --git a/torch/csrc/jit/passes/common_subexpression_elimination.cpp b/torch/csrc/jit/passes/common_subexpression_elimination.cpp index d9c75e134d0a9..f6164024f2365 100644 --- a/torch/csrc/jit/passes/common_subexpression_elimination.cpp +++ b/torch/csrc/jit/passes/common_subexpression_elimination.cpp @@ -117,7 +117,6 @@ void EliminateCommonSubexpression(Block * block) { for (auto it = block->nodes().begin(); it != block->nodes().end(); ++ it) { auto node = *it; if (node->kind() == prim::PythonOp - || node->kind() == prim::CppOp || node->kind() == prim::Eval || node->blocks().size() > 0 ) { diff --git a/torch/csrc/jit/passes/dead_code_elimination.cpp b/torch/csrc/jit/passes/dead_code_elimination.cpp index 2db4971617a3e..d8341cbb99c6a 100644 --- a/torch/csrc/jit/passes/dead_code_elimination.cpp +++ b/torch/csrc/jit/passes/dead_code_elimination.cpp @@ -7,8 +7,8 @@ namespace torch { namespace jit { using bool_memo_type = std::unordered_map; bool hasSideEffects(Node * node, bool_memo_type& memo) { - // FIXME: PythonOp and CppOp should be treated as having side effects as well! - // Unfortunately ONNX depends on them getting removed in this pass, so it's not + // FIXME: PythonOp should be treated as having side effects as well! + // Unfortunately ONNX depends on it getting removed in this pass, so it's not // a simple change. auto it = memo.find(node); if (it != memo.end()) diff --git a/torch/csrc/jit/passes/lower_tuples.cpp b/torch/csrc/jit/passes/lower_tuples.cpp index 981fbf5690fc3..49b9c99641db3 100644 --- a/torch/csrc/jit/passes/lower_tuples.cpp +++ b/torch/csrc/jit/passes/lower_tuples.cpp @@ -14,7 +14,7 @@ std::unordered_set white_list = { prim::TupleConstruct, prim::Param, prim::Return, - }; +}; static void LowerTuples(Block* block); diff --git a/torch/csrc/jit/passes/onnx.cpp b/torch/csrc/jit/passes/onnx.cpp index 6114a0fc4cece..0ead52f923817 100644 --- a/torch/csrc/jit/passes/onnx.cpp +++ b/torch/csrc/jit/passes/onnx.cpp @@ -8,22 +8,7 @@ namespace torch { namespace jit { -namespace { - -bool hasHandleOutput(Node *node) { - auto last_output = node->outputs().back(); - return last_output->isHandle(); -} - -bool hasUsedHandle(Node *node) { - if (!hasHandleOutput(node)) return false; - return node->outputs().back()->uses().size() > 0; -} - - -} // anonymous namespace - -// Transform PythonOps and Cpp Ops into Node's that match ONNX semantics. +// Transform PythonOps into Nodes that match ONNX semantics. std::shared_ptr ToONNX(std::shared_ptr& graph, ::torch::onnx::OperatorExportTypes operator_export_type) { auto new_graph = std::make_shared(graph->scope_root()); std::unordered_map env; @@ -58,8 +43,7 @@ void BlockToONNX(Block* old_block, Block* new_block, ::torch::onnx::OperatorExpo auto setOutputs = [&](const std::string& op_name, Node * node, const value_list & outputs) { auto old_outputs = node->outputs(); // Count all outputs, excluding Handles - bool has_handle = hasHandleOutput(node); - auto num_old_outputs = old_outputs.size() - (has_handle ? 1 : 0); + auto num_old_outputs = old_outputs.size(); if (outputs.size() != num_old_outputs) { std::ostringstream ss; ss << "symbolic for " << op_name << " produced an incorrect number of outputs (expected "; @@ -91,10 +75,6 @@ void BlockToONNX(Block* old_block, Block* new_block, ::torch::onnx::OperatorExpo } } } - if (has_handle) { - JIT_ASSERT(old_outputs.back()->uses().empty()); - env[old_outputs.back()] = nullptr; - } }; // Clone the node and add it to the new graph @@ -198,18 +178,9 @@ void BlockToONNX(Block* old_block, Block* new_block, ::torch::onnx::OperatorExpo // Finally, visit all nodes in the graph for (auto node : old_block->nodes()) { - if (hasUsedHandle(node)) { - // Nothing we can do here. The handle is used, so we'll need to capture the - // original state and can't do anything with this op (we don't know what the - // backward is). - cloneNode(node); - continue; - } // Needed so that symbolic calls create nodes with correct stages. auto stage_guard = ctx.block->owningGraph()->setStageTemporary(node->stage()); - IR_IFM(node, CppOp) - cloneNode(node); - IR_ELSEIFM(PythonOp) + IR_IFM(node, PythonOp) callPySymbolicMethod(value); IR_ELSE() callPySymbolicFunction(node); diff --git a/torch/csrc/jit/python_interpreter.cpp b/torch/csrc/jit/python_interpreter.cpp index 6a979c241c5c0..c0668b7a6e2bd 100644 --- a/torch/csrc/jit/python_interpreter.cpp +++ b/torch/csrc/jit/python_interpreter.cpp @@ -3,7 +3,6 @@ #include "torch/csrc/autograd/edge.h" #include "torch/csrc/autograd/function.h" -#include "torch/csrc/autograd/functions/special.h" #include "torch/csrc/autograd/profiler.h" #include "torch/csrc/autograd/variable.h" #include "torch/csrc/jit/fusion_compiler.h" @@ -29,7 +28,6 @@ namespace { Operation createPythonOperation(Node* op_) { PythonOp* op = static_cast(op_); py::function func = py::reinterpret_borrow(py::handle(op->pyobj.get())); - JIT_ASSERT(!hasHandleOutput(op)); size_t num_inputs = 0; for(auto arg_type : op->cconv) { if(arg_type == 't') diff --git a/torch/csrc/jit/python_ir.cpp b/torch/csrc/jit/python_ir.cpp index 337024059f028..534297aa3f174 100644 --- a/torch/csrc/jit/python_ir.cpp +++ b/torch/csrc/jit/python_ir.cpp @@ -270,7 +270,6 @@ void initPythonIRBindings(PyObject * module_) { .VS(stage) .VS(offset) .VS(uses) - .VS(isHandle) .VS(replaceAllUsesWith) .def("node",[](Value &v) { return v.node(); }) .def("setTypeAs", [](Value * node, Value * other) { @@ -427,8 +426,6 @@ void initPythonIRBindings(PyObject * module_) { .def("kind",[](Type& t_) { Type * t = &t_; switch(t->kind()) { - case TypeKind::HandleType: - return "HandleType"; case TypeKind::DynamicType: return "DynamicType"; case TypeKind::TensorType: diff --git a/torch/csrc/jit/python_tracer.cpp b/torch/csrc/jit/python_tracer.cpp index c35ed75152190..2ad7a79e9a947 100644 --- a/torch/csrc/jit/python_tracer.cpp +++ b/torch/csrc/jit/python_tracer.cpp @@ -45,7 +45,7 @@ std::shared_ptr createGraphByTracing( py::function func, tracer::variable_list trace_inputs, size_t num_func_inputs) { - auto enter_info = tracer::enter(std::move(trace_inputs), 1); + auto enter_info = tracer::enter(std::move(trace_inputs)); py::tuple py_inputs(num_func_inputs); for(size_t i = 0; i < num_func_inputs; ++i) { py_inputs[i] = py::cast(enter_info.second[i]); @@ -84,8 +84,6 @@ void pythonRecordSourceLocation(Node* n) { n->setSourceLocation(sl); } -#define ASSERT_UNEXPIRED(METHOD_NAME) if (s.is_expired()) throw std::runtime_error("calling " METHOD_NAME " on an expired trace") - void initPythonTracerBindings(PyObject* module_) { setRecordSourceLocation(pythonRecordSourceLocation); @@ -98,34 +96,25 @@ void initPythonTracerBindings(PyObject* module_) { return ss.str(); }) .def("__str__", [](const TracingState& s) -> std::string { - if (s.is_expired()) return ""; std::ostringstream ss; ss << *s.graph; return ss.str(); }) .def("push_scope", [](TracingState& s, const std::string& scope_name) { - ASSERT_UNEXPIRED("push_scope"); - s.push_scope(scope_name); + s.graph->push_scope(scope_name); }) .def("pop_scope", [](TracingState& s) { - ASSERT_UNEXPIRED("pop_scope"); - s.pop_scope(); + s.graph->pop_scope(); }) .def("set_graph", [](TracingState& s, std::shared_ptr g) { s.graph = g; }) .def("graph", [](TracingState& s) { return s.graph; - }) - .def_property_readonly("is_expired", [](TracingState& s) { - return s.is_expired(); - }) - .def_property_readonly("is_complete", [](TracingState& s) { - return s.is_complete(); }); - m.def("_tracer_enter", [](variable_list trace_inputs, size_t num_backwards) { - return tracer::enter(std::move(trace_inputs), num_backwards + 1); + m.def("_tracer_enter", [](variable_list trace_inputs) { + return tracer::enter(std::move(trace_inputs)); }); m.def("_tracer_exit", [](variable_list var_outputs) { tracer::exit(var_outputs); diff --git a/torch/csrc/jit/register_prim_ops.cpp b/torch/csrc/jit/register_prim_ops.cpp index 29e404626a1be..0d084edefa52d 100644 --- a/torch/csrc/jit/register_prim_ops.cpp +++ b/torch/csrc/jit/register_prim_ops.cpp @@ -1,6 +1,5 @@ #include "torch/csrc/autograd/edge.h" #include "torch/csrc/autograd/function.h" -#include "torch/csrc/autograd/functions/special.h" #include "torch/csrc/autograd/generated/variable_factories.h" #include "torch/csrc/autograd/profiler.h" #include "torch/csrc/autograd/variable.h" @@ -34,27 +33,6 @@ Operation noop(Node* n) { RegisterOperators reg({ - Operator( - prim::CppOp, - [](Node* node) { - CppOp* op = static_cast(node); - std::shared_ptr func = op->fn; - JIT_ASSERT(!hasHandleOutput(op)); - auto num_inputs = op->inputs().size(); - return [=](Stack& stack) { - autograd::variable_list v_inputs; - for (size_t i = 0; i < num_inputs; i++) { - v_inputs.push_back(std::move(peek(stack, i, num_inputs))); - } - drop(stack, num_inputs); - autograd::variable_list v_outputs = (*func)(v_inputs); - for (auto& output : v_outputs) { - stack.push_back(output); - } - return 0; - }; - }), - Operator( prim::FusionGroup, [](Node* node) { diff --git a/torch/csrc/jit/script/compiler.cpp b/torch/csrc/jit/script/compiler.cpp index 2db051bf5c29f..8d1d3f754515f 100644 --- a/torch/csrc/jit/script/compiler.cpp +++ b/torch/csrc/jit/script/compiler.cpp @@ -162,12 +162,12 @@ struct Environment { // control flow if(auto parent = findInParentFrame(name)) { if(!as_simple_value) { - throw ErrorReport(loc) << "Cannot re-assign '" << name << "' to a value of type " << value->kind() << + throw ErrorReport(loc) << "Cannot re-assign '" << name << "' to a value of type " << value->kind() << " because " << name << " is not a first-class value. Only reassignments to first-class values are allowed"; } Value* simple_parent = asSimple(parent); if(!simple_parent) { - throw ErrorReport(loc) << "Cannot re-assign '" << name << "' because it has type " << value->kind() << + throw ErrorReport(loc) << "Cannot re-assign '" << name << "' because it has type " << value->kind() << " and " << name << " is not a first-class value. Only reassignments to first-class values are allowed"; } if(!as_simple_value->type()->isSubtypeOf(*interpreterType(simple_parent->type()))) { diff --git a/torch/csrc/jit/test_jit.cpp b/torch/csrc/jit/test_jit.cpp index 758ca73862468..54e99f98e4648 100644 --- a/torch/csrc/jit/test_jit.cpp +++ b/torch/csrc/jit/test_jit.cpp @@ -17,6 +17,7 @@ #include "torch/csrc/jit/interpreter.h" #include "torch/csrc/jit/symbolic_variable.h" #include "torch/csrc/jit/autodiff.h" +#include "torch/csrc/jit/tracer.h" #include "torch/csrc/jit/passes/create_autodiff_subgraphs.h" #include "torch/csrc/autograd/variable.h" #include "torch/csrc/utils/hash.h" @@ -536,7 +537,7 @@ variable_list get_grad_outputs(const variable_list& vars) { std::shared_ptr trace(const ADTestSpec& test, const variable_list& vars_in) { std::shared_ptr state; variable_list trace_vars_in; - std::tie(state, trace_vars_in) = tracer::enter(vars_in, 1); + std::tie(state, trace_vars_in) = tracer::enter(vars_in); auto trace_vars_out = test(trace_vars_in); tracer::exit(trace_vars_out); return state->graph; diff --git a/torch/csrc/jit/tracer.cpp b/torch/csrc/jit/tracer.cpp index 820c28482253c..0fda835290928 100644 --- a/torch/csrc/jit/tracer.cpp +++ b/torch/csrc/jit/tracer.cpp @@ -3,7 +3,6 @@ #include "torch/csrc/autograd/variable.h" #include "torch/csrc/autograd/function.h" #include "torch/csrc/autograd/engine.h" -#include "torch/csrc/autograd/functions/special.h" #include "torch/csrc/jit/passes/dead_code_elimination.h" #include "torch/csrc/jit/passes/remove_expands.h" #include "torch/csrc/variable_tensor_functions.h" @@ -14,102 +13,6 @@ namespace torch { namespace jit { namespace tracer { - -namespace { - -struct TraceEval : autograd::Eval { - TraceEval(const std::shared_ptr& tracing_state) - : weak_tracing_state(tracing_state) { - flag.clear(); - tracing_state->eval_count++; - this->traceable = true; - } - - virtual ~TraceEval() { - auto state = weak_tracing_state.lock(); - if (!state) return; - if (--state->eval_count == 0 && !state->is_complete()) { - state->graph = nullptr; - } - } - - virtual std::shared_ptr newEval() override { - if (auto state = weak_tracing_state.lock()) { - return std::make_shared(state); - } else { - return std::make_shared(); - } - } - - virtual variable_list apply(const variable_list& inputs) override { - auto should_trace = !flag.test_and_set(); - if (!should_trace) { - return Eval::apply(inputs); - } - variable_list local_inputs = inputs; - enterTrace(local_inputs); - auto outputs = Eval::apply(local_inputs); - exitTrace(local_inputs, outputs); - return outputs; - } - - void enterTrace(variable_list& inputs) { - auto tracing_state = weak_tracing_state.lock(); - if (!tracing_state) return; - - auto& graph = tracing_state->graph; - graph->advanceStage(); - - for (size_t i = 0, num_inputs = inputs.size(); i < num_inputs; ++i) { - auto input = inputs[i]; - Value *input_node = graph->addInput(); - if (!input.defined()) continue; - auto * value_state = detail::getValueState(tracing_state, input, false); - if (value_state) { - // Note [Repeated inputs] - // Repeated inputs cause us some problems in here, because there's no way - // for us to attach a single Variable to two inputs, and to tell which one - // is used when performing an operation. To deal with it, we allocate a view - // of such input, and use that instead. - inputs[i] = input = input.view(input.sizes()); - } - setValueTrace(tracing_state, input, input_node); - input_node->inferTypeFrom(input.data()); - } - tracing_state->active = true; - tracing_state->var_flags.at(graph->stage()).first = detail::getVarFlags(inputs); - } - - void exitTrace(const variable_list& inputs, const variable_list& outputs) { - auto tracing_state = weak_tracing_state.lock(); - if (!tracing_state) return; - - detail::_exit(tracing_state, outputs); - auto stage = tracing_state->graph->stage(); - tracing_state->output_edges[stage] = fmap(placeholders, [](const std::shared_ptr& p) { - return p->next_edge; - }); - } - - std::atomic_flag flag; - std::weak_ptr weak_tracing_state; -}; - -} // anonymous namespace - -namespace detail { - -void traceBackward(const std::shared_ptr& tracing_state, const variable_list& inputs, const variable_list& outputs) { - // TODO: add note on how we depend on TracedEval being created in here if num_stages == 1 - std::make_shared(tracing_state)->replaceSubgraph(inputs, outputs); -} - -} // namespace detail - -void nontraceableBackwardSubgraph(const variable_list& inputs, const variable_list& outputs) { - std::make_shared()->replaceSubgraph(inputs, outputs); -} - PreTraceInfo preRecordTrace(Symbol op, at::ArrayRef inputs) { return makePreTraceInfo(inputs, [&op](const std::shared_ptr& state, Graph& graph) { diff --git a/torch/csrc/jit/tracer.h b/torch/csrc/jit/tracer.h index 7836623eb7d24..5775091f5b8e6 100644 --- a/torch/csrc/jit/tracer.h +++ b/torch/csrc/jit/tracer.h @@ -51,10 +51,6 @@ inline bool isElemActive(const ValueTracingStateElem& vts) { return state && state->active; } -inline std::vector getVarFlags(const variable_list& vars) { - return fmap(vars, &VariableFlags::of); -} - } // namespace detail @@ -214,8 +210,8 @@ inline Value* getOutputTrace(const std::shared_ptr& state, const V // reference to at::Tensor buffer to call unsafeGetTH, but you can't get this // out of a const vector (silly std::vector...) inline std::pair, variable_list> enter( - variable_list inputs, size_t num_stages) { - auto state = std::make_shared(num_stages); + variable_list inputs) { + auto state = std::make_shared(); for (auto& input : inputs) { auto * value_state = detail::getValueState(state, input, false); if (value_state) { @@ -226,46 +222,22 @@ inline std::pair, variable_list> enter( setValueTrace(state, input, input_node); input_node->inferTypeFrom(input.data()); } - state->var_flags[0].first = detail::getVarFlags(inputs); - state->active = true; - state->inputs = inputs; return std::make_pair(state, inputs); } -namespace detail { - -// Exit code shared between exit and TraceExitHook::run -inline void _exit(const std::shared_ptr& state, const variable_list& outputs) { +// Exit a trace, treating 'outputs' as the outputs of the trace. These +// are the variables whose values will be computed upon subsequent +// invocations of the trace. +inline void exit(const variable_list& outputs) { + auto state = getTracingState(outputs); size_t i = 0; for (auto& output : outputs) { state->graph->registerOutput(getOutputTrace(state, output, i)); i++; } state->active = false; - state->var_flags[state->graph->stage()].second = detail::getVarFlags(outputs); -} - -// Marks a backwards subgraph that should be traced as the next stage. -// Mutates some of the outputs. -void traceBackward(const std::shared_ptr& state, const variable_list& inputs, - const variable_list& outputs); - -} // namespace detail - -// Exit a trace, treating 'outputs' as the outputs of the trace. These -// are the variables whose values will be computed upon subsequent -// invocations of the trace. -inline void exit(const variable_list& outputs) { - auto state = getTracingState(outputs); - detail::_exit(state, outputs); - detail::traceBackward(state, state->inputs, outputs); - state->inputs.clear(); } -// Marks part of the backward graph as non-traceable (i.e. one that should be replaced -// with an Eval in the trace). -void nontraceableBackwardSubgraph(const variable_list& inputs, const variable_list& outputs); - // Pre-recorded information about the trace before we actually carry // out the trace struct PreTraceInfo { diff --git a/torch/csrc/jit/tracer_state.cpp b/torch/csrc/jit/tracer_state.cpp index a12feba5ae555..6f445625fd6b7 100644 --- a/torch/csrc/jit/tracer_state.cpp +++ b/torch/csrc/jit/tracer_state.cpp @@ -1,38 +1,12 @@ #include "torch/csrc/jit/tracer_state.h" -#include "torch/csrc/autograd/edge.h" -#include "torch/csrc/autograd/variable.h" #include "torch/csrc/jit/ir.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include - namespace torch { namespace jit { namespace tracer { -TracingState::TracingState(size_t num_stages) - : graph(new Graph()), - active(false), - num_stages(num_stages), - eval_count(0), - var_flags(num_stages), - output_edges(num_stages) {} - -TracingState::~TracingState() = default; -bool TracingState::is_complete() const { - return !is_expired() && graph->stage() == num_stages - 1; -} +TracingState::TracingState() + : graph(new Graph()) + , active(true) {} -void TracingState::push_scope(const std::string& scope_name) { - graph->push_scope(scope_name); -} +TracingState::~TracingState() = default; -void TracingState::pop_scope() { - graph->pop_scope(); -} }}} // namespace torch::jit::tracer diff --git a/torch/csrc/jit/tracer_state.h b/torch/csrc/jit/tracer_state.h index f7517650ca6e3..887ad94dced89 100644 --- a/torch/csrc/jit/tracer_state.h +++ b/torch/csrc/jit/tracer_state.h @@ -16,14 +16,10 @@ namespace torch { namespace jit { struct Graph; struct Value; -struct VariableFlags; }} // namespace torch::jit namespace torch { namespace jit { namespace tracer { -using edge_list = std::vector; -using variable_list = std::vector; - // TracingState tracks the necessary state when we are tracing the execution of // autograd code; most importantly, it holds a reference to the actual IR // graph which we are recording the trace to. @@ -34,38 +30,17 @@ using variable_list = std::vector; // from arising when a variable that participated in a trace outlives the // actual trace itself. -using io_variable_flags_list = std::vector< - std::pair, std::vector>>; - struct TracingState : public std::enable_shared_from_this { - explicit TracingState(size_t num_stages); + TracingState(); ~TracingState(); std::shared_ptr graph; + std::mutex mutex; bool active; - // Used to free the Graph as soon as we know this trace will fail - size_t num_stages; - std::atomic eval_count; - - // A pair of (input_flags, output_flags) for each stage - io_variable_flags_list var_flags; - std::vector output_edges; - - std::mutex mutex; - variable_list inputs; // Used only for the duration of first stage - std::unique_lock lock() { return std::unique_lock(mutex); } - - bool is_expired() const noexcept { - return !graph; - } - - bool is_complete() const; - void push_scope(const std::string& scope_name); - void pop_scope(); }; struct ValueTracingStateElem { @@ -81,8 +56,4 @@ struct ValueTracingStateElem { using ValueTracingState = std::list; -struct FunctionTracingState { - bool in_eval_subgraph = false; -}; - }}} // namespace torch::jit::tracer diff --git a/torch/csrc/jit/type.cpp b/torch/csrc/jit/type.cpp index 32484a441123d..79171ede7283c 100644 --- a/torch/csrc/jit/type.cpp +++ b/torch/csrc/jit/type.cpp @@ -23,8 +23,6 @@ std::ostream& operator<<(std::ostream & out, const Type & t) { } } out << ")"; - } else if(t.kind() == TypeKind::HandleType) { - out << "Handle"; } else if(t.kind() == TypeKind::DynamicType) { out << "Dynamic"; } else if(t.kind() == TypeKind::TupleType) { @@ -44,10 +42,6 @@ std::ostream& operator<<(std::ostream & out, const Type & t) { return out; } -TypePtr HandleType::get() { - static auto value = std::make_shared(); - return value; -} TypePtr DynamicType::get() { static auto value = std::make_shared(); return value; diff --git a/torch/csrc/jit/type.h b/torch/csrc/jit/type.h index 541669d89cdff..1eed81b555204 100644 --- a/torch/csrc/jit/type.h +++ b/torch/csrc/jit/type.h @@ -13,7 +13,6 @@ namespace torch { namespace jit { #define TH_FORALL_TYPES(_) \ _(DynamicType) \ _(TensorType) \ -_(HandleType) \ _(TupleType) \ _(ListType) \ _(NumberType) \ @@ -186,38 +185,6 @@ struct TensorType : public Type { std::vector strides_; }; -// This value represents an opaque handle to external state. -// Operators that produce/consume values of this type agree on -// the format. - -/* Example Usage: passing state to opaque autograd Functions: -graph(%1, %8) { - %2.0, %2.1 = ^AddConstant(2, False)(%1) // first output is Type::Handle, containing ctx - %4.0, %4.1 = ^Add(False)(%2.1, %1) // first output is Type::Handle, containing ctx - %6.0, %6.1 = ^Abs()(%4.1) // first output is Type::Handle, containing ctx - ---------------- stage 1 ---------------- - %13 = AutogradOp[AbsBackward](%6.0, %8) // first argument is Type::Handle, consuming ctx - %15 = AutogradOp[AddBackward](%4.0, %13.0) // first argument is Type::Handle, consuming ctx - %18 = AutogradOp[AddConstantBackward](%2.0, %15.1) // first argument is Type::Handle, consuming ctx - %20 = AutogradOp[N5torch8autograd3AddE](%18.0, %18.0) - return (%6.0, %20.0); -} -*/ -struct HandleType : public Type { - friend struct Type; - HandleType() - : Type(TypeKind::HandleType) {} - virtual bool operator==(const Type& rhs) const override { - return rhs.kind() == kind(); - } - virtual std::string str() const override { - return "Handle"; - } - static const TypeKind Kind = TypeKind::HandleType; - // global singleton - static TypePtr get(); -}; - struct ListType : public Type { friend struct Type; static const TypeKind Kind = TypeKind::ListType; diff --git a/torch/jit/__init__.py b/torch/jit/__init__.py index 9c705167e8816..edab86fb61114 100644 --- a/torch/jit/__init__.py +++ b/torch/jit/__init__.py @@ -47,7 +47,7 @@ def scope(scope_name, *vars): tracing_state.pop_scope() -def get_trace_graph(f, args=tuple(), kwargs=None, nderivs=0): +def get_trace_graph(f, args=tuple(), kwargs=None): """ Trace a function or model, returning a tuple consisting of the both the *trace* of an execution, as well as the original return value. @@ -63,28 +63,17 @@ def get_trace_graph(f, args=tuple(), kwargs=None, nderivs=0): be a single positional argument to be passed to the model. kwargs (dict): the keyword arguments to pass to the function/module to be traced. - nderivs (int, default 0): the number of derivatives to trace. - Traces of derivatives are recorded into the same trace returned - after executing the `forward` of the resulting module, but - are not present until you run `backward()` (an appropriate - number of times) on the resulting model. - Example: Trace the forwards pass only. + Example: Trace a cell. >>> trace, out = jit.trace(nn.LSTMCell(), (input, hidden)) >>> print(trace) - - Example: Trace the backwards pass too. - - >>> trace, out = jit.trace(nn.LSTMCell(), (input, hidden), nderivs=1) - >>> out.sum().backward() - >>> print(trace) """ if kwargs is None: kwargs = {} if not isinstance(args, tuple): args = (args,) - return LegacyTracedModule(f, nderivs=nderivs)(*args, **kwargs) + return LegacyTracedModule(f)(*args, **kwargs) def _unique_state_dict(module, keep_vars=False): @@ -100,13 +89,12 @@ def _unique_state_dict(module, keep_vars=False): class LegacyTracedModule(Module): - def __init__(self, inner, nderivs=0): + def __init__(self, inner): super(LegacyTracedModule, self).__init__() # inner may be a Module, or it may be an arbitrary callable # If it's a Module, we get its parameters automatically, which lets # us avoid a special casing functions versus modules. self.inner = inner - self.nderivs = nderivs def forward(self, *args): global _tracing @@ -114,7 +102,7 @@ def forward(self, *args): # NOTE: use full state, because we need it for BatchNorm export # This differs from the compiler path, which doesn't support it at the moment. module_state = list(_unique_state_dict(self, keep_vars=True).values()) - trace, all_trace_inputs = torch._C._tracer_enter(in_vars + module_state, self.nderivs) + trace, all_trace_inputs = torch._C._tracer_enter(in_vars + module_state) _tracing = True trace_inputs = _unflatten(all_trace_inputs[:len(in_vars)], in_desc) out = self.inner(*trace_inputs) From 8da936ab5226f4d4f390080a41e57fea63989c52 Mon Sep 17 00:00:00 2001 From: JerryShih Date: Wed, 11 Jul 2018 10:38:12 -0700 Subject: [PATCH 18/36] Fix the build break for python3.7 PyUnicode_AsUTF8AndSize() prototype changing (#9259) Summary: https://docs.python.org/3.7/c-api/unicode.html#c.PyUnicode_AsUTF8AndSize The return type changes from "char*" to "const char*". Pull Request resolved: https://github.com/pytorch/pytorch/pull/9259 Reviewed By: orionr Differential Revision: D8776219 Pulled By: pjh5 fbshipit-source-id: e5eadf71264002ba57cfb68dd39686a7ec074092 --- caffe2/python/pybind_state.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/caffe2/python/pybind_state.h b/caffe2/python/pybind_state.h index 492b17550319a..f46972a05561c 100644 --- a/caffe2/python/pybind_state.h +++ b/caffe2/python/pybind_state.h @@ -197,7 +197,7 @@ class TensorFeeder : public BlobFeederBase { PyBytes_AsStringAndSize(input[i], &str, &strSize) != -1, "Had a PyBytes object but cannot convert it to a string."); } else if (PyUnicode_Check(input[i])) { // string - str = PyUnicode_AsUTF8AndSize(input[i], &strSize); + str = const_cast(PyUnicode_AsUTF8AndSize(input[i], &strSize)); CAFFE_ENFORCE( str, "Had a PyUnicode object but cannot convert it to a string."); From 491f317b24b8c4210c672d3f07628d741357934e Mon Sep 17 00:00:00 2001 From: Viswanath Sivakumar Date: Wed, 11 Jul 2018 11:14:47 -0700 Subject: [PATCH 19/36] NMS util for rotated boxes (#8954) Summary: Pull Request resolved: https://github.com/pytorch/pytorch/pull/8954 Closes https://github.com/pytorch/pytorch/pull/8954 Based on RRPN paper: https://arxiv.org/abs/1703.01086 Reviewed By: pjh5 Differential Revision: D8618673 fbshipit-source-id: 4c54297e3b3bf614de4d7c0146176a419518790a --- .../generate_proposals_op_util_nms.h | 364 ++++++++++++++++-- .../generate_proposals_op_util_nms_test.cc | 227 +++++++++++ 2 files changed, 561 insertions(+), 30 deletions(-) diff --git a/caffe2/operators/generate_proposals_op_util_nms.h b/caffe2/operators/generate_proposals_op_util_nms.h index 563a1080f0084..39e7febe27296 100644 --- a/caffe2/operators/generate_proposals_op_util_nms.h +++ b/caffe2/operators/generate_proposals_op_util_nms.h @@ -1,14 +1,16 @@ #ifndef CAFFE2_OPERATORS_UTILS_NMS_H_ #define CAFFE2_OPERATORS_UTILS_NMS_H_ -#include #include -#include "caffe2/utils/eigen_utils.h" - #include "caffe2/core/logging.h" +#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/math.h" +#if defined(CV_MAJOR_VERSION) && (CV_MAJOR_VERSION >= 3) +#include +#endif // CV_MAJOR_VERSION >= 3 + namespace caffe2 { namespace utils { @@ -23,7 +25,7 @@ namespace utils { // sorted_indices: indices that sorts the scores from high to low // return: row indices of the selected proposals template -std::vector nms_cpu( +std::vector nms_cpu_upright( const Eigen::ArrayBase& proposals, const Eigen::ArrayBase& scores, const std::vector& sorted_indices, @@ -45,7 +47,6 @@ std::vector nms_cpu( EArrXi order = AsEArrXt(sorted_indices); std::vector keep; - int ci = 0; while (order.size() > 0) { // exit if already enough proposals if (topN >= 0 && keep.size() >= topN) { @@ -74,36 +75,13 @@ std::vector nms_cpu( return keep; } -// Greedy non-maximum suppression for proposed bounding boxes -// Reject a bounding box if its region has an intersection-overunion (IoU) -// overlap with a higher scoring selected bounding box larger than a -// threshold. -// Reference: detectron/lib/utils/cython_nms.pyx -// proposals: pixel coordinates of proposed bounding boxes, -// size: (M, 4), format: [x1; y1; x2; y2] -// scores: scores for each bounding box, size: (M, 1) -// return: row indices of the selected proposals -template -std::vector nms_cpu( - const Eigen::ArrayBase& proposals, - const Eigen::ArrayBase& scores, - float thres) { - std::vector indices(proposals.rows()); - std::iota(indices.begin(), indices.end(), 0); - std::sort( - indices.data(), - indices.data() + indices.size(), - [&scores](int lhs, int rhs) { return scores(lhs) > scores(rhs); }); - - return nms_cpu(proposals, scores, indices, thres); -} - /** * Soft-NMS implementation as outlined in https://arxiv.org/abs/1704.04503. * Reference: detectron/lib/utils/cython_nms.pyx * out_scores: Output updated scores after applying Soft-NMS * proposals: pixel coordinates of proposed bounding boxes, * size: (M, 4), format: [x1; y1; x2; y2] + * size: (M, 5), format: [ctr_x; ctr_y; w; h; angle (degrees)] for RRPN * scores: scores for each bounding box, size: (M, 1) * indices: Indices to consider within proposals and scores. Can be used * to pre-filter proposals/scores based on some threshold. @@ -114,7 +92,7 @@ std::vector nms_cpu( * return: row indices of the selected proposals */ template -std::vector soft_nms_cpu( +std::vector soft_nms_cpu_upright( Eigen::ArrayBase* out_scores, const Eigen::ArrayBase& proposals, const Eigen::ArrayBase& scores, @@ -194,6 +172,332 @@ std::vector soft_nms_cpu( return keep; } +#if defined(CV_MAJOR_VERSION) && (CV_MAJOR_VERSION >= 3) +namespace { + +template +cv::RotatedRect bbox_to_rotated_rect(const Eigen::ArrayBase& box) { + CAFFE_ENFORCE_EQ(box.size(), 5); + // cv::RotatedRect takes angle to mean clockwise rotation, but RRPN bbox + // representation means counter-clockwise rotation. + return cv::RotatedRect( + cv::Point2f(box[0], box[1]), cv::Size2f(box[2], box[3]), -box[4]); +} + +/** + * Returns the intersection area of two rotated rectangles. + */ +double rotated_rect_intersection( + const cv::RotatedRect& rect1, + const cv::RotatedRect& rect2) { + std::vector intersectPts, orderedPts; + + // Find points of intersection + auto ret = cv::rotatedRectangleIntersection(rect1, rect2, intersectPts); + if (intersectPts.size() <= 2) { + return 0.0; + } + + // If one rectangle is fully enclosed within another, return the area + // of the smaller one early. + if (ret == cv::INTERSECT_FULL) { + return std::min(rect1.size.area(), rect2.size.area()); + } + + // Convex Hull to order the intersection points in clockwise or + // counter-clockwise order and find the countour area. + cv::convexHull(intersectPts, orderedPts); + return cv::contourArea(orderedPts); +} + +} // namespace + +/** + * Find the intersection area of two rotated boxes represented in format + * [ctr_x, ctr_y, width, height, angle]. + * `angle` represents counter-clockwise rotation in degrees. + */ +template +double bbox_intersection_rotated( + const Eigen::ArrayBase& box1, + const Eigen::ArrayBase& box2) { + CAFFE_ENFORCE(box1.size() == 5 && box2.size() == 5); + const auto& rect1 = bbox_to_rotated_rect(box1); + const auto& rect2 = bbox_to_rotated_rect(box2); + return rotated_rect_intersection(rect1, rect2); +} + +/** + * Similar to `bbox_overlaps()` in detectron/utils/cython_bbox.pyx, + * but handles rotated boxes represented in format + * [ctr_x, ctr_y, width, height, angle]. + * `angle` represents counter-clockwise rotation in degrees. + */ +template +Eigen::ArrayXXf bbox_overlaps_rotated( + const Eigen::ArrayBase& boxes, + const Eigen::ArrayBase& query_boxes) { + CAFFE_ENFORCE(boxes.cols() == 5 && query_boxes.cols() == 5); + + const auto& boxes_areas = boxes.col(2) * boxes.col(3); + const auto& query_boxes_areas = query_boxes.col(2) * query_boxes.col(3); + + Eigen::ArrayXXf overlaps(boxes.rows(), query_boxes.rows()); + for (int i = 0; i < boxes.rows(); ++i) { + for (int j = 0; j < query_boxes.rows(); ++j) { + auto inter = bbox_intersection_rotated(boxes.row(i), query_boxes.row(j)); + overlaps(i, j) = (inter == 0.0) + ? 0.0 + : inter / (boxes_areas[i] + query_boxes_areas[j] - inter); + } + } + return overlaps; +} + +// Similar to nms_cpu_upright, but handles rotated proposal boxes +// in the format: +// size (M, 5), format [ctr_x; ctr_y; width; height; angle (in degrees)]. +// +// For now, we only consider IoU as the metric for suppression. No angle info +// is used yet. +template +std::vector nms_cpu_rotated( + const Eigen::ArrayBase& proposals, + const Eigen::ArrayBase& scores, + const std::vector& sorted_indices, + float thresh, + int topN = -1) { + CAFFE_ENFORCE_EQ(proposals.rows(), scores.rows()); + CAFFE_ENFORCE_EQ(proposals.cols(), 5); + CAFFE_ENFORCE_EQ(scores.cols(), 1); + CAFFE_ENFORCE_LE(sorted_indices.size(), proposals.rows()); + + using EArrX = EArrXt; + + auto widths = proposals.col(2); + auto heights = proposals.col(3); + EArrX areas = widths * heights; + + std::vector rotated_rects(proposals.rows()); + for (int i = 0; i < proposals.rows(); ++i) { + rotated_rects[i] = bbox_to_rotated_rect(proposals.row(i)); + } + + EArrXi order = AsEArrXt(sorted_indices); + std::vector keep; + while (order.size() > 0) { + // exit if already enough proposals + if (topN >= 0 && keep.size() >= topN) { + break; + } + + int i = order[0]; + keep.push_back(i); + ConstEigenVectorArrayMap rest_indices( + order.data() + 1, order.size() - 1); + + EArrX inter(rest_indices.size()); + for (int j = 0; j < rest_indices.size(); ++j) { + inter[j] = rotated_rect_intersection( + rotated_rects[i], rotated_rects[rest_indices[j]]); + } + EArrX ovr = inter / (areas[i] + GetSubArray(areas, rest_indices) - inter); + + // indices for sub array order[1:n]. + // TODO (viswanath): Should angle info be included as well while filtering? + auto inds = GetArrayIndices(ovr <= thresh); + order = GetSubArray(order, AsEArrXt(inds) + 1); + } + + return keep; +} + +// Similar to soft_nms_cpu_upright, but handles rotated proposal boxes +// in the format: +// size (M, 5), format [ctr_x; ctr_y; width; height; angle (in degrees)]. +// +// For now, we only consider IoU as the metric for suppression. No angle info +// is used yet. +template +std::vector soft_nms_cpu_rotated( + Eigen::ArrayBase* out_scores, + const Eigen::ArrayBase& proposals, + const Eigen::ArrayBase& scores, + const std::vector& indices, + float sigma = 0.5, + float overlap_thresh = 0.3, + float score_thresh = 0.001, + unsigned int method = 1, + int topN = -1) { + CAFFE_ENFORCE_EQ(proposals.rows(), scores.rows()); + CAFFE_ENFORCE_EQ(proposals.cols(), 5); + CAFFE_ENFORCE_EQ(scores.cols(), 1); + + using EArrX = EArrXt; + + auto widths = proposals.col(2); + auto heights = proposals.col(3); + EArrX areas = widths * heights; + + std::vector rotated_rects(proposals.rows()); + for (int i = 0; i < proposals.rows(); ++i) { + rotated_rects[i] = bbox_to_rotated_rect(proposals.row(i)); + } + + // Initialize out_scores with original scores. Will be iteratively updated + // as Soft-NMS is applied. + *out_scores = scores; + + std::vector keep; + EArrXi pending = AsEArrXt(indices); + while (pending.size() > 0) { + // Exit if already enough proposals + if (topN >= 0 && keep.size() >= topN) { + break; + } + + // Find proposal with max score among remaining proposals + int max_pos; + auto max_score = GetSubArray(*out_scores, pending).maxCoeff(&max_pos); + int i = pending[max_pos]; + keep.push_back(i); + + // Compute IoU of the remaining boxes with the identified max box + std::swap(pending(0), pending(max_pos)); + const auto& rest_indices = pending.tail(pending.size() - 1); + EArrX inter(rest_indices.size()); + for (int j = 0; j < rest_indices.size(); ++j) { + inter[j] = rotated_rect_intersection( + rotated_rects[i], rotated_rects[rest_indices[j]]); + } + EArrX ovr = inter / (areas[i] + GetSubArray(areas, rest_indices) - inter); + + // Update scores based on computed IoU, overlap threshold and NMS method + // TODO (viswanath): Should angle info be included as well while filtering? + for (int j = 0; j < rest_indices.size(); ++j) { + typename Derived2::Scalar weight; + switch (method) { + case 1: // Linear + weight = (ovr(j) > overlap_thresh) ? (1.0 - ovr(j)) : 1.0; + break; + case 2: // Gaussian + weight = std::exp(-1.0 * ovr(j) * ovr(j) / sigma); + break; + default: // Original NMS + weight = (ovr(j) > overlap_thresh) ? 0.0 : 1.0; + } + (*out_scores)(rest_indices[j]) *= weight; + } + + // Discard boxes with new scores below min threshold and update pending + // indices + const auto& rest_scores = GetSubArray(*out_scores, rest_indices); + const auto& inds = GetArrayIndices(rest_scores >= score_thresh); + pending = GetSubArray(rest_indices, AsEArrXt(inds)); + } + + return keep; +} +#endif // CV_MAJOR_VERSION >= 3 + +template +std::vector nms_cpu( + const Eigen::ArrayBase& proposals, + const Eigen::ArrayBase& scores, + const std::vector& sorted_indices, + float thresh, + int topN = -1) { +#if defined(CV_MAJOR_VERSION) && (CV_MAJOR_VERSION >= 3) + CAFFE_ENFORCE(proposals.cols() == 4 || proposals.cols() == 5); + if (proposals.cols() == 4) { + // Upright boxes + return nms_cpu_upright(proposals, scores, sorted_indices, thresh, topN); + } else { + // Rotated boxes with angle info + return nms_cpu_rotated(proposals, scores, sorted_indices, thresh, topN); + } +#else + return nms_cpu_upright(proposals, scores, sorted_indices, thresh, topN); +#endif // CV_MAJOR_VERSION >= 3 +} + +// Greedy non-maximum suppression for proposed bounding boxes +// Reject a bounding box if its region has an intersection-overunion (IoU) +// overlap with a higher scoring selected bounding box larger than a +// threshold. +// Reference: detectron/lib/utils/cython_nms.pyx +// proposals: pixel coordinates of proposed bounding boxes, +// size: (M, 4), format: [x1; y1; x2; y2] +// size: (M, 5), format: [ctr_x; ctr_y; w; h; angle (degrees)] for RRPN +// scores: scores for each bounding box, size: (M, 1) +// return: row indices of the selected proposals +template +std::vector nms_cpu( + const Eigen::ArrayBase& proposals, + const Eigen::ArrayBase& scores, + float thres) { + std::vector indices(proposals.rows()); + std::iota(indices.begin(), indices.end(), 0); + std::sort( + indices.data(), + indices.data() + indices.size(), + [&scores](int lhs, int rhs) { return scores(lhs) > scores(rhs); }); + + return nms_cpu(proposals, scores, indices, thres); +} + +template +std::vector soft_nms_cpu( + Eigen::ArrayBase* out_scores, + const Eigen::ArrayBase& proposals, + const Eigen::ArrayBase& scores, + const std::vector& indices, + float sigma = 0.5, + float overlap_thresh = 0.3, + float score_thresh = 0.001, + unsigned int method = 1, + int topN = -1) { +#if defined(CV_MAJOR_VERSION) && (CV_MAJOR_VERSION >= 3) + CAFFE_ENFORCE(proposals.cols() == 4 || proposals.cols() == 5); + if (proposals.cols() == 4) { + // Upright boxes + return soft_nms_cpu_upright( + out_scores, + proposals, + scores, + indices, + sigma, + overlap_thresh, + score_thresh, + method, + topN); + } else { + // Rotated boxes with angle info + return soft_nms_cpu_rotated( + out_scores, + proposals, + scores, + indices, + sigma, + overlap_thresh, + score_thresh, + method, + topN); + } +#else + return soft_nms_cpu_upright( + out_scores, + proposals, + scores, + indices, + sigma, + overlap_thresh, + score_thresh, + method, + topN); +#endif // CV_MAJOR_VERSION >= 3 +} + template std::vector soft_nms_cpu( Eigen::ArrayBase* out_scores, diff --git a/caffe2/operators/generate_proposals_op_util_nms_test.cc b/caffe2/operators/generate_proposals_op_util_nms_test.cc index a7825c81b6354..9d685a716bb3b 100644 --- a/caffe2/operators/generate_proposals_op_util_nms_test.cc +++ b/caffe2/operators/generate_proposals_op_util_nms_test.cc @@ -8,6 +8,7 @@ TEST(UtilsNMSTest, TestNMS) { Eigen::ArrayXXf input(5, 5); input << 10, 10, 50, 60, 0.5, 11, 12, 48, 60, 0.7, 8, 9, 40, 50, 0.6, 100, 100, 150, 140, 0.9, 99, 110, 155, 139, 0.8; + std::vector input_thresh{0.1f, 0.3f, 0.5f, 0.8f, 0.9f}; // ground truth generated based on detection.caffe2/lib/nms/py_cpu_nms.py std::vector> output_gt{ @@ -159,4 +160,230 @@ TEST(UtilsNMSTest, TestSoftNMS) { } } +#if defined(CV_MAJOR_VERSION) && (CV_MAJOR_VERSION >= 3) +TEST(UtilsNMSTest, TestNMSRotatedAngle0) { + // Same inputs as TestNMS, but in RRPN format with angle 0 for testing + // nms_cpu_rotated + Eigen::ArrayXXf input(5, 5); + input << 10, 10, 50, 60, 0.5, 11, 12, 48, 60, 0.7, 8, 9, 40, 50, 0.6, 100, + 100, 150, 140, 0.9, 99, 110, 155, 139, 0.8; + + std::vector input_thresh{0.1f, 0.3f, 0.5f, 0.8f, 0.9f}; + // ground truth generated based on detection.caffe2/lib/nms/py_cpu_nms.py + std::vector> output_gt{ + {3, 1}, {3, 1}, {3, 1}, {3, 4, 1, 2}, {3, 4, 1, 2, 0}}; + + // test utils::nms_cpu without indices input. + // Add additional dim for angle and convert from + // [x1, y1, x2, y1] to [ctr_x, ctr_y, w, h] format. + Eigen::ArrayXXf proposals = Eigen::ArrayXXf::Zero(input.rows(), 5); + proposals.col(0) = (input.col(0) + input.col(2)) / 2.0; // ctr_x = (x1 + x2)/2 + proposals.col(1) = (input.col(1) + input.col(3)) / 2.0; // ctr_y = (y1 + y2)/2 + proposals.col(2) = input.col(2) - input.col(0) + 1.0; // w = x2 - x1 + 1 + proposals.col(3) = input.col(3) - input.col(1) + 1.0; // h = y2 - y1 + 1 + + auto scores = input.col(4); + for (int i = 0; i < input_thresh.size(); i++) { + auto cur_out = utils::nms_cpu(proposals, scores, input_thresh[i]); + EXPECT_EQ(output_gt[i], cur_out); + } + + // test utils::nms_cpu with indices + std::vector indices(proposals.rows()); + std::iota(indices.begin(), indices.end(), 0); + std::sort( + indices.data(), + indices.data() + indices.size(), + [&scores](int lhs, int rhs) { return scores(lhs) > scores(rhs); }); + for (int i = 0; i < input_thresh.size(); i++) { + auto cur_out = utils::nms_cpu(proposals, scores, indices, input_thresh[i]); + EXPECT_EQ(output_gt[i], cur_out); + } + + // test utils::nms_cpu with topN + std::vector top_n = {1, 1, 2, 2, 3}; + auto gt_out = output_gt; + for (int i = 0; i < input_thresh.size(); i++) { + auto cur_out = + utils::nms_cpu(proposals, scores, indices, input_thresh[i], top_n[i]); + gt_out[i].resize(top_n[i]); + EXPECT_EQ(gt_out[i], cur_out); + } +} + +TEST(UtilsNMSTest, TestSoftNMSRotatedAngle0) { + // Same inputs as TestSoftNMS, but in RRPN format with angle 0 for testing + // nms_cpu_rotated + Eigen::ArrayXXf input(5, 5); + input.row(0) << 5.18349426e+02, 1.77783920e+02, 9.06085266e+02, + 2.59163239e+02, 8.17906916e-01; + input.row(1) << 2.11392624e+02, 1.76144958e+02, 6.14215149e+02, + 2.48934662e+02, 9.52467501e-01; + input.row(2) << 4.65724518e+02, 1.83594269e+02, 9.39000000e+02, + 2.55136627e+02, 6.73921347e-01; + input.row(3) << 6.07164246e+02, 2.60230377e+02, 8.32768127e+02, + 3.39919891e+02, 9.99834776e-01; + input.row(4) << 3.23936859e+02, 3.43427063e+02, 6.20561157e+02, + 3.98286072e+02, 9.99737203e-01; + + // Add additional dim for angle and convert from + // [x1, y1, x2, y1] to [ctr_x, ctr_y, w, h] format. + Eigen::ArrayXXf proposals = Eigen::ArrayXXf::Zero(input.rows(), 5); + proposals.col(0) = (input.col(0) + input.col(2)) / 2.0; // ctr_x = (x1 + x2)/2 + proposals.col(1) = (input.col(1) + input.col(3)) / 2.0; // ctr_y = (y1 + y2)/2 + proposals.col(2) = input.col(2) - input.col(0) + 1.0; // w = x2 - x1 + 1 + proposals.col(3) = input.col(3) - input.col(1) + 1.0; // h = y2 - y1 + 1 + + const auto& scores = input.col(4); + + vector method{1, 1, 2, 2}; + vector overlap_thresh{0.1f, 0.3f, 0.1f, 0.3f}; + + // Ground truth generated based on + // detectron/lib/utils/cython_nms.pyx + std::vector keep_gt{3, 4, 1, 0, 2}; + + // Explicitly use colmajor order to match scores + Eigen::ArrayXXf scores_gt(5, 4); + // Linear, overlap_thresh=0.1 + scores_gt.col(0) << 7.13657320e-01, 9.52467501e-01, 1.44501388e-01, + 9.99834776e-01, 9.99737203e-01; + // Linear, overlap_thresh=0.3 + scores_gt.col(1) << 8.17906916e-01, 9.52467501e-01, 1.76800430e-01, + 9.99834776e-01, 9.99737203e-01; + // Gaussian, overlap_thresh=0.1 + scores_gt.col(2) << 7.91758895e-01, 9.52467501e-01, 2.12320581e-01, + 9.99834776e-01, 9.99737203e-01; + // Gaussian, overlap_thresh=0.3 + scores_gt.col(3) << 7.91758895e-01, 9.52467501e-01, 2.12320581e-01, + 9.99834776e-01, 9.99737203e-01; + + Eigen::ArrayXf out_scores; + for (int i = 0; i < method.size(); ++i) { + LOG(INFO) << "Testing SoftNMS with method=" << method[i] + << ", overlap_thresh=" << overlap_thresh[i]; + const auto& expected_scores = scores_gt.col(i); + + auto keep = utils::soft_nms_cpu( + &out_scores, + proposals, + scores, + 0.5, + overlap_thresh[i], + 0.0001, + method[i]); + EXPECT_EQ(keep, keep_gt); + { + auto diff = expected_scores - out_scores; + EXPECT_TRUE((diff.abs() < 1e-6).all()); + } + + // Test with topN + for (int topN = 1; topN <= 3; ++topN) { + keep = utils::soft_nms_cpu( + &out_scores, + proposals, + scores, + 0.5, + overlap_thresh[i], + 0.0001, + method[i], + topN); + std::vector expected_keep(keep_gt.begin(), keep_gt.begin() + topN); + EXPECT_EQ(expected_keep, keep); + } + + // Test with filtered indices + auto indices = utils::GetArrayIndices(scores >= 0.9); + keep = utils::soft_nms_cpu( + &out_scores, + proposals, + scores, + indices, + 0.5, + overlap_thresh[i], + 0.0001, + method[i]); + std::sort(keep.begin(), keep.end()); + EXPECT_EQ(indices, keep); + { + const auto& expected = utils::GetSubArray(expected_scores, indices); + const auto& actual = utils::GetSubArray(out_scores, indices); + EXPECT_TRUE(((expected - actual).abs() < 1e-6).all()); + } + + // Test with high score_thresh + float score_thresh = 0.9; + keep = utils::soft_nms_cpu( + &out_scores, + proposals, + scores, + 0.5, + overlap_thresh[i], + score_thresh, + method[i]); + { + auto expected_keep = + utils::GetArrayIndices(expected_scores >= score_thresh); + std::sort(keep.begin(), keep.end()); + EXPECT_EQ(expected_keep, keep); + + const auto& expected = utils::GetSubArray(expected_scores, expected_keep); + const auto& actual = utils::GetSubArray(out_scores, expected_keep); + EXPECT_TRUE(((expected - actual).abs() < 1e-6).all()); + } + } +} + +TEST(UtilsNMSTest, RotatedBBoxOverlaps) { + { + // Simple case with angle 0 (upright boxes) + Eigen::ArrayXXf boxes(2, 5); + boxes << 10.5, 15.5, 21, 31, 0, 14.0, 17, 4, 10, 0; + + Eigen::ArrayXXf query_boxes(3, 5); + query_boxes << 30.5, 10.5, 41, 1, 0, 13.5, 21.5, 5, 21, 0, 10.5, 15.5, 21, + 31, 0; + + Eigen::ArrayXXf expected(2, 3); + expected << 0.0161527172, 0.152439028, 1., 0., 0.38095239, 0.0614439324; + + auto actual = utils::bbox_overlaps_rotated(boxes, query_boxes); + EXPECT_TRUE(((expected - actual).abs() < 1e-6).all()); + } + + { + // Angle 45 + Eigen::ArrayXXf boxes(1, 5); + boxes << 0, 0, 2.0 * std::sqrt(2), 2.0 * std::sqrt(2), 45; + + Eigen::ArrayXXf query_boxes(1, 5); + query_boxes << 1, 1, 2, 2, 0; + + Eigen::ArrayXXf expected(1, 1); + expected << 0.2; + + auto actual = utils::bbox_overlaps_rotated(boxes, query_boxes); + EXPECT_TRUE(((expected - actual).abs() < 1e-6).all()); + } + + { + Eigen::ArrayXXf boxes(2, 5); + boxes << 60.0, 60.0, 100.0, 100.0, 0.0, 50.0, 50.0, 100.0, 100.0, 135.0; + + Eigen::ArrayXXf query_boxes(6, 5); + query_boxes << 60.0, 60.0, 100.0, 100.0, 180.0, 50.0, 50.0, 100.0, 100.0, + 45.0, 80.0, 50.0, 100.0, 100.0, 0.0, 50.0, 50.0, 200.0, 50.0, 45.0, + 200.0, 200.0, 100.0, 100.0, 0, 60.0, 60.0, 100.0, 100.0, 1.0; + + Eigen::ArrayXXf expected(2, 6); + expected << 1., 0.6507467031, 0.5625, 0.3718426526, 0., 0.9829941392, + 0.6507467628, 1., 0.4893216789, 0.3333334029, 0., 0.6508141756; + + auto actual = utils::bbox_overlaps_rotated(boxes, query_boxes); + EXPECT_TRUE(((expected - actual).abs() < 1e-6).all()); + } +} +#endif // CV_MAJOR_VERSION >= 3 + } // namespace caffe2 From 9126f95ac3b24effead123dd3e0c39a8e222f73d Mon Sep 17 00:00:00 2001 From: Viswanath Sivakumar Date: Wed, 11 Jul 2018 11:19:08 -0700 Subject: [PATCH 20/36] GenerateProposals and BoxWithNMSLimit ops: Add support for rotated boxes (#8953) Summary: Pull Request resolved: https://github.com/pytorch/pytorch/pull/8953 Closes https://github.com/pytorch/pytorch/pull/8953 Based on RRPN paper: https://arxiv.org/abs/1703.01086 Reviewed By: pjh5 Differential Revision: D8655687 fbshipit-source-id: 4985739e585c07dd406b9386dc7f46ad93576798 --- caffe2/operators/box_with_nms_limit_op.cc | 33 +- caffe2/operators/box_with_nms_limit_op.h | 6 +- caffe2/operators/generate_proposals_op.cc | 87 +++-- .../operators/generate_proposals_op_test.cc | 366 +++++++++++++++++- .../generate_proposals_op_util_boxes.h | 2 + 5 files changed, 446 insertions(+), 48 deletions(-) diff --git a/caffe2/operators/box_with_nms_limit_op.cc b/caffe2/operators/box_with_nms_limit_op.cc index 9caadb3629b6e..9a3f45f85b85d 100644 --- a/caffe2/operators/box_with_nms_limit_op.cc +++ b/caffe2/operators/box_with_nms_limit_op.cc @@ -34,6 +34,8 @@ bool BoxWithNMSLimitOp::RunOnDevice() { auto* out_boxes = Output(1); auto* out_classes = Output(2); + const int box_dim = rotated_ ? 5 : 4; + // tscores: (num_boxes, num_classes), 0 for background if (tscores.ndim() == 4) { CAFFE_ENFORCE_EQ(tscores.dim(2), 1, tscores.dim(2)); @@ -42,7 +44,7 @@ bool BoxWithNMSLimitOp::RunOnDevice() { CAFFE_ENFORCE_EQ(tscores.ndim(), 2, tscores.ndim()); } CAFFE_ENFORCE(tscores.template IsType(), tscores.meta().name()); - // tboxes: (num_boxes, num_classes * 4) + // tboxes: (num_boxes, num_classes * box_dim) if (tboxes.ndim() == 4) { CAFFE_ENFORCE_EQ(tboxes.dim(2), 1, tboxes.dim(2)); CAFFE_ENFORCE_EQ(tboxes.dim(3), 1, tboxes.dim(3)); @@ -55,7 +57,7 @@ bool BoxWithNMSLimitOp::RunOnDevice() { int num_classes = tscores.dim(1); CAFFE_ENFORCE_EQ(N, tboxes.dim(0)); - CAFFE_ENFORCE_EQ(num_classes * 4, tboxes.dim(1)); + CAFFE_ENFORCE_EQ(num_classes * box_dim, tboxes.dim(1)); int batch_size = 1; vector batch_splits_default(1, tscores.dim(0)); @@ -72,7 +74,7 @@ bool BoxWithNMSLimitOp::RunOnDevice() { CAFFE_ENFORCE_EQ(batch_splits.sum(), N); out_scores->Resize(0); - out_boxes->Resize(0, 4); + out_boxes->Resize(0, box_dim); out_classes->Resize(0); TensorCPU* out_keeps = nullptr; @@ -107,7 +109,7 @@ bool BoxWithNMSLimitOp::RunOnDevice() { for (int j = 1; j < num_classes; j++) { auto cur_scores = scores.col(j); auto inds = utils::GetArrayIndices(cur_scores > score_thres_); - auto cur_boxes = boxes.block(0, j * 4, boxes.rows(), 4); + auto cur_boxes = boxes.block(0, j * box_dim, boxes.rows(), box_dim); if (soft_nms_enabled_) { auto cur_soft_nms_scores = soft_nms_scores.col(j); @@ -189,15 +191,16 @@ bool BoxWithNMSLimitOp::RunOnDevice() { int cur_out_idx = 0; for (int j = 1; j < num_classes; j++) { auto cur_scores = scores.col(j); - auto cur_boxes = boxes.block(0, j * 4, boxes.rows(), 4); + auto cur_boxes = boxes.block(0, j * box_dim, boxes.rows(), box_dim); auto& cur_keep = keeps[j]; Eigen::Map cur_out_scores( out_scores->mutable_data() + cur_start_idx + cur_out_idx, cur_keep.size()); Eigen::Map cur_out_boxes( - out_boxes->mutable_data() + (cur_start_idx + cur_out_idx) * 4, + out_boxes->mutable_data() + + (cur_start_idx + cur_out_idx) * box_dim, cur_keep.size(), - 4); + box_dim); Eigen::Map cur_out_classes( out_classes->mutable_data() + cur_start_idx + cur_out_idx, cur_keep.size()); @@ -272,11 +275,19 @@ returned boxes. .Arg( "soft_nms_min_score_thres", "(float) Lower bound on updated scores to discard boxes") + .Arg( + "rotated", + "bool (default false). If true, then boxes (rois and deltas) include " + "angle info to handle rotation. The format will be " + "[ctr_x, ctr_y, width, height, angle (in degrees)].") .Input(0, "scores", "Scores, size (count, num_classes)") .Input( 1, "boxes", - "Bounding box for each class, size (count, num_classes * 4)") + "Bounding box for each class, size (count, num_classes * 4). " + "For rotated boxes, this would have an additional angle (in degrees) " + "in the format [, ctr_x, ctr_y, w, h, angle]. " + "Size: (count, num_classes * 5).") .Input( 2, "batch_splits", @@ -284,7 +295,11 @@ returned boxes. "of RoIs/boxes belonging to the corresponding image in batch. " "Sum should add up to total count of scores/boxes.") .Output(0, "scores", "Filtered scores, size (n)") - .Output(1, "boxes", "Filtered boxes, size (n, 4)") + .Output( + 1, + "boxes", + "Filtered boxes, size (n, 4). " + "For rotated boxes, size (n, 5), format [ctr_x, ctr_y, w, h, angle].") .Output(2, "classes", "Class id for each filtered score/box, size (n)") .Output( 3, diff --git a/caffe2/operators/box_with_nms_limit_op.h b/caffe2/operators/box_with_nms_limit_op.h index 679081b9dec58..bb0e5d0e52f92 100644 --- a/caffe2/operators/box_with_nms_limit_op.h +++ b/caffe2/operators/box_with_nms_limit_op.h @@ -29,7 +29,8 @@ class BoxWithNMSLimitOp final : public Operator { OperatorBase::GetSingleArgument("soft_nms_sigma", 0.5)), soft_nms_min_score_thres_(OperatorBase::GetSingleArgument( "soft_nms_min_score_thres", - 0.001)) { + 0.001)), + rotated_(OperatorBase::GetSingleArgument("rotated", false)) { CAFFE_ENFORCE( soft_nms_method_str_ == "linear" || soft_nms_method_str_ == "gaussian", "Unexpected soft_nms_method"); @@ -56,6 +57,9 @@ class BoxWithNMSLimitOp final : public Operator { float soft_nms_sigma_ = 0.5; // Lower-bound on updated scores to discard boxes float soft_nms_min_score_thres_ = 0.001; + // Set for RRPN case to handle rotated boxes. Inputs should be in format + // [ctr_x, ctr_y, width, height, angle (in degrees)]. + bool rotated_{false}; }; } // namespace caffe2 diff --git a/caffe2/operators/generate_proposals_op.cc b/caffe2/operators/generate_proposals_op.cc index 49cb0315eb3f9..66afc7988c65a 100644 --- a/caffe2/operators/generate_proposals_op.cc +++ b/caffe2/operators/generate_proposals_op.cc @@ -59,36 +59,51 @@ ERMatXf ComputeAllAnchors( float feat_stride) { const auto K = height * width; const auto A = anchors.dim(0); + const auto box_dim = anchors.dim(1); + CAFFE_ENFORCE(box_dim == 4 || box_dim == 5); ERMatXf shift_x = (ERVecXf::LinSpaced(width, 0.0, width - 1.0) * feat_stride) .replicate(height, 1); ERMatXf shift_y = (EVecXf::LinSpaced(height, 0.0, height - 1.0) * feat_stride) .replicate(1, width); - Eigen::MatrixXf shifts(K, 4); - shifts << ConstEigenVectorMap(shift_x.data(), shift_x.size()), - ConstEigenVectorMap(shift_y.data(), shift_y.size()), - ConstEigenVectorMap(shift_x.data(), shift_x.size()), - ConstEigenVectorMap(shift_y.data(), shift_y.size()); + Eigen::MatrixXf shifts(K, box_dim); + if (box_dim == 4) { + // Upright boxes in [x1, y1, x2, y2] format + shifts << ConstEigenVectorMap(shift_x.data(), shift_x.size()), + ConstEigenVectorMap(shift_y.data(), shift_y.size()), + ConstEigenVectorMap(shift_x.data(), shift_x.size()), + ConstEigenVectorMap(shift_y.data(), shift_y.size()); + } else { + // Rotated boxes in [ctr_x, ctr_y, w, h, angle] format. + // Zero shift for width, height and angle. + ERMatXf shift_zero = ERMatXf::Constant(height, width, 0.0); + shifts << ConstEigenVectorMap(shift_x.data(), shift_x.size()), + ConstEigenVectorMap(shift_y.data(), shift_y.size()), + ConstEigenVectorMap(shift_zero.data(), shift_zero.size()), + ConstEigenVectorMap(shift_zero.data(), shift_zero.size()), + ConstEigenVectorMap(shift_zero.data(), shift_zero.size()); + } // Broacast anchors over shifts to enumerate all anchors at all positions // in the (H, W) grid: - // - add A anchors of shape (1, A, 4) to - // - K shifts of shape (K, 1, 4) to get - // - all shifted anchors of shape (K, A, 4) - // - reshape to (K*A, 4) shifted anchors + // - add A anchors of shape (1, A, box_dim) to + // - K shifts of shape (K, 1, box_dim) to get + // - all shifted anchors of shape (K, A, box_dim) + // - reshape to (K*A, box_dim) shifted anchors ConstEigenMatrixMap anchors_vec( - anchors.template data(), 1, A * 4); + anchors.template data(), 1, A * box_dim); // equivalent to python code // all_anchors = ( - // self._model.anchors.reshape((1, A, 4)) + - // shifts.reshape((1, K, 4)).transpose((1, 0, 2))) - // all_anchors = all_anchors.reshape((K * A, 4)) - // all_anchors_vec: (K, A * 4) + // self._model.anchors.reshape((1, A, box_dim)) + + // shifts.reshape((1, K, box_dim)).transpose((1, 0, 2))) + // all_anchors = all_anchors.reshape((K * A, box_dim)) + // all_anchors_vec: (K, A * box_dim) ERMatXf all_anchors_vec = anchors_vec.replicate(K, 1) + shifts.rowwise().replicate(A); - // use the following to reshape to (K * A, 4) - // Eigen::Map all_anchors(all_anchors_vec.data(), K * A, 4); + // use the following to reshape to (K * A, box_dim) + // Eigen::Map all_anchors( + // all_anchors_vec.data(), K * A, box_dim); return all_anchors_vec; } @@ -106,23 +121,25 @@ void GenerateProposalsOp::ProposalsForOneImage( const auto& post_nms_topN = rpn_post_nms_topN_; const auto& nms_thresh = rpn_nms_thresh_; const auto& min_size = rpn_min_size_; + const int box_dim = static_cast(all_anchors.cols()); + CAFFE_ENFORCE(box_dim == 4 || box_dim == 5); // Transpose and reshape predicted bbox transformations to get them // into the same order as the anchors: - // - bbox deltas will be (4 * A, H, W) format from conv output - // - transpose to (H, W, 4 * A) - // - reshape to (H * W * A, 4) where rows are ordered by (H, W, A) + // - bbox deltas will be (box_dim * A, H, W) format from conv output + // - transpose to (H, W, box_dim * A) + // - reshape to (H * W * A, box_dim) where rows are ordered by (H, W, A) // in slowest to fastest order to match the enumerated anchors CAFFE_ENFORCE_EQ(bbox_deltas_tensor.ndim(), 3); - CAFFE_ENFORCE_EQ(bbox_deltas_tensor.dim(0) % 4, 0); - auto A = bbox_deltas_tensor.dim(0) / 4; + CAFFE_ENFORCE_EQ(bbox_deltas_tensor.dim(0) % box_dim, 0); + auto A = bbox_deltas_tensor.dim(0) / box_dim; auto H = bbox_deltas_tensor.dim(1); auto W = bbox_deltas_tensor.dim(2); // equivalent to python code - // bbox_deltas = bbox_deltas.transpose((1, 2, 0)).reshape((-1, 4)) - ERArrXXf bbox_deltas(H * W * A, 4); - Eigen::Map(bbox_deltas.data(), H * W, 4 * A) = - Eigen::Map(bbox_deltas_tensor.data(), A * 4, H * W) + // bbox_deltas = bbox_deltas.transpose((1, 2, 0)).reshape((-1, box_dim)) + ERArrXXf bbox_deltas(H * W * A, box_dim); + Eigen::Map(bbox_deltas.data(), H * W, box_dim * A) = + Eigen::Map(bbox_deltas_tensor.data(), A * box_dim, H * W) .transpose(); CAFFE_ENFORCE_EQ(bbox_deltas.rows(), all_anchors.rows()); @@ -177,6 +194,7 @@ void GenerateProposalsOp::ProposalsForOneImage( // 2. clip proposals to image (may result in proposals with zero area // that will be removed in the next step) + // TODO (viswanath): Should we clip rotated boxes as well? proposals = utils::clip_boxes(proposals, im_info[0], im_info[1]); // 3. remove predicted boxes with either height or width < min_size @@ -214,31 +232,34 @@ bool GenerateProposalsOp::RunOnDevice() { const auto height = scores.dim(2); const auto width = scores.dim(3); const auto K = height * width; + const auto box_dim = anchors.dim(1); + CAFFE_ENFORCE(box_dim == 4 || box_dim == 5); - // bbox_deltas: (num_images, A * 4, H, W) + // bbox_deltas: (num_images, A * box_dim, H, W) CAFFE_ENFORCE_EQ( - bbox_deltas.dims(), (vector{num_images, 4 * A, height, width})); + bbox_deltas.dims(), + (vector{num_images, box_dim * A, height, width})); // im_info_tensor: (num_images, 3), format [height, width, scale; ...] CAFFE_ENFORCE_EQ(im_info_tensor.dims(), (vector{num_images, 3})); CAFFE_ENFORCE( im_info_tensor.template IsType(), im_info_tensor.meta().name()); - // anchors: (A, 4) - CAFFE_ENFORCE_EQ(anchors.dims(), (vector{A, 4})); + // anchors: (A, box_dim) + CAFFE_ENFORCE_EQ(anchors.dims(), (vector{A, box_dim})); CAFFE_ENFORCE(anchors.template IsType(), anchors.meta().name()); // Broadcast the anchors to all pixels auto all_anchors_vec = utils::ComputeAllAnchors(anchors, height, width, feat_stride_); - Eigen::Map all_anchors(all_anchors_vec.data(), K * A, 4); + Eigen::Map all_anchors(all_anchors_vec.data(), K * A, box_dim); Eigen::Map im_info( im_info_tensor.data(), im_info_tensor.dim(0), im_info_tensor.dim(1)); - const int roi_col_count = 5; + const int roi_col_count = box_dim + 1; out_rois->Resize(0, roi_col_count); out_rois_probs->Resize(0); @@ -274,9 +295,9 @@ bool GenerateProposalsOp::RunOnDevice() { int csz = im_i_boxes.rows(); // write rois - Eigen::Map cur_rois(out_rois_ptr, csz, 5); + Eigen::Map cur_rois(out_rois_ptr, csz, roi_col_count); cur_rois.col(0).setConstant(i); - cur_rois.block(0, 1, csz, 4) = im_i_boxes; + cur_rois.block(0, 1, csz, box_dim) = im_i_boxes; // write rois_probs Eigen::Map(out_rois_probs_ptr, csz) = im_i_probs; diff --git a/caffe2/operators/generate_proposals_op_test.cc b/caffe2/operators/generate_proposals_op_test.cc index b8edacd2c729a..d8e1021010aa3 100644 --- a/caffe2/operators/generate_proposals_op_test.cc +++ b/caffe2/operators/generate_proposals_op_test.cc @@ -87,6 +87,70 @@ TEST(GenerateProposalsTest, TestComputeAllAnchors) { EXPECT_EQ((all_anchors_result - all_anchors_gt).norm(), 0); } +namespace { + +template +ERMatXf boxes_xyxy_to_xywh(const Eigen::MatrixBase& boxes) { + CAFFE_ENFORCE_EQ(boxes.cols(), 4); + ERMatXf res(boxes.rows(), 4); + auto ones = ERMatXf::Constant(boxes.rows(), 1, 1.0); + res.col(0) = (boxes.col(0) + boxes.col(2)) / 2.0; // ctr_x = (x1 + x2)/2 + res.col(1) = (boxes.col(1) + boxes.col(3)) / 2.0; // ctr_y = (y1 + y2)/2 + res.col(2) = boxes.col(2) - boxes.col(0) + ones; // w = x2 - x1 + 1 + res.col(3) = boxes.col(3) - boxes.col(1) + ones; // h = y2 - y1 + 1 + return res; +} + +} // namespace + +TEST(GenerateProposalsTest, TestComputeAllAnchorsRotated) { + // Similar to TestComputeAllAnchors but for rotated boxes with angle info. + ERMatXf anchors_xyxy(3, 4); + anchors_xyxy << -38, -16, 53, 31, -84, -40, 99, 55, -176, -88, 191, 103; + + // Convert to RRPN format and add angles + ERMatXf anchors(3, 5); + anchors.block(0, 0, 3, 4) = boxes_xyxy_to_xywh(anchors_xyxy); + std::vector angles{0.0, 45.0, -120.0}; + for (int i = 0; i < anchors.rows(); ++i) { + anchors(i, 4) = angles[i % angles.size()]; + } + + int height = 4; + int width = 3; + float feat_stride = 16; + ERMatXf all_anchors_gt_xyxy(36, 4); + all_anchors_gt_xyxy << -38, -16, 53, 31, -84, -40, 99, 55, -176, -88, 191, + 103, -22, -16, 69, 31, -68, -40, 115, 55, -160, -88, 207, 103, -6, -16, + 85, 31, -52, -40, 131, 55, -144, -88, 223, 103, -38, 0, 53, 47, -84, -24, + 99, 71, -176, -72, 191, 119, -22, 0, 69, 47, -68, -24, 115, 71, -160, -72, + 207, 119, -6, 0, 85, 47, -52, -24, 131, 71, -144, -72, 223, 119, -38, 16, + 53, 63, -84, -8, 99, 87, -176, -56, 191, 135, -22, 16, 69, 63, -68, -8, + 115, 87, -160, -56, 207, 135, -6, 16, 85, 63, -52, -8, 131, 87, -144, -56, + 223, 135, -38, 32, 53, 79, -84, 8, 99, 103, -176, -40, 191, 151, -22, 32, + 69, 79, -68, 8, 115, 103, -160, -40, 207, 151, -6, 32, 85, 79, -52, 8, + 131, 103, -144, -40, 223, 151; + + // Convert gt to RRPN format and add angles + ERMatXf all_anchors_gt(36, 5); + all_anchors_gt.block(0, 0, 36, 4) = boxes_xyxy_to_xywh(all_anchors_gt_xyxy); + for (int i = 0; i < all_anchors_gt.rows(); ++i) { + all_anchors_gt(i, 4) = angles[i % angles.size()]; + } + + TensorCPU anchors_tensor(vector{anchors.rows(), anchors.cols()}); + Eigen::Map( + anchors_tensor.mutable_data(), anchors.rows(), anchors.cols()) = + anchors; + + auto result = + utils::ComputeAllAnchors(anchors_tensor, height, width, feat_stride); + Eigen::Map all_anchors_result( + result.data(), height * width * anchors.rows(), 5); + + EXPECT_EQ((all_anchors_result - all_anchors_gt).norm(), 0); +} + TEST(GenerateProposalsTest, TestEmpty) { Workspace ws; OperatorDef def; @@ -196,11 +260,11 @@ TEST(GenerateProposalsTest, TestRealDownSampled) { vector anchors{-38, -16, 53, 31, -120, -120, 135, 135}; ERMatXf rois_gt(9, 5); - rois_gt << 0, 0, 0, 79, 59, 0, 0, 5.0005703f, 52.63237f, 43.69501495f, 0, - 24.13628387f, 7.51243401f, 79, 46.06628418f, 0, 0, 7.50924301f, - 68.47792816f, 46.03357315f, 0, 0, 23.09477997f, 51.61448669f, 59, 0, 0, - 39.52141571f, 52.44710541f, 59, 0, 23.57396317f, 29.98791885f, 79, 59, 0, - 0, 41.90219116f, 79, 59, 0, 0, 23.30098343f, 79, 59; + rois_gt << 0, 0, 0, 79, 59, 0, 0, 5.0005703f, 51.6324f, 42.6950f, 0, + 24.13628387f, 7.51243401f, 79, 45.0663f, 0, 0, 7.50924301f, 67.4779f, + 45.0336, 0, 0, 23.09477997f, 50.61448669f, 59, 0, 0, 39.52141571f, + 51.44710541f, 59, 0, 23.57396317f, 29.98791885f, 79, 59, 0, 0, + 41.90219116f, 79, 59, 0, 0, 23.30098343f, 78.2413f, 58.7287f; vector rois_probs_gt{2.66913995e-02f, 5.44218998e-03f, 1.20544003e-03f, @@ -221,6 +285,7 @@ TEST(GenerateProposalsTest, TestRealDownSampled) { def.add_arg()->CopyFrom(MakeArgument("post_nms_topN", 300)); def.add_arg()->CopyFrom(MakeArgument("nms_thresh", 0.7f)); def.add_arg()->CopyFrom(MakeArgument("min_size", 16.0f)); + def.add_arg()->CopyFrom(MakeArgument("correct_transform_coords", true)); unique_ptr op(CreateOperator(def, &ws)); EXPECT_NE(nullptr, op.get()); @@ -250,4 +315,295 @@ TEST(GenerateProposalsTest, TestRealDownSampled) { 1e-4); } +#if defined(CV_MAJOR_VERSION) && (CV_MAJOR_VERSION >= 3) +TEST(GenerateProposalsTest, TestRealDownSampledRotatedAngle0) { + // Similar to TestRealDownSampled but for rotated boxes with angle info. + float angle = 0; + float delta_angle = 0; + + Workspace ws; + OperatorDef def; + def.set_name("test"); + def.set_type("GenerateProposals"); + def.add_input("scores"); + def.add_input("bbox_deltas"); + def.add_input("im_info"); + def.add_input("anchors"); + def.add_output("rois"); + def.add_output("rois_probs"); + const int img_count = 1; + const int A = 2; + const int H = 4; + const int W = 5; + + vector scores{ + 5.44218998e-03f, 1.19207997e-03f, 1.12379994e-03f, 1.17181998e-03f, + 1.20544003e-03f, 6.17993006e-04f, 1.05261997e-05f, 8.91025957e-06f, + 9.29536981e-09f, 6.09605013e-05f, 4.72735002e-04f, 1.13482002e-10f, + 1.50015003e-05f, 4.45032993e-06f, 3.21612994e-08f, 8.02662980e-04f, + 1.40488002e-04f, 3.12508007e-07f, 3.02616991e-06f, 1.97759000e-08f, + 2.66913995e-02f, 5.26766013e-03f, 5.05053019e-03f, 5.62100019e-03f, + 5.37420018e-03f, 5.26280981e-03f, 2.48894998e-04f, 1.06842002e-04f, + 3.92931997e-06f, 1.79388002e-03f, 4.79440019e-03f, 3.41609990e-07f, + 5.20430971e-04f, 3.34090000e-05f, 2.19159006e-07f, 2.28786003e-03f, + 5.16703985e-05f, 4.04523007e-06f, 1.79227004e-06f, 5.32449000e-08f}; + vector bbx{ + -1.65040009e-02f, -1.84051003e-02f, -1.85930002e-02f, -2.08263006e-02f, + -1.83814000e-02f, -2.89172009e-02f, -3.89706008e-02f, -7.52277970e-02f, + -1.54091999e-01f, -2.55433004e-02f, -1.77490003e-02f, -1.10340998e-01f, + -4.20190990e-02f, -2.71421000e-02f, 6.89801015e-03f, 5.71171008e-02f, + -1.75665006e-01f, 2.30021998e-02f, 3.08554992e-02f, -1.39333997e-02f, + 3.40579003e-01f, 3.91070992e-01f, 3.91624004e-01f, 3.92527014e-01f, + 3.91445011e-01f, 3.79328012e-01f, 4.26631987e-01f, 3.64892989e-01f, + 2.76894987e-01f, 5.13985991e-01f, 3.79999995e-01f, 1.80457994e-01f, + 4.37402993e-01f, 4.18545991e-01f, 2.51549989e-01f, 4.48318988e-01f, + 1.68564007e-01f, 4.65440989e-01f, 4.21891987e-01f, 4.45928007e-01f, + 3.27155995e-03f, 3.71480011e-03f, 3.60032008e-03f, 4.27092984e-03f, + 3.74579988e-03f, 5.95752988e-03f, -3.14473989e-03f, 3.52022005e-03f, + -1.88564006e-02f, 1.65188999e-03f, 1.73791999e-03f, -3.56074013e-02f, + -1.66615995e-04f, 3.14146001e-03f, -1.11830998e-02f, -5.35363983e-03f, + 6.49790000e-03f, -9.27671045e-03f, -2.83346009e-02f, -1.61233004e-02f, + -2.15505004e-01f, -2.19910994e-01f, -2.20872998e-01f, -2.12831005e-01f, + -2.19145000e-01f, -2.27687001e-01f, -3.43973994e-01f, -2.75869995e-01f, + -3.19516987e-01f, -2.50418007e-01f, -2.48537004e-01f, -5.08224010e-01f, + -2.28724003e-01f, -2.82402009e-01f, -3.75815988e-01f, -2.86352992e-01f, + -5.28333001e-02f, -4.43836004e-01f, -4.55134988e-01f, -4.34897989e-01f, + -5.65053988e-03f, -9.25739005e-04f, -1.06790999e-03f, -2.37016007e-03f, + -9.71166010e-04f, -8.90910998e-03f, -1.17592998e-02f, -2.08992008e-02f, + -4.94231991e-02f, 6.63906988e-03f, 3.20469006e-03f, -6.44695014e-02f, + -3.11607006e-03f, 2.02738005e-03f, 1.48096997e-02f, 4.39785011e-02f, + -8.28424022e-02f, 3.62076014e-02f, 2.71668993e-02f, 1.38250999e-02f, + 6.76669031e-02f, 1.03252999e-01f, 1.03255004e-01f, 9.89722982e-02f, + 1.03646003e-01f, 4.79663983e-02f, 1.11014001e-01f, 9.31736007e-02f, + 1.15768999e-01f, 1.04014002e-01f, -8.90677981e-03f, 1.13103002e-01f, + 1.33085996e-01f, 1.25405997e-01f, 1.50051996e-01f, -1.13038003e-01f, + 7.01059997e-02f, 1.79651007e-01f, 1.41055003e-01f, 1.62841007e-01f, + -1.00247003e-02f, -8.17587040e-03f, -8.32176022e-03f, -8.90108012e-03f, + -8.13035015e-03f, -1.77263003e-02f, -3.69572006e-02f, -3.51580009e-02f, + -5.92143014e-02f, -1.80795006e-02f, -5.46086021e-03f, -4.10550982e-02f, + -1.83081999e-02f, -2.15411000e-02f, -1.17953997e-02f, 3.33894007e-02f, + -5.29635996e-02f, -6.97528012e-03f, -3.15250992e-03f, -3.27355005e-02f, + 1.29676998e-01f, 1.16080999e-01f, 1.15947001e-01f, 1.21797003e-01f, + 1.16089001e-01f, 1.44875005e-01f, 1.15617000e-01f, 1.31586999e-01f, + 1.74735002e-02f, 1.21973999e-01f, 1.31596997e-01f, 2.48907991e-02f, + 6.18605018e-02f, 1.12855002e-01f, -6.99798986e-02f, 9.58312973e-02f, + 1.53593004e-01f, -8.75087008e-02f, -4.92327996e-02f, -3.32239009e-02f}; + + // Add angle in bbox deltas + int num_boxes = scores.size(); + CHECK_EQ(bbx.size() / 4, num_boxes); + vector bbx_with_angle(num_boxes * 5); + // bbx (deltas) is in shape (A * 4, H, W). Insert angle delta + // at each spatial location for each anchor. + int i = 0, j = 0; + for (int a = 0; a < A; ++a) { + for (int k = 0; k < 4 * H * W; ++k) { + bbx_with_angle[i++] = bbx[j++]; + } + for (int k = 0; k < H * W; ++k) { + bbx_with_angle[i++] = delta_angle; + } + } + + vector im_info{60, 80, 0.166667f}; + // vector anchors{-38, -16, 53, 31, -120, -120, 135, 135}; + vector anchors{8, 8, 92, 48, angle, 8, 8, 256, 256, angle}; + + // Although angle == 0, the results aren't exactly the same as + // TestRealDownSampled because because clip_boxes() is not performed + // for RRPN style boxes. + ERMatXf rois_gt(13, 6); + rois_gt << 0, 6.55346, 25.3227, 253.447, 291.446, 0, 0, 55.3932, 33.3369, + 253.731, 289.158, 0, 0, 6.48163, 24.3478, 92.3015, 38.6944, 0, 0, 70.3089, + 26.7894, 92.3453, 38.5539, 0, 0, 22.3067, 26.7714, 92.3424, 38.5243, 0, 0, + 054.084, 26.8413, 92.3938, 38.798, 0, 0, 5.33962, 42.2077, 92.5497, + 38.2259, 0, 0, 6.36709, 58.24, 92.16, 37.4372, 0, 0, 69.65, 48.6713, + 92.1521, 37.3668, 0, 0, 20.4147, 44.4783, 91.7111, 34.0295, 0, 0, 033.079, + 41.5149, 92.3244, 36.4278, 0, 0, 41.8235, 037.291, 90.2815, 034.872, 0, 0, + 13.8486, 48.662, 88.7818, 28.875, 0; + vector rois_probs_gt{0.0266914, + 0.005621, + 0.00544219, + 0.00120544, + 0.00119208, + 0.00117182, + 0.000617993, + 0.000472735, + 6.09605e-05, + 1.05262e-05, + 8.91026e-06, + 9.29537e-09, + 1.13482e-10}; + + AddInput(vector{img_count, A, H, W}, scores, "scores", &ws); + AddInput( + vector{img_count, 5 * A, H, W}, + bbx_with_angle, + "bbox_deltas", + &ws); + AddInput(vector{img_count, 3}, im_info, "im_info", &ws); + AddInput(vector{A, 5}, anchors, "anchors", &ws); + + def.add_arg()->CopyFrom(MakeArgument("spatial_scale", 1.0f / 16.0f)); + def.add_arg()->CopyFrom(MakeArgument("pre_nms_topN", 6000)); + def.add_arg()->CopyFrom(MakeArgument("post_nms_topN", 300)); + def.add_arg()->CopyFrom(MakeArgument("nms_thresh", 0.7f)); + def.add_arg()->CopyFrom(MakeArgument("min_size", 16.0f)); + def.add_arg()->CopyFrom(MakeArgument("correct_transform_coords", true)); + + unique_ptr op(CreateOperator(def, &ws)); + EXPECT_NE(nullptr, op.get()); + EXPECT_TRUE(op->Run()); + + // test rois + Blob* rois_blob = ws.GetBlob("rois"); + EXPECT_NE(nullptr, rois_blob); + auto& rois = rois_blob->Get(); + EXPECT_EQ(rois.dims(), (vector{rois_gt.rows(), rois_gt.cols()})); + auto rois_data = + Eigen::Map(rois.data(), rois.dim(0), rois.dim(1)); + EXPECT_NEAR((rois_data.matrix() - rois_gt).cwiseAbs().maxCoeff(), 0, 1e-3); + + // test rois_probs + Blob* rois_probs_blob = ws.GetBlob("rois_probs"); + EXPECT_NE(nullptr, rois_probs_blob); + auto& rois_probs = rois_probs_blob->Get(); + EXPECT_EQ(rois_probs.dims(), (vector{TIndex(rois_probs_gt.size())})); + auto rois_probs_data = + ConstEigenVectorArrayMap(rois_probs.data(), rois.dim(0)); + EXPECT_NEAR( + (rois_probs_data.matrix() - utils::AsEArrXt(rois_probs_gt).matrix()) + .cwiseAbs() + .maxCoeff(), + 0, + 1e-4); +} + +TEST(GenerateProposalsTest, TestRealDownSampledRotated) { + // Similar to TestRealDownSampled but for rotated boxes with angle info. + float angle = 45.0; + float delta_angle = 0.174533; // 0.174533 radians -> 10 degrees + float expected_angle = 55.0; + + Workspace ws; + OperatorDef def; + def.set_name("test"); + def.set_type("GenerateProposals"); + def.add_input("scores"); + def.add_input("bbox_deltas"); + def.add_input("im_info"); + def.add_input("anchors"); + def.add_output("rois"); + def.add_output("rois_probs"); + const int img_count = 1; + const int A = 2; + const int H = 4; + const int W = 5; + + vector scores{ + 5.44218998e-03f, 1.19207997e-03f, 1.12379994e-03f, 1.17181998e-03f, + 1.20544003e-03f, 6.17993006e-04f, 1.05261997e-05f, 8.91025957e-06f, + 9.29536981e-09f, 6.09605013e-05f, 4.72735002e-04f, 1.13482002e-10f, + 1.50015003e-05f, 4.45032993e-06f, 3.21612994e-08f, 8.02662980e-04f, + 1.40488002e-04f, 3.12508007e-07f, 3.02616991e-06f, 1.97759000e-08f, + 2.66913995e-02f, 5.26766013e-03f, 5.05053019e-03f, 5.62100019e-03f, + 5.37420018e-03f, 5.26280981e-03f, 2.48894998e-04f, 1.06842002e-04f, + 3.92931997e-06f, 1.79388002e-03f, 4.79440019e-03f, 3.41609990e-07f, + 5.20430971e-04f, 3.34090000e-05f, 2.19159006e-07f, 2.28786003e-03f, + 5.16703985e-05f, 4.04523007e-06f, 1.79227004e-06f, 5.32449000e-08f}; + vector bbx{ + -1.65040009e-02f, -1.84051003e-02f, -1.85930002e-02f, -2.08263006e-02f, + -1.83814000e-02f, -2.89172009e-02f, -3.89706008e-02f, -7.52277970e-02f, + -1.54091999e-01f, -2.55433004e-02f, -1.77490003e-02f, -1.10340998e-01f, + -4.20190990e-02f, -2.71421000e-02f, 6.89801015e-03f, 5.71171008e-02f, + -1.75665006e-01f, 2.30021998e-02f, 3.08554992e-02f, -1.39333997e-02f, + 3.40579003e-01f, 3.91070992e-01f, 3.91624004e-01f, 3.92527014e-01f, + 3.91445011e-01f, 3.79328012e-01f, 4.26631987e-01f, 3.64892989e-01f, + 2.76894987e-01f, 5.13985991e-01f, 3.79999995e-01f, 1.80457994e-01f, + 4.37402993e-01f, 4.18545991e-01f, 2.51549989e-01f, 4.48318988e-01f, + 1.68564007e-01f, 4.65440989e-01f, 4.21891987e-01f, 4.45928007e-01f, + 3.27155995e-03f, 3.71480011e-03f, 3.60032008e-03f, 4.27092984e-03f, + 3.74579988e-03f, 5.95752988e-03f, -3.14473989e-03f, 3.52022005e-03f, + -1.88564006e-02f, 1.65188999e-03f, 1.73791999e-03f, -3.56074013e-02f, + -1.66615995e-04f, 3.14146001e-03f, -1.11830998e-02f, -5.35363983e-03f, + 6.49790000e-03f, -9.27671045e-03f, -2.83346009e-02f, -1.61233004e-02f, + -2.15505004e-01f, -2.19910994e-01f, -2.20872998e-01f, -2.12831005e-01f, + -2.19145000e-01f, -2.27687001e-01f, -3.43973994e-01f, -2.75869995e-01f, + -3.19516987e-01f, -2.50418007e-01f, -2.48537004e-01f, -5.08224010e-01f, + -2.28724003e-01f, -2.82402009e-01f, -3.75815988e-01f, -2.86352992e-01f, + -5.28333001e-02f, -4.43836004e-01f, -4.55134988e-01f, -4.34897989e-01f, + -5.65053988e-03f, -9.25739005e-04f, -1.06790999e-03f, -2.37016007e-03f, + -9.71166010e-04f, -8.90910998e-03f, -1.17592998e-02f, -2.08992008e-02f, + -4.94231991e-02f, 6.63906988e-03f, 3.20469006e-03f, -6.44695014e-02f, + -3.11607006e-03f, 2.02738005e-03f, 1.48096997e-02f, 4.39785011e-02f, + -8.28424022e-02f, 3.62076014e-02f, 2.71668993e-02f, 1.38250999e-02f, + 6.76669031e-02f, 1.03252999e-01f, 1.03255004e-01f, 9.89722982e-02f, + 1.03646003e-01f, 4.79663983e-02f, 1.11014001e-01f, 9.31736007e-02f, + 1.15768999e-01f, 1.04014002e-01f, -8.90677981e-03f, 1.13103002e-01f, + 1.33085996e-01f, 1.25405997e-01f, 1.50051996e-01f, -1.13038003e-01f, + 7.01059997e-02f, 1.79651007e-01f, 1.41055003e-01f, 1.62841007e-01f, + -1.00247003e-02f, -8.17587040e-03f, -8.32176022e-03f, -8.90108012e-03f, + -8.13035015e-03f, -1.77263003e-02f, -3.69572006e-02f, -3.51580009e-02f, + -5.92143014e-02f, -1.80795006e-02f, -5.46086021e-03f, -4.10550982e-02f, + -1.83081999e-02f, -2.15411000e-02f, -1.17953997e-02f, 3.33894007e-02f, + -5.29635996e-02f, -6.97528012e-03f, -3.15250992e-03f, -3.27355005e-02f, + 1.29676998e-01f, 1.16080999e-01f, 1.15947001e-01f, 1.21797003e-01f, + 1.16089001e-01f, 1.44875005e-01f, 1.15617000e-01f, 1.31586999e-01f, + 1.74735002e-02f, 1.21973999e-01f, 1.31596997e-01f, 2.48907991e-02f, + 6.18605018e-02f, 1.12855002e-01f, -6.99798986e-02f, 9.58312973e-02f, + 1.53593004e-01f, -8.75087008e-02f, -4.92327996e-02f, -3.32239009e-02f}; + + // Add angle in bbox deltas + int num_boxes = scores.size(); + CHECK_EQ(bbx.size() / 4, num_boxes); + vector bbx_with_angle(num_boxes * 5); + // bbx (deltas) is in shape (A * 4, H, W). Insert angle delta + // at each spatial location for each anchor. + int i = 0, j = 0; + for (int a = 0; a < A; ++a) { + for (int k = 0; k < 4 * H * W; ++k) { + bbx_with_angle[i++] = bbx[j++]; + } + for (int k = 0; k < H * W; ++k) { + bbx_with_angle[i++] = delta_angle; + } + } + + vector im_info{60, 80, 0.166667f}; + // vector anchors{-38, -16, 53, 31, -120, -120, 135, 135}; + vector anchors{8, 8, 92, 48, angle, 8, 8, 256, 256, angle}; + + AddInput(vector{img_count, A, H, W}, scores, "scores", &ws); + AddInput( + vector{img_count, 5 * A, H, W}, + bbx_with_angle, + "bbox_deltas", + &ws); + AddInput(vector{img_count, 3}, im_info, "im_info", &ws); + AddInput(vector{A, 5}, anchors, "anchors", &ws); + + def.add_arg()->CopyFrom(MakeArgument("spatial_scale", 1.0f / 16.0f)); + def.add_arg()->CopyFrom(MakeArgument("pre_nms_topN", 6000)); + def.add_arg()->CopyFrom(MakeArgument("post_nms_topN", 300)); + def.add_arg()->CopyFrom(MakeArgument("nms_thresh", 0.7f)); + def.add_arg()->CopyFrom(MakeArgument("min_size", 16.0f)); + def.add_arg()->CopyFrom(MakeArgument("correct_transform_coords", true)); + + unique_ptr op(CreateOperator(def, &ws)); + EXPECT_NE(nullptr, op.get()); + EXPECT_TRUE(op->Run()); + + // Verify that the resulting angles are correct + Blob* rois_blob = ws.GetBlob("rois"); + EXPECT_NE(nullptr, rois_blob); + auto& rois = rois_blob->Get(); + EXPECT_GT(rois.dim(0), 0); + auto rois_data = + Eigen::Map(rois.data(), rois.dim(0), rois.dim(1)); + for (int i = 0; i < rois.dim(0); ++i) { + EXPECT_LE(std::abs(rois_data(i, 5) - expected_angle), 1e-4); + } +} +#endif // CV_MAJOR_VERSION >= 3 + } // namespace caffe2 diff --git a/caffe2/operators/generate_proposals_op_util_boxes.h b/caffe2/operators/generate_proposals_op_util_boxes.h index 633e9630eb7b9..5350d21c5c78f 100644 --- a/caffe2/operators/generate_proposals_op_util_boxes.h +++ b/caffe2/operators/generate_proposals_op_util_boxes.h @@ -177,6 +177,8 @@ clip_boxes(const Eigen::ArrayBase& boxes, int height, int width) { CAFFE_ENFORCE(boxes.cols() == 4 || boxes.cols() == 5); if (boxes.cols() == 5) { // No clipping for rotated boxes. + // TODO (viswanath): Should this be implemented for backward compatibility + // with angle=0 case? return boxes; } From c2dd90c40ef196e6a40c217016f0e4bf7c1dffbb Mon Sep 17 00:00:00 2001 From: Viswanath Sivakumar Date: Wed, 11 Jul 2018 11:22:06 -0700 Subject: [PATCH 21/36] Add angle normalization for rotated boxes (#9056) Summary: Pull Request resolved: https://github.com/pytorch/pytorch/pull/9056 Closes https://github.com/pytorch/pytorch/pull/9056 Updates bbox_transform for rotated boxes with angle info to normalize the predicted angle to be within [angle_bound_lo, angle_bound_hi] range. Reviewed By: pjh5 Differential Revision: D8706240 fbshipit-source-id: f3ee834cf362736136e285f0f8f0c063af94a879 --- caffe2/operators/bbox_transform_op.cc | 17 ++++++- caffe2/operators/bbox_transform_op.h | 13 +++++- caffe2/operators/generate_proposals_op.cc | 5 ++- caffe2/operators/generate_proposals_op.h | 13 +++++- .../generate_proposals_op_util_boxes.h | 36 +++++++++++++-- .../generate_proposals_op_util_boxes_test.cc | 44 ++++++++++++++++-- .../operator_test/bbox_transform_test.py | 45 ++++++++++++++++--- 7 files changed, 155 insertions(+), 18 deletions(-) diff --git a/caffe2/operators/bbox_transform_op.cc b/caffe2/operators/bbox_transform_op.cc index 6572fb56ab3f1..5dde4b121dab5 100644 --- a/caffe2/operators/bbox_transform_op.cc +++ b/caffe2/operators/bbox_transform_op.cc @@ -42,6 +42,18 @@ Transform proposal bounding boxes to target bounding box using bounding box "bool (default false). If true, then boxes (rois and deltas) include " "angle info to handle rotation. The format will be " "[ctr_x, ctr_y, width, height, angle (in degrees)].") + .Arg( + "angle_bound_on", + "bool (default true). If set, for rotated boxes, angle is " + "normalized to be within [angle_bound_lo, angle_bound_hi].") + .Arg( + "angle_bound_lo", + "int (default -90 degrees). If set, for rotated boxes, angle is " + "normalized to be within [angle_bound_lo, angle_bound_hi].") + .Arg( + "angle_bound_hi", + "int (default 90 degrees). If set, for rotated boxes, angle is " + "normalized to be within [angle_bound_lo, angle_bound_hi].") .Input( 0, "rois", @@ -152,7 +164,10 @@ bool BBoxTransformOp::RunOnDevice() { cur_deltas, weights_, utils::BBOX_XFORM_CLIP_DEFAULT, - correct_transform_coords_); + correct_transform_coords_, + angle_bound_on_, + angle_bound_lo_, + angle_bound_hi_); EArrXXf clip_boxes = utils::clip_boxes(trans_boxes, img_h, img_w); // Do not apply scale for angle in rotated boxes clip_boxes.leftCols(4) *= scale_after; diff --git a/caffe2/operators/bbox_transform_op.h b/caffe2/operators/bbox_transform_op.h index e7d5e476c38c5..e57d90e0266cf 100644 --- a/caffe2/operators/bbox_transform_op.h +++ b/caffe2/operators/bbox_transform_op.h @@ -23,7 +23,13 @@ class BBoxTransformOp final : public Operator { correct_transform_coords_(OperatorBase::GetSingleArgument( "correct_transform_coords", false)), - rotated_(OperatorBase::GetSingleArgument("rotated", false)) { + rotated_(OperatorBase::GetSingleArgument("rotated", false)), + angle_bound_on_( + OperatorBase::GetSingleArgument("angle_bound_on", true)), + angle_bound_lo_( + OperatorBase::GetSingleArgument("angle_bound_lo", -90)), + angle_bound_hi_( + OperatorBase::GetSingleArgument("angle_bound_hi", 90)) { CAFFE_ENFORCE_EQ( weights_.size(), 4, @@ -48,6 +54,11 @@ class BBoxTransformOp final : public Operator { // Set for RRPN case to handle rotated boxes. Inputs should be in format // [ctr_x, ctr_y, width, height, angle (in degrees)]. bool rotated_{false}; + // If set, for rotated boxes in RRPN, output angles are normalized to be + // within [angle_bound_lo, angle_bound_hi]. + bool angle_bound_on_{true}; + int angle_bound_lo_{-90}; + int angle_bound_hi_{90}; }; } // namespace caffe2 diff --git a/caffe2/operators/generate_proposals_op.cc b/caffe2/operators/generate_proposals_op.cc index 66afc7988c65a..dff52aa2ac2e2 100644 --- a/caffe2/operators/generate_proposals_op.cc +++ b/caffe2/operators/generate_proposals_op.cc @@ -190,7 +190,10 @@ void GenerateProposalsOp::ProposalsForOneImage( bbox_deltas_sorted, bbox_weights, utils::BBOX_XFORM_CLIP_DEFAULT, - correct_transform_coords_); + correct_transform_coords_, + angle_bound_on_, + angle_bound_lo_, + angle_bound_hi_); // 2. clip proposals to image (may result in proposals with zero area // that will be removed in the next step) diff --git a/caffe2/operators/generate_proposals_op.h b/caffe2/operators/generate_proposals_op.h index d05f98d42de58..c1ae4889e8931 100644 --- a/caffe2/operators/generate_proposals_op.h +++ b/caffe2/operators/generate_proposals_op.h @@ -78,7 +78,13 @@ class GenerateProposalsOp final : public Operator { rpn_min_size_(OperatorBase::GetSingleArgument("min_size", 16)), correct_transform_coords_(OperatorBase::GetSingleArgument( "correct_transform_coords", - false)) {} + false)), + angle_bound_on_( + OperatorBase::GetSingleArgument("angle_bound_on", true)), + angle_bound_lo_( + OperatorBase::GetSingleArgument("angle_bound_lo", -90)), + angle_bound_hi_( + OperatorBase::GetSingleArgument("angle_bound_hi", 90)) {} ~GenerateProposalsOp() {} @@ -116,6 +122,11 @@ class GenerateProposalsOp final : public Operator { // Set to true to match the detectron code, set to false for backward // compatibility bool correct_transform_coords_{false}; + // If set, for rotated boxes in RRPN, output angles are normalized to be + // within [angle_bound_lo, angle_bound_hi]. + bool angle_bound_on_{true}; + int angle_bound_lo_{-90}; + int angle_bound_hi_{90}; }; } // namespace caffe2 diff --git a/caffe2/operators/generate_proposals_op_util_boxes.h b/caffe2/operators/generate_proposals_op_util_boxes.h index 5350d21c5c78f..440d141899e2f 100644 --- a/caffe2/operators/generate_proposals_op_util_boxes.h +++ b/caffe2/operators/generate_proposals_op_util_boxes.h @@ -101,7 +101,10 @@ EArrXXt bbox_transform_rotated( const Eigen::ArrayBase& deltas, const std::vector& weights = std::vector{1.0, 1.0, 1.0, 1.0}, - const float bbox_xform_clip = BBOX_XFORM_CLIP_DEFAULT) { + const float bbox_xform_clip = BBOX_XFORM_CLIP_DEFAULT, + const bool angle_bound_on = true, + const int angle_bound_lo = -90, + const int angle_bound_hi = 90) { using T = typename Derived1::Scalar; using EArrXX = EArrXXt; using EArrX = EArrXt; @@ -140,7 +143,22 @@ EArrXXt bbox_transform_rotated( pred_boxes.col(3) = dh.exp() * heights; // new angle pred_boxes.col(4) = da + angles; - // TODO (viswanath): Normalize angle + + if (angle_bound_on) { + // Normalize angle to be within [angle_bound_lo, angle_bound_hi]. + // Deltas are guaranteed to be <= period / 2 while computing training + // targets by bbox_transform_inv. + const int period = angle_bound_hi - angle_bound_lo; + CAFFE_ENFORCE(period > 0 && period % 180 == 0); + auto angles = pred_boxes.col(4); + for (int i = 0; i < angles.size(); ++i) { + if (angles[i] < angle_bound_lo) { + angles[i] += T(period); + } else if (angles[i] > angle_bound_hi) { + angles[i] -= T(period); + } + } + } return pred_boxes; } @@ -152,7 +170,10 @@ EArrXXt bbox_transform( const std::vector& weights = std::vector{1.0, 1.0, 1.0, 1.0}, const float bbox_xform_clip = BBOX_XFORM_CLIP_DEFAULT, - const bool correct_transform_coords = false) { + const bool correct_transform_coords = false, + const bool angle_bound_on = true, + const int angle_bound_lo = -90, + const int angle_bound_hi = 90) { CAFFE_ENFORCE(boxes.cols() == 4 || boxes.cols() == 5); if (boxes.cols() == 4) { // Upright boxes @@ -160,7 +181,14 @@ EArrXXt bbox_transform( boxes, deltas, weights, bbox_xform_clip, correct_transform_coords); } else { // Rotated boxes with angle info - return bbox_transform_rotated(boxes, deltas, weights, bbox_xform_clip); + return bbox_transform_rotated( + boxes, + deltas, + weights, + bbox_xform_clip, + angle_bound_on, + angle_bound_lo, + angle_bound_hi); } } diff --git a/caffe2/operators/generate_proposals_op_util_boxes_test.cc b/caffe2/operators/generate_proposals_op_util_boxes_test.cc index fe6f4206a7764..4716001460a73 100644 --- a/caffe2/operators/generate_proposals_op_util_boxes_test.cc +++ b/caffe2/operators/generate_proposals_op_util_boxes_test.cc @@ -36,12 +36,13 @@ TEST(UtilsBoxesTest, TestBboxTransformRandom) { } TEST(UtilsBoxesTest, TestBboxTransformRotated) { + // Test rotated bbox transform w/o angle normalization using EMatXf = Eigen::MatrixXf; EMatXf bbox(5, 5); bbox << 214.986, 88.4628, 78.7317, 135.104, 0.0, 199.553, 55.4367, 60.6142, 101.169, 45.0, 187.829, 207.427, 0012.11, 15.1967, 90.0, 235.777, 209.518, - 122.828, 45.5215, -60.0, 79.6505, 150.914, 113.838, 117.777, 170.0; + 122.828, 45.5215, -60.0, 79.6505, 150.914, 113.838, 117.777, 170.5; EMatXf deltas(5, 5); // 0.174533 radians -> 10 degrees @@ -55,14 +56,51 @@ TEST(UtilsBoxesTest, TestBboxTransformRotated) { result_gt << 252.668, 107.367, 91.4381, 276.165, 0.0, 217.686, 19.3551, 147.631, 205.397, 55.0, 187.363, 214.185, 19.865, 31.0368, 100.0, 270.234, 210.513, 235.963, 130.163, -50.0, 36.1956, 140.863, 62.2665, 259.645, - 180.0; + 180.5; const float BBOX_XFORM_CLIP = log(1000.0 / 16.0); auto result = utils::bbox_transform( bbox.array(), deltas.array(), std::vector{1.0, 1.0, 1.0, 1.0}, - BBOX_XFORM_CLIP); + BBOX_XFORM_CLIP, + true, /* correct_transform_coords */ + false /* angle_bound_on */); + EXPECT_NEAR((result.matrix() - result_gt).norm(), 0.0, 1e-2); +} + +TEST(UtilsBoxesTest, TestBboxTransformRotatedNormalized) { + // Test rotated bbox transform with angle normalization + using EMatXf = Eigen::MatrixXf; + + EMatXf bbox(5, 5); + bbox << 214.986, 88.4628, 78.7317, 135.104, 0.0, 199.553, 55.4367, 60.6142, + 101.169, 45.0, 187.829, 207.427, 0012.11, 15.1967, 90.0, 235.777, 209.518, + 122.828, 45.5215, -60.0, 79.6505, 150.914, 113.838, 117.777, 170.5; + + EMatXf deltas(5, 5); + // 0.174533 radians -> 10 degrees + deltas << 0.47861834, 0.13992102, 0.14961673, 0.71495209, 0.0, 0.29915856, + -0.35664671, 0.89018666, 0.70815367, 0.174533, -0.03852064, 0.44466892, + 0.49492538, 0.71409376, 0.174533, 0.28052918, 0.02184832, 0.65289006, + 1.05060139, 0.174533, -0.38172557, -0.08533806, -0.60335309, 0.79052375, + 0.174533; + + EMatXf result_gt(5, 5); + result_gt << 252.668, 107.367, 91.4381, 276.165, 0.0, 217.686, 19.3551, + 147.631, 205.397, 55.0, 187.363, 214.185, 19.865, 31.0368, -80.0, 270.234, + 210.513, 235.963, 130.163, -50.0, 36.1956, 140.863, 62.2665, 259.645, 0.5; + + const float BBOX_XFORM_CLIP = log(1000.0 / 16.0); + auto result = utils::bbox_transform( + bbox.array(), + deltas.array(), + std::vector{1.0, 1.0, 1.0, 1.0}, + BBOX_XFORM_CLIP, + true, /* correct_transform_coords */ + true, /* angle_bound_on */ + -90, /* angle_bound_lo */ + 90 /* angle_bound_hi */); EXPECT_NEAR((result.matrix() - result_gt).norm(), 0.0, 1e-2); } diff --git a/caffe2/python/operator_test/bbox_transform_test.py b/caffe2/python/operator_test/bbox_transform_test.py index aaf6c0eb11ae2..20008acaa626c 100644 --- a/caffe2/python/operator_test/bbox_transform_test.py +++ b/caffe2/python/operator_test/bbox_transform_test.py @@ -101,7 +101,14 @@ def generate_rois(roi_counts, im_dims): return np.empty((0, 5)).astype(np.float32) -def bbox_transform_rotated(boxes, deltas, weights=(1.0, 1.0, 1.0, 1.0)): +def bbox_transform_rotated( + boxes, + deltas, + weights=(1.0, 1.0, 1.0, 1.0), + angle_bound_on=True, + angle_bound_lo=-90, + angle_bound_hi=90, +): """ Similar to bbox_transform but for rotated boxes with angle info. """ @@ -133,9 +140,15 @@ def bbox_transform_rotated(boxes, deltas, weights=(1.0, 1.0, 1.0, 1.0)): pred_boxes[:, 1::5] = dy * heights[:, np.newaxis] + ctr_y[:, np.newaxis] pred_boxes[:, 2::5] = np.exp(dw) * widths[:, np.newaxis] pred_boxes[:, 3::5] = np.exp(dh) * heights[:, np.newaxis] - pred_boxes[:, 4::5] = da + angles[:, np.newaxis] - # TODO (viswanath): Normalize angles + pred_angle = da + angles[:, np.newaxis] + if angle_bound_on: + period = angle_bound_hi - angle_bound_lo + assert period % 180 == 0 + pred_angle[np.where(pred_angle < angle_bound_lo)] += period + pred_angle[np.where(pred_angle > angle_bound_hi)] -= period + pred_boxes[:, 4::5] = pred_angle + return pred_boxes @@ -159,10 +172,19 @@ class TestBBoxTransformOp(hu.HypothesisTestCase): im_dim=st.integers(100, 600), skip_batch_id=st.booleans(), rotated=st.booleans(), + angle_bound_on=st.booleans(), **hu.gcs_cpu_only ) def test_bbox_transform( - self, num_rois, num_classes, im_dim, skip_batch_id, rotated, gc, dc + self, + num_rois, + num_classes, + im_dim, + skip_batch_id, + rotated, + angle_bound_on, + gc, + dc, ): """ Test with all rois belonging to a single image per run. @@ -181,7 +203,9 @@ def test_bbox_transform( def bbox_transform_ref(rois, deltas, im_info): boxes = rois if rois.shape[1] == box_dim else rois[:, 1:] if rotated: - box_out = bbox_transform_rotated(boxes, deltas) + box_out = bbox_transform_rotated( + boxes, deltas, angle_bound_on=angle_bound_on + ) # No clipping for rotated boxes else: box_out = bbox_transform(boxes, deltas) @@ -196,6 +220,7 @@ def bbox_transform_ref(rois, deltas, im_info): apply_scale=False, correct_transform_coords=True, rotated=rotated, + angle_bound_on=angle_bound_on, ) self.assertReferenceChecks( @@ -209,9 +234,12 @@ def bbox_transform_ref(rois, deltas, im_info): roi_counts=st.lists(st.integers(0, 5), min_size=1, max_size=10), num_classes=st.integers(1, 10), rotated=st.booleans(), + angle_bound_on=st.booleans(), **hu.gcs_cpu_only ) - def test_bbox_transform_batch(self, roi_counts, num_classes, rotated, gc, dc): + def test_bbox_transform_batch( + self, roi_counts, num_classes, rotated, angle_bound_on, gc, dc + ): """ Test with rois for multiple images in a batch """ @@ -239,7 +267,9 @@ def bbox_transform_ref(rois, deltas, im_info): cur_boxes = rois[offset : offset + num_rois, 1:] cur_deltas = deltas[offset : offset + num_rois] if rotated: - cur_box_out = bbox_transform_rotated(cur_boxes, cur_deltas) + cur_box_out = bbox_transform_rotated( + cur_boxes, cur_deltas, angle_bound_on=angle_bound_on + ) # No clipping for rotated boxes else: cur_box_out = bbox_transform(cur_boxes, cur_deltas) @@ -261,6 +291,7 @@ def bbox_transform_ref(rois, deltas, im_info): apply_scale=False, correct_transform_coords=True, rotated=rotated, + angle_bound_on=angle_bound_on, ) self.assertReferenceChecks( From 18a975210d1190b109d7e5fa80546b9518c63e9a Mon Sep 17 00:00:00 2001 From: Peter Goldsborough Date: Wed, 11 Jul 2018 12:02:17 -0700 Subject: [PATCH 22/36] Add explicit to conversions (#9336) Summary: Another code-mod for clang-tidy: Conversion operators should be marked explicit so that they don't cause unwanted implicit conversions. This is especially important for `operator bool()`, see https://stackoverflow.com/questions/39995573/when-can-i-use-explicit-operator-bool-without-a-cast ezyang apaszke Pull Request resolved: https://github.com/pytorch/pytorch/pull/9336 Reviewed By: apaszke Differential Revision: D8807065 Pulled By: goldsborough fbshipit-source-id: 0e9f4ebd0048a2a510c0d05fa410695d7e977eb1 --- .clang-tidy | 44 ++++++++++++++++-------------- torch/csrc/jit/autodiff.h | 2 +- torch/csrc/jit/graph_executor.h | 2 +- torch/csrc/jit/interpreter.h | 2 +- torch/csrc/jit/passes/batch_mm.cpp | 2 +- torch/csrc/utils/object_ptr.h | 2 +- 6 files changed, 28 insertions(+), 26 deletions(-) diff --git a/.clang-tidy b/.clang-tidy index 377111e41c747..5466a4a31d20a 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -3,36 +3,38 @@ Checks: ' * ,modernize-* - ,clang-analyzer-* + ,-cert-err58-cpp + ,-cert-err60-cpp ,-clang-diagnostic-* - ,-hicpp-no-array-decay + ,-cppcoreguidelines-owning-memory + ,-cppcoreguidelines-pro-bounds-array-to-pointer-decay + ,-cppcoreguidelines-pro-bounds-constant-array-index + ,-cppcoreguidelines-pro-type-static-cast-downcast + ,-cppcoreguidelines-pro-type-vararg + ,-cppcoreguidelines-special-member-functions ,-fuchsia-* + ,-google-build-using-namespace + ,-google-explicit-constructor + ,-google-readability-braces-around-statements ,-google-readability-namespace-comments - ,-llvm-namespace-comment ,-google-readability-todo - ,-cppcoreguidelines-pro-bounds-array-to-pointer-decay - ,-cert-err60-cpp - ,-llvm-header-guard - ,-cppcoreguidelines-special-member-functions - ,-misc-unused-parameters + ,-google-runtime-references + ,-google-runtime-references ,-hicpp-braces-around-statements + ,-hicpp-explicit-conversions + ,-hicpp-no-array-decay ,-hicpp-special-member-functions - ,-readability-braces-around-statements - ,-modernize-use-default-member-init - ,-google-runtime-references - ,-cppcoreguidelines-pro-type-vararg - ,-google-readability-braces-around-statements - ,-google-build-using-namespace ,-hicpp-vararg - ,-hicpp-explicit-conversions - ,-performance-unnecessary-value-param - ,-google-runtime-references - ,-cppcoreguidelines-pro-type-static-cast-downcast - ,-cppcoreguidelines-pro-bounds-constant-array-index - ,-cert-err58-cpp + ,-llvm-header-guard + ,-llvm-namespace-comment + ,-misc-unused-parameters ,-modernize-make-unique - ,-cppcoreguidelines-owning-memory + ,-modernize-use-default-member-init + ,-performance-unnecessary-value-param + ,-readability-braces-around-statements + ,-readability-else-after-return ,-readability-named-parameter + ,clang-analyzer-* ' WarningsAsErrors: '' HeaderFilterRegex: 'torch/csrc/' diff --git a/torch/csrc/jit/autodiff.h b/torch/csrc/jit/autodiff.h index afec738b84a66..e0dd63c925ef2 100644 --- a/torch/csrc/jit/autodiff.h +++ b/torch/csrc/jit/autodiff.h @@ -33,7 +33,7 @@ using value_list = std::vector; // Terminology: vjp = vector-jacobian product struct Gradient { - operator bool() const { + explicit operator bool() const { return df != nullptr; } std::shared_ptr f; diff --git a/torch/csrc/jit/graph_executor.h b/torch/csrc/jit/graph_executor.h index 10e10fc481224..affcd38a065c9 100644 --- a/torch/csrc/jit/graph_executor.h +++ b/torch/csrc/jit/graph_executor.h @@ -39,7 +39,7 @@ struct GraphExecutor { // note: if not specified, symbolically_differentiable is computed from the graph. GraphExecutor(std::shared_ptr graph, bool optimize, bool symbolically_differentiable); variable_tensor_list run(variable_tensor_list && inputs); - operator bool() const { + explicit operator bool() const { return pImpl != nullptr; } std::shared_ptr graph() const; diff --git a/torch/csrc/jit/interpreter.h b/torch/csrc/jit/interpreter.h index 0bd8a2891a18b..ed086bd05f881 100644 --- a/torch/csrc/jit/interpreter.h +++ b/torch/csrc/jit/interpreter.h @@ -29,7 +29,7 @@ struct Code { // Returns pointers to GraphExecutors created to run GraphExecutor nodes in the given graph. const std::vector& executors(); - operator bool() const { + explicit operator bool() const { return pImpl != nullptr; } diff --git a/torch/csrc/jit/passes/batch_mm.cpp b/torch/csrc/jit/passes/batch_mm.cpp index 1b1bb03e8fa9e..15926fdab850a 100644 --- a/torch/csrc/jit/passes/batch_mm.cpp +++ b/torch/csrc/jit/passes/batch_mm.cpp @@ -119,7 +119,7 @@ struct TreeToken { return token; } - operator bool() { + explicit operator bool() { return is_root; } diff --git a/torch/csrc/utils/object_ptr.h b/torch/csrc/utils/object_ptr.h index e1099d0f5c6dd..14991b8779d9c 100644 --- a/torch/csrc/utils/object_ptr.h +++ b/torch/csrc/utils/object_ptr.h @@ -17,7 +17,7 @@ class THPPointer { THPPointer& operator =(T *new_ptr) { free(); ptr = new_ptr; return *this; } THPPointer& operator =(THPPointer &&p) { free(); ptr = p.ptr; p.ptr = nullptr; return *this; } T * operator ->() { return ptr; } - operator bool() const { return ptr != nullptr; } + explicit operator bool() const { return ptr != nullptr; } private: void free(); From 80380f637c066864929e688bf0f67fd25adfeeee Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Wed, 11 Jul 2018 12:54:31 -0700 Subject: [PATCH 23/36] Fix to make ONNXIFI flow work (#9340) Summary: Small step to have Relu test work. Pull Request resolved: https://github.com/pytorch/pytorch/pull/9340 Reviewed By: bddppq Differential Revision: D8807018 Pulled By: yinghai fbshipit-source-id: 429f3185e12afb12aaecfea8dd9595fdf838d356 --- caffe2/operators/onnxifi_op.cc | 9 ++++--- caffe2/operators/onnxifi_op.h | 8 +++---- caffe2/python/onnx/test_onnxifi.py | 38 ++++++++++++++++++++++++++++++ third_party/onnx | 2 +- 4 files changed, 46 insertions(+), 11 deletions(-) create mode 100644 caffe2/python/onnx/test_onnxifi.py diff --git a/caffe2/operators/onnxifi_op.cc b/caffe2/operators/onnxifi_op.cc index 734258d3b7eb2..f4d0c5eafbd69 100644 --- a/caffe2/operators/onnxifi_op.cc +++ b/caffe2/operators/onnxifi_op.cc @@ -107,21 +107,20 @@ bool OnnxifiOp::RunOnDevice() { ONNXIFI_STATUS_SUCCESS); onnxMemoryFence input_fence; - input_fence.event = nullptr; input_fence.type = ONNXIFI_SYNCHRONIZATION_EVENT; CAFFE_ENFORCE_EQ( - lib_->onnxInitEvent(backend_, input_fence.event), ONNXIFI_STATUS_SUCCESS); + lib_->onnxInitEvent(backend_, &input_fence.event), + ONNXIFI_STATUS_SUCCESS); onnxMemoryFence output_fence; output_fence.type = ONNXIFI_SYNCHRONIZATION_EVENT; - output_fence.event = nullptr; // Call the asycn run on backend, singal event on input fence and wait for the // event on output fence + CAFFE_ENFORCE_EQ( + lib_->onnxSignalEvent(input_fence.event), ONNXIFI_STATUS_SUCCESS); CAFFE_ENFORCE_EQ( lib_->onnxRunGraph(graph_, &input_fence, &output_fence), ONNXIFI_STATUS_SUCCESS); - CAFFE_ENFORCE_EQ( - lib_->onnxSignalEvent(input_fence.event), ONNXIFI_STATUS_SUCCESS); CAFFE_ENFORCE_EQ( lib_->onnxWaitEvent(output_fence.event), ONNXIFI_STATUS_SUCCESS); diff --git a/caffe2/operators/onnxifi_op.h b/caffe2/operators/onnxifi_op.h index b1f638d733ca0..965bf876c60ff 100644 --- a/caffe2/operators/onnxifi_op.h +++ b/caffe2/operators/onnxifi_op.h @@ -85,15 +85,13 @@ class OnnxifiOp final : public Operator { CAFFE_ENFORCE_EQ( lib_->onnxGetBackendIDs(nullptr, &num_backends_), ONNXIFI_STATUS_SUCCESS); + CAFFE_ENFORCE_GT( + num_backends_, 0, "At least 1 onnxifi backend should be available"); backend_ids_.resize(num_backends_); - size_t num_backends = 0; CAFFE_ENFORCE_EQ( - lib_->onnxGetBackendIDs(backend_ids_.data(), &num_backends), + lib_->onnxGetBackendIDs(backend_ids_.data(), &num_backends_), ONNXIFI_STATUS_SUCCESS); - CAFFE_ENFORCE_LT( - num_backends_, 0, "At least 1 onnxifi backend should be available"); - // TODO: choose backend id CAFFE_ENFORCE_EQ( lib_->onnxInitBackend( diff --git a/caffe2/python/onnx/test_onnxifi.py b/caffe2/python/onnx/test_onnxifi.py new file mode 100644 index 0000000000000..39278c95117ad --- /dev/null +++ b/caffe2/python/onnx/test_onnxifi.py @@ -0,0 +1,38 @@ +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function +from __future__ import unicode_literals + +import numpy as np +import unittest + +import onnx +import onnx.defs +from onnx.helper import make_node, make_graph, make_tensor, make_tensor_value_info, make_model +from caffe2.proto import caffe2_pb2 +from caffe2.python import core, workspace +from caffe2.python.onnx.tests.test_utils import TestCase + +class OnnxifiTest(TestCase): + @unittest.skipIf(not workspace.C.use_trt, "No TensortRT support") + def test_relu_graph(self): + batch_size = 1 + X = np.random.randn(batch_size, 1, 3, 2).astype(np.float32) + graph_def = make_graph( + [make_node("Relu", ["X"], ["Y"])], + name="test", + inputs=[make_tensor_value_info("X", onnx.TensorProto.FLOAT, + [batch_size, 1, 3, 2])], + outputs=[make_tensor_value_info("Y", onnx.TensorProto.FLOAT, + [batch_size, 1, 3, 2])]) + model_def = make_model(graph_def, producer_name='relu-test') + op = core.CreateOperator( + "Onnxifi", + ["X"], + ["Y"], + onnx_model=model_def.SerializeToString(), + output_size_hint_0=[batch_size, 1, 3, 2]) + workspace.FeedBlob("X", X) + workspace.RunOperatorOnce(op) + Y = workspace.FetchBlob("Y") + np.testing.assert_almost_equal(Y, np.maximum(X, 0)) diff --git a/third_party/onnx b/third_party/onnx index 8e47fb2ed3af8..b4072194c2e6e 160000 --- a/third_party/onnx +++ b/third_party/onnx @@ -1 +1 @@ -Subproject commit 8e47fb2ed3af8dc723a3dce25df9c363a007edcf +Subproject commit b4072194c2e6ef90693bcfdea4c6f45cf30bb65e From 7d8b532c1f729f2e856c775f2ba7b04aff9b8186 Mon Sep 17 00:00:00 2001 From: Mingzhe Li Date: Wed, 11 Jul 2018 13:28:46 -0700 Subject: [PATCH 24/36] Fix CUDA build failures (#9347) Summary: Breaking this out of #8338 This fixes some CUDA related build and runtime issues after BUILD_CAFFE2 and BUILD_ATEN are removed. cc orionr Pull Request resolved: https://github.com/pytorch/pytorch/pull/9347 Reviewed By: orionr Differential Revision: D8806954 Pulled By: mingzhe09088 fbshipit-source-id: 9f8e3feee06478d1ac2deb30796939453352d388 --- .jenkins/pytorch/test.sh | 1 + aten/src/ATen/cudnn/cudnn-wrapper.h | 3 ++- cmake/Utils.cmake | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.jenkins/pytorch/test.sh b/.jenkins/pytorch/test.sh index f5aac680a6cbb..b1dd9d348e8c0 100755 --- a/.jenkins/pytorch/test.sh +++ b/.jenkins/pytorch/test.sh @@ -70,6 +70,7 @@ test_aten() { # put the dynamic libraries somewhere were the dynamic linker can find them. # This is a bit of a hack. ln -s "$TORCH_LIB_PATH"/libcaffe2* build/bin + ln -s "$TORCH_LIB_PATH"/libnccl* build/bin ls build/bin aten/tools/run_tests.sh build/bin fi diff --git a/aten/src/ATen/cudnn/cudnn-wrapper.h b/aten/src/ATen/cudnn/cudnn-wrapper.h index c71bdb2e67113..320646eec07ae 100644 --- a/aten/src/ATen/cudnn/cudnn-wrapper.h +++ b/aten/src/ATen/cudnn/cudnn-wrapper.h @@ -7,7 +7,8 @@ #if CUDNN_MAJOR < 6 #pragma message ("CuDNN v" STRING(CUDNN_MAJOR) " found, but need at least CuDNN v6. You can get the latest version of CuDNN from https://developer.nvidia.com/cudnn or disable CuDNN with NO_CUDNN=1") -#error "CuDNN version not supported" +#pragma message "We strongly encourage you to move to 6.0 and above." +#pragma message "This message is intended to annoy you enough to update." #endif #undef STRINGIFY diff --git a/cmake/Utils.cmake b/cmake/Utils.cmake index 959a22d1a89a6..5f7c077baa164 100644 --- a/cmake/Utils.cmake +++ b/cmake/Utils.cmake @@ -278,7 +278,7 @@ function(target_enable_style_warnings TARGET) -Wredundant-decls -Wno-shadow -Wsign-promo - -Wstrict-overflow=5 + -Wno-strict-overflow -fdiagnostics-show-option -Wno-conversion -Wpedantic From cbcf45274b04989e13fff00a078de95768aac3b7 Mon Sep 17 00:00:00 2001 From: Xiaomeng Yang Date: Wed, 11 Jul 2018 13:42:04 -0700 Subject: [PATCH 25/36] Move tanh function to math (#9328) Summary: Pull Request resolved: https://github.com/pytorch/pytorch/pull/9328 Move tanh function to math Reviewed By: houseroad Differential Revision: D8794745 fbshipit-source-id: ea525dedde6f53592b06c2caffd6426688dea5fc --- caffe2/operators/tanh_op.cc | 7 ++----- caffe2/operators/tanh_op.cu | 23 ----------------------- caffe2/operators/tanh_op.h | 5 ++++- caffe2/python/brew_test.py | 4 ++-- caffe2/utils/math.h | 2 ++ caffe2/utils/math_cpu.cc | 13 +++++++++++++ caffe2/utils/math_gpu.cu | 1 + 7 files changed, 24 insertions(+), 31 deletions(-) diff --git a/caffe2/operators/tanh_op.cc b/caffe2/operators/tanh_op.cc index 28ca87c13a20f..312fdab36fd8d 100644 --- a/caffe2/operators/tanh_op.cc +++ b/caffe2/operators/tanh_op.cc @@ -2,6 +2,7 @@ namespace caffe2 { +#ifdef CAFFE2_USE_ACCELERATE template <> template <> bool TanhFunctor::operator()( @@ -9,14 +10,10 @@ bool TanhFunctor::operator()( const float* X, float* Y, CPUContext* /* context */) const { -#ifdef CAFFE2_USE_ACCELERATE vvtanhf(Y, X, &N); -#else - ConstEigenVectorArrayMap X_arr(X, N); - EigenVectorMap(Y, N) = 1 - 2 * ((X_arr * 2).exp() + 1).inverse(); -#endif return true; } +#endif // CAFFE2_USE_ACCELERATE REGISTER_CPU_OPERATOR( Tanh, diff --git a/caffe2/operators/tanh_op.cu b/caffe2/operators/tanh_op.cu index ff0ab2b558aaf..17ebac1ed1645 100644 --- a/caffe2/operators/tanh_op.cu +++ b/caffe2/operators/tanh_op.cu @@ -9,17 +9,6 @@ namespace caffe2 { namespace { -template -__global__ void TanhCUDAKernel(const int N, const T* X, T* Y) { - CUDA_1D_KERNEL_LOOP(i, N) { -#if __CUDA_ARCH__ >= 350 - Y[i] = tanh(__ldg(X + i)); -#else - Y[i] = tanh(X[i]); -#endif - } -} - template __global__ void TanhGradientCUDAKernel(const int N, const T* dY, const T* Y, T* dX) { @@ -34,18 +23,6 @@ TanhGradientCUDAKernel(const int N, const T* dY, const T* Y, T* dX) { } // namespace -template <> -template -bool TanhFunctor:: -operator()(const int N, const T* X, T* Y, CUDAContext* context) const { - TanhCUDAKernel - <<cuda_stream()>>>(N, X, Y); - return true; -} - template <> template bool TanhGradientFunctor::Forward( diff --git a/caffe2/operators/tanh_op.h b/caffe2/operators/tanh_op.h index 117767b3c6ea1..123773dfff0d1 100644 --- a/caffe2/operators/tanh_op.h +++ b/caffe2/operators/tanh_op.h @@ -11,7 +11,10 @@ namespace caffe2 { template struct TanhFunctor { template - bool operator()(const int N, const T* X, T* Y, Context* context) const; + bool operator()(const int N, const T* X, T* Y, Context* context) const { + math::Tanh(N, X, Y, context); + return true; + } }; template diff --git a/caffe2/python/brew_test.py b/caffe2/python/brew_test.py index 17b2f57c50841..8b3d08977c2c6 100644 --- a/caffe2/python/brew_test.py +++ b/caffe2/python/brew_test.py @@ -81,7 +81,7 @@ def test_tanh(self): workspace.RunNetOnce(model.net) out = workspace.FetchBlob("out_tanh") - self.assertAlmostEqual(out.mean(), 0.46211711) + self.assertAlmostEqual(out.mean(), np.tanh(0.5), places=5) def test_validate(self): model = ModelHelper(name="test_model") @@ -325,4 +325,4 @@ def test_tanh(self): workspace.RunNetOnce(model.net) out = workspace.FetchBlob("out_tanh") - self.assertAlmostEqual(out.mean(), 0.46211711) + self.assertAlmostEqual(out.mean(), np.tanh(0.5), places=5) diff --git a/caffe2/utils/math.h b/caffe2/utils/math.h index fe1da18647464..0e7bc2b56f669 100644 --- a/caffe2/utils/math.h +++ b/caffe2/utils/math.h @@ -78,6 +78,8 @@ void Cosh(const int N, const T* x, T* y, Context* context); template void SinCos(const int N, const T* x, T* ys, T* yc, Context* context); template +void Tanh(const int N, const T* x, T* y, Context* context); +template void Abs(const int N, const T* x, T* y, Context* context); template void Sqr(const int N, const T* x, T* y, Context* context); diff --git a/caffe2/utils/math_cpu.cc b/caffe2/utils/math_cpu.cc index feb44a762c3bb..c958f9f43a2bc 100644 --- a/caffe2/utils/math_cpu.cc +++ b/caffe2/utils/math_cpu.cc @@ -556,6 +556,8 @@ DELEGATE_SIMPLE_UNARY_FUNCTION(float, Sinh, vsSinh) DELEGATE_SIMPLE_UNARY_FUNCTION(double, Sinh, vdSinh) DELEGATE_SIMPLE_UNARY_FUNCTION(float, Cosh, vsCosh) DELEGATE_SIMPLE_UNARY_FUNCTION(double, Cosh, vdCosh) +DELEGATE_SIMPLE_UNARY_FUNCTION(float, Tanh, vsTanh) +DELEGATE_SIMPLE_UNARY_FUNCTION(double, Tanh, vdTanh) DELEGATE_SIMPLE_UNARY_FUNCTION(float, Abs, vsAbs) DELEGATE_SIMPLE_UNARY_FUNCTION(double, Abs, vdAbs) DELEGATE_SIMPLE_UNARY_FUNCTION(float, Sqr, vsSqr) @@ -636,6 +638,17 @@ DELEGATE_SINCOS_FUNCTION(float) DELEGATE_SINCOS_FUNCTION(double) #undef DELEGATE_SINCOS_FUNCTION +#define DELEGATE_TANH_FUNCTION(T) \ + template <> \ + void Tanh(const int N, const T* X, T* Y, CPUContext*) { \ + EigenVectorMap(Y, N) = T(1) - \ + ((ConstEigenVectorArrayMap(X, N) * T(2)).exp() + T(1)).inverse() * \ + T(2); \ + } +DELEGATE_TANH_FUNCTION(float) +DELEGATE_TANH_FUNCTION(double) +#undef DELEGATE_TANH_FUNCTION + #define DELEGATE_CBRT_FUNCTION(T) \ template <> \ void Cbrt(const int N, const T* X, T* Y, CPUContext*) { \ diff --git a/caffe2/utils/math_gpu.cu b/caffe2/utils/math_gpu.cu index 17e941c975864..4b2a0661642d7 100644 --- a/caffe2/utils/math_gpu.cu +++ b/caffe2/utils/math_gpu.cu @@ -331,6 +331,7 @@ DELEGATE_SIMPLE_CUDA_UNARY_FUNCTION(float, Tan, tanf) DELEGATE_SIMPLE_CUDA_UNARY_FUNCTION(float, Atan, atanf) DELEGATE_SIMPLE_CUDA_UNARY_FUNCTION(float, Sinh, sinhf) DELEGATE_SIMPLE_CUDA_UNARY_FUNCTION(float, Cosh, coshf) +DELEGATE_SIMPLE_CUDA_UNARY_FUNCTION(float, Tanh, tanhf) DELEGATE_SIMPLE_CUDA_UNARY_FUNCTION(float, Abs, fabsf) DELEGATE_SIMPLE_CUDA_UNARY_FUNCTION(float, Sqr, utils::Square) DELEGATE_SIMPLE_CUDA_UNARY_FUNCTION(float, Sqrt, sqrtf) From 7f33ec55b266911ee29558cbef00adc4a623c52d Mon Sep 17 00:00:00 2001 From: Orion Reblitz-Richardson Date: Wed, 11 Jul 2018 13:52:48 -0700 Subject: [PATCH 26/36] Fix Eigen issue on OS X with CUDA and nvcc compile (#9350) Summary: Pull Request resolved: https://github.com/pytorch/pytorch/pull/9350 Re-apply #9270 Breaking this out of #8338 This takes care of the Eigen failure we saw on Mac CUDA builds when BUILD_CAFFE2 and BUILD_ATEN were removed. Fix is to isolate Eigen from headers included by cu files and processed by nvcc. This was worked on with smessmer. Reviewed By: mingzhe09088 Differential Revision: D8794431 fbshipit-source-id: de656334af46c697802073f8e8d9a6aeb9ca65a7 --- caffe2/mkl/operators/operator_fallback_mkl.cc | 1 + caffe2/mobile/contrib/ulp2/ulp.cc | 3 + caffe2/mobile/contrib/ulp2/ulp_neon.cc | 1 + caffe2/operators/abs_op.cc | 1 + caffe2/operators/acos_op.cc | 1 + caffe2/operators/affine_channel_op.cc | 1 + caffe2/operators/asin_op.cc | 1 + caffe2/operators/atan_op.cc | 1 + caffe2/operators/cbrt_op.cc | 1 + caffe2/operators/channel_backprop_stats_op.cc | 1 + caffe2/operators/channel_stats_op.cc | 1 + caffe2/operators/clip_op.cc | 1 + caffe2/operators/conv_op_eigen.cc | 1 + .../operators/conv_transpose_op_mobile_impl.h | 1 + caffe2/operators/cos_op.cc | 1 + caffe2/operators/cross_entropy_op.cc | 1 + caffe2/operators/cube_op.cc | 1 + caffe2/operators/distance_op.cc | 1 + .../operators/elementwise_div_gradient_op.cc | 1 + caffe2/operators/elementwise_ops.cc | 1 + caffe2/operators/elementwise_ops.h | 1 + caffe2/operators/elu_op.cc | 1 + caffe2/operators/ensure_clipped_op.h | 1 + .../fused_rowwise_8bit_conversion_ops.h | 1 + .../operators/gather_fused_8bit_rowwise_op.h | 1 + caffe2/operators/gather_ranges_to_dense_op.h | 1 + .../generate_proposals_op_util_boxes_test.cc | 1 + .../generate_proposals_op_util_nms_test.cc | 1 + caffe2/operators/group_norm_op.cc | 1 + caffe2/operators/instance_norm_gradient_op.cc | 1 + caffe2/operators/instance_norm_op.cc | 1 + caffe2/operators/integral_image_op.cc | 116 ++++++++++++++++++ caffe2/operators/integral_image_op.h | 113 +---------------- caffe2/operators/layer_norm_op.cc | 1 + caffe2/operators/leaky_relu_op.cc | 1 + .../lengths_reducer_rowwise_8bit_ops.h | 1 + caffe2/operators/listwise_l2r_op.cc | 1 + caffe2/operators/logit_op.cc | 1 + caffe2/operators/lpnorm_op.cc | 1 + caffe2/operators/minmax_gradient_ops.cc | 1 + caffe2/operators/minmax_ops.cc | 1 + caffe2/operators/norm_planar_yuv_op.cc | 1 + caffe2/operators/normalize_l1_op.cc | 1 + caffe2/operators/normalize_op.cc | 1 + caffe2/operators/pool_gradient_op.cc | 1 + caffe2/operators/pool_op.cc | 1 + caffe2/operators/pow_op.cc | 1 + caffe2/operators/prelu_op.cc | 1 + caffe2/operators/reducer_functors.h | 1 + caffe2/operators/relu_n_op.cc | 1 + caffe2/operators/relu_op.cc | 1 + caffe2/operators/roi_align_op_gpu_test.cc | 1 + caffe2/operators/rsqrt_op.cc | 2 + caffe2/operators/selu_op.cc | 1 + caffe2/operators/sigmoid_gradient_op.cc | 2 + caffe2/operators/sigmoid_op.cc | 2 + caffe2/operators/sin_op.cc | 1 + .../operators/sinusoid_position_encoding_op.h | 1 + caffe2/operators/softplus_op.cc | 1 + caffe2/operators/softsign_op.cc | 2 + caffe2/operators/sparse_normalize_op.cc | 1 + .../spatial_batch_norm_gradient_op.cc | 2 + caffe2/operators/spatial_batch_norm_op.cc | 2 + caffe2/operators/swish_op.cc | 1 + caffe2/operators/tan_op.cc | 2 + caffe2/operators/tanh_gradient_op.cc | 2 + caffe2/operators/tanh_op.cc | 2 + caffe2/operators/thresholded_relu_op.cc | 1 + caffe2/operators/tt_linear_op.h | 1 + caffe2/operators/utility_ops.cc | 2 +- .../variable_length_sequence_padding.h | 1 + caffe2/perfkernels/embedding_lookup.cc | 1 + .../fused_8bit_rowwise_embedding_lookup.cc | 1 + caffe2/sgd/lars_op.cc | 1 + caffe2/sgd/rmsprop_op.cc | 1 + caffe2/utils/eigen_utils.h | 24 ++++ caffe2/utils/math.h | 27 ---- caffe2/utils/math_cpu.cc | 1 + caffe2/utils/math_gpu.cu | 1 + 79 files changed, 228 insertions(+), 139 deletions(-) diff --git a/caffe2/mkl/operators/operator_fallback_mkl.cc b/caffe2/mkl/operators/operator_fallback_mkl.cc index 91c43e746a9ad..106fa05dec70a 100644 --- a/caffe2/mkl/operators/operator_fallback_mkl.cc +++ b/caffe2/mkl/operators/operator_fallback_mkl.cc @@ -15,6 +15,7 @@ #include "caffe2/operators/roi_align_rotated_op.h" #include "caffe2/operators/softmax_op.h" #include "caffe2/operators/utility_ops.h" +#include "caffe2/utils/eigen_utils.h" namespace caffe2 { namespace { diff --git a/caffe2/mobile/contrib/ulp2/ulp.cc b/caffe2/mobile/contrib/ulp2/ulp.cc index 7a1652e6ba343..1d8e0e8fe69a5 100644 --- a/caffe2/mobile/contrib/ulp2/ulp.cc +++ b/caffe2/mobile/contrib/ulp2/ulp.cc @@ -1,5 +1,8 @@ #include "ulp.h" + +#include #include "caffe2/operators/conv_pool_op_base.h" +#include "caffe2/utils/eigen_utils.h" #include "ulp_neon.h" namespace caffe2 { diff --git a/caffe2/mobile/contrib/ulp2/ulp_neon.cc b/caffe2/mobile/contrib/ulp2/ulp_neon.cc index faa2b4b982edf..15ad59a47916e 100644 --- a/caffe2/mobile/contrib/ulp2/ulp_neon.cc +++ b/caffe2/mobile/contrib/ulp2/ulp_neon.cc @@ -1,5 +1,6 @@ #include "ulp_neon.h" #include "caffe2/core/timer.h" +#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/math.h" namespace caffe2 { diff --git a/caffe2/operators/abs_op.cc b/caffe2/operators/abs_op.cc index 81881c71c3898..9b9e93f7eff66 100644 --- a/caffe2/operators/abs_op.cc +++ b/caffe2/operators/abs_op.cc @@ -1,4 +1,5 @@ #include "caffe2/operators/abs_op.h" +#include "caffe2/utils/eigen_utils.h" #include #include diff --git a/caffe2/operators/acos_op.cc b/caffe2/operators/acos_op.cc index 8e3c814dbbde4..204bdce146115 100644 --- a/caffe2/operators/acos_op.cc +++ b/caffe2/operators/acos_op.cc @@ -1,4 +1,5 @@ #include "caffe2/operators/acos_op.h" +#include "caffe2/utils/eigen_utils.h" #include #include diff --git a/caffe2/operators/affine_channel_op.cc b/caffe2/operators/affine_channel_op.cc index 0e358f451b9cf..26953876b4891 100644 --- a/caffe2/operators/affine_channel_op.cc +++ b/caffe2/operators/affine_channel_op.cc @@ -1,4 +1,5 @@ #include "caffe2/operators/affine_channel_op.h" +#include "caffe2/utils/eigen_utils.h" #include diff --git a/caffe2/operators/asin_op.cc b/caffe2/operators/asin_op.cc index e3f440e14c764..3f7db59a15cf1 100644 --- a/caffe2/operators/asin_op.cc +++ b/caffe2/operators/asin_op.cc @@ -1,4 +1,5 @@ #include "caffe2/operators/asin_op.h" +#include "caffe2/utils/eigen_utils.h" #include #include diff --git a/caffe2/operators/atan_op.cc b/caffe2/operators/atan_op.cc index ad11136e5b9db..59c0ebbc2b89e 100644 --- a/caffe2/operators/atan_op.cc +++ b/caffe2/operators/atan_op.cc @@ -1,4 +1,5 @@ #include "caffe2/operators/atan_op.h" +#include "caffe2/utils/eigen_utils.h" #include #include diff --git a/caffe2/operators/cbrt_op.cc b/caffe2/operators/cbrt_op.cc index 84d93f33c14a4..6d1a7025cab7c 100644 --- a/caffe2/operators/cbrt_op.cc +++ b/caffe2/operators/cbrt_op.cc @@ -1,4 +1,5 @@ #include "caffe2/operators/cbrt_op.h" +#include "caffe2/utils/eigen_utils.h" #include #include diff --git a/caffe2/operators/channel_backprop_stats_op.cc b/caffe2/operators/channel_backprop_stats_op.cc index c5d26247f049a..bee287d29cef9 100644 --- a/caffe2/operators/channel_backprop_stats_op.cc +++ b/caffe2/operators/channel_backprop_stats_op.cc @@ -1,4 +1,5 @@ #include "caffe2/operators/channel_backprop_stats_op.h" +#include "caffe2/utils/eigen_utils.h" namespace caffe2 { diff --git a/caffe2/operators/channel_stats_op.cc b/caffe2/operators/channel_stats_op.cc index 4cf9ce68743c5..442ab48d764de 100644 --- a/caffe2/operators/channel_stats_op.cc +++ b/caffe2/operators/channel_stats_op.cc @@ -1,4 +1,5 @@ #include "caffe2/operators/channel_stats_op.h" +#include "caffe2/utils/eigen_utils.h" namespace caffe2 { diff --git a/caffe2/operators/clip_op.cc b/caffe2/operators/clip_op.cc index efb40ff8c8afe..02e80bd131beb 100644 --- a/caffe2/operators/clip_op.cc +++ b/caffe2/operators/clip_op.cc @@ -1,4 +1,5 @@ #include "caffe2/operators/clip_op.h" +#include "caffe2/utils/eigen_utils.h" namespace caffe2 { diff --git a/caffe2/operators/conv_op_eigen.cc b/caffe2/operators/conv_op_eigen.cc index 2862d80777b55..b565b567ab294 100644 --- a/caffe2/operators/conv_op_eigen.cc +++ b/caffe2/operators/conv_op_eigen.cc @@ -1,4 +1,5 @@ #include "Eigen/Core" +#include "caffe2/utils/eigen_utils.h" #if EIGEN_VERSION_AT_LEAST(3, 3, 0) diff --git a/caffe2/operators/conv_transpose_op_mobile_impl.h b/caffe2/operators/conv_transpose_op_mobile_impl.h index 2d9e1ba902a27..d434ec49e3e5b 100644 --- a/caffe2/operators/conv_transpose_op_mobile_impl.h +++ b/caffe2/operators/conv_transpose_op_mobile_impl.h @@ -15,6 +15,7 @@ #include "caffe2/operators/conv_op_shared.h" #include "caffe2/operators/conv_transpose_op_mobile.h" #include "caffe2/utils/cpu_neon.h" +#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/fixed_divisor.h" #include "caffe2/utils/math.h" diff --git a/caffe2/operators/cos_op.cc b/caffe2/operators/cos_op.cc index cf2eeb0ae5ed4..262ccee482e1b 100644 --- a/caffe2/operators/cos_op.cc +++ b/caffe2/operators/cos_op.cc @@ -1,4 +1,5 @@ #include "caffe2/operators/cos_op.h" +#include "caffe2/utils/eigen_utils.h" #include #include diff --git a/caffe2/operators/cross_entropy_op.cc b/caffe2/operators/cross_entropy_op.cc index 31a981d18b9db..c288eb7be69d8 100644 --- a/caffe2/operators/cross_entropy_op.cc +++ b/caffe2/operators/cross_entropy_op.cc @@ -1,4 +1,5 @@ #include "caffe2/operators/cross_entropy_op.h" +#include "caffe2/utils/eigen_utils.h" namespace caffe2 { diff --git a/caffe2/operators/cube_op.cc b/caffe2/operators/cube_op.cc index 5b28c5bcdea77..1f0cf7d4bdafc 100644 --- a/caffe2/operators/cube_op.cc +++ b/caffe2/operators/cube_op.cc @@ -1,4 +1,5 @@ #include "caffe2/operators/cube_op.h" +#include "caffe2/utils/eigen_utils.h" #include #include diff --git a/caffe2/operators/distance_op.cc b/caffe2/operators/distance_op.cc index 6d6e5a35c7abf..4e00cd4396726 100644 --- a/caffe2/operators/distance_op.cc +++ b/caffe2/operators/distance_op.cc @@ -1,4 +1,5 @@ #include "caffe2/operators/distance_op.h" +#include "caffe2/utils/eigen_utils.h" namespace caffe2 { diff --git a/caffe2/operators/elementwise_div_gradient_op.cc b/caffe2/operators/elementwise_div_gradient_op.cc index 288b09cdfc3bd..f8562951d1673 100644 --- a/caffe2/operators/elementwise_div_gradient_op.cc +++ b/caffe2/operators/elementwise_div_gradient_op.cc @@ -1,4 +1,5 @@ #include "caffe2/operators/elementwise_div_op.h" +#include "caffe2/utils/eigen_utils.h" #include #include diff --git a/caffe2/operators/elementwise_ops.cc b/caffe2/operators/elementwise_ops.cc index ad46541c8f48a..1cd7d65917a4e 100644 --- a/caffe2/operators/elementwise_ops.cc +++ b/caffe2/operators/elementwise_ops.cc @@ -1,4 +1,5 @@ #include "caffe2/operators/elementwise_ops.h" +#include "caffe2/utils/eigen_utils.h" #include diff --git a/caffe2/operators/elementwise_ops.h b/caffe2/operators/elementwise_ops.h index 2b7072e33d9f8..aec5ea458fff4 100644 --- a/caffe2/operators/elementwise_ops.h +++ b/caffe2/operators/elementwise_ops.h @@ -12,6 +12,7 @@ #include "caffe2/core/operator.h" #include "caffe2/core/tensor.h" #include "caffe2/operators/elementwise_ops_utils.h" +#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/math.h" namespace caffe2 { diff --git a/caffe2/operators/elu_op.cc b/caffe2/operators/elu_op.cc index e08d6f2eb2bd9..45c0ebe9b751b 100644 --- a/caffe2/operators/elu_op.cc +++ b/caffe2/operators/elu_op.cc @@ -1,5 +1,6 @@ #include "caffe2/operators/elu_op.h" +#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/math.h" namespace caffe2 { diff --git a/caffe2/operators/ensure_clipped_op.h b/caffe2/operators/ensure_clipped_op.h index e53d5759f4a62..23a10928a0ceb 100644 --- a/caffe2/operators/ensure_clipped_op.h +++ b/caffe2/operators/ensure_clipped_op.h @@ -1,6 +1,7 @@ #pragma once #include "caffe2/core/operator.h" +#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/math.h" namespace caffe2 { diff --git a/caffe2/operators/fused_rowwise_8bit_conversion_ops.h b/caffe2/operators/fused_rowwise_8bit_conversion_ops.h index bf098a610f2cb..ca5002078129a 100644 --- a/caffe2/operators/fused_rowwise_8bit_conversion_ops.h +++ b/caffe2/operators/fused_rowwise_8bit_conversion_ops.h @@ -5,6 +5,7 @@ #include "caffe2/core/logging.h" #include "caffe2/core/operator.h" #include "caffe2/operators/reducer_functors.h" +#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/math.h" namespace caffe2 { diff --git a/caffe2/operators/gather_fused_8bit_rowwise_op.h b/caffe2/operators/gather_fused_8bit_rowwise_op.h index de5dd61255979..621ea335a4993 100644 --- a/caffe2/operators/gather_fused_8bit_rowwise_op.h +++ b/caffe2/operators/gather_fused_8bit_rowwise_op.h @@ -1,6 +1,7 @@ #pragma once #include "caffe2/core/operator.h" +#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/math.h" namespace caffe2 { diff --git a/caffe2/operators/gather_ranges_to_dense_op.h b/caffe2/operators/gather_ranges_to_dense_op.h index c9a4084b9158e..81f4fa53d5599 100644 --- a/caffe2/operators/gather_ranges_to_dense_op.h +++ b/caffe2/operators/gather_ranges_to_dense_op.h @@ -10,6 +10,7 @@ #include "caffe2/core/types.h" #include "caffe2/utils/math.h" +#include #include #include diff --git a/caffe2/operators/generate_proposals_op_util_boxes_test.cc b/caffe2/operators/generate_proposals_op_util_boxes_test.cc index 4716001460a73..a8d4f4c327e64 100644 --- a/caffe2/operators/generate_proposals_op_util_boxes_test.cc +++ b/caffe2/operators/generate_proposals_op_util_boxes_test.cc @@ -1,4 +1,5 @@ #include "caffe2/operators/generate_proposals_op_util_boxes.h" +#include "caffe2/utils/eigen_utils.h" #include diff --git a/caffe2/operators/generate_proposals_op_util_nms_test.cc b/caffe2/operators/generate_proposals_op_util_nms_test.cc index 9d685a716bb3b..696ff83b0be99 100644 --- a/caffe2/operators/generate_proposals_op_util_nms_test.cc +++ b/caffe2/operators/generate_proposals_op_util_nms_test.cc @@ -1,3 +1,4 @@ +#include "caffe2/utils/eigen_utils.h" #include "generate_proposals_op_util_nms.h" #include diff --git a/caffe2/operators/group_norm_op.cc b/caffe2/operators/group_norm_op.cc index 733ec52680e1e..9c203f24a8683 100644 --- a/caffe2/operators/group_norm_op.cc +++ b/caffe2/operators/group_norm_op.cc @@ -10,6 +10,7 @@ #include +#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/math.h" namespace caffe2 { diff --git a/caffe2/operators/instance_norm_gradient_op.cc b/caffe2/operators/instance_norm_gradient_op.cc index 079992140022f..077020ee48b9b 100644 --- a/caffe2/operators/instance_norm_gradient_op.cc +++ b/caffe2/operators/instance_norm_gradient_op.cc @@ -1,4 +1,5 @@ #include "caffe2/operators/instance_norm_op.h" +#include "caffe2/utils/eigen_utils.h" namespace caffe2 { diff --git a/caffe2/operators/instance_norm_op.cc b/caffe2/operators/instance_norm_op.cc index 7011ecf40bf7e..b0d0dea73ea28 100644 --- a/caffe2/operators/instance_norm_op.cc +++ b/caffe2/operators/instance_norm_op.cc @@ -1,4 +1,5 @@ #include "caffe2/operators/instance_norm_op.h" +#include "caffe2/utils/eigen_utils.h" namespace caffe2 { diff --git a/caffe2/operators/integral_image_op.cc b/caffe2/operators/integral_image_op.cc index 6da5ee6d5600f..27356104bbd66 100644 --- a/caffe2/operators/integral_image_op.cc +++ b/caffe2/operators/integral_image_op.cc @@ -1,6 +1,122 @@ #include "integral_image_op.h" +#include "caffe2/utils/eigen_utils.h" + namespace caffe2 { +namespace { +template +using EigenMatrixMapRowMajor = Eigen::Map< + Eigen::Matrix>; + +template +using ConstEigenMatrixMapRowMajor = Eigen::Map< + const Eigen::Matrix>; +} // namespace + +template <> +bool IntegralImageOp::RunOnDevice() { + const auto& X = Input(0); + auto* Y = Output(0); + CAFFE_ENFORCE_EQ(X.ndim(), 4, "Only supports 4D tensors for the momement"); + + vector out_shape(X.dims()); + out_shape[2] += 1; // H + 1 output size + out_shape[3] += 1; // W + 1 output size + Y->Resize(out_shape); + const int ind = X.dim32(0); + const int chans = X.dim32(1); + const int rows_in = X.dim32(2); + const int cols_in = X.dim32(3); + const int rows_out = Y->dim32(2); + const int cols_out = Y->dim32(3); + + const float* input_data = X.template data(); + float* output_data = Y->template mutable_data(); + + const int row_out_pass_size = ind * chans * rows_out; + const int row_in_pass_size = ind * chans * rows_in; + EigenMatrixMapRowMajor Y_arr(output_data, row_out_pass_size, cols_out); + ConstEigenMatrixMapRowMajor X_arr( + input_data, row_in_pass_size, cols_in); + + // Row Pass + for (int i = 0; i < row_out_pass_size; i++) { + int row = i % rows_out; + int diff = i / rows_out + 1; + Y_arr(i, 0) = 0.; + if (row == 0) { + for (int j = 1; j < cols_out; ++j) { + Y_arr(i, j) = 0.; + } + } else { + for (int j = 1; j < cols_out; ++j) { + Y_arr(i, j) = Y_arr(i, j - 1) + X_arr(i - diff, j - 1); + } + } + } + + // Col Pass + const int col_out_pass_size = X.dim32(0) * chans * cols_out; + for (int i = 0; i < col_out_pass_size; i++) { + int col = i % cols_out; + int row = i / cols_out; + for (int j = row * rows_out + 1; j < (row + 1) * rows_out; ++j) { + Y_arr(j, col) += Y_arr(j - 1, col); + } + } + return true; +} + +template <> +bool IntegralImageGradientOp::RunOnDevice() { + auto& X = Input(0); // Original input to "forward" op + auto& dY = Input(1); // Gradient of net w.r.t. output of "forward" op + // (aka "gradOutput") + auto* dX = Output(0); // Gradient of net w.r.t. input to "forward" op + // (aka "gradInput") + + dX->ResizeLike(X); + const int ind = X.dim32(0); + const int chans = X.dim32(1); + const int rows_in = dY.dim32(2); + const int cols_in = dY.dim32(3); + const int rows_out = dX->dim32(2); + const int cols_out = dX->dim32(3); + + const float* input_data = dY.template data(); + float* output_data = dX->template mutable_data(); + + const int row_out_pass_size = ind * chans * rows_out; + const int row_in_pass_size = ind * chans * rows_in; + EigenMatrixMapRowMajor dX_arr( + output_data, row_out_pass_size, cols_out); + ConstEigenMatrixMapRowMajor dY_arr( + input_data, row_in_pass_size, cols_in); + Eigen::MatrixXf tmp(row_in_pass_size, cols_out); + + // Row Pass dY(N, C, H+1, W+1) => tmp(N, C, H+1, W) + for (int i = 0; i < row_in_pass_size; i++) { + tmp(i, 0) = dY_arr(i, 0); + for (int j = 1; j < cols_out; ++j) { + tmp(i, j) = tmp(i, j - 1) + dY_arr(i, j); + } + } + + // Col Pass tmp(N, C, H+1, W)=>dX(N, C, H, W) + const int col_out_pass_size = X.dim32(0) * chans * cols_out; + for (int i = 0; i < col_out_pass_size; i++) { + int col = i % cols_out; + int row_out_start = (i / cols_out) * rows_out; + int row_in_start = (i / cols_out) * rows_in; + dX_arr(row_out_start, col) = tmp(row_in_start, col); + for (int j = 1; j < rows_out; ++j) { + dX_arr(row_out_start + j, col) = + dX_arr(row_out_start + j - 1, col) + tmp(row_in_start + j, col); + } + } + return true; +} + REGISTER_CPU_OPERATOR(IntegralImage, IntegralImageOp); REGISTER_CPU_OPERATOR( IntegralImageGradient, diff --git a/caffe2/operators/integral_image_op.h b/caffe2/operators/integral_image_op.h index 71d9b076336fa..b8920d677de83 100644 --- a/caffe2/operators/integral_image_op.h +++ b/caffe2/operators/integral_image_op.h @@ -8,16 +8,6 @@ namespace caffe2 { -namespace { -template -using EigenMatrixMapRowMajor = Eigen::Map< - Eigen::Matrix>; - -template -using ConstEigenMatrixMapRowMajor = Eigen::Map< - const Eigen::Matrix>; -} // namespace - template class IntegralImageOp final : public Operator { public: @@ -25,59 +15,7 @@ class IntegralImageOp final : public Operator { : Operator(operator_def, ws) {} USE_OPERATOR_CONTEXT_FUNCTIONS; - bool RunOnDevice() override { - const auto& X = Input(0); - auto* Y = Output(0); - CAFFE_ENFORCE_EQ(X.ndim(), 4, "Only supports 4D tensors for the momement"); - - vector out_shape(X.dims()); - out_shape[2] += 1; // H + 1 output size - out_shape[3] += 1; // W + 1 output size - Y->Resize(out_shape); - const int ind = X.dim32(0); - const int chans = X.dim32(1); - const int rows_in = X.dim32(2); - const int cols_in = X.dim32(3); - const int rows_out = Y->dim32(2); - const int cols_out = Y->dim32(3); - - const float* input_data = X.template data(); - float* output_data = Y->template mutable_data(); - - const int row_out_pass_size = ind * chans * rows_out; - const int row_in_pass_size = ind * chans * rows_in; - EigenMatrixMapRowMajor Y_arr( - output_data, row_out_pass_size, cols_out); - ConstEigenMatrixMapRowMajor X_arr( - input_data, row_in_pass_size, cols_in); - - // Row Pass - for (int i = 0; i < row_out_pass_size; i++) { - int row = i % rows_out; - int diff = i / rows_out + 1; - Y_arr(i, 0) = 0.; - if (row == 0) { - for (int j = 1; j < cols_out; ++j) { - Y_arr(i, j) = 0.; - } - } else { - for (int j = 1; j < cols_out; ++j) { - Y_arr(i, j) = Y_arr(i, j - 1) + X_arr(i - diff, j - 1); - } - } - } - - // Col Pass - const int col_out_pass_size = X.dim32(0) * chans * cols_out; - for (int i = 0; i < col_out_pass_size; i++) { - int col = i % cols_out; - int row = i / cols_out; - for (int j = row * rows_out + 1; j < (row + 1) * rows_out; ++j) { - Y_arr(j, col) += Y_arr(j - 1, col); - } - } - return true; - } + bool RunOnDevice() override; }; template @@ -87,54 +25,7 @@ class IntegralImageGradientOp final : public Operator { : Operator(def, ws) {} USE_OPERATOR_CONTEXT_FUNCTIONS; - bool RunOnDevice() override { - auto& X = Input(0); // Original input to "forward" op - auto& dY = Input(1); // Gradient of net w.r.t. output of "forward" op - // (aka "gradOutput") - auto* dX = Output(0); // Gradient of net w.r.t. input to "forward" op - // (aka "gradInput") - - dX->ResizeLike(X); - const int ind = X.dim32(0); - const int chans = X.dim32(1); - const int rows_in = dY.dim32(2); - const int cols_in = dY.dim32(3); - const int rows_out = dX->dim32(2); - const int cols_out = dX->dim32(3); - - const float* input_data = dY.template data(); - float* output_data = dX->template mutable_data(); - - const int row_out_pass_size = ind * chans * rows_out; - const int row_in_pass_size = ind * chans * rows_in; - EigenMatrixMapRowMajor dX_arr( - output_data, row_out_pass_size, cols_out); - ConstEigenMatrixMapRowMajor dY_arr( - input_data, row_in_pass_size, cols_in); - Eigen::MatrixXf tmp(row_in_pass_size, cols_out); - - // Row Pass dY(N, C, H+1, W+1) => tmp(N, C, H+1, W) - for (int i = 0; i < row_in_pass_size; i++) { - tmp(i, 0) = dY_arr(i, 0); - for (int j = 1; j < cols_out; ++j) { - tmp(i, j) = tmp(i, j - 1) + dY_arr(i, j); - } - } - - // Col Pass tmp(N, C, H+1, W)=>dX(N, C, H, W) - const int col_out_pass_size = X.dim32(0) * chans * cols_out; - for (int i = 0; i < col_out_pass_size; i++) { - int col = i % cols_out; - int row_out_start = (i / cols_out) * rows_out; - int row_in_start = (i / cols_out) * rows_in; - dX_arr(row_out_start, col) = tmp(row_in_start, col); - for (int j = 1; j < rows_out; ++j) { - dX_arr(row_out_start + j, col) = - dX_arr(row_out_start + j - 1, col) + tmp(row_in_start + j, col); - } - } - return true; - } + bool RunOnDevice() override; protected: Tensor row_pass_buffer_; diff --git a/caffe2/operators/layer_norm_op.cc b/caffe2/operators/layer_norm_op.cc index eb5ae0d33e5b7..4b995fa49d8ce 100644 --- a/caffe2/operators/layer_norm_op.cc +++ b/caffe2/operators/layer_norm_op.cc @@ -1,4 +1,5 @@ #include "caffe2/operators/layer_norm_op.h" +#include "caffe2/utils/eigen_utils.h" namespace caffe2 { diff --git a/caffe2/operators/leaky_relu_op.cc b/caffe2/operators/leaky_relu_op.cc index fc66edcdbbe9b..dcf62084a1207 100644 --- a/caffe2/operators/leaky_relu_op.cc +++ b/caffe2/operators/leaky_relu_op.cc @@ -1,5 +1,6 @@ #include "caffe2/operators/leaky_relu_op.h" +#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/math.h" namespace caffe2 { diff --git a/caffe2/operators/lengths_reducer_rowwise_8bit_ops.h b/caffe2/operators/lengths_reducer_rowwise_8bit_ops.h index 0423fcf34a270..58ebe6cb58e84 100644 --- a/caffe2/operators/lengths_reducer_rowwise_8bit_ops.h +++ b/caffe2/operators/lengths_reducer_rowwise_8bit_ops.h @@ -8,6 +8,7 @@ #include "caffe2/core/operator.h" #include "caffe2/operators/reducer_functors.h" #include "caffe2/perfkernels/embedding_lookup.h" +#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/math.h" namespace caffe2 { diff --git a/caffe2/operators/listwise_l2r_op.cc b/caffe2/operators/listwise_l2r_op.cc index 24c5e26e5faaf..3940dfb2b1670 100644 --- a/caffe2/operators/listwise_l2r_op.cc +++ b/caffe2/operators/listwise_l2r_op.cc @@ -1,6 +1,7 @@ #include "caffe2/operators/listwise_l2r_op.h" #include "caffe2/core/context.h" #include "caffe2/core/operator.h" +#include "caffe2/utils/eigen_utils.h" namespace caffe2 { diff --git a/caffe2/operators/logit_op.cc b/caffe2/operators/logit_op.cc index 8d1859a405a49..225608f87b38d 100644 --- a/caffe2/operators/logit_op.cc +++ b/caffe2/operators/logit_op.cc @@ -4,6 +4,7 @@ #include #include "caffe2/operators/elementwise_ops.h" +#include "caffe2/utils/eigen_utils.h" namespace caffe2 { diff --git a/caffe2/operators/lpnorm_op.cc b/caffe2/operators/lpnorm_op.cc index c302d42c92b07..f79d51ad51c44 100644 --- a/caffe2/operators/lpnorm_op.cc +++ b/caffe2/operators/lpnorm_op.cc @@ -2,6 +2,7 @@ #include "caffe2/core/operator.h" #include "caffe2/core/types.h" +#include "caffe2/utils/eigen_utils.h" namespace caffe2 { diff --git a/caffe2/operators/minmax_gradient_ops.cc b/caffe2/operators/minmax_gradient_ops.cc index 5b223b2551332..0c640d4d58e81 100644 --- a/caffe2/operators/minmax_gradient_ops.cc +++ b/caffe2/operators/minmax_gradient_ops.cc @@ -1,4 +1,5 @@ #include "caffe2/operators/minmax_ops.h" +#include "caffe2/utils/eigen_utils.h" namespace caffe2 { diff --git a/caffe2/operators/minmax_ops.cc b/caffe2/operators/minmax_ops.cc index 802788531e072..16b8f026072e5 100644 --- a/caffe2/operators/minmax_ops.cc +++ b/caffe2/operators/minmax_ops.cc @@ -1,4 +1,5 @@ #include "caffe2/operators/minmax_ops.h" +#include "caffe2/utils/eigen_utils.h" namespace caffe2 { diff --git a/caffe2/operators/norm_planar_yuv_op.cc b/caffe2/operators/norm_planar_yuv_op.cc index b9d9b9c44ecc2..ea3ccc222dc96 100644 --- a/caffe2/operators/norm_planar_yuv_op.cc +++ b/caffe2/operators/norm_planar_yuv_op.cc @@ -1,5 +1,6 @@ #include #include "caffe2/core/operator.h" +#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/math.h" namespace caffe2 { diff --git a/caffe2/operators/normalize_l1_op.cc b/caffe2/operators/normalize_l1_op.cc index cb02ff7d52397..908131f43532d 100644 --- a/caffe2/operators/normalize_l1_op.cc +++ b/caffe2/operators/normalize_l1_op.cc @@ -1,6 +1,7 @@ #include "caffe2/operators/normalize_l1_op.h" #include "caffe2/core/tensor.h" +#include "caffe2/utils/eigen_utils.h" namespace caffe2 { diff --git a/caffe2/operators/normalize_op.cc b/caffe2/operators/normalize_op.cc index 4a1aac7f02a96..1a7d720deb6c3 100644 --- a/caffe2/operators/normalize_op.cc +++ b/caffe2/operators/normalize_op.cc @@ -1,6 +1,7 @@ #include "caffe2/operators/normalize_op.h" #include "caffe2/core/tensor.h" +#include "caffe2/utils/eigen_utils.h" namespace caffe2 { diff --git a/caffe2/operators/pool_gradient_op.cc b/caffe2/operators/pool_gradient_op.cc index 048d8fc06177d..f7062a616dc8d 100644 --- a/caffe2/operators/pool_gradient_op.cc +++ b/caffe2/operators/pool_gradient_op.cc @@ -1,4 +1,5 @@ #include "caffe2/operators/pool_op.h" +#include "caffe2/utils/eigen_utils.h" namespace caffe2 { diff --git a/caffe2/operators/pool_op.cc b/caffe2/operators/pool_op.cc index edb14bc82b7ac..eca7978e024aa 100644 --- a/caffe2/operators/pool_op.cc +++ b/caffe2/operators/pool_op.cc @@ -1,6 +1,7 @@ // TODO(ataei): reduce the apparent redundancy of all the code below. #include "caffe2/operators/pool_op.h" #include "caffe2/utils/cpu_neon.h" +#include "caffe2/utils/eigen_utils.h" namespace caffe2 { diff --git a/caffe2/operators/pow_op.cc b/caffe2/operators/pow_op.cc index bef995093ddaa..a028d6d0bdcea 100644 --- a/caffe2/operators/pow_op.cc +++ b/caffe2/operators/pow_op.cc @@ -1,4 +1,5 @@ #include "caffe2/operators/pow_op.h" +#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/math.h" // definition of NumericTypes and SameTypeAsInput is in below header file //#include "caffe2/operators/elementwise_op.h" diff --git a/caffe2/operators/prelu_op.cc b/caffe2/operators/prelu_op.cc index 680b987e74292..8bacf1e29153c 100644 --- a/caffe2/operators/prelu_op.cc +++ b/caffe2/operators/prelu_op.cc @@ -1,4 +1,5 @@ #include "caffe2/operators/prelu_op.h" +#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/math.h" #include "caffe2/core/types.h" diff --git a/caffe2/operators/reducer_functors.h b/caffe2/operators/reducer_functors.h index 708c964af213c..f3dd35b956078 100644 --- a/caffe2/operators/reducer_functors.h +++ b/caffe2/operators/reducer_functors.h @@ -6,6 +6,7 @@ #include "caffe2/core/context.h" #include "caffe2/core/tensor.h" +#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/math.h" #include "caffe2/utils/proto_utils.h" diff --git a/caffe2/operators/relu_n_op.cc b/caffe2/operators/relu_n_op.cc index b69baff7725bd..4b5afed3528c3 100644 --- a/caffe2/operators/relu_n_op.cc +++ b/caffe2/operators/relu_n_op.cc @@ -16,6 +16,7 @@ #include "caffe2/operators/relu_n_op.h" +#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/math.h" namespace caffe2 { diff --git a/caffe2/operators/relu_op.cc b/caffe2/operators/relu_op.cc index 8737cddc59756..45b622ae8409f 100644 --- a/caffe2/operators/relu_op.cc +++ b/caffe2/operators/relu_op.cc @@ -1,5 +1,6 @@ #include "caffe2/operators/relu_op.h" +#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/math.h" namespace caffe2 { diff --git a/caffe2/operators/roi_align_op_gpu_test.cc b/caffe2/operators/roi_align_op_gpu_test.cc index afbf60c85b4bd..199500f93df3a 100644 --- a/caffe2/operators/roi_align_op_gpu_test.cc +++ b/caffe2/operators/roi_align_op_gpu_test.cc @@ -3,6 +3,7 @@ #include "caffe2/core/context_gpu.h" #include "caffe2/core/flags.h" +#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/math.h" #include "gtest/gtest.h" diff --git a/caffe2/operators/rsqrt_op.cc b/caffe2/operators/rsqrt_op.cc index 0587fea21dcab..de4fc499f4215 100644 --- a/caffe2/operators/rsqrt_op.cc +++ b/caffe2/operators/rsqrt_op.cc @@ -1,5 +1,7 @@ #include "caffe2/operators/rsqrt_op.h" +#include "caffe2/utils/eigen_utils.h" + #include #include #include diff --git a/caffe2/operators/selu_op.cc b/caffe2/operators/selu_op.cc index 715e53cd6ea14..50d823d8bedf1 100644 --- a/caffe2/operators/selu_op.cc +++ b/caffe2/operators/selu_op.cc @@ -1,5 +1,6 @@ #include "caffe2/operators/selu_op.h" +#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/math.h" namespace caffe2 { diff --git a/caffe2/operators/sigmoid_gradient_op.cc b/caffe2/operators/sigmoid_gradient_op.cc index 3db4d60a61b0e..dd3c0c40f701f 100644 --- a/caffe2/operators/sigmoid_gradient_op.cc +++ b/caffe2/operators/sigmoid_gradient_op.cc @@ -1,5 +1,7 @@ #include "caffe2/operators/sigmoid_op.h" +#include "caffe2/utils/eigen_utils.h" + #include #include #include diff --git a/caffe2/operators/sigmoid_op.cc b/caffe2/operators/sigmoid_op.cc index 4dcfdc676472d..f1c4828cb37b2 100644 --- a/caffe2/operators/sigmoid_op.cc +++ b/caffe2/operators/sigmoid_op.cc @@ -1,5 +1,7 @@ #include "caffe2/operators/sigmoid_op.h" +#include "caffe2/utils/eigen_utils.h" + namespace caffe2 { template <> diff --git a/caffe2/operators/sin_op.cc b/caffe2/operators/sin_op.cc index 30d76cd162e37..90fcb97bf0799 100644 --- a/caffe2/operators/sin_op.cc +++ b/caffe2/operators/sin_op.cc @@ -1,4 +1,5 @@ #include "caffe2/operators/sin_op.h" +#include "caffe2/utils/eigen_utils.h" #include #include diff --git a/caffe2/operators/sinusoid_position_encoding_op.h b/caffe2/operators/sinusoid_position_encoding_op.h index 69c8ea8244b38..5591b9749a704 100644 --- a/caffe2/operators/sinusoid_position_encoding_op.h +++ b/caffe2/operators/sinusoid_position_encoding_op.h @@ -9,6 +9,7 @@ #include "caffe2/core/operator.h" #include "Eigen/Core" +#include "caffe2/utils/eigen_utils.h" namespace caffe2 { diff --git a/caffe2/operators/softplus_op.cc b/caffe2/operators/softplus_op.cc index 3a81a80b2235b..7d2efd578560a 100644 --- a/caffe2/operators/softplus_op.cc +++ b/caffe2/operators/softplus_op.cc @@ -1,5 +1,6 @@ #include "caffe2/operators/softplus_op.h" +#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/math.h" namespace caffe2 { diff --git a/caffe2/operators/softsign_op.cc b/caffe2/operators/softsign_op.cc index 8e3be424887cc..4062848105b1c 100644 --- a/caffe2/operators/softsign_op.cc +++ b/caffe2/operators/softsign_op.cc @@ -1,5 +1,7 @@ #include "caffe2/operators/softsign_op.h" +#include "caffe2/utils/eigen_utils.h" + #include #include diff --git a/caffe2/operators/sparse_normalize_op.cc b/caffe2/operators/sparse_normalize_op.cc index 2f0f353b5088a..43ded9024d277 100644 --- a/caffe2/operators/sparse_normalize_op.cc +++ b/caffe2/operators/sparse_normalize_op.cc @@ -1,5 +1,6 @@ #include "caffe2/operators/sparse_normalize_op.h" #include "caffe2/core/tensor.h" +#include "caffe2/utils/eigen_utils.h" namespace caffe2 { diff --git a/caffe2/operators/spatial_batch_norm_gradient_op.cc b/caffe2/operators/spatial_batch_norm_gradient_op.cc index 1c4c1bfb5f05a..dd5434db725a7 100644 --- a/caffe2/operators/spatial_batch_norm_gradient_op.cc +++ b/caffe2/operators/spatial_batch_norm_gradient_op.cc @@ -1,5 +1,7 @@ #include "caffe2/operators/spatial_batch_norm_op.h" +#include "caffe2/utils/eigen_utils.h" + namespace caffe2 { template <> diff --git a/caffe2/operators/spatial_batch_norm_op.cc b/caffe2/operators/spatial_batch_norm_op.cc index f089a288069c4..671493a1df010 100644 --- a/caffe2/operators/spatial_batch_norm_op.cc +++ b/caffe2/operators/spatial_batch_norm_op.cc @@ -1,5 +1,7 @@ #include "caffe2/operators/spatial_batch_norm_op.h" +#include "caffe2/utils/eigen_utils.h" + namespace caffe2 { template <> diff --git a/caffe2/operators/swish_op.cc b/caffe2/operators/swish_op.cc index cd8dfa7ea5d3f..a636d23d85f7c 100644 --- a/caffe2/operators/swish_op.cc +++ b/caffe2/operators/swish_op.cc @@ -4,6 +4,7 @@ #include #include "caffe2/core/types.h" +#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/math.h" namespace caffe2 { diff --git a/caffe2/operators/tan_op.cc b/caffe2/operators/tan_op.cc index 7dd873c18e927..62a48bb520a52 100644 --- a/caffe2/operators/tan_op.cc +++ b/caffe2/operators/tan_op.cc @@ -1,5 +1,7 @@ #include "caffe2/operators/tan_op.h" +#include "caffe2/utils/eigen_utils.h" + #include #include diff --git a/caffe2/operators/tanh_gradient_op.cc b/caffe2/operators/tanh_gradient_op.cc index 6daebce46adb9..385d895c688bb 100644 --- a/caffe2/operators/tanh_gradient_op.cc +++ b/caffe2/operators/tanh_gradient_op.cc @@ -1,5 +1,7 @@ #include "caffe2/operators/tanh_op.h" +#include "caffe2/utils/eigen_utils.h" + #include #include #include diff --git a/caffe2/operators/tanh_op.cc b/caffe2/operators/tanh_op.cc index 312fdab36fd8d..b0378a54b4c2b 100644 --- a/caffe2/operators/tanh_op.cc +++ b/caffe2/operators/tanh_op.cc @@ -1,5 +1,7 @@ #include "caffe2/operators/tanh_op.h" +#include "caffe2/utils/eigen_utils.h" + namespace caffe2 { #ifdef CAFFE2_USE_ACCELERATE diff --git a/caffe2/operators/thresholded_relu_op.cc b/caffe2/operators/thresholded_relu_op.cc index d79d20cd5d159..8b5e6b514478c 100644 --- a/caffe2/operators/thresholded_relu_op.cc +++ b/caffe2/operators/thresholded_relu_op.cc @@ -1,5 +1,6 @@ #include "caffe2/operators/thresholded_relu_op.h" +#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/math.h" namespace caffe2 { diff --git a/caffe2/operators/tt_linear_op.h b/caffe2/operators/tt_linear_op.h index 05653c9003913..13196bf3761b7 100644 --- a/caffe2/operators/tt_linear_op.h +++ b/caffe2/operators/tt_linear_op.h @@ -9,6 +9,7 @@ #include "Eigen/Dense" #include "caffe2/core/context.h" #include "caffe2/core/operator.h" +#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/math.h" namespace caffe2 { diff --git a/caffe2/operators/utility_ops.cc b/caffe2/operators/utility_ops.cc index c5bad002779fa..1abf2130953a7 100644 --- a/caffe2/operators/utility_ops.cc +++ b/caffe2/operators/utility_ops.cc @@ -1,6 +1,6 @@ #include "caffe2/operators/utility_ops.h" - #include +#include "caffe2/utils/eigen_utils.h" namespace caffe2 { diff --git a/caffe2/operators/variable_length_sequence_padding.h b/caffe2/operators/variable_length_sequence_padding.h index 53196489b0553..7318b2e78b080 100644 --- a/caffe2/operators/variable_length_sequence_padding.h +++ b/caffe2/operators/variable_length_sequence_padding.h @@ -2,6 +2,7 @@ #include "caffe2/core/context.h" #include "caffe2/core/operator.h" +#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/math.h" namespace caffe2 { diff --git a/caffe2/perfkernels/embedding_lookup.cc b/caffe2/perfkernels/embedding_lookup.cc index 460787e4bdb52..b076d88f5accd 100644 --- a/caffe2/perfkernels/embedding_lookup.cc +++ b/caffe2/perfkernels/embedding_lookup.cc @@ -4,6 +4,7 @@ #include "caffe2/perfkernels/common.h" #include "caffe2/perfkernels/typed_axpy.h" #include "caffe2/utils/cpuid.h" +#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/math.h" namespace caffe2 { diff --git a/caffe2/perfkernels/fused_8bit_rowwise_embedding_lookup.cc b/caffe2/perfkernels/fused_8bit_rowwise_embedding_lookup.cc index 40ab3dafff979..675d7c08ddbf3 100644 --- a/caffe2/perfkernels/fused_8bit_rowwise_embedding_lookup.cc +++ b/caffe2/perfkernels/fused_8bit_rowwise_embedding_lookup.cc @@ -4,6 +4,7 @@ #include "caffe2/perfkernels/common.h" #include "caffe2/perfkernels/typed_axpy.h" #include "caffe2/utils/cpuid.h" +#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/math.h" namespace caffe2 { diff --git a/caffe2/sgd/lars_op.cc b/caffe2/sgd/lars_op.cc index a47d5c94d5f1a..3e013a943464b 100644 --- a/caffe2/sgd/lars_op.cc +++ b/caffe2/sgd/lars_op.cc @@ -1,5 +1,6 @@ #include "caffe2/sgd/lars_op.h" #include +#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/math.h" namespace caffe2 { diff --git a/caffe2/sgd/rmsprop_op.cc b/caffe2/sgd/rmsprop_op.cc index 3d5c01d8542a0..ae73706190077 100644 --- a/caffe2/sgd/rmsprop_op.cc +++ b/caffe2/sgd/rmsprop_op.cc @@ -1,5 +1,6 @@ #include "rmsprop_op.h" +#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/math.h" namespace caffe2 { diff --git a/caffe2/utils/eigen_utils.h b/caffe2/utils/eigen_utils.h index b00e355627fb2..cf41d268d7132 100644 --- a/caffe2/utils/eigen_utils.h +++ b/caffe2/utils/eigen_utils.h @@ -9,6 +9,30 @@ namespace caffe2 { +// Common Eigen types that we will often use +template +using EigenMatrixMap = + Eigen::Map>; +template +using EigenArrayMap = + Eigen::Map>; +template +using EigenVectorMap = Eigen::Map>; +template +using EigenVectorArrayMap = Eigen::Map>; +template +using ConstEigenMatrixMap = + Eigen::Map>; +template +using ConstEigenArrayMap = + Eigen::Map>; +template +using ConstEigenVectorMap = + Eigen::Map>; +template +using ConstEigenVectorArrayMap = + Eigen::Map>; + // 1-d array template using EArrXt = Eigen::Array; diff --git a/caffe2/utils/math.h b/caffe2/utils/math.h index 0e7bc2b56f669..c3d3adcc37023 100644 --- a/caffe2/utils/math.h +++ b/caffe2/utils/math.h @@ -17,9 +17,6 @@ extern "C" { #include "caffe2/core/types.h" #include "caffe2/utils/math_utils.h" -#include "Eigen/Core" -#include "Eigen/Dense" - namespace caffe2 { template @@ -29,30 +26,6 @@ class Tensor; // engine specified. class DefaultEngine {}; -// Common Eigen types that we will often use -template -using EigenMatrixMap = - Eigen::Map>; -template -using EigenArrayMap = - Eigen::Map>; -template -using EigenVectorMap = Eigen::Map>; -template -using EigenVectorArrayMap = Eigen::Map>; -template -using ConstEigenMatrixMap = - Eigen::Map>; -template -using ConstEigenArrayMap = - Eigen::Map>; -template -using ConstEigenVectorMap = - Eigen::Map>; -template -using ConstEigenVectorArrayMap = - Eigen::Map>; - namespace math { template diff --git a/caffe2/utils/math_cpu.cc b/caffe2/utils/math_cpu.cc index c958f9f43a2bc..f2797b4fc688a 100644 --- a/caffe2/utils/math_cpu.cc +++ b/caffe2/utils/math_cpu.cc @@ -11,6 +11,7 @@ // platforms, it allows one to quickly port Caffe2 to different platforms // where BLAS may not be present. +#include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/math.h" #include diff --git a/caffe2/utils/math_gpu.cu b/caffe2/utils/math_gpu.cu index 4b2a0661642d7..e93c1a729b429 100644 --- a/caffe2/utils/math_gpu.cu +++ b/caffe2/utils/math_gpu.cu @@ -2,6 +2,7 @@ #include "caffe2/utils/math.h" +#include #include #include #include From 82539472562b84bc1e17f545e9175ce4c9b7f37a Mon Sep 17 00:00:00 2001 From: Yan Shang Date: Wed, 11 Jul 2018 14:59:22 -0700 Subject: [PATCH 27/36] Make error message more informative (#9352) Summary: Pull Request resolved: https://github.com/pytorch/pytorch/pull/9352 I am debugging a failed workflow f61490672, and found the original error message to be not informative. Differential Revision: D8808181 fbshipit-source-id: 3f524ca092881186a492c5c0456124ce31d54751 --- caffe2/python/core.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/caffe2/python/core.py b/caffe2/python/core.py index 721da8e6c8f6e..3caa3ee715d5d 100644 --- a/caffe2/python/core.py +++ b/caffe2/python/core.py @@ -1718,7 +1718,7 @@ def ClonePartial(self, name, inputs, outputs, remap_funcs=None): OrderedDict(inputs) if input_is_pair_list else OrderedDict(zip(inputs, inputs))) for output in outputs: - assert self.BlobIsDefined(output) + assert self.BlobIsDefined(output), "{} is not defined".format(output) input_names = {str(k): str(v) for k, v in viewitems(inputs)} output_names = [str(o) for o in outputs] proto = self._net @@ -1901,7 +1901,7 @@ def AddExternalInput(self, *inputs): def AddExternalOutput(self, *outputs): for output in outputs: assert isinstance(output, BlobReference) - assert self.BlobIsDefined(output) + assert self.BlobIsDefined(output), "{} is not defined".format(output) for output in outputs: self.Proto().external_output.extend([str(output)]) @@ -1988,7 +1988,7 @@ def AppendOutputRecordField(self, field_name, record): 'Tried to append to missing output record' ) for blob in record.field_blobs(): - assert self.BlobIsDefined(blob) + assert self.BlobIsDefined(blob), "{} is not defined".format(blob) for blob in record.field_blobs(): self.AddExternalOutput(blob) self._output_record = self._output_record + schema.Struct( From 94bc4c6091ed3ef0a8ac7548179045f624504841 Mon Sep 17 00:00:00 2001 From: Ilia Cherniavskii Date: Wed, 11 Jul 2018 15:35:45 -0700 Subject: [PATCH 28/36] Ensure pending tasks are finished in case of failure (#9290) Summary: Pull Request resolved: https://github.com/pytorch/pytorch/pull/9290 Ensure pending tasks (e.g. network ops) are finished when net fails Reviewed By: heslami Differential Revision: D8777230 fbshipit-source-id: e57fcf1df6aa0ed8847923391502b666edb43674 --- caffe2/core/net_async_scheduling.cc | 17 +++++++++++ caffe2/core/net_test.cc | 46 +++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+) diff --git a/caffe2/core/net_async_scheduling.cc b/caffe2/core/net_async_scheduling.cc index 0a7be39389b8a..7feb3631abfd6 100644 --- a/caffe2/core/net_async_scheduling.cc +++ b/caffe2/core/net_async_scheduling.cc @@ -125,6 +125,23 @@ void AsyncSchedulingNet::schedule(int task_id, bool run_inline) { } } + // In case of net's failure, make sure all pending tasks are finished + if (!success_) { + // Simple logic to capture all pending tasks - check all tasks + // at the end of each task in case of net's failure + for (auto tid = 0; tid < tasksNum(); ++tid) { + if (event(tid).Query() == EventStatus::EVENT_SCHEDULED) { + // SetFinished may throw, e.g. when we call it on already finished + // event, and in some other cases (CUDA) + try { + event(tid).SetFinished("Cancelled"); + } catch (const EnforceNotMet&) { + // ignore + } + } + } + } + // finishRun may cause waiters to wake up and destroy the net, // before we call finishRun we need to make sure all other (finishing) // tasks are done; diff --git a/caffe2/core/net_test.cc b/caffe2/core/net_test.cc index 3262984260d5a..1b9397038e9be 100644 --- a/caffe2/core/net_test.cc +++ b/caffe2/core/net_test.cc @@ -769,4 +769,50 @@ TEST(NetTest, NoTypeNet) { } } +class NotFinishingOp final : public Operator { + public: + NotFinishingOp(const OperatorDef& operator_def, Workspace* ws) + : Operator(operator_def, ws) {} + + bool RunOnDevice() override { + // never calls SetFinished + return true; + } + + bool HasAsyncPart() const override { + return true; + } +}; + +REGISTER_CPU_OPERATOR(NotFinishingOp, NotFinishingOp); + +OPERATOR_SCHEMA(NotFinishingOp); + +TEST(NetTest, PendingOpsAndNetFailure) { + const auto spec = R"DOC( + name: "example" + type: "async_scheduling" + op { + type: "NotFinishingOp" + } + op { + type: "NetTestDummy" + arg { + name: "fail" + i: 1 + } + } +)DOC"; + + NetDef net_def; + CAFFE_ENFORCE( + ::google::protobuf::TextFormat::ParseFromString(spec, &net_def)); + + Workspace ws; + std::unique_ptr net(CreateNet(net_def, &ws)); + + // net is not stuck and returns false + ASSERT_FALSE(net->Run()); +} + } // namespace caffe2 From 153e2e96d4aaf0c3d97dea7ee9375b2ad26d679f Mon Sep 17 00:00:00 2001 From: Peter Goldsborough Date: Wed, 11 Jul 2018 17:15:08 -0700 Subject: [PATCH 29/36] Make Sequential ref-counted (#9151) Summary: In the C++ API, `Sequential` currently was not refcounted itself, but stored `shared_ptr` to get the reference semantics. This is unfortunate because most modules in the API are accessed via `->`, e.g. `Linear l(1, 2); l->forward(...);`. `Sequential` was different in that it had value semantics itself, thus was accessed via `.`. This PR makes `Sequential` store `AnyModule` (without extra indirection), and uses the same pImpl mechanism we use for all other modules to make `Sequential` have reference semantics itself. This makes it consistent with the rest of the library. It also removes one level of indirection inside of `Sequential`, which is cool. One thing I had to change was that the `ModuleHolder` with which the whole pImpl thing is implemented previously did some tricks to make `Linear(3, 4)` actually construct `Linear(LinearOptions(3, 4))`. This doesn't work well with `Sequential` since it takes a variadic parameter pack. Instead, I made `ModuleHolder` forward all arguments to the underlying module, and then further pushed the trick to forward parameters to modules' options types into the actual Modules. This adds one constructor per Module in the library. This is not something user modules have to do (unless they want this nice forwarding themselves). It makes the code simpler overall. ezyang ebetica apaszke Pull Request resolved: https://github.com/pytorch/pytorch/pull/9151 Reviewed By: ezyang Differential Revision: D8809298 Pulled By: goldsborough fbshipit-source-id: da68452c3de912fbc67af330ba93b5220de6909f --- test/cpp/api/any.cpp | 7 -- test/cpp/api/module.cpp | 2 +- test/cpp/api/modules.cpp | 18 ++- test/cpp/api/optim.cpp | 10 +- test/cpp/api/sequential.cpp | 105 +++++++++++------- test/cpp/api/serialization.cpp | 8 +- test/cpp/api/static.cpp | 2 +- torch/csrc/api/include/torch/nn/modules/any.h | 25 ++++- .../api/include/torch/nn/modules/batchnorm.h | 3 + .../csrc/api/include/torch/nn/modules/conv.h | 3 + .../api/include/torch/nn/modules/dropout.h | 3 + .../api/include/torch/nn/modules/embedding.h | 3 + .../api/include/torch/nn/modules/functional.h | 41 +++---- .../api/include/torch/nn/modules/linear.h | 3 + torch/csrc/api/include/torch/nn/modules/rnn.h | 7 ++ .../api/include/torch/nn/modules/sequential.h | 52 +++++---- torch/csrc/api/include/torch/nn/pimpl.h | 87 +++++++++------ torch/csrc/api/src/nn/modules/functional.cpp | 3 - torch/csrc/api/src/nn/modules/rnn.cpp | 1 + 19 files changed, 220 insertions(+), 163 deletions(-) diff --git a/test/cpp/api/any.cpp b/test/cpp/api/any.cpp index 32840a3226814..32bfe3ce3880c 100644 --- a/test/cpp/api/any.cpp +++ b/test/cpp/api/any.cpp @@ -201,13 +201,6 @@ TEST_CASE("any-module") { REQUIRE(!any.is_empty()); REQUIRE(any.forward(5.0f).get() == 8); } - SECTION("has reference semantics") { - Sequential first(Linear(2, 3), Linear(4, 4), Linear(4, 5)); - Sequential second(first); - - REQUIRE(first.size() == second.size()); - REQUIRE(std::equal(first.begin(), first.end(), second.begin())); - } SECTION("constructs from ModuleHolder") { struct MImpl : torch::nn::Module { explicit MImpl(int value_) : torch::nn::Module("M"), value(value_) {} diff --git a/test/cpp/api/module.cpp b/test/cpp/api/module.cpp index 40db9f1eb3902..af790466d24f1 100644 --- a/test/cpp/api/module.cpp +++ b/test/cpp/api/module.cpp @@ -202,7 +202,7 @@ TEST_CASE("module/clone") { buffer = register_buffer("buf", torch::ones({2, 2})); } - Linear l1, l2, l3; + Linear l1{nullptr}, l2{nullptr}, l3{nullptr}; torch::Tensor buffer; }; diff --git a/test/cpp/api/modules.cpp b/test/cpp/api/modules.cpp index 586777f529417..ac40ec2081185 100644 --- a/test/cpp/api/modules.cpp +++ b/test/cpp/api/modules.cpp @@ -16,22 +16,20 @@ using namespace torch::nn; class TestModel : public torch::nn::Module { public: - TestModel() { - l1 = register_module("l1", Linear(10, 3)); - l2 = register_module("l2", Linear(3, 5)); - l3 = register_module("l3", Linear(5, 100)); - } + TestModel() + : l1(register_module("l1", Linear(10, 3))), + l2(register_module("l2", Linear(3, 5))), + l3(register_module("l3", Linear(5, 100))) {} Linear l1, l2, l3; }; class NestedModel : public torch::nn::Module { public: - NestedModel() { - l1 = register_module("l1", Linear(5, 20)); - t = register_module("test", std::make_shared()); - param_ = register_parameter("param", torch::empty({3, 2, 21})); - } + NestedModel() + : l1(register_module("l1", Linear(5, 20))), + t(register_module("test", std::make_shared())), + param_(register_parameter("param", torch::empty({3, 2, 21}))) {} torch::Tensor param_; Linear l1; diff --git a/test/cpp/api/optim.cpp b/test/cpp/api/optim.cpp index 55557e469ff68..02a9ca14a3670 100644 --- a/test/cpp/api/optim.cpp +++ b/test/cpp/api/optim.cpp @@ -35,7 +35,7 @@ bool test_optimizer_xor(Options options) { const int64_t kBatchSize = 4; const int64_t kMaximumNumberOfEpochs = 3000; - auto optimizer = OptimizerClass(model.parameters(), options); + auto optimizer = OptimizerClass(model->parameters(), options); float running_loss = 1; int epoch = 0; @@ -48,7 +48,7 @@ bool test_optimizer_xor(Options options) { } inputs.set_requires_grad(true); optimizer.zero_grad(); - auto x = model.forward(inputs); + auto x = model->forward(inputs); torch::Tensor loss = torch::binary_cross_entropy(x, labels); loss.backward(); @@ -91,10 +91,10 @@ void check_exact_values( Linear(3, 1), Functional(torch::sigmoid)); - model.to(torch::kFloat64); + model->to(torch::kFloat64); // Use exact input values because matching random values is hard. - auto parameters = model.parameters(); + auto parameters = model->parameters(); assign_parameter( parameters, "0.weight", @@ -111,7 +111,7 @@ void check_exact_values( for (size_t i = 0; i < kIterations; ++i) { optimizer.zero_grad(); - auto output = model.forward(input); + auto output = model->forward(input); auto loss = output.sum(); loss.backward(); diff --git a/test/cpp/api/sequential.cpp b/test/cpp/api/sequential.cpp index a4b735e9e9cde..0d608cd856481 100644 --- a/test/cpp/api/sequential.cpp +++ b/test/cpp/api/sequential.cpp @@ -24,7 +24,7 @@ TEST_CASE("sequential") { }; Sequential sequential( std::make_shared(1), std::make_shared(2), std::make_shared(3)); - REQUIRE(sequential.size() == 3); + REQUIRE(sequential->size() == 3); } SECTION("construction from concrete type") { struct M : torch::nn::Module { @@ -36,7 +36,7 @@ TEST_CASE("sequential") { }; Sequential sequential(M(1), M(2), M(3)); - REQUIRE(sequential.size() == 3); + REQUIRE(sequential->size() == 3); } SECTION("construction from module holders") { struct MImpl : torch::nn::Module { @@ -53,7 +53,7 @@ TEST_CASE("sequential") { }; Sequential sequential(M(1), M(2), M(3)); - REQUIRE(sequential.size() == 3); + REQUIRE(sequential->size() == 3); } SECTION("push_back") { struct M : torch::nn::Module { @@ -64,14 +64,14 @@ TEST_CASE("sequential") { int value; }; Sequential sequential; - REQUIRE(sequential.size() == 0); - REQUIRE(sequential.is_empty()); - sequential.push_back(Linear(3, 4)); - REQUIRE(sequential.size() == 1); - sequential.push_back(std::make_shared(1)); - REQUIRE(sequential.size() == 2); - sequential.push_back(M(2)); - REQUIRE(sequential.size() == 3); + REQUIRE(sequential->size() == 0); + REQUIRE(sequential->is_empty()); + sequential->push_back(Linear(3, 4)); + REQUIRE(sequential->size() == 1); + sequential->push_back(std::make_shared(1)); + REQUIRE(sequential->size() == 2); + sequential->push_back(M(2)); + REQUIRE(sequential->size() == 3); } SECTION("access") { struct M : torch::nn::Module { @@ -86,22 +86,22 @@ TEST_CASE("sequential") { Sequential sequential; for (auto& module : modules) { - sequential.push_back(module); + sequential->push_back(module); } - REQUIRE(sequential.size() == 3); + REQUIRE(sequential->size() == 3); SECTION("at()") { SECTION("returns the correct module for a given index") { for (size_t i = 0; i < modules.size(); ++i) { - REQUIRE(&sequential.at(i) == modules[i].get()); + REQUIRE(&sequential->at(i) == modules[i].get()); } } SECTION("throws for a bad index") { REQUIRE_THROWS_WITH( - sequential.at(modules.size() + 1), + sequential->at(modules.size() + 1), StartsWith("Index out of range")); REQUIRE_THROWS_WITH( - sequential.at(modules.size() + 1000000), + sequential->at(modules.size() + 1000000), StartsWith("Index out of range")); } } @@ -109,17 +109,17 @@ TEST_CASE("sequential") { SECTION("ptr()") { SECTION("returns the correct module for a given index") { for (size_t i = 0; i < modules.size(); ++i) { - REQUIRE(sequential.ptr(i).get() == modules[i].get()); + REQUIRE(sequential->ptr(i).get() == modules[i].get()); REQUIRE(sequential[i].get() == modules[i].get()); - REQUIRE(sequential.ptr(i).get() == modules[i].get()); + REQUIRE(sequential->ptr(i).get() == modules[i].get()); } } SECTION("throws for a bad index") { REQUIRE_THROWS_WITH( - sequential.ptr(modules.size() + 1), + sequential->ptr(modules.size() + 1), StartsWith("Index out of range")); REQUIRE_THROWS_WITH( - sequential.ptr(modules.size() + 1000000), + sequential->ptr(modules.size() + 1000000), StartsWith("Index out of range")); } } @@ -128,7 +128,7 @@ TEST_CASE("sequential") { SECTION("calling forward() on an empty sequential is disallowed") { Sequential empty; REQUIRE_THROWS_WITH( - empty.forward(), + empty->forward(), StartsWith("Cannot call forward() on an empty Sequential")); } @@ -144,7 +144,7 @@ TEST_CASE("sequential") { Sequential sequential(MockModule{1}, MockModule{2}, MockModule{3}); - REQUIRE(sequential.forward(1) == 4); + REQUIRE(sequential->forward(1) == 4); } SECTION("calling forward() with the wrong return type throws") { @@ -155,9 +155,9 @@ TEST_CASE("sequential") { }; Sequential sequential(M{}); - REQUIRE(sequential.forward() == 5); + REQUIRE(sequential->forward() == 5); REQUIRE_THROWS_WITH( - sequential.forward(), + sequential->forward(), StartsWith("The type of the return value " "is int, but you asked for type float")); } @@ -171,7 +171,7 @@ TEST_CASE("sequential") { Sequential sequential(M{}); auto variable = torch::ones({3, 3}, torch::requires_grad()); - REQUIRE(sequential.forward(variable).equal(variable)); + REQUIRE(sequential->forward(variable).equal(variable)); } } @@ -180,7 +180,7 @@ TEST_CASE("sequential") { Sequential sequential(Linear(10, 3), Linear(3, 5), Linear(5, 100)); auto x = torch::randn({1000, 10}, torch::requires_grad()); - auto y = sequential.forward(x); + auto y = sequential->forward(x); REQUIRE(y.ndimension() == 2); REQUIRE(y.size(0) == 1000); REQUIRE(y.size(1) == 100); @@ -205,42 +205,71 @@ TEST_CASE("sequential") { Sequential sequential(M{}); torch::Tensor variable = torch::ones(5); - REQUIRE(sequential.forward(variable).sum().toCFloat() == 5); + REQUIRE(sequential->forward(variable).sum().toCFloat() == 5); at::Tensor tensor_that_is_actually_a_variable = variable * 2; REQUIRE( - sequential.forward(tensor_that_is_actually_a_variable) + sequential->forward(tensor_that_is_actually_a_variable) .sum() .toCFloat() == 10); } - SECTION("extend() pushes modules from other Sequential") { - struct A : torch::nn::Module { int forward(int x) { return x; } }; - struct B : torch::nn::Module { int forward(int x) { return x; } }; - struct C : torch::nn::Module { int forward(int x) { return x; } }; - struct D : torch::nn::Module { int forward(int x) { return x; } }; + struct A : torch::nn::Module { + int forward(int x) { + return x; + } + }; + struct B : torch::nn::Module { + int forward(int x) { + return x; + } + }; + struct C : torch::nn::Module { + int forward(int x) { + return x; + } + }; + struct D : torch::nn::Module { + int forward(int x) { + return x; + } + }; Sequential a(A{}, B{}); Sequential b(C{}, D{}); - a.extend(b); + a->extend(*b); - REQUIRE(a.size() == 4); + REQUIRE(a->size() == 4); REQUIRE(a[0]->as()); REQUIRE(a[1]->as()); REQUIRE(a[2]->as()); REQUIRE(a[3]->as()); - REQUIRE(b.size() == 2); + REQUIRE(b->size() == 2); REQUIRE(b[0]->as()); REQUIRE(b[1]->as()); std::vector> c = {std::make_shared(), std::make_shared()}; - b.extend(c); + b->extend(c); - REQUIRE(b.size() == 4); + REQUIRE(b->size() == 4); REQUIRE(b[0]->as()); REQUIRE(b[1]->as()); REQUIRE(b[2]->as()); REQUIRE(b[3]->as()); } + SECTION("has reference semantics") { + Sequential first(Linear(2, 3), Linear(4, 4), Linear(4, 5)); + Sequential second(first); + + REQUIRE(first.get() == second.get()); + REQUIRE(first->size() == second->size()); + REQUIRE(std::equal( + first->begin(), + first->end(), + second->begin(), + [](const AnyModule& first, const AnyModule& second) { + return &first == &second; + })); + } } diff --git a/test/cpp/api/serialization.cpp b/test/cpp/api/serialization.cpp index 5d266e6051aa0..5cc8cc9e7d27b 100644 --- a/test/cpp/api/serialization.cpp +++ b/test/cpp/api/serialization.cpp @@ -21,8 +21,8 @@ using namespace torch::nn; namespace { -std::shared_ptr xor_model() { - return std::make_shared( +Sequential xor_model() { + return Sequential( Linear(2, 8), Functional(at::sigmoid), Linear(8, 1), @@ -174,7 +174,7 @@ TEST_CASE("serialization") { SECTION("xor") { // We better be able to save and load a XOR model! - auto getLoss = [](std::shared_ptr model, uint32_t batch_size) { + auto getLoss = [](Sequential model, uint32_t batch_size) { auto inputs = torch::empty({batch_size, 2}); auto labels = torch::empty({batch_size}); for (size_t i = 0; i < batch_size; i++) { @@ -279,7 +279,7 @@ TEST_CASE("serialization") { TEST_CASE("serialization_cuda", "[cuda]") { torch::manual_seed(0); // We better be able to save and load a XOR model! - auto getLoss = [](std::shared_ptr model, uint32_t batch_size) { + auto getLoss = [](Sequential model, uint32_t batch_size) { auto inputs = torch::empty({batch_size, 2}); auto labels = torch::empty({batch_size}); for (size_t i = 0; i < batch_size; i++) { diff --git a/test/cpp/api/static.cpp b/test/cpp/api/static.cpp index 2bfc18e2e2fd6..121478c928ac1 100644 --- a/test/cpp/api/static.cpp +++ b/test/cpp/api/static.cpp @@ -39,7 +39,7 @@ TEST_CASE("static") { REQUIRE(torch::any_of::value == true); } SECTION("enable_if_module_t") { - REQUIRE(f(torch::nn::LinearImpl({1, 2})) == true); + REQUIRE(f(torch::nn::LinearImpl(1, 2)) == true); REQUIRE(f(5) == false); } SECTION("check_not_lvalue_references") { diff --git a/torch/csrc/api/include/torch/nn/modules/any.h b/torch/csrc/api/include/torch/nn/modules/any.h index edf2ed1ad36b0..121a8afe0ff92 100644 --- a/torch/csrc/api/include/torch/nn/modules/any.h +++ b/torch/csrc/api/include/torch/nn/modules/any.h @@ -36,7 +36,7 @@ class AnyModule { /// Constructs an `AnyModule` from a concrete module object. template < typename ModuleType, - typename = torch::detail::disable_if_module_holder_t> + typename = torch::detail::enable_if_module_t> explicit AnyModule(ModuleType&& module); /// Constructs an `AnyModule` from a module holder. @@ -48,9 +48,9 @@ class AnyModule { AnyModule(AnyModule&&) = default; AnyModule& operator=(AnyModule&&) = default; - /// Copy is disallowed. - AnyModule(const AnyModule& other) = delete; - AnyModule& operator=(const AnyModule& other) = delete; + /// Creates a copy of an `AnyModule`. + AnyModule(const AnyModule& other); + AnyModule& operator=(const AnyModule& other); /// Assigns a module to the `AnyModule` (to circumvent the explicit /// constructor). @@ -237,6 +237,9 @@ struct AnyModule::Placeholder : public AnyModule::Value::Placeholder { /// Returns std::shared_ptr pointing to the erased module. virtual std::shared_ptr ptr() = 0; + + /// Returns a `Placeholder` with a copy of this `AnyModule`. + virtual std::unique_ptr clone() const = 0; }; // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ AnyModule::Holder ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -294,6 +297,10 @@ struct AnyModule::Holder : public AnyModule::Placeholder { return module; } + std::unique_ptr clone() const override { + return torch::make_unique(*this); + } + /// The actual concrete module instance. std::shared_ptr module; }; @@ -315,6 +322,16 @@ template AnyModule::AnyModule(const ModuleHolder& module_holder) : AnyModule(module_holder.ptr()) {} +inline AnyModule::AnyModule(const AnyModule& other) + : content_(other.content_ ? other.content_->clone() : nullptr) {} + +inline AnyModule& AnyModule::operator=(const AnyModule& other) { + if (this != &other) { + content_ = other.content_ ? other.content_->clone() : nullptr; + } + return *this; +} + template AnyModule& AnyModule::operator=(std::shared_ptr module) { return (*this = AnyModule(std::move(module))); diff --git a/torch/csrc/api/include/torch/nn/modules/batchnorm.h b/torch/csrc/api/include/torch/nn/modules/batchnorm.h index bc6fbacff957b..25c75b85a7df7 100644 --- a/torch/csrc/api/include/torch/nn/modules/batchnorm.h +++ b/torch/csrc/api/include/torch/nn/modules/batchnorm.h @@ -19,6 +19,9 @@ struct BatchNormOptions { class BatchNormImpl : public torch::nn::Cloneable { public: + template + explicit BatchNormImpl(Ts&&... ts) + : BatchNormImpl(BatchNormOptions(std::forward(ts)...)) {} explicit BatchNormImpl(BatchNormOptions options); void reset() override; diff --git a/torch/csrc/api/include/torch/nn/modules/conv.h b/torch/csrc/api/include/torch/nn/modules/conv.h index 386a1937de7f0..f7a7cc0b14246 100644 --- a/torch/csrc/api/include/torch/nn/modules/conv.h +++ b/torch/csrc/api/include/torch/nn/modules/conv.h @@ -32,6 +32,9 @@ struct ConvOptions { template class ConvImpl : public torch::nn::Cloneable { public: + template + explicit ConvImpl(Ts&&... ts) + : ConvImpl(ConvOptions(std::forward(ts)...)) {} explicit ConvImpl(ConvOptions options); void reset() override; diff --git a/torch/csrc/api/include/torch/nn/modules/dropout.h b/torch/csrc/api/include/torch/nn/modules/dropout.h index 876b042550b31..91f4c5b244dd8 100644 --- a/torch/csrc/api/include/torch/nn/modules/dropout.h +++ b/torch/csrc/api/include/torch/nn/modules/dropout.h @@ -18,6 +18,9 @@ namespace detail { template class DropoutImplBase : public torch::nn::Cloneable { public: + template + explicit DropoutImplBase(Ts&&... ts) + : DropoutImplBase(DropoutOptions(std::forward(ts)...)) {} explicit DropoutImplBase(DropoutOptions options_); void reset() override; diff --git a/torch/csrc/api/include/torch/nn/modules/embedding.h b/torch/csrc/api/include/torch/nn/modules/embedding.h index 861d75220606f..f35cd05cb7ca2 100644 --- a/torch/csrc/api/include/torch/nn/modules/embedding.h +++ b/torch/csrc/api/include/torch/nn/modules/embedding.h @@ -18,6 +18,9 @@ struct EmbeddingOptions { class EmbeddingImpl : public torch::nn::Cloneable { public: + template + explicit EmbeddingImpl(Ts&&... ts) + : EmbeddingImpl(EmbeddingOptions(std::forward(ts)...)) {} explicit EmbeddingImpl(EmbeddingOptions options); void reset() override; diff --git a/torch/csrc/api/include/torch/nn/modules/functional.h b/torch/csrc/api/include/torch/nn/modules/functional.h index e3a9d6897e7b7..4e234a8ad3fc8 100644 --- a/torch/csrc/api/include/torch/nn/modules/functional.h +++ b/torch/csrc/api/include/torch/nn/modules/functional.h @@ -16,33 +16,22 @@ class FunctionalImpl : public torch::nn::Cloneable { public: using Function = std::function; - /// A small type that is used only in the constructor of `FunctionalImpl`, - /// that allows constructing it with a function with more than one argument, - /// and binding all but the first parameter to specific values. It is - /// necessary due to interaction with the `ModuleHolder` class, which expects - /// to construct a module with `Module({...})` when there is more than one - /// argument. It also deals with argument binding. - struct BoundFunction { - template < - typename AnyFunction, - typename... Args, - typename = torch::enable_if_t<(sizeof...(Args) > 0)>> - /* implicit */ BoundFunction(AnyFunction original_function, Args&&... args) - : function_(std::bind( - original_function, - /*input=*/std::placeholders::_1, - std::forward(args)...)) { - // std::bind is normally evil, but (1) gcc is broken w.r.t. handling - // parameter pack expansion in lambdas and (2) moving parameter packs into - // a lambda only works with C++14, so std::bind is the more move-aware - // solution here. - } - - Function function_; - }; - explicit FunctionalImpl(Function function); - explicit FunctionalImpl(BoundFunction bound_function); + + template < + typename SomeFunction, + typename... Args, + typename = torch::enable_if_t<(sizeof...(Args) > 0)>> + explicit FunctionalImpl(SomeFunction original_function, Args&&... args) + : function_(std::bind( + original_function, + /*input=*/std::placeholders::_1, + std::forward(args)...)) { + // std::bind is normally evil, but (1) gcc is broken w.r.t. handling + // parameter pack expansion in lambdas and (2) moving parameter packs into + // a lambda only works with C++14, so std::bind is the more move-aware + // solution here. + } void reset() override; Tensor forward(Tensor input); diff --git a/torch/csrc/api/include/torch/nn/modules/linear.h b/torch/csrc/api/include/torch/nn/modules/linear.h index 40daaef77e37c..34f674991b1e1 100644 --- a/torch/csrc/api/include/torch/nn/modules/linear.h +++ b/torch/csrc/api/include/torch/nn/modules/linear.h @@ -19,6 +19,9 @@ struct LinearOptions { class LinearImpl : public Cloneable { public: + template + explicit LinearImpl(Ts&&... ts) + : LinearImpl(LinearOptions(std::forward(ts)...)) {} explicit LinearImpl(LinearOptions options); void reset() override; diff --git a/torch/csrc/api/include/torch/nn/modules/rnn.h b/torch/csrc/api/include/torch/nn/modules/rnn.h index bf3ffb863352b..e6d2ea918e9ec 100644 --- a/torch/csrc/api/include/torch/nn/modules/rnn.h +++ b/torch/csrc/api/include/torch/nn/modules/rnn.h @@ -121,6 +121,8 @@ struct RNNOptions { class RNNImpl : public detail::RNNImplBase { public: + template + explicit RNNImpl(Ts&&... ts) : RNNImpl(RNNOptions(std::forward(ts)...)) {} explicit RNNImpl(RNNOptions options); RNNOptions options; @@ -138,6 +140,9 @@ using LSTMOptions = detail::RNNOptionsBase; class LSTMImpl : public detail::RNNImplBase { public: + template + explicit LSTMImpl(Ts&&... ts) + : LSTMImpl(LSTMOptions(std::forward(ts)...)) {} explicit LSTMImpl(LSTMOptions options); private: @@ -152,6 +157,8 @@ using GRUOptions = detail::RNNOptionsBase; class GRUImpl : public detail::RNNImplBase { public: + template + explicit GRUImpl(Ts&&... ts) : GRUImpl(GRUOptions(std::forward(ts)...)) {} explicit GRUImpl(GRUOptions options); private: diff --git a/torch/csrc/api/include/torch/nn/modules/sequential.h b/torch/csrc/api/include/torch/nn/modules/sequential.h index f0ff16d4b561e..755e712a9f1a2 100644 --- a/torch/csrc/api/include/torch/nn/modules/sequential.h +++ b/torch/csrc/api/include/torch/nn/modules/sequential.h @@ -20,19 +20,17 @@ namespace nn { /// A `Sequential` module is a container for any number of other modules. Its /// `forward()` method chains outputs to inputs and returns the final output. /// The `Sequential` class reference semantics. -class Sequential : public Cloneable { +class SequentialImpl : public Cloneable { public: - using Iterator = std::vector>::iterator; - using ConstIterator = std::vector>::const_iterator; + using Iterator = std::vector::iterator; + using ConstIterator = std::vector::const_iterator; /// Constructs the `Sequential` from a pack of modules. Each module can either /// be a plain value (e.g. `Linear`) or a boxed value (e.g. /// `shared_ptr`). Unboxed modules will be moved into `shared_ptr`s /// internally. - template < - typename... Modules, - typename = disable_if_contains_t> - explicit Sequential(Modules&&... modules) { + template + explicit SequentialImpl(Modules&&... modules) { modules_.reserve(sizeof...(Modules)); push_back(std::forward(modules)...); } @@ -48,11 +46,10 @@ class Sequential : public Cloneable { AT_CHECK(!is_empty(), "Cannot call forward() on an empty Sequential"); auto iterator = modules_.begin(); - auto input = - (*iterator)->forward(std::forward(arguments)...); + auto input = iterator->forward(std::forward(arguments)...); for (++iterator; iterator != modules_.end(); ++iterator) { - input = (*iterator)->forward(std::move(input)); + input = iterator->forward(std::move(input)); } // Check the return value and give a nice error message if the requsted @@ -73,7 +70,7 @@ class Sequential : public Cloneable { // Nesting Sequential doesn't work because `forward()`'s return type is // templatized, so it'll give a nasty compiler error. static_assert( - !std::is_same::value, + !std::is_same::value, "Sequential is not nestable"); static_assert( torch::detail::is_module::value, @@ -81,7 +78,7 @@ class Sequential : public Cloneable { static_assert( torch::detail::has_forward::value, "Can only add modules with a forward() method to Sequential"); - push_back(std::make_shared(std::move(module_ptr))); + push_back(AnyModule(std::move(module_ptr))); } /// Adds a new `Module` to the `Sequential` container, moving or copying it @@ -89,7 +86,7 @@ class Sequential : public Cloneable { /// and letting the container deal with the boxing. This means you can write /// `Sequential(Module(3, 4))` instead of /// `Sequential(std::make_shared(3, 4))`. - template > + template > void push_back(M&& module) { // Need to get rid of any reference components for make_unique. using Type = typename std::remove_reference::type; @@ -104,15 +101,7 @@ class Sequential : public Cloneable { push_back(module_holder.ptr()); } - /// Adds a type-erased `AnyModule` to the `Sequential`. - void push_back(std::shared_ptr any_module) { - modules_.push_back(std::move(any_module)); - const auto index = modules_.size() - 1; - register_module(std::to_string(index), modules_[index]->ptr()); - } - - /// Iterates over the container and calls `push_back()` on each iterated - /// value. + /// Iterates over the container and calls `push_back()` on each value. template void extend(const Container& container) { for (const auto& module : container) { @@ -145,7 +134,7 @@ class Sequential : public Cloneable { torch::detail::is_module::value, "Can only call Sequential::at with an nn::Module type"); AT_CHECK(index < size(), "Index out of range"); - return modules_[index]->get(); + return modules_[index].get(); } /// Attempts to return the module at the given index as the requested type. @@ -157,7 +146,7 @@ class Sequential : public Cloneable { torch::detail::is_module::value, "Can only call Sequential::at with an nn::Module type"); AT_CHECK(index < size(), "Index out of range"); - return modules_[index]->get(); + return modules_[index].get(); } /// Attempts to return a `std::shared_ptr` whose dynamic type is that of the @@ -165,7 +154,7 @@ class Sequential : public Cloneable { /// out of bounds. std::shared_ptr ptr(size_t index) const { AT_CHECK(index < size(), "Index out of range"); - return modules_[index]->ptr(); + return modules_[index].ptr(); } /// Attempts to return a `std::shared_ptr` whose type is the one provided. @@ -177,7 +166,7 @@ class Sequential : public Cloneable { torch::detail::is_module::value, "Can only call Sequential::ptr with an nn::Module type"); AT_CHECK(index < size(), "Index out of range"); - return modules_[index]->ptr(); + return modules_[index].ptr(); } /// Like `ptr(index)`. @@ -209,13 +198,22 @@ class Sequential : public Cloneable { push_back(std::forward(second), std::forward(rest)...); } + /// Adds a type-erased `AnyModule` to the `Sequential`. + void push_back(AnyModule any_module) { + modules_.push_back(std::move(any_module)); + const auto index = modules_.size() - 1; + register_module(std::to_string(index), modules_[index].ptr()); + } + /// The base case, when the list of modules is empty. void push_back() {} // Box the AnyModules to give Sequential reference semantics, like the rest of // the API. Note that this is not required otherwise, this could just be a // `vector`. - std::vector> modules_; + std::vector modules_; }; + +TORCH_MODULE(Sequential); } // namespace nn } // namespace torch diff --git a/torch/csrc/api/include/torch/nn/pimpl.h b/torch/csrc/api/include/torch/nn/pimpl.h index c2b4cbb08ebec..e4b6aa76b5a98 100644 --- a/torch/csrc/api/include/torch/nn/pimpl.h +++ b/torch/csrc/api/include/torch/nn/pimpl.h @@ -19,8 +19,7 @@ template using is_module_holder = std::is_base_of>; template -using disable_if_module_holder_t = - disable_if_t>::value>; +using disable_if_module_holder_t = disable_if_t::value>; } // namespace detail namespace nn { @@ -30,27 +29,25 @@ namespace nn { /// the kind of constructions we want to allow for our modules. template class ModuleHolder : torch::detail::ModuleHolderIndicator { + protected: + /// The module pointer this class wraps. + /// NOTE: Must be placed at the top of the class so that we can use it with + /// trailing return types below. + std::shared_ptr impl_; + public: using ContainedType = Contained; - /// Constructs the `ModuleHolder` with an empty contained value. - ModuleHolder() = default; - - /// Single argument constructor of the underlying type. - /// Example: `Linear(4)` or `Linear(LinearOptions(4))`. - template - explicit ModuleHolder(T&& t) - : impl_(std::make_shared(std::forward(t))) {} - - /// Multi-argument constructor. This constructor is special in that the - /// expectation is that the constructor of the contained type takes an object - /// that can be constructed with the given arguments. For our modules, this is - /// always the `Options` struct. For this reason, the arguments are forwarded - /// inside braces, as to construct the constructor argument. - /// Example: `Linear(3, 4)`, equivalent to `Linear(LinearOptions(3, 4))`. - template - explicit ModuleHolder(T&& t, Ts&&... ts) - : impl_(new Contained({std::forward(t), std::forward(ts)...})) {} + /// Constructs the `ModuleHolder` with an empty contained value. Access to + /// the underlying module is not permitted and will throw an exception, until + /// a value is assigned. + explicit ModuleHolder(std::nullptr_t) : impl_(nullptr) {} + + /// Constructs the `ModuleHolder` with a contained module, forwarding all + /// arguments to its constructor. + template + explicit ModuleHolder(Ts&&... ts) + : impl_(new Contained(std::forward(ts)...)) {} /// Constructs the `ModuleHolder` from a pointer to the contained type. /// Example: `Linear(std::make_shared(...))`. @@ -65,20 +62,22 @@ class ModuleHolder : torch::detail::ModuleHolderIndicator { /// Forwards to the contained module. Contained* operator->() { - AT_CHECK(!is_empty(), "Accessing empty ModuleHolder"); - return impl_.get(); + return get(); } /// Forwards to the contained module. const Contained* operator->() const { - AT_CHECK(!is_empty(), "Accessing empty ModuleHolder"); - return impl_.get(); + return get(); } - /// Forwards to the call operator of the contained module. - template - Tensor operator()(Args&&... args) { - return (*impl_)(std::forward(args)...); + /// Returns a reference to the contained module. + Contained& operator*() { + return *get(); + } + + /// Returns a const reference to the contained module. + const Contained& operator*() const { + return *get(); } /// Returns a shared pointer to the underlying module. @@ -93,20 +92,29 @@ class ModuleHolder : torch::detail::ModuleHolderIndicator { return impl_.get(); } - /// Returns a pointer to the underlying module. + /// Returns a const pointer to the underlying module. const Contained* get() const { AT_CHECK(!is_empty(), "Accessing empty ModuleHolder"); return impl_.get(); } + /// Forwards to the call operator of the contained module. + template + auto operator()(Args&&... args) + -> decltype((*impl_)(std::forward(args)...)) { + return (*impl_)(std::forward(args)...); + } + + /// Forwards to the subscript operator of the contained module. + template + auto operator[](Arg&& arg) -> decltype((*impl_)[std::forward(arg)]) { + return (*impl_)[std::forward(arg)]; + } + /// Returns true if the `ModuleHolder` does not contain a module. bool is_empty() const noexcept { return impl_ == nullptr; } - - protected: - /// The module pointer this class wraps. - std::shared_ptr impl_; }; } // namespace nn } // namespace torch @@ -127,10 +135,15 @@ class ModuleHolder : torch::detail::ModuleHolderIndicator { /// Defines a class `Name` which inherits from `nn::ModuleHolder` to provide a /// wrapper over a `std::shared_ptr`. -#define TORCH_MODULE_IMPL(Name, Impl) \ - class Name : public torch::nn::ModuleHolder { \ - public: \ - using torch::nn::ModuleHolder::ModuleHolder; \ +#define TORCH_MODULE_IMPL(Name, Impl) \ + class Name : public torch::nn::ModuleHolder { \ + public: \ + using torch::nn::ModuleHolder::ModuleHolder; \ + Name(const Name&) = default; \ + Name(Name&&) = default; \ + Name(Name& other) : Name(static_cast(other)) {} \ + Name& operator=(const Name&) = default; \ + Name& operator=(Name&&) = default; \ } /// Like `TORCH_MODULE_IMPL`, but defaults the `Impl` name to `Impl`. diff --git a/torch/csrc/api/src/nn/modules/functional.cpp b/torch/csrc/api/src/nn/modules/functional.cpp index d4a4cc3728358..878a58f059770 100644 --- a/torch/csrc/api/src/nn/modules/functional.cpp +++ b/torch/csrc/api/src/nn/modules/functional.cpp @@ -10,9 +10,6 @@ namespace nn { FunctionalImpl::FunctionalImpl(std::function function) : function_(std::move(function)) {} -FunctionalImpl::FunctionalImpl(BoundFunction bound_function) - : function_(std::move(bound_function.function_)) {} - void FunctionalImpl::reset() {} Tensor FunctionalImpl::forward(Tensor input) { diff --git a/torch/csrc/api/src/nn/modules/rnn.cpp b/torch/csrc/api/src/nn/modules/rnn.cpp index 095e942e06c90..ae5688f5745d8 100644 --- a/torch/csrc/api/src/nn/modules/rnn.cpp +++ b/torch/csrc/api/src/nn/modules/rnn.cpp @@ -52,6 +52,7 @@ RNNImplBase::RNNImplBase( int64_t number_of_gates, bool has_cell_state) : options(options_), + dropout(nullptr), number_of_gates_(number_of_gates), has_cell_state_(has_cell_state), cudnn_mode_(cudnn_mode) { From 1a8e826ed4de0475acd06793fbf34ef88325dadf Mon Sep 17 00:00:00 2001 From: Lu Fang Date: Wed, 11 Jul 2018 17:25:45 -0700 Subject: [PATCH 30/36] Skip the count_include_pad in average pool for now (#9365) Summary: Will create a bootcamp task. Pull Request resolved: https://github.com/pytorch/pytorch/pull/9365 Reviewed By: bddppq Differential Revision: D8813889 Pulled By: houseroad fbshipit-source-id: bce1eaafd0efb3c27c0f71fcc40a8313e2b1c7b8 --- caffe2/python/onnx/tests/onnx_backend_test.py | 1 + 1 file changed, 1 insertion(+) diff --git a/caffe2/python/onnx/tests/onnx_backend_test.py b/caffe2/python/onnx/tests/onnx_backend_test.py index 24d6bc83878de..e1604cc8a36d0 100644 --- a/caffe2/python/onnx/tests/onnx_backend_test.py +++ b/caffe2/python/onnx/tests/onnx_backend_test.py @@ -35,6 +35,7 @@ '|test_operator_repeat.*' # Tile is not compliant with ONNX yet '|test_.*pool_.*same.*' # Does not support pool same. '|test_convtranspose.*' # ConvTranspose needs some more complicated translation + '|test_averagepool.*count_include_pad.*' # Waiting for the support in Caffe2 onnx backend. ')') # Quick patch to unbreak master CI, is working on the debugging. From e30ff68410e57840ef0533385ebb04fc52125f9c Mon Sep 17 00:00:00 2001 From: Akshay Chalana Date: Wed, 11 Jul 2018 17:27:26 -0700 Subject: [PATCH 31/36] Add Hardtanh Export (#8804) Summary: Added hartanh CPU/GPU Implementations and backend tests to Caffe2 Pull Request resolved: https://github.com/pytorch/pytorch/pull/8804 Reviewed By: bddppq Differential Revision: D8813987 Pulled By: houseroad fbshipit-source-id: 2480296eab3373425b9e1734a10c009b4f5d3e26 --- caffe2/python/operator_test/clip_op_test.py | 21 ++++++- .../expect/TestOperators.test_hardtanh.expect | 56 +++++++++++++++++++ test/onnx/test_operators.py | 4 ++ torch/onnx/symbolic.py | 4 ++ 4 files changed, 83 insertions(+), 2 deletions(-) create mode 100644 test/onnx/expect/TestOperators.test_hardtanh.expect diff --git a/caffe2/python/operator_test/clip_op_test.py b/caffe2/python/operator_test/clip_op_test.py index 1b62132007d50..38499a69eb1d9 100644 --- a/caffe2/python/operator_test/clip_op_test.py +++ b/caffe2/python/operator_test/clip_op_test.py @@ -14,8 +14,8 @@ class TestClip(hu.HypothesisTestCase): @given(X=hu.tensor(), - min_=st.floats(min_value=-1, max_value=0), - max_=st.floats(min_value=0, max_value=1), + min_=st.floats(min_value=-2, max_value=0), + max_=st.floats(min_value=0, max_value=2), inplace=st.booleans(), **hu.gcs) def test_clip(self, X, min_, max_, inplace, gc, dc): @@ -39,6 +39,23 @@ def clip_ref(X): # Gradient check wrt X self.assertGradientChecks(gc, op, [X], 0, [0]) + @given(X=hu.tensor(), + inplace=st.booleans(), + **hu.gcs) + def test_clip_default(self, X, inplace, gc, dc): + # go away from the origin point to avoid kink problems + X += 0.04 * np.sign(X) + + def clip_ref(X): + return (X,) + + op = core.CreateOperator( + "Clip", + ["X"], ["Y" if not inplace else "X"]) + self.assertReferenceChecks(gc, op, [X], clip_ref) + # Check over multiple devices + self.assertDeviceChecks(dc, op, [X], [0]) + if __name__ == "__main__": import unittest diff --git a/test/onnx/expect/TestOperators.test_hardtanh.expect b/test/onnx/expect/TestOperators.test_hardtanh.expect new file mode 100644 index 0000000000000..97958cc9f48ae --- /dev/null +++ b/test/onnx/expect/TestOperators.test_hardtanh.expect @@ -0,0 +1,56 @@ +ir_version: 3 +producer_name: "pytorch" +producer_version: "0.3" +graph { + node { + input: "0" + output: "1" + op_type: "Clip" + attribute { + name: "max" + f: 0.5 + type: FLOAT + } + attribute { + name: "min" + f: -0.5 + type: FLOAT + } + } + name: "torch-jit-export" + input { + name: "0" + type { + tensor_type { + elem_type: FLOAT + shape { + dim { + dim_value: 3 + } + dim { + dim_value: 4 + } + } + } + } + } + output { + name: "1" + type { + tensor_type { + elem_type: FLOAT + shape { + dim { + dim_value: 3 + } + dim { + dim_value: 4 + } + } + } + } + } +} +opset_import { + version: 6 +} diff --git a/test/onnx/test_operators.py b/test/onnx/test_operators.py index 875c17bc724c7..902705d1b01ea 100644 --- a/test/onnx/test_operators.py +++ b/test/onnx/test_operators.py @@ -265,6 +265,10 @@ def test_clip_max(self): x = Variable(torch.randn(1, 2, 3, 4), requires_grad=True) self.assertONNX(lambda x: x.clamp(max=0.1), x) + def test_hardtanh(self): + x = Variable(torch.randn(3, 4), requires_grad=True) + self.assertONNX(lambda x: torch.nn.Hardtanh(-0.5, 0.5)(x), x) + def test_max(self): x = Variable(torch.randn(3, 4), requires_grad=True) y = Variable(torch.randn(3, 4), requires_grad=True) diff --git a/torch/onnx/symbolic.py b/torch/onnx/symbolic.py index f164d80fd945d..c03707519ea25 100644 --- a/torch/onnx/symbolic.py +++ b/torch/onnx/symbolic.py @@ -741,6 +741,10 @@ def slice(g, self, dim, start, end, step): return g.op("Slice", self, axes_i=[dim], starts_i=[start], ends_i=[end]) +def hardtanh(g, self, min_val, max_val): + return g.op("Clip", self, min_f=min_val, max_f=max_val) + + def alias(g, self): return self From a487b08c2e9170e79b88fa9b0933ddae15dfba04 Mon Sep 17 00:00:00 2001 From: Chunli Fu Date: Wed, 11 Jul 2018 18:12:25 -0700 Subject: [PATCH 32/36] AutoBatching - IR transformation(basic operators) (#9198) Summary: Use decorator `torch.jit.batch` to implement auto-batching (call `to_batch` pass to do IR tranformation). - `to_batch` pass: "to_batch.h/cpp" in csrc/jit/passess to transform a graph to a new batched graph. - Write several basic operators for BatchTensor (add, mul, sigmoid, tanh, mm, matmul, select). - Register the operators in a lookup table `>`. (use the Graph to replace the original node in IR graph) Move BatchTensor in python from torch.BatchTensor to torch.jit.BatchTensor Pull Request resolved: https://github.com/pytorch/pytorch/pull/9198 Reviewed By: zdevito Differential Revision: D8744466 Pulled By: ChunliF fbshipit-source-id: 9ea56a30f55cb870f13a2069a47cc635419763ff --- setup.py | 1 + test/test_jit.py | 161 ++++++++++++++++++++++++- torch/csrc/jit/batched/BatchTensor.cpp | 16 ++- torch/csrc/jit/batched/BatchTensor.h | 2 + torch/csrc/jit/init.cpp | 2 + torch/csrc/jit/passes/to_batch.cpp | 73 +++++++++++ torch/csrc/jit/passes/to_batch.h | 19 +++ torch/csrc/jit/script/init.cpp | 1 + torch/jit/__init__.py | 27 +++++ torch/jit/batchop.py | 111 +++++++++++++++++ 10 files changed, 409 insertions(+), 4 deletions(-) create mode 100644 torch/csrc/jit/passes/to_batch.cpp create mode 100644 torch/csrc/jit/passes/to_batch.h create mode 100644 torch/jit/batchop.py diff --git a/setup.py b/setup.py index 25bbc1c7f0f8e..85f2f5bca6396 100644 --- a/setup.py +++ b/setup.py @@ -788,6 +788,7 @@ def run(self): "torch/csrc/jit/passes/specialize_undef.cpp", "torch/csrc/jit/passes/erase_number_types.cpp", "torch/csrc/jit/passes/loop_unrolling.cpp", + "torch/csrc/jit/passes/to_batch.cpp", "torch/csrc/jit/passes/onnx/peephole.cpp", "torch/csrc/jit/passes/onnx/fixup_onnx_loop.cpp", "torch/csrc/jit/generated/register_aten_ops.cpp", diff --git a/test/test_jit.py b/test/test_jit.py index c13f2d6e80b5a..f187c944d1043 100644 --- a/test/test_jit.py +++ b/test/test_jit.py @@ -27,6 +27,8 @@ import random from torch.jit.frontend import NotSupportedError +from torch.jit import BatchTensor +import torch.jit.batchop try: import torchvision @@ -1063,18 +1065,171 @@ class TestBatched(TestCase): def rand_batch(self, *dims): dims = [dim for dim in dims if dim != ()] xs = [torch.rand(1, *(random.randint(1, size) if b else size for b, size in dims[1:])) for i in range(dims[0])] - xb = torch.BatchTensor(xs, torch.tensor([b for b, d in dims[1:]])) + xb = BatchTensor(xs, torch.tensor([b for b, d in dims[1:]])) return xs, xb def test_create_batchtensor(self): + # create from tensorlist xs, batch = self.rand_batch(4, (True, 3), (False, 2), (True, 5)) self.assertEqual(xs, batch.examples()) - batch2 = torch.BatchTensor(batch.get_data(), batch.get_mask(), batch.get_dims()) + # create from data, mask, dims + batch2 = BatchTensor(batch.get_data(), batch.get_mask(), batch.get_dims()) self.assertEqual(xs, batch2.examples()) + # expand a tensor to a batchtensor given batch_size + xs = torch.rand(3, 4, 5) + batch3 = BatchTensor(xs, 2) + xs = xs.unsqueeze(0) + self.assertEqual([xs, xs], batch3.examples()) + + def test_batch_elementwise_unary(self): + @torch.jit.batch(batch_size=4) + def tanh(a): + return torch.tanh(a) + + xs, batch = self.rand_batch(4, (True, 3), (False, 2)) + res_batch = tanh(batch) + res = [torch.tanh(xs[j]) for j in range(4)] + self.assertEqual(res, res_batch.examples()) + + def test_batch_elementwise_binary(self): + @torch.jit.batch(batch_size=4) + def add(a, b): + return a + b + xs, batch = self.rand_batch(4, (True, 3), (False, 2)) + xs2, batch2 = xs, batch + res_batch = add(batch, batch2) + res = [torch.add(xs[j], xs2[j]) for j in range(4)] + self.assertEqual(res, res_batch.examples()) + + # test broadcast + xs, batch = self.rand_batch(4, (False, 3), (False, 2)) + b = torch.rand(3, 2) + res_batch = add(batch, b) + res = [torch.add(xs[j], b) for j in range(4)] + self.assertEqual(res, res_batch.examples()) + + def test_batch_mm(self): + @torch.jit.batch(batch_size=4) + def mm(a, b): + return torch.mm(a, b) + + xs, batch = self.rand_batch(4, (True, 3), (False, 2)) + xs2, batch2 = self.rand_batch(4, (False, 2), (True, 3)) + res_batch = mm(batch, batch2) + res = [torch.mm(xs[j].squeeze(0), xs2[j].squeeze(0)).unsqueeze(0) for j in range(4)] + self.assertEqual(res, res_batch.examples()) + + # test broadcast + b = torch.rand(2, 4) + res_batch = mm(batch, b) + res = [torch.mm(xs[j].squeeze(0), b).unsqueeze(0) for j in range(4)] + self.assertEqual(res, res_batch.examples()) + + def test_batch_matmul(self): + @torch.jit.batch(batch_size=4) + def matmul(a, b): + return torch.matmul(a, b) + + def matmul_test(xs, batch, xs2, batch2): + ys = [torch.matmul(xs[j].squeeze(0), xs2[j].squeeze(0)).unsqueeze(0) for j in range(4)] + ybs = matmul(batch, batch2) + self.assertEqual(ys, ybs.examples()) + + # 1 dimension * 1 dimension + xs, batch = self.rand_batch(4, (False, 2)) + xs2, batch2 = self.rand_batch(4, (False, 2)) + matmul_test(xs, batch, xs2, batch2) + # 1 dimension * 2 dimension + xs, batch = self.rand_batch(4, (False, 2)) + xs2, batch2 = self.rand_batch(4, (False, 2), (True, 3)) + matmul_test(xs, batch, xs2, batch2) + # 2 dimension * 1 dimensions + xs, batch = self.rand_batch(4, (True, 3), (False, 2)) + xs2, batch2 = self.rand_batch(4, (False, 2)) + matmul_test(xs, batch, xs2, batch2) + # 2 dimension * 2 dimension + xs, batch = self.rand_batch(4, (True, 3), (False, 2)) + xs2, batch2 = self.rand_batch(4, (False, 2), (True, 3)) + matmul_test(xs, batch, xs2, batch2) + + def test_batch_where(self): + @torch.jit.batch(batch_size=4) + def where(c, a, b): + return torch.where(c, a, b) + + xs, batch = self.rand_batch(4, (False, 3), (False, 2)) + xs2, batch2 = self.rand_batch(4, (False, 3), (False, 2)) + + dims = [4, (False, 3), (False, 2)] + xs_cond = [torch.rand(1, 3, 2).byte() for i in range(dims[0])] + batch_cond = BatchTensor(xs_cond, torch.tensor([b for b, d in dims[1:]])) + + res_batch = where(batch_cond, batch, batch2) + res = [torch.where(xs_cond[j], xs[j], xs2[j]) for j in range(4)] + self.assertEqual(res, res_batch.examples()) + + def test_lstm_cell(self): + def LSTMCell(x, h, c, w_xi, w_xf, w_xo, w_xc, w_hi, w_hf, w_ho, w_hc, b_i, b_f, b_o, b_c): + i_t = torch.matmul(x, w_xi) + torch.matmul(h, w_hi) + b_i + f_t = torch.matmul(x, w_xf) + torch.matmul(h, w_hf) + b_f + o_t = torch.matmul(x, w_xo) + torch.matmul(h, w_ho) + b_o + # activations + i_t = torch.sigmoid(i_t) + f_t = torch.sigmoid(f_t) + o_t = torch.sigmoid(o_t) + # cell computations + c_t = torch.matmul(x, w_xc) + torch.matmul(h, w_hc) + b_c + c_t = torch.tanh(c_t) + c_t = torch.mul(c, f_t) + torch.mul(i_t, c_t) + h_t = torch.mul(o_t, torch.tanh(c_t)) + return h_t + + @torch.jit.batch(batch_size=4) + def LSTMCell_batch(x, h, c, w_xi, w_xf, w_xo, w_xc, w_hi, w_hf, w_ho, w_hc, b_i, b_f, b_o, b_c): + i_t = torch.matmul(x, w_xi) + torch.matmul(h, w_hi) + b_i + f_t = torch.matmul(x, w_xf) + torch.matmul(h, w_hf) + b_f + o_t = torch.matmul(x, w_xo) + torch.matmul(h, w_ho) + b_o + # activations + i_t = torch.sigmoid(i_t) + f_t = torch.sigmoid(f_t) + o_t = torch.sigmoid(o_t) + # cell computations + c_t = torch.matmul(x, w_xc) + torch.matmul(h, w_hc) + b_c + c_t = torch.tanh(c_t) + c_t = torch.mul(c, f_t) + torch.mul(i_t, c_t) + h_t = torch.mul(o_t, torch.tanh(c_t)) + return h_t + + batch_size, input_size, hidden_size = 4, 3, 2 + xs, batch = self.rand_batch(batch_size, (False, input_size)) + hx, h_batch = self.rand_batch(batch_size, (False, hidden_size)) + cx, c_batch = self.rand_batch(batch_size, (False, hidden_size)) + + # input to hidden weights + w_xi = torch.rand(input_size, hidden_size) + w_xf = torch.rand(input_size, hidden_size) + w_xo = torch.rand(input_size, hidden_size) + w_xc = torch.rand(input_size, hidden_size) + # hidden to hidden weights + w_hi = torch.rand(hidden_size, hidden_size) + w_hf = torch.rand(hidden_size, hidden_size) + w_ho = torch.rand(hidden_size, hidden_size) + w_hc = torch.rand(hidden_size, hidden_size) + # bias terms + b_i = torch.rand(hidden_size) + b_f = torch.rand(hidden_size) + b_o = torch.rand(hidden_size) + b_c = torch.rand(hidden_size) + + ys = [LSTMCell(xs[j].squeeze(0), hx[j], cx[j], w_xi, w_xf, w_xo, w_xc, + w_hi, w_hf, w_ho, w_hc, b_i, b_f, b_o, b_c) for j in range(batch_size)] + ybs = LSTMCell_batch(batch, h_batch, c_batch, w_xi, w_xf, w_xo, w_xc, + w_hi, w_hf, w_ho, w_hc, b_i, b_f, b_o, b_c) + self.assertEqual(ys, ybs.examples()) -class TestScript(JitTestCase): +class TestScript(JitTestCase): @contextmanager def capture_stdout(self): # No idea how to capture stdout from C++ on Windows diff --git a/torch/csrc/jit/batched/BatchTensor.cpp b/torch/csrc/jit/batched/BatchTensor.cpp index a7e4ca8f00807..a843280912437 100644 --- a/torch/csrc/jit/batched/BatchTensor.cpp +++ b/torch/csrc/jit/batched/BatchTensor.cpp @@ -13,6 +13,18 @@ BatchTensor::BatchTensor(at::Tensor data, at::Tensor mask, at::Tensor dims){ this->dims = dims; } +BatchTensor::BatchTensor(at::Tensor data, int64_t batch_size){ + dims = data.type().toScalarType(at::kByte).tensor(data.dim()); + dims.fill_(0); + std::vector sizes(data.dim() + 1, -1); + sizes[0] = batch_size; + this->data = data.unsqueeze(0).expand(sizes); + std::vector mask_sizes(data.dim() + 1, 1); + mask_sizes[0] = batch_size; + mask = data.type().toScalarType(at::kByte).tensor(mask_sizes); + mask.fill_(1); +} + BatchTensor::BatchTensor(const std::vector datalist, at::Tensor dims) { auto bs = datalist.size(); std::vector sizes(dims.size(0) + 1, 0), mask_sizes(dims.size(0) + 1, 0); @@ -66,8 +78,10 @@ std::vector BatchTensor::examples() { void initBatchTensorBindings(PyObject* module) { auto m = py::handle(module).cast(); - py::class_(m, "BatchTensor") + auto jit = m.def_submodule("_jit"); + py::class_(jit, "BatchTensor") .def(py::init()) + .def(py::init()) .def(py::init, at::Tensor>()) .def("examples", &BatchTensor::examples) .def("get_data", &BatchTensor::get_data) diff --git a/torch/csrc/jit/batched/BatchTensor.h b/torch/csrc/jit/batched/BatchTensor.h index 61d7481c47ed3..dd624c354d792 100644 --- a/torch/csrc/jit/batched/BatchTensor.h +++ b/torch/csrc/jit/batched/BatchTensor.h @@ -9,6 +9,8 @@ namespace torch { namespace jit { struct BatchTensor { public: BatchTensor(at::Tensor data, at::Tensor mask, at::Tensor dims); + // expand a tensor to a batchtensor given batch_size + BatchTensor(at::Tensor data, int64_t batch_size); BatchTensor(const std::vector datalist, at::Tensor dims); ~BatchTensor(){}; const char * toString() const { diff --git a/torch/csrc/jit/init.cpp b/torch/csrc/jit/init.cpp index 4787546e7e86f..e1b9ac512cdb7 100644 --- a/torch/csrc/jit/init.cpp +++ b/torch/csrc/jit/init.cpp @@ -18,6 +18,7 @@ #include "torch/csrc/jit/passes/shape_analysis.h" #include "torch/csrc/jit/passes/decompose_addmm.h" #include "torch/csrc/jit/passes/loop_unrolling.h" +#include "torch/csrc/jit/passes/to_batch.h" #include "torch/csrc/jit/passes/specialize_undef.h" #include "torch/csrc/jit/graph_executor.h" #include "torch/csrc/jit/script/init.h" @@ -205,6 +206,7 @@ void initJITBindings(PyObject *module) { script::initTreeViewBindings(module); script::initJitScriptBindings(module); initBatchTensorBindings(module); + initRegisterBatchOpsBindings(module); } }} diff --git a/torch/csrc/jit/passes/to_batch.cpp b/torch/csrc/jit/passes/to_batch.cpp new file mode 100644 index 0000000000000..5494cf2b78a79 --- /dev/null +++ b/torch/csrc/jit/passes/to_batch.cpp @@ -0,0 +1,73 @@ +#include "torch/csrc/jit/passes/to_batch.h" +#include "torch/csrc/jit/script/compiler.h" + +namespace torch { namespace jit { + +std::unordered_map> ToBatch::batch_operator_table; + +void ToBatch::toBatch(Block* block, Block* res_block) { + // change inputs of a graph - expand tensor to {data, mask, dims} + auto size = block->inputs().size(); + for(size_t i = 0; i < size; i++){ + auto input = block->inputs()[i]; + auto name = input->uniqueName(); + res_block->addInput(name + "_data"); + res_block->addInput(name + "_mask"); + res_block->addInput(name + "_dims"); + batch_map[input] = std::vector(res_block->inputs().slice(i * 3, 3)); + } + + for (auto it = block->nodes().begin(); it != block->nodes().end(); it++) { + auto n = *it; + // replace tensor operator to BatchTensor operator + if(n->kind().is_aten()){ + auto batch_graph = batch_operator_table.at(n->kind().toUnqualString()); + WithInsertPoint guard(res_block); + std::vector new_inputs; + for(Value *input : n->inputs()){ + if(batch_map.find(input) != batch_map.end()){ + auto new_input = batch_map.at(input); + new_inputs.insert(new_inputs.end(), new_input.begin(), new_input.end()); + } + else{ + throw std::runtime_error("NYI: non-tensor input for aten operator is not supported yet"); + } + } + auto outputs = script::inlineCallTo(*res_block->owningGraph(), *batch_graph, new_inputs); + // Assume all outputs from inlined operator implementation are in the triple form. + for(size_t i = 0; i < n->outputs().size(); i++){ + auto output = n->outputs()[i]; + batch_map[output] = std::vector(outputs.begin() + i * 3, outputs.begin() + i * 3 + 3); + } + } + else if(n->kind().is_prim()){ + throw std::runtime_error("NYI: node of prim kind is not supported to transform to batch graph yet"); + } + } + // change outputs of a graph - expand tensor to {data, mask, dims} + for(Value* output : block->outputs()){ + auto r_output = batch_map.at(output); + res_block->registerOutput(r_output[0]); + res_block->registerOutput(r_output[1]); + res_block->registerOutput(r_output[2]); + } +} + +std::shared_ptr to_batch_graph(std::shared_ptr& graph){ + // std::cout<toString()<(graph->scope_root()); + ToBatch to_batch; + to_batch.toBatch(graph->block(), res_graph->block()); + // std::cout<toString()<(); + m.def("to_batch_graph", &to_batch_graph); + m.def("register_batch_operator", [](std::string name, std::shared_ptr graph){ + ToBatch::batch_operator_table[name] = graph; + }); +} + +}} // namespace torch.jit diff --git a/torch/csrc/jit/passes/to_batch.h b/torch/csrc/jit/passes/to_batch.h new file mode 100644 index 0000000000000..1d3113cd8cddc --- /dev/null +++ b/torch/csrc/jit/passes/to_batch.h @@ -0,0 +1,19 @@ +#pragma once + +#include "torch/csrc/jit/pybind.h" +#include "torch/csrc/jit/ir.h" + +namespace torch { namespace jit { + +class ToBatch { +private: + // mapping from tensor in original graph to {data, mask, dims} in new graph + std::unordered_map> batch_map; +public: + static std::unordered_map> batch_operator_table; + void toBatch(Block* block, Block* res_block); +}; + +std::shared_ptr to_batch_graph(std::shared_ptr& graph); +void initRegisterBatchOpsBindings(PyObject* module); +}} diff --git a/torch/csrc/jit/script/init.cpp b/torch/csrc/jit/script/init.cpp index a481eb601f8af..2bb72c4a18b7a 100644 --- a/torch/csrc/jit/script/init.cpp +++ b/torch/csrc/jit/script/init.cpp @@ -7,6 +7,7 @@ #include "torch/csrc/jit/tensor_conversions.h" #include "torch/csrc/jit/python_tracer.h" #include "torch/csrc/jit/pybind_utils.h" +#include "torch/csrc/jit/passes/to_batch.h" #include diff --git a/torch/jit/__init__.py b/torch/jit/__init__.py index edab86fb61114..a7d45a7720a41 100644 --- a/torch/jit/__init__.py +++ b/torch/jit/__init__.py @@ -22,6 +22,7 @@ _flatten = torch._C._jit_flatten _unflatten = torch._C._jit_unflatten _jit_script_compile = torch._C._jit_script_compile +BatchTensor = torch._C._jit.BatchTensor # This global variable is set when we are tracing a *forwards* computation. # It is intended to be a cheap way to test if tracing has occurred, before @@ -387,6 +388,32 @@ def script_method(fn): return ScriptMethodStub(createResolutionCallback(frames_up=2), get_jit_ast(fn), fn) +def batch(batch_size=1, optimize=True, _frames_up=0): + def decorator(fn): + mod = script(fn, optimize, _frames_up) + res_graph = torch.to_batch_graph(mod.graph) + res_mod = ScriptModule() + res_mod._create_method_from_graph('forward', res_graph) + + def wrapper(*args): + new_args = [] + for arg in args: + if isinstance(arg, torch.Tensor): + arg = BatchTensor(arg, batch_size) + if isinstance(arg, BatchTensor): + new_args.extend([arg.get_data(), arg.get_mask(), arg.get_dims()]) + else: + new_args.append(arg) + res = res_mod(*new_args) + # assert len(res) / 3 == 0 + # result = [BatchTensor(*res[i * 3: i * 3 + 3]) for i in range(len(res) // 3)] + result = BatchTensor(*res) + return result + wrapper.__doc__ = fn.__doc__ + return wrapper + return decorator + + # These OrderedDictWrapper classes replace the actual OrderedDicts in # module with versions that get/set properties inside of script::Module. # This allows us to reuse most of nn.Module while still storing the diff --git a/torch/jit/batchop.py b/torch/jit/batchop.py new file mode 100644 index 0000000000000..cfad94a03e820 --- /dev/null +++ b/torch/jit/batchop.py @@ -0,0 +1,111 @@ +import torch + + +@torch.jit.script +def batch_tanh(data, mask, dims): + data = torch.tanh(data) + return data, mask, dims + + +@torch.jit.script +def batch_sigmoid(data, mask, dims): + data = torch.sigmoid(data) + return data, mask, dims + + +@torch.jit.script +def batch_add(data1, mask1, dims1, data2, mask2, dims2): + data = torch.add(data1, data2) + mask = mask1 * mask2 + dims = dims1 or dims2 + return data, mask, dims + + +@torch.jit.script +def batch_mul(data1, mask1, dims1, data2, mask2, dims2): + data = torch.mul(data1, data2) + mask = mask1 * mask2 + dims = dims1 or dims2 + return data, mask, dims + + +@torch.jit.script +def batch_mm(data1, mask1, dims1, data2, mask2, dims2): + data1 = data1 * mask1.type_as(data1) + data2 = data2 * mask2.type_as(data2) + data = torch.bmm(data1, data2) + mask = torch.bmm(mask1.narrow(2, 0, 1), mask2.narrow(1, 0, 1)) + dims = torch.cat((dims1[:1], dims2[1:dims2.size(0)])) + return data, mask, dims + + +@torch.jit.script +def batch_matmul(data1, mask1, dims1, data2, mask2, dims2): + d1 = data1.dim() - 1 + d2 = data2.dim() - 1 + data1 = data1 * mask1.type_as(data1) + data2 = data2 * mask2.type_as(data2) + if d1 == 1: + data1 = data1.unsqueeze(-2) + if d2 == 1: + data2 = data2.unsqueeze(-1) + data = torch.bmm(data1, data2) + mask = mask1 + dims = dims1 + if d1 == 1 and d2 == 1: + # if (batch1.dims[0] or batch2.dims[0]) and not batch1.mask.eq(batch2.mask).all(): + # raise ValueError("cannot contract non-matching dimensions") + data = data.squeeze(-1).squeeze(-1) + mask = mask1.narrow(1, 0, 1).squeeze(-1) + dims = dims1[:0] # empty tensor + if d1 == 2 and d2 == 1: + # if (batch1.dims[1] or batch2.dims[0]) and not batch1.mask[:, 0].eq(batch2.mask).all(): + # raise ValueError("cannot contract non-matching dimensions") + data = data.squeeze(-1) + mask = torch.bmm(mask1.narrow(2, 0, 1), mask2.narrow(1, 0, 1).unsqueeze(-1)).squeeze(-1) + dims = dims1[:1] + elif d1 == 1 and d2 == 2: + # if (batch1.dims[0] or batch2.dims[0]) and not batch1.mask.eq(batch2.mask[:, :, 0]).all(): + # raise ValueError("cannot contract non-matching dimensions") + data = data.squeeze(-2) + mask = torch.bmm(mask1.narrow(1, 0, 1).unsqueeze(-2), mask2.narrow(1, 0, 1)).squeeze(-2) + dims = dims2[1:dims2.size(0)] + elif d1 == 2 and d2 == 2: + # if (batch1.dims[1] or batch2.dims[0]) and not batch1.mask[:, 0].eq(batch2.mask[:, :, 0]).all(): + # raise ValueError("cannot contract non-matching dimensions") + mask = torch.bmm(mask1.narrow(2, 0, 1), mask2.narrow(1, 0, 1)) + dims = torch.cat((dims1[:1], dims2[1:dims2.size(0)])) + # else: + # raise NotImplementedError("matmul not implemented with batches of 3+D tensors") + return data, mask, dims + + +@torch.jit.script +def batch_select(data, mask, dims, dim, index): + # if dim == 0: + # raise ValueError("Cannot select 0 dim in BatchTensor") + data = data.select(dim, index) + if dims[dim - 1]: + mask = mask.select(dim, 0) + else: + mask = mask.select(dim, index) + dims = torch.cat((dims[:dim - 1], dims[dim:dims.size(0)])) + return data, mask, dims + + +# assume data, data1, data2 have same size +@torch.jit.script +def batch_where(data, mask, dims, data1, mask1, dims1, data2, mask2, dims2): + res_data = torch.where(data, data1, data2) + res_mask = torch.where(data, mask1, mask2) + res_dims = dims1 or dims2 + return res_data, res_mask, res_dims + +torch.register_batch_operator("tanh", batch_tanh.graph) +torch.register_batch_operator("sigmoid", batch_sigmoid.graph) +torch.register_batch_operator("add", batch_add.graph) +torch.register_batch_operator("mul", batch_mul.graph) +torch.register_batch_operator("matmul", batch_matmul.graph) +torch.register_batch_operator("mm", batch_mm.graph) +torch.register_batch_operator("select", batch_select.graph) +torch.register_batch_operator("where", batch_where.graph) From 7f38ea45555a27659e67a77bcc8d3b7c909ba7e8 Mon Sep 17 00:00:00 2001 From: Hassan Eslami Date: Wed, 11 Jul 2018 18:42:23 -0700 Subject: [PATCH 33/36] Remove unused feature: num PS tuning Summary: Pull Request resolved: https://github.com/pytorch/pytorch/pull/9293 Reviewed By: huitseeker Differential Revision: D8778499 fbshipit-source-id: 0cf59e02cb37b3fe22885c1b5e10b5d2e7585382 --- caffe2/core/plan_executor.cc | 10 +--------- caffe2/core/plan_executor.h | 10 ---------- caffe2/operators/stats_ops.cc | 34 ---------------------------------- 3 files changed, 1 insertion(+), 53 deletions(-) diff --git a/caffe2/core/plan_executor.cc b/caffe2/core/plan_executor.cc index 9bbe80525350b..fba9c9d56a1c8 100644 --- a/caffe2/core/plan_executor.cc +++ b/caffe2/core/plan_executor.cc @@ -512,15 +512,7 @@ bool RunPlanOnWorkspace( LOG(INFO) << "Step " << step.name() << " took " << step_timer.Seconds() << " seconds."; } - float exec_time = plan_timer.Seconds(); - -#ifndef CAFFE2_MOBILE - PlanExecutionTime plan_stat(plan.name()); - CAFFE_EVENT( - plan_stat, plan_execution_time_ns, (long)(exec_time * 1000000000)); -#endif // CAFFE2_MOBILE - - LOG(INFO) << "Total plan took " << exec_time << " seconds."; + LOG(INFO) << "Total plan took " << plan_timer.Seconds() << " seconds."; LOG(INFO) << "Plan executed successfully."; return true; } diff --git a/caffe2/core/plan_executor.h b/caffe2/core/plan_executor.h index 891e68cdd29ab..6b4992d8d0194 100644 --- a/caffe2/core/plan_executor.h +++ b/caffe2/core/plan_executor.h @@ -1,9 +1,6 @@ #pragma once #include -#ifndef CAFFE2_MOBILE -#include "caffe2/core/stats.h" -#endif // CAFFE2_MOBILE namespace caffe2 { @@ -13,11 +10,4 @@ class PlanDef; typedef std::function ShouldContinue; bool RunPlanOnWorkspace(Workspace* ws, const PlanDef& plan, ShouldContinue); - -#ifndef CAFFE2_MOBILE -struct PlanExecutionTime { - CAFFE_STAT_CTOR(PlanExecutionTime); - CAFFE_EXPORTED_STAT(plan_execution_time_ns); -}; -#endif // CAFFE2_MOBILE } diff --git a/caffe2/operators/stats_ops.cc b/caffe2/operators/stats_ops.cc index dab72bf855815..64a0c1a888800 100644 --- a/caffe2/operators/stats_ops.cc +++ b/caffe2/operators/stats_ops.cc @@ -173,28 +173,6 @@ struct TimerGetOp : public Operator { } }; -struct CpuUtilizationReportOp : public Operator { - CpuUtilizationReportOp(const OperatorDef& operator_def, Workspace* ws) - : Operator(operator_def, ws), - statsName_(GetSingleArgument("stats_name", "utilization")), - stat_([this]() { return statsName_; }()) {} - - bool RunOnDevice() override { - float utilization = Input(0).template data()[0]; - // Utilization is a float value, but CAFFE_EVENT only keeps int64_t values. - // We will keep 100x of the received utilization to maintain accuracy. - CAFFE_EVENT(stat_, cpu_utilization, (int)(utilization * 100)); - return true; - } - - private: - std::string statsName_; - struct CpuStats { - CAFFE_STAT_CTOR(CpuStats); - CAFFE_EXPORTED_STAT(cpu_utilization); - } stat_; -}; - REGISTER_CPU_OPERATOR(StatRegistryCreate, StatRegistryCreateOp); REGISTER_CPU_OPERATOR(StatRegistryUpdate, StatRegistryUpdateOp); REGISTER_CPU_OPERATOR(StatRegistryExport, StatRegistryExportOp); @@ -203,7 +181,6 @@ REGISTER_CPU_OPERATOR(TimerBegin, TimerBeginOp); REGISTER_CPU_OPERATOR(TimerEnd, TimerEndOp); REGISTER_CPU_OPERATOR(TimerGetAndEnd, TimerGetAndEndOp); REGISTER_CPU_OPERATOR(TimerGet, TimerGetOp); -REGISTER_CPU_OPERATOR(CpuUtilizationReport, CpuUtilizationReportOp); OPERATOR_SCHEMA(StatRegistryCreate) .NumInputs(0) @@ -359,17 +336,6 @@ Github Links: .Input(0, "timer", "(*Tensor``*): pointer to a timer object; obtained from **TimerBegin** op") .Output(0, "nanos", "(*Tensor``*): scalar containing time in nanoseconds"); -OPERATOR_SCHEMA(CpuUtilizationReport) - .NumInputs(1) - .NumOutputs(0) - .SetDoc(R"DOC(Report the delta in max CPU utilization observed so far in the - plan)DOC") - .Input( - 0, - "utilization", - "Delta in max CPU utilization observed, in percentage as a float value") - .Arg("stats_name", "String name of the stat entry holding CPU utilization"); - CAFFE_KNOWN_TYPE(TimerInstance*); CAFFE_KNOWN_TYPE(std::unique_ptr); } // namespace caffe2 From 00b4b4703e27b4f531db5e8a88fb2348c77b4ee4 Mon Sep 17 00:00:00 2001 From: Tongzhou Wang Date: Wed, 11 Jul 2018 21:15:34 -0700 Subject: [PATCH 34/36] fix unsqueeze doc (#9374) Summary: fixes #9348 Pull Request resolved: https://github.com/pytorch/pytorch/pull/9374 Differential Revision: D8817215 Pulled By: SsnL fbshipit-source-id: 047661ae4556bb19e4cd125b01a3fd75ed6642f3 --- torch/_torch_docs.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/torch/_torch_docs.py b/torch/_torch_docs.py index f93e2246ae888..f064318c03f38 100644 --- a/torch/_torch_docs.py +++ b/torch/_torch_docs.py @@ -4820,9 +4820,9 @@ def parse_kwargs(desc): The returned tensor shares the same underlying data with this tensor. -A negative `dim` value within the range -[-:attr:`input.dim()`, :attr:`input.dim()`) can be used and -will correspond to :meth:`unsqueeze` applied at :attr:`dim` = :attr:`dim + input.dim() + 1` +A :attr:`dim` value within the range ``[-input.dim() - 1, input.dim() + 1)`` +can be used. Negative :attr:`dim` will correspond to :meth:`unsqueeze` +applied at :attr:`dim` = ``dim + input.dim() + 1``. Args: input (Tensor): the input tensor From aeccec755de69ece191f4d8266c20df18d96005d Mon Sep 17 00:00:00 2001 From: Pieter Noordhuis Date: Wed, 11 Jul 2018 21:29:33 -0700 Subject: [PATCH 35/36] In Gloo backend use ring reduction by default (#9309) Summary: Pull Request resolved: https://github.com/pytorch/pytorch/pull/9309 This is faster when you're dealing with a small number of processes. Around the 16 processes mark the halving/doubling algorithm is faster. Reviewed By: apaszke Differential Revision: D8785364 fbshipit-source-id: 4a03326266e473026d943787186e149d0cc489f0 --- torch/lib/c10d/ProcessGroupGloo.cpp | 44 +++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/torch/lib/c10d/ProcessGroupGloo.cpp b/torch/lib/c10d/ProcessGroupGloo.cpp index 8ff0af867b629..e4d77b9afd738 100644 --- a/torch/lib/c10d/ProcessGroupGloo.cpp +++ b/torch/lib/c10d/ProcessGroupGloo.cpp @@ -1,8 +1,10 @@ #include "ProcessGroupGloo.hpp" #include +#include #include #include +#include #include #include #include @@ -320,22 +322,40 @@ void ProcessGroupGloo::createAllreduce(AlgorithmEntry& entry) { auto& context = contexts_[0]; if (backend == at::kCPU) { - entry.algorithm = std::unique_ptr<::gloo::Algorithm>( - new ::gloo::AllreduceHalvingDoubling( - context, - getDataPointers(entry.src), - entry.src[0].numel(), - reductionFunction(key.reduceOp))); + if (getSize() < 16) { + entry.algorithm = std::unique_ptr<::gloo::Algorithm>( + new ::gloo::AllreduceRingChunked( + context, + getDataPointers(entry.src), + entry.src[0].numel(), + reductionFunction(key.reduceOp))); + } else { + entry.algorithm = std::unique_ptr<::gloo::Algorithm>( + new ::gloo::AllreduceHalvingDoubling( + context, + getDataPointers(entry.src), + entry.src[0].numel(), + reductionFunction(key.reduceOp))); + } return; } if (backend == at::kCUDA) { - entry.algorithm = std::unique_ptr<::gloo::Algorithm>( - new ::gloo::CudaAllreduceHalvingDoubling( - context, - getDataPointers(entry.src), - entry.src[0].numel(), - getStreamVector(entry))); + if (getSize() < 16) { + entry.algorithm = std::unique_ptr<::gloo::Algorithm>( + new ::gloo::CudaAllreduceRingChunked( + context, + getDataPointers(entry.src), + entry.src[0].numel(), + getStreamVector(entry))); + } else { + entry.algorithm = std::unique_ptr<::gloo::Algorithm>( + new ::gloo::CudaAllreduceHalvingDoubling( + context, + getDataPointers(entry.src), + entry.src[0].numel(), + getStreamVector(entry))); + } return; } From e1863778e3931017df93840d99ac5749e842defa Mon Sep 17 00:00:00 2001 From: Adam Paszke Date: Wed, 11 Jul 2018 23:03:03 -0700 Subject: [PATCH 36/36] Guard gloo algorithm creation with DeviceGuard (#9371) Summary: Let us avoid creating a context on GPU0 unnecessarily. Pull Request resolved: https://github.com/pytorch/pytorch/pull/9371 Reviewed By: pietern Differential Revision: D8817343 Pulled By: apaszke fbshipit-source-id: a6cc91a1dd127840486a42c64f97f117475b0d5f --- torch/lib/c10d/ProcessGroupGloo.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/torch/lib/c10d/ProcessGroupGloo.cpp b/torch/lib/c10d/ProcessGroupGloo.cpp index e4d77b9afd738..c134f5ccb909f 100644 --- a/torch/lib/c10d/ProcessGroupGloo.cpp +++ b/torch/lib/c10d/ProcessGroupGloo.cpp @@ -320,6 +320,7 @@ void ProcessGroupGloo::createAllreduce(AlgorithmEntry& entry) { // Create algorithm against first context auto& context = contexts_[0]; + at::DeviceGuard guard(entry.src[0].device()); if (backend == at::kCPU) { if (getSize() < 16) { @@ -370,6 +371,7 @@ void ProcessGroupGloo::createBroadcast(AlgorithmEntry& entry) { // Create algorithm against first context auto& context = contexts_[0]; + at::DeviceGuard guard(entry.src[0].device()); if (backend == at::kCPU) { entry.algorithm =