aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Asim Shankar <ashankar@google.com>2017-05-12 12:38:21 -0700
committerGravatar TensorFlower Gardener <gardener@tensorflow.org>2017-05-12 12:42:37 -0700
commit7d785f1e18af9d22d940f18aac6e8c9ffd268b22 (patch)
tree6d837fdd0ccd8c417020d182d7ddce0095aeeada
parentf8a98002491b7cd5f04ec7def6fa7dc30a66215a (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.cc12
-rw-r--r--tensorflow/c/c_api_test.cc83
-rw-r--r--tensorflow/java/src/test/java/org/tensorflow/OperationBuilderTest.java2
-rw-r--r--tensorflow/python/BUILD1
-rw-r--r--tensorflow/python/ops/math_ops_test.py7
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):