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

Patches for Release 1.7 #18812

Merged
merged 12 commits into from
Apr 30, 2018
5 changes: 5 additions & 0 deletions tensorflow/compiler/tf2xla/tf2xla_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,11 @@ TEST(ConvertGraphDefToXla, Sum) {
TF_EXPECT_OK(result_or.status());
std::unique_ptr<xla::Literal> result = std::move(result_or.ValueOrDie());
EXPECT_EQ("(s32[]) (\n42\n)", result->ToString());

config.mutable_feed(0)->mutable_id()->set_output_index(
123); /* invalid output_index */
EXPECT_TRUE(errors::IsInvalidArgument(
ConvertGraphDefToXla(graph_def, config, client, &computation)));
}

} // namespace
Expand Down
11 changes: 9 additions & 2 deletions tensorflow/compiler/tf2xla/tf2xla_util.cc
Original file line number Diff line number Diff line change
Expand Up @@ -151,8 +151,15 @@ Status AddPlaceholdersForFeeds(
Status status;
Node* feed_node = g.AddNode(gd.node(0), &status);
TF_RETURN_IF_ERROR(status);
info.data_type =
BaseType(feed_node->output_type(info.feed->id().output_index()));

if (info.feed->id().output_index() < feed_node->num_outputs()) {
info.data_type =
BaseType(feed_node->output_type(info.feed->id().output_index()));
} else {
return errors::InvalidArgument(
"Invalid output_index ", info.feed->id().output_index(),
" for feed node ", info.feed->id().node_name());
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,16 @@ void ComputeConvSizes(const Shape& input_shape, int output_depth, int kwidth,
const int input_height = input_shape.dims(1);
const int batch = input_shape.dims(0);

CHECK_GE(input_width, 1);
CHECK_GE(input_height, 1);
CHECK_GE(batch, 1);
CHECK_GE(kwidth, 1);
CHECK_GE(kheight, 1);
CHECK_GE(stride_width, 1);
CHECK_GE(stride_height, 1);
CHECK_GE(dilation_width_factor, 1);
CHECK_GE(dilation_height_factor, 1);

int dilated_kwidth = dilation_width_factor * (kwidth - 1) + 1;
int dilated_kheight = dilation_height_factor * (kheight - 1) + 1;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,9 @@ std::unique_ptr<GraphDef> MaybeReplaceCompositeSubgraph(
MaybeResolveClusters(tf_graph, cluster_factories);

// Copy function definitions
*(pruned_graph->mutable_library()) = tf_graph.library();
if (pruned_graph) {
*(pruned_graph->mutable_library()) = tf_graph.library();
}
return pruned_graph;
}

Expand Down
2 changes: 2 additions & 0 deletions tensorflow/contrib/lite/toco/tflite/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -115,9 +115,11 @@ cc_library(
deps = [
":operator",
":types",
"//tensorflow/contrib/lite:framework",
"//tensorflow/contrib/lite/schema:schema_fbs",
"//tensorflow/contrib/lite/toco:model",
"//tensorflow/contrib/lite/toco:tooling_util",
"//tensorflow/contrib/lite/tools:verifier",
"@flatbuffers",
],
)
Expand Down
18 changes: 16 additions & 2 deletions tensorflow/contrib/lite/toco/tflite/import.cc
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,12 @@ limitations under the License.
#include "tensorflow/contrib/lite/toco/tflite/import.h"

#include "flatbuffers/flexbuffers.h"
#include "tensorflow/contrib/lite/model.h"
#include "tensorflow/contrib/lite/schema/schema_generated.h"
#include "tensorflow/contrib/lite/toco/tflite/operator.h"
#include "tensorflow/contrib/lite/toco/tflite/types.h"
#include "tensorflow/contrib/lite/toco/tooling_util.h"
#include "tensorflow/contrib/lite/tools/verifier.h"

namespace toco {

Expand Down Expand Up @@ -162,16 +164,28 @@ void ImportIOTensors(const ::tflite::Model& input_model,
}
}

namespace {
bool Verify(const void* buf, size_t len) {
::flatbuffers::Verifier verifier(static_cast<const uint8_t*>(buf), len);
return ::tflite::VerifyModelBuffer(verifier);
}
} // namespace

std::unique_ptr<Model> Import(const ModelFlags& model_flags,
const string& input_file_contents) {
::tflite::AlwaysTrueResolver r;
if (!::tflite::Verify(input_file_contents.data(), input_file_contents.size(),
r, ::tflite::DefaultErrorReporter())) {
LOG(FATAL) << "Invalid flatbuffer.";
}
const ::tflite::Model* input_model =
::tflite::GetModel(input_file_contents.data());

// Full list of all known operators.
const auto ops_by_name = BuildOperatorByNameMap();

if (input_model->subgraphs()->size() != 1) {
LOG(FATAL) << "# of subgraphs in tflite should be exactly 1 for now.";
if (!input_model->subgraphs() || input_model->subgraphs()->size() != 1) {
LOG(FATAL) << "Number of subgraphs in tflite should be exactly 1.";
}
std::unique_ptr<Model> model;
model.reset(new Model);
Expand Down
205 changes: 164 additions & 41 deletions tensorflow/contrib/lite/toco/tflite/import_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -27,60 +27,110 @@ namespace {

using ::testing::ElementsAre;

using flatbuffers::Offset;
using flatbuffers::Vector;
class ImportTest : public ::testing::Test {
protected:
template <typename T>
flatbuffers::Offset<flatbuffers::Vector<unsigned char>> CreateDataVector(
const std::vector<T>& data) {
Offset<Vector<unsigned char>> CreateDataVector(const std::vector<T>& data) {
return builder_.CreateVector(reinterpret_cast<const uint8_t*>(data.data()),
sizeof(T) * data.size());
}
// This is a very simplistic model. We are not interested in testing all the
// details here, since tf.mini's testing framework will be exercising all the
// conversions multiple times, and the conversion of operators is tested by
// separate unittests.
void BuildTestModel() {
// The tensors

Offset<Vector<Offset<::tflite::Buffer>>> BuildBuffers() {
auto buf0 = ::tflite::CreateBuffer(builder_, CreateDataVector<float>({}));
auto buf1 = ::tflite::CreateBuffer(
builder_, CreateDataVector<float>({1.0f, 2.0f, 3.0f, 4.0f}));
auto buf2 =
::tflite::CreateBuffer(builder_, CreateDataVector<float>({3.0f, 4.0f}));
return builder_.CreateVector(
std::vector<Offset<::tflite::Buffer>>({buf0, buf1, buf2}));
}

Offset<Vector<Offset<::tflite::Tensor>>> BuildTensors() {
auto q = ::tflite::CreateQuantizationParameters(
builder_,
/*min=*/builder_.CreateVector<float>({0.1f}),
/*max=*/builder_.CreateVector<float>({0.2f}),
/*scale=*/builder_.CreateVector<float>({0.3f}),
/*zero_point=*/builder_.CreateVector<int64_t>({100ll}));
auto buf0 = ::tflite::CreateBuffer(builder_, CreateDataVector<float>({}));
auto buf1 =
::tflite::CreateBuffer(builder_, CreateDataVector<float>({1.0f, 2.0f}));
auto buf2 =
::tflite::CreateBuffer(builder_, CreateDataVector<float>({3.0f}));
auto buffers = builder_.CreateVector(
std::vector<flatbuffers::Offset<::tflite::Buffer>>({buf0, buf1, buf2}));
auto t1 = ::tflite::CreateTensor(builder_,
builder_.CreateVector<int>({1, 2, 3, 4}),
::tflite::TensorType_FLOAT32, 1,
builder_.CreateString("tensor_one"), q);
auto t1 =
::tflite::CreateTensor(builder_, builder_.CreateVector<int>({1, 2, 2}),
::tflite::TensorType_FLOAT32, 1,
builder_.CreateString("tensor_one"), q);
auto t2 =
::tflite::CreateTensor(builder_, builder_.CreateVector<int>({2, 1}),
::tflite::TensorType_FLOAT32, 2,
builder_.CreateString("tensor_two"), q);
auto tensors = builder_.CreateVector(
std::vector<flatbuffers::Offset<::tflite::Tensor>>({t1, t2}));

// The operator codes.
auto c1 =
::tflite::CreateOperatorCode(builder_, ::tflite::BuiltinOperator_CUSTOM,
builder_.CreateString("custom_op_one"));
auto c2 = ::tflite::CreateOperatorCode(
builder_, ::tflite::BuiltinOperator_CONV_2D, 0);
auto opcodes = builder_.CreateVector(
std::vector<flatbuffers::Offset<::tflite::OperatorCode>>({c1, c2}));

auto subgraph = ::tflite::CreateSubGraph(builder_, tensors, 0, 0, 0);
std::vector<flatbuffers::Offset<::tflite::SubGraph>> subgraph_vector(
{subgraph});
auto subgraphs = builder_.CreateVector(subgraph_vector);
return builder_.CreateVector(
std::vector<Offset<::tflite::Tensor>>({t1, t2}));
}

Offset<Vector<Offset<::tflite::OperatorCode>>> BuildOpCodes(
std::initializer_list<::tflite::BuiltinOperator> op_codes) {
std::vector<Offset<::tflite::OperatorCode>> op_codes_vector;
for (auto op : op_codes) {
op_codes_vector.push_back(::tflite::CreateOperatorCode(builder_, op, 0));
}
return builder_.CreateVector(op_codes_vector);
}

Offset<Vector<Offset<::tflite::OperatorCode>>> BuildOpCodes() {
return BuildOpCodes({::tflite::BuiltinOperator_MAX_POOL_2D,
::tflite::BuiltinOperator_CONV_2D});
}

Offset<Vector<Offset<::tflite::Operator>>> BuildOperators(
std::initializer_list<int> inputs, std::initializer_list<int> outputs) {
auto is = builder_.CreateVector<int>(inputs);
if (inputs.size() == 0) is = 0;
auto os = builder_.CreateVector<int>(outputs);
if (outputs.size() == 0) os = 0;
auto op = ::tflite::CreateOperator(
builder_, 0, is, os, ::tflite::BuiltinOptions_Conv2DOptions,
::tflite::CreateConv2DOptions(builder_, ::tflite::Padding_VALID, 1, 1,
::tflite::ActivationFunctionType_NONE)
.Union(),
/*custom_options=*/0, ::tflite::CustomOptionsFormat_FLEXBUFFERS);

return builder_.CreateVector(std::vector<Offset<::tflite::Operator>>({op}));
}

Offset<Vector<Offset<::tflite::Operator>>> BuildOperators() {
return BuildOperators({0}, {1});
}

Offset<Vector<Offset<::tflite::SubGraph>>> BuildSubGraphs(
Offset<Vector<Offset<::tflite::Tensor>>> tensors,
Offset<Vector<Offset<::tflite::Operator>>> operators,
int num_sub_graphs = 1) {
std::vector<int32_t> inputs = {0};
std::vector<int32_t> outputs = {1};
std::vector<Offset<::tflite::SubGraph>> v;
for (int i = 0; i < num_sub_graphs; ++i) {
v.push_back(::tflite::CreateSubGraph(
builder_, tensors, builder_.CreateVector(inputs),
builder_.CreateVector(outputs), operators,
builder_.CreateString("subgraph")));
}
return builder_.CreateVector(v);
}

// This is a very simplistic model. We are not interested in testing all the
// details here, since tf.mini's testing framework will be exercising all the
// conversions multiple times, and the conversion of operators is tested by
// separate unittests.
void BuildTestModel() {
auto buffers = BuildBuffers();
auto tensors = BuildTensors();
auto opcodes = BuildOpCodes();
auto operators = BuildOperators();
auto subgraphs = BuildSubGraphs(tensors, operators);
auto s = builder_.CreateString("");
builder_.Finish(::tflite::CreateModel(builder_, TFLITE_SCHEMA_VERSION,
opcodes, subgraphs, s, buffers));

::tflite::FinishModelBuffer(
builder_, ::tflite::CreateModel(builder_, TFLITE_SCHEMA_VERSION,
opcodes, subgraphs, s, buffers));

input_model_ = ::tflite::GetModel(builder_.GetBufferPointer());
}
Expand All @@ -89,7 +139,6 @@ class ImportTest : public ::testing::Test {
builder_.GetSize());
}
flatbuffers::FlatBufferBuilder builder_;
// const uint8_t* buffer_ = nullptr;
const ::tflite::Model* input_model_ = nullptr;
};

Expand All @@ -106,7 +155,7 @@ TEST_F(ImportTest, LoadOperatorsTable) {

details::OperatorsTable operators;
details::LoadOperatorsTable(*input_model_, &operators);
EXPECT_THAT(operators, ElementsAre("custom_op_one", "CONV_2D"));
EXPECT_THAT(operators, ElementsAre("MAX_POOL_2D", "CONV_2D"));
}

TEST_F(ImportTest, Tensors) {
Expand All @@ -118,9 +167,9 @@ TEST_F(ImportTest, Tensors) {
Array& a1 = model->GetArray("tensor_one");
EXPECT_EQ(ArrayDataType::kFloat, a1.data_type);
EXPECT_THAT(a1.GetBuffer<ArrayDataType::kFloat>().data,
ElementsAre(1.0f, 2.0f));
ElementsAre(1.0f, 2.0f, 3.0f, 4.0f));
ASSERT_TRUE(a1.has_shape());
EXPECT_THAT(a1.shape().dims(), ElementsAre(1, 2, 3, 4));
EXPECT_THAT(a1.shape().dims(), ElementsAre(1, 2, 2));

const auto& mm = a1.minmax;
ASSERT_TRUE(mm.get());
Expand All @@ -133,6 +182,80 @@ TEST_F(ImportTest, Tensors) {
EXPECT_EQ(100, q->zero_point);
}

TEST_F(ImportTest, NoBuffers) {
auto buffers = 0;
auto tensors = BuildTensors();
auto opcodes = BuildOpCodes();
auto operators = BuildOperators();
auto subgraphs = BuildSubGraphs(tensors, operators);
auto comment = builder_.CreateString("");
::tflite::FinishModelBuffer(
builder_, ::tflite::CreateModel(builder_, TFLITE_SCHEMA_VERSION, opcodes,
subgraphs, comment, buffers));
EXPECT_DEATH(Import(ModelFlags(), InputModelAsString()),
"Missing 'buffers' section.");
}

TEST_F(ImportTest, NoInputs) {
auto buffers = BuildBuffers();
auto tensors = BuildTensors();
auto opcodes = BuildOpCodes();
auto operators = BuildOperators({}, {1});
auto subgraphs = BuildSubGraphs(tensors, operators);
auto comment = builder_.CreateString("");
::tflite::FinishModelBuffer(
builder_, ::tflite::CreateModel(builder_, TFLITE_SCHEMA_VERSION, opcodes,
subgraphs, comment, buffers));
EXPECT_DEATH(Import(ModelFlags(), InputModelAsString()),
"Missing 'inputs' for operator.");
}

TEST_F(ImportTest, NoOutputs) {
auto buffers = BuildBuffers();
auto tensors = BuildTensors();
auto opcodes = BuildOpCodes();
auto operators = BuildOperators({0}, {});
auto subgraphs = BuildSubGraphs(tensors, operators);
auto comment = builder_.CreateString("");
::tflite::FinishModelBuffer(
builder_, ::tflite::CreateModel(builder_, TFLITE_SCHEMA_VERSION, opcodes,
subgraphs, comment, buffers));
EXPECT_DEATH(Import(ModelFlags(), InputModelAsString()),
"Missing 'outputs' for operator.");
}

TEST_F(ImportTest, InvalidOpCode) {
auto buffers = BuildBuffers();
auto tensors = BuildTensors();
auto opcodes = BuildOpCodes({static_cast<::tflite::BuiltinOperator>(-1),
::tflite::BuiltinOperator_CONV_2D});
auto operators = BuildOperators();
auto subgraphs = BuildSubGraphs(tensors, operators);
auto comment = builder_.CreateString("");
::tflite::FinishModelBuffer(
builder_, ::tflite::CreateModel(builder_, TFLITE_SCHEMA_VERSION, opcodes,
subgraphs, comment, buffers));
EXPECT_DEATH(Import(ModelFlags(), InputModelAsString()),
"Operator id '-1' is out of range.");
}

TEST_F(ImportTest, MultipleSubGraphs) {
auto buffers = BuildBuffers();
auto tensors = BuildTensors();
auto opcodes = BuildOpCodes();
auto operators = BuildOperators();
auto subgraphs = BuildSubGraphs(tensors, operators, 2);
auto comment = builder_.CreateString("");
::tflite::FinishModelBuffer(
builder_, ::tflite::CreateModel(builder_, TFLITE_SCHEMA_VERSION, opcodes,
subgraphs, comment, buffers));

input_model_ = ::tflite::GetModel(builder_.GetBufferPointer());

EXPECT_DEATH(Import(ModelFlags(), InputModelAsString()),
"Number of subgraphs in tflite should be exactly 1.");
}

// TODO(ahentz): still need tests for Operators and IOTensors.

} // namespace
Expand Down