Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add TF-TRT converter for Shape op #39990

Merged
merged 1 commit into from
Aug 6, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
35 changes: 35 additions & 0 deletions tensorflow/compiler/tf2tensorrt/convert/convert_nodes.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2410,6 +2410,40 @@ Status ConvertTranspose(OpConverterParams* params) {
return Status::OK();
}

Status ConvertShape(OpConverterParams* params) {
const auto& inputs = params->inputs;
TF_RETURN_IF_ERROR(
CheckInputsWeights(*params, {{"input", TrtInputArg::kBoth}}));
if (params->use_implicit_batch) {
return errors::Unimplemented(
"Shape is only supported for explicit batch mode.");
}
if (HasStaticShape(inputs.at(0).GetTrtDims())) {
if (params->validation_only) return Status::OK();
nvinfer1::Dims input_dims = inputs.at(0).GetTrtDims();
nvinfer1::Dims output_dims{1, {input_dims.nbDims}};
// Create a const node with the values of output_dims
TRT_ShapedWeights weight = params->weight_store->GetTempWeights(
nvinfer1::DataType::kINT32, output_dims);
int32* values_ptr = static_cast<int32*>(weight.GetValues());
std::copy(input_dims.d, input_dims.d + input_dims.nbDims, values_ptr);
auto output = params->converter->CreateConstantLayer(weight, output_dims);
params->outputs->push_back(TRT_TensorOrWeights(output));
tfeher marked this conversation as resolved.
Show resolved Hide resolved
return Status::OK();
}
#if IS_TRT_VERSION_GE(6, 0, 0, 0)
if (params->validation_only) return Status::OK();
nvinfer1::IShapeLayer* shape_layer =
params->converter->network()->addShape(*inputs.at(0).tensor());
TFTRT_RETURN_ERROR_IF_NULLPTR(shape_layer, params->node_def.name());
params->outputs->push_back(TRT_TensorOrWeights(shape_layer->getOutput(0)));
return Status::OK();
#else
return errors::Unavailable(
"Shape op conversion requires TensorRT 6 or above");
#endif
}

Status ConvertReshape(OpConverterParams* params) {
const auto& inputs = params->inputs;
TF_RETURN_IF_ERROR(
Expand Down Expand Up @@ -5958,6 +5992,7 @@ static void RegisterValidatableOpConverters(
(*registration)[pool_op_type] = ConvertPool3D;
}
#endif
(*registration)["Shape"] = ConvertShape;
(*registration)["Rsqrt"] = ConvertRsqrt;
(*registration)["Slice"] = ConvertSlice;
(*registration)["Softmax"] = ConvertSoftmax;
Expand Down
69 changes: 62 additions & 7 deletions tensorflow/compiler/tf2tensorrt/convert/convert_nodes_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1781,7 +1781,8 @@ class ParameterizedOpConverterTestBase
void BuildAndRun(const string& name,
const std::vector<std::vector<int>>& expected_output_dims,
const Status& expected_runtime_status,
const std::vector<Matcher<std::vector<float>>>& matcher) {
const std::vector<Matcher<std::vector<float>>>& matcher,
const std::vector<DataType>& out_tf_types = {}) {
TensorShape shape;
const int n_output = expected_output_dims.size();
ASSERT_EQ(n_output, matcher.size());
Expand All @@ -1790,12 +1791,14 @@ class ParameterizedOpConverterTestBase
TF_EXPECT_OK(
TensorShapeUtils::MakeShape(expected_output_dims[i], &shape));
string out_name = (n_output == 1) ? name : StrCat(name, ":", i);
InputOutputData data{out_name,
ConstructTensor(shape.num_elements(), 0, tf_type)};
DataType out_tf_type =
out_tf_types.size() > i ? out_tf_types[i] : tf_type;
InputOutputData data{
out_name, ConstructTensor(shape.num_elements(), 0, out_tf_type)};
output_data.push_back(data);
}
ASSERT_FALSE(input_data_.empty());
const int batch_size = input_data_[0].tensor.shape().dim_size(0);
const int batch_size =
input_data_.empty() ? 1 : input_data_[0].tensor.shape().dim_size(0);
Status stat =
OpConverterTest::BuildAndRun(input_data_, &output_data, batch_size);
ASSERT_EQ(expected_runtime_status.ok(), stat.ok())
Expand All @@ -1820,13 +1823,15 @@ class ParameterizedOpConverterTestBase
const std::vector<int>& expected_output_dims,
const Status& expected_conversion_status,
const Status& expected_runtime_status,
const Matcher<std::vector<float>>& matcher) {
const Matcher<std::vector<float>>& matcher,
const std::vector<DataType>& out_tf_types = {}) {
RunValidationAndConversion(node_def, expected_conversion_status,
name.c_str(), expected_output_dims);
if (expected_conversion_status.ok()) {
BuildAndRun(name, std::vector<std::vector<int>>({expected_output_dims}),
expected_runtime_status,
std::vector<Matcher<std::vector<float>>>({matcher}));
std::vector<Matcher<std::vector<float>>>({matcher}),
out_tf_types);
}
}

Expand Down Expand Up @@ -2169,6 +2174,56 @@ TEST_F(OpConverterTest, ConvertReshape) {
}
}

TEST_P(OpConverterTest1, ConvertShape) {
// Get the NodeDef for Shape op.
Scope s = Scope::NewRootScope();
auto input = ops::Placeholder(s.WithOpName("input"), tf_type);
auto shape = ops::Shape(s.WithOpName("my_shape"), input);
const NodeDef& node_def = shape.operation.node()->def();

Status conversion_status =
(trt_mode == TrtTestMode::kImplicitBatch)
? errors::Unimplemented(
"Shape is only supported for explicit batch mode.")
: Status::OK();
std::vector<TestParamBase> test_params = {
TestParamBase{{1, 2, 3}, {}, {3}, {}, conversion_status},
// Add input as weight (we use non empty param ({1}) to trigger this).
TestParamBase{{1, 2, 3}, {}, {3}, {1}, conversion_status},
};

auto input_is_weight = [](const TestParamBase p) { return !p.param.empty(); };
for (auto p : test_params) {
SCOPED_TRACE(p);
Reset();
// Number of elements of the input tensor. We leave it 0 in case we do
// not need to add an input tensor. This happens in explicit batch mode: the
// shape is known at conversion time and therefore the shape is added to the
// network as a constant layer. (In this case the single node network that
// we use for the unit test will have no actual input tensor when converted
// to a TensorRT network.)
int n_elements = 0;
// In explicit batch mode the shape is known at conversion time and
// therefore the shape is added to the network as a constant layer. As
// a result, the single node network that we use for this unit test will
// have no actual input tensor when converted to a TensorRT network.
if (input_is_weight(p) || trt_mode != TrtTestMode::kExplicitBatch) {
// Calculate the number of elements for adding input data.
n_elements = std::accumulate(p.input_dims.begin(), p.input_dims.end(), 1,
std::multiplies<int>());
}
std::vector<float> input_val(n_elements, 1);
if (!input_is_weight(p)) {
AddTestTensor("input", p.input_dims, input_val);
} else {
AddTestWeights("input", p.input_dims, input_val, tf_type);
}
TestOpConverter("my_shape", node_def, p.expected_output_dims, p.status,
p.runtime_status, ElementsAreArray(p.input_dims),
{DT_INT32});
}
}

// Helper function for testing MatMul and BatchMatMul
// get_matmul corresponds to the function used to generate the node. It should
// accept (DataType, transpose_a, transpose_b) as parameters.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ limitations under the License.
#include <algorithm>
#include <functional>

#include "absl/algorithm/container.h"
#include "tensorflow/compiler/tf2tensorrt/convert/utils.h"

#if GOOGLE_CUDA && GOOGLE_TENSORRT
Expand All @@ -35,14 +36,16 @@ void TrtShapeOptimizationProfile::InitProfiles() {
<< "for each input (min=opt=max).";
}
for (auto& shape_vec : input_shapes_) {
std::vector<nvinfer1::Dims> dimvec;
for (auto& shape : shape_vec) {
dimvec.push_back(TensorShapeToTrtDims(shape, false));
if (!shape_vec.empty()) {
std::vector<nvinfer1::Dims> dimvec(shape_vec.size());
absl::c_transform(shape_vec, dimvec.begin(), [](TensorShape shape) {
return TensorShapeToTrtDims(shape, false);
});
// Set min=opt=max.
OptimizationProfileConfig profConfig{dimvec, dimvec, dimvec};
profiles_.push_back(std::move(profConfig));
VLOG(1) << "Created profile " << profiles_.back().DebugString();
}
// We set min=opt=max.
OptimizationProfileConfig profConfig{dimvec, dimvec, dimvec};
profiles_.push_back(std::move(profConfig));
VLOG(1) << "Created profile " << profiles_.back().DebugString();
}
}

Expand Down