Add positive test cases for Conv2D. Reuse build_graph in conv2d_test.

This commit is contained in:
Trevor Morris 2019-01-03 14:56:44 -08:00
parent 560e4dd67f
commit cf471f0c15
3 changed files with 183 additions and 62 deletions

View File

@ -62,14 +62,14 @@ limitations under the License.
#define TFTRT_RETURN_ERROR_IF_FALSE(status, node) \ #define TFTRT_RETURN_ERROR_IF_FALSE(status, node) \
do { \ do { \
if ((status) == false) { \ if (status == false) { \
TFTRT_INTERNAL_ERROR_AT_NODE(node); \ TFTRT_INTERNAL_ERROR_AT_NODE(node); \
} \ } \
} while (0) } while (0)
#define TFTRT_RETURN_ERROR_IF_NULLPTR(ptr, node) \ #define TFTRT_RETURN_ERROR_IF_NULLPTR(ptr, node) \
do { \ do { \
if ((ptr) == nullptr) { \ if (ptr == nullptr) { \
TFTRT_INTERNAL_ERROR_AT_NODE(node); \ TFTRT_INTERNAL_ERROR_AT_NODE(node); \
} \ } \
} while (0) } while (0)
@ -1593,6 +1593,7 @@ tensorflow::Status ConvertConv2DHelper(OpConverterParams* params, int group) {
node_def.name()); node_def.name());
} }
const nvinfer1::DimsHW dilation(tf_dilations[h_index], tf_dilations[w_index]); const nvinfer1::DimsHW dilation(tf_dilations[h_index], tf_dilations[w_index]);
const auto tf_stride = attrs.get<std::vector<int>>("strides"); const auto tf_stride = attrs.get<std::vector<int>>("strides");
if (tf_stride.size() != 4) { if (tf_stride.size() != 4) {
return tensorflow::errors::InvalidArgument( return tensorflow::errors::InvalidArgument(

View File

@ -2697,6 +2697,17 @@ TEST_F(OpConverterTest, ConvertConv2D) {
"Dilation rate must be 1 for batch and channel " "Dilation rate must be 1 for batch and channel "
"dimensions, at my_conv2d"); "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<float>("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. // Strides is not 4D, should fail.
Reset(); Reset();
@ -2719,6 +2730,129 @@ TEST_F(OpConverterTest, ConvertConv2D) {
node_def, error::UNIMPLEMENTED, node_def, error::UNIMPLEMENTED,
"Stride must be 1 for batch and channel dimensions, at my_conv2d"); "Stride must be 1 for batch and channel dimensions, at my_conv2d");
} }
struct TestParams {
TestParams(const std::vector<int>& input_dims,
const std::vector<float>& input,
const std::vector<int>& filter_dims,
const std::vector<float>& filter,
const std::vector<int>& strides, const string& padding,
const string& data_format, const std::vector<int>& dilations,
const std::vector<int>& expected_output_dims,
const std::vector<float>& 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<int> input_dims;
std::vector<float> input;
std::vector<int> filter_dims;
std::vector<float> filter;
std::vector<int> strides;
string padding;
string data_format;
std::vector<int> dilations;
std::vector<int> expected_output_dims;
std::vector<float> 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<float>("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<float> output_data(ok_params[i].expected_output.size());
BuildAndRun<float>({{"input", ok_params[i].input}}, "my_conv2d",
&output_data);
EXPECT_THAT(output_data, ElementsAreArray(ok_params[i].expected_output));
}
} }
} // namespace convert } // namespace convert

View File

@ -51,37 +51,60 @@ def conv2d_layer(inputs, filters, kernel_size, strides=(1, 1), padding='valid',
def div_round_up(n, d): def div_round_up(n, d):
return (n - 1) // d + 1 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): class Conv2DNCHWTest(trt_test.TfTrtIntegrationTestBase):
def GetParams(self): def GetParams(self):
"""Testing conversion of Conv2D (data_format=NCHW) in TF-TRT conversion.""" """Testing conversion of Conv2D (data_format=NCHW) in TF-TRT conversion."""
np.random.seed(1234) np.random.seed(1234)
dtype = dtypes.float32 input_dims = [13, 3, 7, 11]
input_name = "input" g = build_graph(input_dims=input_dims, dtype=dtypes.float32, num_filters=5,
n, c, h, w = 13, 3, 7, 11 data_format="channels_first", kernel_sizes=[(3, 3), (3, 2)],
num_filters = 5 dilation_rates=[(1, 1), (2, 3)])
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)
return trt_test.TfTrtIntegrationTestParams( return trt_test.TfTrtIntegrationTestParams(
gdef=g.as_graph_def(), gdef=g.as_graph_def(),
input_names=[input_name], input_names=["input"],
input_dims=[input_dims], input_dims=[input_dims],
output_names=[output_name], output_names=["output"],
expected_output_dims=[(n, num_filters, h, w)]) 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): def ExpectedEnginesToBuild(self, run_params):
"""Return the expected engines to build.""" """Return the expected engines to build."""
@ -128,42 +151,5 @@ class Conv2DStridedNCHWTest(trt_test.TfTrtIntegrationTestBase):
return ["TRTEngineOp_0"] 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__": if __name__ == "__main__":
test.main() test.main()