From 3c5774d5d1e0c718ebf981f51f42a0d31acbfb27 Mon Sep 17 00:00:00 2001 From: Benoit Steiner Date: Wed, 10 Aug 2016 10:11:41 -0800 Subject: [PATCH 1/2] Upgraded eigen to the latest version Change: 129887348 --- tensorflow/core/kernels/cwise_ops.h | 53 +++---------------- tensorflow/core/util/tensor_slice_util.h | 2 +- .../kernel_tests/self_adjoint_eig_op_test.py | 12 ++--- tensorflow/workspace.bzl | 4 +- 4 files changed, 15 insertions(+), 56 deletions(-) diff --git a/tensorflow/core/kernels/cwise_ops.h b/tensorflow/core/kernels/cwise_ops.h index fac3cb6fcea..f6d00e574dc 100644 --- a/tensorflow/core/kernels/cwise_ops.h +++ b/tensorflow/core/kernels/cwise_ops.h @@ -386,61 +386,20 @@ struct logical_not : base > { // NOTE: std::isinf, std::isnan, std::isfinite are plain function. // Therefore we need to wrap them in functors to be used with Eigen's // type system. +template +struct isinf : base, bool> {}; template -struct isinf_func { - typedef bool result_type; - EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool operator()(T x) const { - return Eigen::numext::isinf(x); - } -}; +struct isnan : base, bool> {}; template -struct isinf : base, bool> {}; +struct isfinite : base, bool> {}; template -struct isnan_func { - typedef bool result_type; - EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool operator()(T x) const { - return Eigen::numext::isnan(x); - } -}; +struct floor : base> {}; template -struct isnan : base, bool> {}; - -template -struct isfinite_func { - typedef bool result_type; - EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool operator()(T x) const { - return Eigen::numext::isfinite(x); - } -}; - -template -struct isfinite : base, bool> {}; - -template -struct floor_func { - typedef T result_type; - EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T operator()(T x) const { - return Eigen::numext::floor(x); - } -}; - -template -struct floor : base > {}; - -template -struct ceil_func { - typedef T result_type; - EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T operator()(T x) const { - return Eigen::numext::ceil(x); - } -}; - -template -struct ceil : base > {}; +struct ceil : base> {}; //////////////////////////////////////////////////////////////////////////////// // Binary functors diff --git a/tensorflow/core/util/tensor_slice_util.h b/tensorflow/core/util/tensor_slice_util.h index 89fc9163d87..c7edae66b26 100644 --- a/tensorflow/core/util/tensor_slice_util.h +++ b/tensorflow/core/util/tensor_slice_util.h @@ -110,7 +110,7 @@ struct CopyThatWorksWithStringPointer { d(d_start[0] + i0, d_start[1] + i1, d_start[2] + i2, d_start[3] + i3, d_start[4] + i4, d_start[5] + i5, d_start[6] + i6, d_start[7] + i7) = - Eigen::internal::raw_uint16_to_half( + Eigen::half_impl::raw_uint16_to_half( s(s_start[0] + i0, s_start[1] + i1, s_start[2] + i2, s_start[3] + i3, s_start[4] + i4, s_start[5] + i5, s_start[6] + i6, s_start[7] + i7)); diff --git a/tensorflow/python/kernel_tests/self_adjoint_eig_op_test.py b/tensorflow/python/kernel_tests/self_adjoint_eig_op_test.py index 3d08c2afbbe..0ab606c03f4 100644 --- a/tensorflow/python/kernel_tests/self_adjoint_eig_op_test.py +++ b/tensorflow/python/kernel_tests/self_adjoint_eig_op_test.py @@ -55,13 +55,13 @@ def SortEigenDecomposition(e, v): def _GetSelfAdjointEigTest(dtype_, shape_): - def CompareEigenVectors(self, x, y, atol): + def CompareEigenVectors(self, x, y, tol): # Eigenvectors are only unique up to sign so we normalize the signs first. signs = np.sign(np.sum(np.divide(x, y), -2, keepdims=True)) x *= signs - self.assertAllClose(x, y, atol) + self.assertAllClose(x, y, atol=tol, rtol=tol) - def CompareEigenDecompositions(self, x_e, x_v, y_e, y_v, atol): + def CompareEigenDecompositions(self, x_e, x_v, y_e, y_v, tol): num_batches = int(np.prod(x_e.shape[:-1])) n = x_e.shape[-1] x_e = np.reshape(x_e, [num_batches] + [n]) @@ -71,8 +71,8 @@ def _GetSelfAdjointEigTest(dtype_, shape_): for i in range(num_batches): x_ei, x_vi = SortEigenDecomposition(x_e[i, :], x_v[i, :, :]) y_ei, y_vi = SortEigenDecomposition(y_e[i, :], y_v[i, :, :]) - self.assertAllClose(x_ei, y_ei, atol=atol) - CompareEigenVectors(self, x_vi, y_vi, atol) + self.assertAllClose(x_ei, y_ei, atol=tol, rtol=tol) + CompareEigenVectors(self, x_vi, y_vi, tol) def Test(self): np.random.seed(1) @@ -85,7 +85,7 @@ def _GetSelfAdjointEigTest(dtype_, shape_): if dtype_ == np.float32: atol = 1e-4 else: - atol = 1e-14 + atol = 1e-12 for compute_v in False, True: np_e, np_v = np.linalg.eig(a) with self.test_session(): diff --git a/tensorflow/workspace.bzl b/tensorflow/workspace.bzl index dd2bf4adc65..05787aa3abe 100644 --- a/tensorflow/workspace.bzl +++ b/tensorflow/workspace.bzl @@ -7,8 +7,8 @@ def tf_workspace(path_prefix = "", tf_repo_name = ""): # These lines need to be changed when updating Eigen. They are parsed from # this file by the cmake and make builds to determine the eigen version and hash. - eigen_version = "b4fa9622b809" - eigen_sha256 = "2862840c2de9c0473a4ef20f8678949ae89ab25965352ee53329e63ba46cec62" + eigen_version = "6f952374ef2b" + eigen_sha256 = "56d658324b09de3f418ae42ca0646dd1e6e0b897dd58b164ec0d21315764afd9" native.new_http_archive( name = "eigen_archive", From 5ce2567953b3bde1665e82a75bebf35066111b2c Mon Sep 17 00:00:00 2001 From: Manjunath Kudlur Date: Fri, 12 Aug 2016 09:19:52 -0800 Subject: [PATCH 2/2] C++ API: Added a Const constructor for non-empty const supporting type cast. Fixes #3752 Change: 130113000 --- tensorflow/cc/framework/cc_ops_test.cc | 45 ++++++++++++++++++++++++++ tensorflow/cc/ops/const_op.h | 37 +++++++++++++-------- tensorflow/cc/ops/const_op_test.cc | 9 ++++++ 3 files changed, 78 insertions(+), 13 deletions(-) diff --git a/tensorflow/cc/framework/cc_ops_test.cc b/tensorflow/cc/framework/cc_ops_test.cc index e1bc666de69..cecc633ca1d 100644 --- a/tensorflow/cc/framework/cc_ops_test.cc +++ b/tensorflow/cc/framework/cc_ops_test.cc @@ -226,4 +226,49 @@ TEST(CCOpTest, ColocateWith) { EXPECT_TRUE(attrs.find("_class") == attrs.end()); } +TEST(CCOpTest, TemplatedConst) { + Scope root = Scope::NewRootScope(); + auto c1 = ops::Const(root, {{3, 2}, {-1, 0}}); + TF_EXPECT_OK(root.status()); + + Tensor out; + GetTensor(root, c1, &out); + test::ExpectTensorEqual( + out, test::AsTensor({3.f, 2.f, -1.f, 0.f}, {2, 2})); + + auto c2 = ops::Const(root, {{"this"}, {"is"}, {"a"}, {"constant"}}); + GetTensor(root, c2, &out); + test::ExpectTensorEqual( + out, test::AsTensor({"this", "is", "a", "constant"}, {4, 1})); +} + +TEST(CCOpTest, EmptyConst) { + Scope root = Scope::NewRootScope(); + + auto c1 = ops::Const(root, {}); + TF_CHECK_OK(root.status()); + + Tensor out; + GetTensor(root, c1, &out); + test::ExpectTensorEqual(out, Tensor(DT_FLOAT, {0})); + + auto c2 = ops::Const(root, {{}}); + TF_CHECK_OK(root.status()); + GetTensor(root, c2, &out); + test::ExpectTensorEqual(out, Tensor(DT_FLOAT, {1, 0})); + + auto c3 = ops::Const(root, {{{}, {}}}); + TF_CHECK_OK(root.status()); + GetTensor(root, c3, &out); + test::ExpectTensorEqual(out, Tensor(DT_FLOAT, {1, 2, 0})); + + auto c4 = ops::Const(root, {{{}}}); + TF_CHECK_OK(root.status()); + GetTensor(root, c4, &out); + test::ExpectTensorEqual(out, Tensor(DT_INT32, {1, 1, 0})); + + ops::Const(root, {{}, {{}}}); + EXPECT_FALSE(root.status().ok()); +} + } // namespace tensorflow diff --git a/tensorflow/cc/ops/const_op.h b/tensorflow/cc/ops/const_op.h index 75844d124d9..8976a24edc6 100644 --- a/tensorflow/cc/ops/const_op.h +++ b/tensorflow/cc/ops/const_op.h @@ -25,22 +25,35 @@ namespace ops { Output Const(const Scope& scope, const Input::Initializer& val); +NodeBuilder::NodeOut AsNodeOut(const Scope& scope, const Input& inp); + template Output Const(const Scope& scope, const Input::Initializer& val) { + auto orig_const_output = Const(scope, val); if (!scope.ok()) return Output(); - if (!val.status.ok()) { - scope.UpdateStatus(val.status); - return Output(); - } + typedef typename Input::Initializer::RealType::type DstT; - if (val.tensor.NumElements() > 0) { - // TODO(keveman): Implement the in-situ cast. - scope.UpdateStatus(errors::Unimplemented( - "Explict cast of a non-empty tensor not implemented yet")); - return Output(); + + if (val.tensor.dtype() == DataTypeToEnum::v()) { + return orig_const_output; } - Tensor t(DataTypeToEnum::v(), val.tensor.shape()); - return Const(scope, Input::Initializer(t)); + if (val.tensor.NumElements() == 0) { + Tensor t(DataTypeToEnum::v(), val.tensor.shape()); + return Const(scope, Input::Initializer(t)); + } + + // TODO(keveman): Refactor Cast op's kernel implementation such that the code + // can be directly called here instead of adding the Cast op to the graph. + auto orig_const = AsNodeOut(scope, orig_const_output); + const auto cast_op_name = scope.GetUniqueNameForOp("Cast"); + + auto cast_builder = NodeBuilder(cast_op_name, "Cast") + .Input(orig_const) + .Attr("DstT", DataTypeToEnum::v()); + scope.UpdateBuilder(&cast_builder); + Node* ret; + scope.UpdateStatus(cast_builder.Finalize(scope.graph(), &ret)); + return Output(ret, 0); } template @@ -54,8 +67,6 @@ Output Const(const Scope& scope, const std::initializer_list& v, return Const(scope, Input::Initializer(v, shape)); } -NodeBuilder::NodeOut AsNodeOut(const Scope& scope, const Input& inp); - std::vector AsNodeOutList(const Scope& scope, const InputList& inp); diff --git a/tensorflow/cc/ops/const_op_test.cc b/tensorflow/cc/ops/const_op_test.cc index a56b66c1ccd..5a4770f879f 100644 --- a/tensorflow/cc/ops/const_op_test.cc +++ b/tensorflow/cc/ops/const_op_test.cc @@ -125,4 +125,13 @@ TEST(ConstOpTest, Names) { EXPECT_EQ(c_y_1.node()->name(), "c/y_1"); } +TEST(ConstOpTest, TemplatedConst) { + Scope root = Scope::NewRootScope(); + auto c1 = ops::Const(root, {1, 2}); + ExpectTypeAndShape(c1.node(), DT_INT32, {2}); + + auto c2 = ops::Const(root, {{"this"}, {"is"}, {"a"}, {"constant"}}); + ExpectTypeAndShape(c2.node(), DT_STRING, {4, 1}); +} + } // namespace tensorflow