From cf471f0c15b0c9c78c44a238fe60fe1e31289503 Mon Sep 17 00:00:00 2001 From: Trevor Morris Date: Thu, 3 Jan 2019 14:56:44 -0800 Subject: [PATCH] Add positive test cases for Conv2D. Reuse build_graph in conv2d_test. --- .../contrib/tensorrt/convert/convert_nodes.cc | 5 +- .../tensorrt/convert/convert_nodes_test.cc | 134 ++++++++++++++++++ .../contrib/tensorrt/test/conv2d_test.py | 106 ++++++-------- 3 files changed, 183 insertions(+), 62 deletions(-) diff --git a/tensorflow/contrib/tensorrt/convert/convert_nodes.cc b/tensorflow/contrib/tensorrt/convert/convert_nodes.cc index 34ba2aeaa47..179d631a3e6 100644 --- a/tensorflow/contrib/tensorrt/convert/convert_nodes.cc +++ b/tensorflow/contrib/tensorrt/convert/convert_nodes.cc @@ -62,14 +62,14 @@ limitations under the License. #define TFTRT_RETURN_ERROR_IF_FALSE(status, node) \ do { \ - if ((status) == false) { \ + if (status == false) { \ TFTRT_INTERNAL_ERROR_AT_NODE(node); \ } \ } while (0) #define TFTRT_RETURN_ERROR_IF_NULLPTR(ptr, node) \ do { \ - if ((ptr) == nullptr) { \ + if (ptr == nullptr) { \ TFTRT_INTERNAL_ERROR_AT_NODE(node); \ } \ } while (0) @@ -1593,6 +1593,7 @@ tensorflow::Status ConvertConv2DHelper(OpConverterParams* params, int group) { node_def.name()); } const nvinfer1::DimsHW dilation(tf_dilations[h_index], tf_dilations[w_index]); + const auto tf_stride = attrs.get>("strides"); if (tf_stride.size() != 4) { return tensorflow::errors::InvalidArgument( diff --git a/tensorflow/contrib/tensorrt/convert/convert_nodes_test.cc b/tensorflow/contrib/tensorrt/convert/convert_nodes_test.cc index cb73d2e07bd..1e49026a34f 100644 --- a/tensorflow/contrib/tensorrt/convert/convert_nodes_test.cc +++ b/tensorflow/contrib/tensorrt/convert/convert_nodes_test.cc @@ -2697,6 +2697,17 @@ TEST_F(OpConverterTest, ConvertConv2D) { "Dilation rate must be 1 for batch and channel " "dimensions, at my_conv2d"); } + { + // Dilation value is not 1 for channel (NHWC), should fail. + Reset(); + NodeDef node_def = + get_conv2d_nodedef({1, 1, 1, 1}, "SAME", "NHWC", {1, 1, 1, 2}); + AddTestTensor("input", {2, 3, 1}); + AddTestWeights("weights", {3, 3, 1, 1}, {1, 2, 3, 4, 5, 6, 7, 8, 9}); + RunValidationAndConversion(node_def, error::UNIMPLEMENTED, + "Dilation rate must be 1 for batch and channel " + "dimensions, at my_conv2d"); + } { // Strides is not 4D, should fail. Reset(); @@ -2719,6 +2730,129 @@ TEST_F(OpConverterTest, ConvertConv2D) { node_def, error::UNIMPLEMENTED, "Stride must be 1 for batch and channel dimensions, at my_conv2d"); } + + struct TestParams { + TestParams(const std::vector& input_dims, + const std::vector& input, + const std::vector& filter_dims, + const std::vector& filter, + const std::vector& strides, const string& padding, + const string& data_format, const std::vector& dilations, + const std::vector& expected_output_dims, + const std::vector& expected_output) + : input_dims(input_dims), + input(input), + filter_dims(filter_dims), + filter(filter), + strides(strides), + padding(padding), + data_format(data_format), + dilations(dilations), + expected_output_dims(expected_output_dims), + expected_output(expected_output) {} + + std::vector input_dims; + std::vector input; + std::vector filter_dims; + std::vector filter; + std::vector strides; + string padding; + string data_format; + std::vector dilations; + std::vector expected_output_dims; + std::vector expected_output; + }; + + // Ok. + const int kConv2DOKCases = 6; + TestParams ok_params[kConv2DOKCases] = { + // Basic + TestParams{/*input_dims=*/{1, 2, 3}, + /*input=*/{0, 1, 2, 3, 3, 4}, + /*filter_dims=*/{1, 2, 1, 1}, + /*filter=*/{-1, 1}, + /*strides=*/{1, 1, 1, 1}, + /*padding=*/"VALID", + /*data_format=*/"NCHW", + /*dilations=*/{1, 1, 1, 1}, + /*expected_output_dims=*/{1, 2, 2}, + /*expected_output=*/{1, 1, 0, 1}}, + // SAME padding (Asymmetric) + TestParams{/*input_dims=*/{1, 2, 3}, + /*input=*/{0, 1, 2, 3, 3, 4}, + /*filter_dims=*/{1, 2, 1, 1}, + /*filter=*/{-1, 1}, + /*strides=*/{1, 1, 1, 1}, + /*padding=*/"SAME", + /*data_format=*/"NCHW", + /*dilations=*/{1, 1, 1, 1}, + /*expected_output_dims=*/{1, 2, 3}, + /*expected_output=*/{1, 1, -2, 0, 1, -4}}, + // SAME padding (Symmetric) + TestParams{/*input_dims=*/{1, 2, 3}, + /*input=*/{0, 1, 2, 3, 3, 4}, + /*filter_dims=*/{1, 3, 1, 1}, + /*filter=*/{-1, 0, 1}, + /*strides=*/{1, 1, 1, 1}, + /*padding=*/"SAME", + /*data_format=*/"NCHW", + /*dilations=*/{1, 1, 1, 1}, + /*expected_output_dims=*/{1, 2, 3}, + /*expected_output=*/{1, 2, -1, 3, 1, -3}}, + // NHWC + TestParams{/*input_dims=*/{2, 3, 1}, + /*input=*/{0, 1, 2, 3, 3, 4}, + /*filter_dims=*/{1, 2, 1, 1}, + /*filter=*/{-1, 1}, + /*strides=*/{1, 1, 1, 1}, + /*padding=*/"VALID", + /*data_format=*/"NHWC", + /*dilations=*/{1, 1, 1, 1}, + /*expected_output_dims=*/{2, 2, 1}, + /*expected_output=*/{1, 1, 0, 1}}, + // Dilated + TestParams{/*input_dims=*/{1, 2, 3}, + /*input=*/{0, 1, 2, 3, 3, 4}, + /*filter_dims=*/{1, 2, 1, 1}, + /*filter=*/{-1, 1}, + /*strides=*/{1, 1, 1, 1}, + /*padding=*/"VALID", + /*data_format=*/"NCHW", + /*dilations=*/{1, 1, 1, 2}, + /*expected_output_dims=*/{1, 2, 1}, + /*expected_output=*/{2, 1}}, + // Strided + TestParams{/*input_dims=*/{1, 2, 4}, + /*input=*/{0, 1, 2, 2, 3, 4, 4, 7}, + /*filter_dims=*/{1, 2, 1, 1}, + /*filter=*/{-1, 1}, + /*strides=*/{1, 1, 1, 2}, + /*padding=*/"VALID", + /*data_format=*/"NCHW", + /*dilations=*/{1, 1, 1, 1}, + /*expected_output_dims=*/{1, 2, 2}, + /*expected_output=*/{1, 0, 1, 3}}, + }; + + for (int i = 0; i < kConv2DOKCases; i++) { + Reset(); + NodeDef node_def = + get_conv2d_nodedef(ok_params[i].strides, ok_params[i].padding, + ok_params[i].data_format, ok_params[i].dilations); + AddTestTensor("input", ok_params[i].input_dims); + AddTestWeights("weights", ok_params[i].filter_dims, + ok_params[i].filter); + RunValidationAndConversion(node_def); + TRT_TensorOrWeights output; + TF_EXPECT_OK(GetTensorOrWeights("my_conv2d", &output)); + EXPECT_TRUE(output.is_tensor()); + ExpectTrtDimsEqualsArray(ok_params[i].expected_output_dims, + output.tensor()->getDimensions()); + std::vector output_data(ok_params[i].expected_output.size()); + BuildAndRun({{"input", ok_params[i].input}}, "my_conv2d", + &output_data); + EXPECT_THAT(output_data, ElementsAreArray(ok_params[i].expected_output)); + } } } // namespace convert diff --git a/tensorflow/contrib/tensorrt/test/conv2d_test.py b/tensorflow/contrib/tensorrt/test/conv2d_test.py index f7d9ca68269..68b65348237 100644 --- a/tensorflow/contrib/tensorrt/test/conv2d_test.py +++ b/tensorflow/contrib/tensorrt/test/conv2d_test.py @@ -51,37 +51,60 @@ def conv2d_layer(inputs, filters, kernel_size, strides=(1, 1), padding='valid', def div_round_up(n, d): return (n - 1) // d + 1 +def build_graph(input_dims, dtype, num_filters, data_format, kernel_sizes, + dilation_rates, padding='same'): + g = ops.Graph() + with g.as_default(): + inp = array_ops.placeholder( + dtype=dtype, shape=[None] + input_dims[1:], name="input") + with g.device("/GPU:0"): + results = [] + for kernel_size in kernel_sizes: + for dilation_rate in dilation_rates: + result = conv2d_layer(inp, num_filters, kernel_size, (1, 1), + padding, data_format, dilation_rate) + results.append(result) + output = sum(results) + output = array_ops.identity(output, name="output") + return g + + class Conv2DNCHWTest(trt_test.TfTrtIntegrationTestBase): def GetParams(self): """Testing conversion of Conv2D (data_format=NCHW) in TF-TRT conversion.""" np.random.seed(1234) - dtype = dtypes.float32 - input_name = "input" - n, c, h, w = 13, 3, 7, 11 - num_filters = 5 - input_dims = [n, c, h, w] - output_name = "output" - g = ops.Graph() - with g.as_default(): - inp = array_ops.placeholder( - dtype=dtype, shape=[None] + input_dims[1:], name=input_name) - with g.device("/GPU:0"): - results = [] - for kernel_size in [(3, 3), (3, 2)]: - for dilation_rate in [(1, 1), (2, 3)]: - result = conv2d_layer(inp, num_filters, kernel_size, - dilation_rate=dilation_rate, padding='same', - data_format='channels_first') - results.append(result) - output = sum(results) - output = array_ops.identity(output, name=output_name) + input_dims = [13, 3, 7, 11] + g = build_graph(input_dims=input_dims, dtype=dtypes.float32, num_filters=5, + data_format="channels_first", kernel_sizes=[(3, 3), (3, 2)], + dilation_rates=[(1, 1), (2, 3)]) return trt_test.TfTrtIntegrationTestParams( gdef=g.as_graph_def(), - input_names=[input_name], + input_names=["input"], input_dims=[input_dims], - output_names=[output_name], - expected_output_dims=[(n, num_filters, h, w)]) + output_names=["output"], + expected_output_dims=[(13, 5, 7, 11)]) + + def ExpectedEnginesToBuild(self, run_params): + """Return the expected engines to build.""" + return ["TRTEngineOp_0"] + + +class Conv2DNHWCTest(trt_test.TfTrtIntegrationTestBase): + + def GetParams(self): + """Testing conversion of Conv2D (data_format=NCHW) in TF-TRT conversion.""" + np.random.seed(1234) + input_dims = [13, 7, 11, 3] + g = build_graph(input_dims=input_dims, dtype=dtypes.float32, num_filters=5, + data_format="channels_last", kernel_sizes=[(3, 3), (3, 2)], + dilation_rates=[(1, 1), (2, 3)]) + return trt_test.TfTrtIntegrationTestParams( + gdef=g.as_graph_def(), + input_names=["input"], + input_dims=[input_dims], + output_names=["output"], + expected_output_dims=[(13, 7, 11, 5)]) def ExpectedEnginesToBuild(self, run_params): """Return the expected engines to build.""" @@ -128,42 +151,5 @@ class Conv2DStridedNCHWTest(trt_test.TfTrtIntegrationTestBase): return ["TRTEngineOp_0"] -class Conv2DNHWCTest(trt_test.TfTrtIntegrationTestBase): - - def GetParams(self): - """Testing conversion of Conv2D (data_format=NHWC) in TF-TRT conversion.""" - np.random.seed(1234) - dtype = dtypes.float32 - input_name = "input" - n, h, w, c = 13, 7, 11, 3 - num_filters = 5 - input_dims = [n, h, w, c] - output_name = "output" - g = ops.Graph() - with g.as_default(): - inp = array_ops.placeholder( - dtype=dtype, shape=[None] + input_dims[1:], name=input_name) - with g.device("/GPU:0"): - results = [] - for kernel_size in [(3, 3), (3, 2)]: - for dilation_rate in [(1, 1), (2, 3)]: - result = conv2d_layer(inp, num_filters, kernel_size, - dilation_rate=dilation_rate, padding='same', - data_format='channels_last') - results.append(result) - output = sum(results) - output = array_ops.identity(output, name=output_name) - return trt_test.TfTrtIntegrationTestParams( - gdef=g.as_graph_def(), - input_names=[input_name], - input_dims=[input_dims], - output_names=[output_name], - expected_output_dims=[(n, h, w, num_filters)]) - - def ExpectedEnginesToBuild(self, run_params): - """Return the expected engines to build.""" - return ["TRTEngineOp_0"] - - if __name__ == "__main__": test.main()