diff options
author | 2017-05-12 12:38:21 -0700 | |
---|---|---|
committer | 2017-05-12 12:42:37 -0700 | |
commit | 7d785f1e18af9d22d940f18aac6e8c9ffd268b22 (patch) | |
tree | 6d837fdd0ccd8c417020d182d7ddce0095aeeada | |
parent | f8a98002491b7cd5f04ec7def6fa7dc30a66215a (diff) |
C API: Do not ignore errors in shape inference when constructing the graph.
Fixes #9826
PiperOrigin-RevId: 155898632
-rw-r--r-- | tensorflow/c/c_api.cc | 12 | ||||
-rw-r--r-- | tensorflow/c/c_api_test.cc | 83 | ||||
-rw-r--r-- | tensorflow/java/src/test/java/org/tensorflow/OperationBuilderTest.java | 2 | ||||
-rw-r--r-- | tensorflow/python/BUILD | 1 | ||||
-rw-r--r-- | tensorflow/python/ops/math_ops_test.py | 7 |
5 files changed, 75 insertions, 30 deletions
diff --git a/tensorflow/c/c_api.cc b/tensorflow/c/c_api.cc index 0f66a47b4a..bbc18569ad 100644 --- a/tensorflow/c/c_api.cc +++ b/tensorflow/c/c_api.cc @@ -1101,14 +1101,14 @@ static TF_Operation* TF_FinishOperationLocked(TF_OperationDescription* desc, if (status->status.ok()) { // Run shape inference function for newly added node. - // - // TODO(b/28152992): Enable returning the result of this - // code-path once we have converted all python shape functions - // to call their C++ versions. - desc->graph->refiner.AddNode(ret).IgnoreError(); - + status->status = desc->graph->refiner.AddNode(ret); + } + if (status->status.ok()) { // Add the node to the name-to-node mapping. desc->graph->name_map[ret->name()] = ret; + } else if (ret != nullptr) { + desc->graph->graph.RemoveNode(ret); + ret = nullptr; } } diff --git a/tensorflow/c/c_api_test.cc b/tensorflow/c/c_api_test.cc index 0ddc59db20..cdb7406c86 100644 --- a/tensorflow/c/c_api_test.cc +++ b/tensorflow/c/c_api_test.cc @@ -23,6 +23,7 @@ limitations under the License. #include "tensorflow/cc/saved_model/tag_constants.h" #include "tensorflow/core/example/example.pb.h" #include "tensorflow/core/example/feature.pb.h" +#include "tensorflow/core/framework/common_shape_fns.h" #include "tensorflow/core/framework/graph.pb_text.h" #include "tensorflow/core/framework/node_def.pb_text.h" #include "tensorflow/core/framework/node_def_util.h" @@ -278,6 +279,19 @@ static void Int32Deallocator(void* data, size_t, void* arg) { delete[] static_cast<int32*>(data); } +// Create a tensor with values of type TF_INT8 provided by `values`. +static TF_Tensor* Int8Tensor(const int64_t* dims, int num_dims, + const char* values) { + int64_t num_values = 1; + for (int i = 0; i < num_dims; ++i) { + num_values *= dims[i]; + } + TF_Tensor* t = + TF_AllocateTensor(TF_INT8, dims, num_dims, sizeof(char) * num_values); + memcpy(TF_TensorData(t), values, sizeof(char) * num_values); + return t; +} + static TF_Tensor* Int32Tensor(int32 v) { const int num_bytes = sizeof(int32); int32* values = new int32[1]; @@ -293,16 +307,21 @@ TF_Operation* Placeholder(TF_Graph* graph, TF_Status* s, return TF_FinishOperation(desc, s); } -TF_Operation* ScalarConst(int32 v, TF_Graph* graph, TF_Status* s, - const char* name = "scalar") { - unique_tensor_ptr tensor(Int32Tensor(v), TF_DeleteTensor); +TF_Operation* Const(TF_Tensor* t, TF_Graph* graph, TF_Status* s, + const char* name = "const") { TF_OperationDescription* desc = TF_NewOperation(graph, "Const", name); - TF_SetAttrTensor(desc, "value", tensor.get(), s); + TF_SetAttrTensor(desc, "value", t, s); if (TF_GetCode(s) != TF_OK) return nullptr; - TF_SetAttrType(desc, "dtype", TF_INT32); + TF_SetAttrType(desc, "dtype", TF_TensorType(t)); return TF_FinishOperation(desc, s); } +TF_Operation* ScalarConst(int32 v, TF_Graph* graph, TF_Status* s, + const char* name = "scalar") { + unique_tensor_ptr tensor(Int32Tensor(v), TF_DeleteTensor); + return Const(tensor.get(), graph, s, name); +} + TF_Operation* Add(TF_Operation* l, TF_Operation* r, TF_Graph* graph, TF_Status* s, const char* name = "add") { TF_OperationDescription* desc = TF_NewOperation(graph, "AddN", name); @@ -1093,6 +1112,35 @@ TEST(CAPI, SessionPRun) { TF_DeleteStatus(s); } +TEST(CAPI, ShapeInferenceError) { + // TF_FinishOperation should fail if the shape of the added operation cannot + // be inferred. + TF_Status* status = TF_NewStatus(); + TF_Graph* graph = TF_NewGraph(); + + // Create this failure by trying to add two nodes with incompatible shapes + // (A tensor with shape [2] and a tensor with shape [3] cannot be added). + const char data[] = {1, 2, 3}; + const int64_t vec2_dims[] = {2}; + unique_tensor_ptr vec2_tensor( + Int8Tensor(vec2_dims, TF_ARRAYSIZE(vec2_dims), data), TF_DeleteTensor); + TF_Operation* vec2 = Const(vec2_tensor.get(), graph, status, "vec2"); + ASSERT_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status); + + const int64_t vec3_dims[] = {3}; + unique_tensor_ptr vec3_tensor( + Int8Tensor(vec3_dims, TF_ARRAYSIZE(vec3_dims), data), TF_DeleteTensor); + TF_Operation* vec3 = Const(vec3_tensor.get(), graph, status, "vec3"); + ASSERT_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status); + + TF_Operation* add = Add(vec2, vec3, graph, status); + ASSERT_NE(TF_OK, TF_GetCode(status)); + ASSERT_TRUE(add == nullptr); + + TF_DeleteGraph(graph); + TF_DeleteStatus(status); +} + TEST(CAPI, ColocateWith) { TF_Status* s = TF_NewStatus(); TF_Graph* graph = TF_NewGraph(); @@ -1535,7 +1583,8 @@ Test op with no grad registered. x: input y: output -)doc"); +)doc") + .SetShapeFn(tensorflow::shape_inference::UnknownShape); class CApiGradientsTest : public ::testing::Test { protected: @@ -1801,18 +1850,6 @@ TEST_F(CApiGradientsTest, OpWithNoGradientRegistered_NoGradInputs) { TestGradientsError(false); } -// Create a tensor with values of type TF_INT8 provided by `values`. -TF_Tensor* Int8Tensor(const int64_t* dims, int num_dims, const char* values) { - int64_t num_values = 1; - for (int i = 0; i < num_dims; ++i) { - num_values *= dims[i]; - } - TF_Tensor* t = - TF_AllocateTensor(TF_INT8, dims, num_dims, sizeof(char) * num_values); - memcpy(TF_TensorData(t), values, sizeof(char) * num_values); - return t; -} - void StringVectorToArrays(const std::vector<string>& v, std::unique_ptr<const void* []>* ptrs, std::unique_ptr<size_t[]>* lens) { @@ -1828,9 +1865,13 @@ void StringVectorToArrays(const std::vector<string>& v, // Registers two ops, each with a single attribute called 'v'. // The attribute in one op will have a type 'type', the other // will have list(type). -#define ATTR_TEST_REGISTER_OP(type) \ - REGISTER_OP("CApiAttributesTestOp" #type).Attr("v: " #type); \ - REGISTER_OP("CApiAttributesTestOpList" #type).Attr("v: list(" #type ")") +#define ATTR_TEST_REGISTER_OP(type) \ + REGISTER_OP("CApiAttributesTestOp" #type) \ + .Attr("v: " #type) \ + .SetShapeFn(tensorflow::shape_inference::UnknownShape); \ + REGISTER_OP("CApiAttributesTestOpList" #type) \ + .Attr("v: list(" #type ")") \ + .SetShapeFn(tensorflow::shape_inference::UnknownShape) ATTR_TEST_REGISTER_OP(string); ATTR_TEST_REGISTER_OP(int); ATTR_TEST_REGISTER_OP(float); diff --git a/tensorflow/java/src/test/java/org/tensorflow/OperationBuilderTest.java b/tensorflow/java/src/test/java/org/tensorflow/OperationBuilderTest.java index 951136180d..9dc400a3d3 100644 --- a/tensorflow/java/src/test/java/org/tensorflow/OperationBuilderTest.java +++ b/tensorflow/java/src/test/java/org/tensorflow/OperationBuilderTest.java @@ -101,7 +101,7 @@ public class OperationBuilderTest { assertTrue(hasNode(g, "StringAndBool")); // int (TF "int" attributes are 64-bit signed, so a Java long). g.opBuilder("RandomUniform", "Int") - .addInput(TestUtil.constant(g, "RandomUniformShape", 1)) + .addInput(TestUtil.constant(g, "RandomUniformShape", new int[]{1})) .setAttr("seed", 10) .setAttr("dtype", DataType.FLOAT) .build(); diff --git a/tensorflow/python/BUILD b/tensorflow/python/BUILD index feab1e2fbc..d2b0f45c72 100644 --- a/tensorflow/python/BUILD +++ b/tensorflow/python/BUILD @@ -2184,6 +2184,7 @@ cuda_py_test( srcs = ["ops/math_ops_test.py"], additional_deps = [ ":array_ops", + ":errors", ":framework_for_generated_wrappers", ":framework_test_lib", ":gradients", diff --git a/tensorflow/python/ops/math_ops_test.py b/tensorflow/python/ops/math_ops_test.py index ed30c4bcfa..120827d18b 100644 --- a/tensorflow/python/ops/math_ops_test.py +++ b/tensorflow/python/ops/math_ops_test.py @@ -20,6 +20,7 @@ from __future__ import print_function import numpy as np from tensorflow.python.framework import constant_op +from tensorflow.python.framework import errors from tensorflow.python.framework import ops from tensorflow.python.framework import test_util from tensorflow.python.ops import array_ops @@ -55,7 +56,8 @@ class ReduceTest(test_util.TensorFlowTestCase): def testReduceInvalidAxis(self): x = np.array([[1, 2, 3], [4, 5, 6]], dtype=np.int32) axis = np.array([[0], [1]]) - with self.assertRaisesRegexp(ValueError, "must be at most rank 1"): + with self.assertRaisesRegexp(errors.InvalidArgumentError, + "must be at most rank 1"): math_ops.reduce_sum(x, axis) @@ -280,7 +282,8 @@ class AddNTest(test_util.TensorFlowTestCase): for _ in range(98): partials.append(math_ops.add_n([constant_op.constant(1)])) partials.append( - math_ops.add_n([constant_op.constant(1), constant_op.constant(1)])) + math_ops.add_n([constant_op.constant(1), + constant_op.constant(1)])) res = math_ops.add_n(partials) + constant_op.constant(0) with self.test_session(use_gpu=True): |