update version to 2.8.2 for fix cves
This commit is contained in:
parent
418faeda4c
commit
5054ed0154
@ -1,25 +0,0 @@
|
||||
From c6f06c2f1b17508670601894378bb89b71fbe37e Mon Sep 17 00:00:00 2001
|
||||
From: bzhaoopenstack <bzhaojyathousandy@gmail.com>
|
||||
Date: Tue, 23 Jun 2020 12:04:12 +0800
|
||||
Subject: [PATCH] Add arm source file into aws-checksums
|
||||
|
||||
According to https://github.com/tensorflow/tensorflow/issues/40463#issuecomment-647640030 , seem the aws libs need to add the arm related libs during build tensorflow package.
|
||||
---
|
||||
third_party/aws/aws-checksums.bazel | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/third_party/aws/aws-checksums.bazel b/third_party/aws/aws-checksums.bazel
|
||||
index 759cb2e6fc..f620a96d2c 100644
|
||||
--- a/third_party/aws/aws-checksums.bazel
|
||||
+++ b/third_party/aws/aws-checksums.bazel
|
||||
@@ -16,6 +16,7 @@ cc_library(
|
||||
"//conditions:default": [],
|
||||
}) + glob([
|
||||
"source/intel/*.c",
|
||||
+ "source/arm/*.c",
|
||||
"source/*.c",
|
||||
]),
|
||||
hdrs = glob([
|
||||
--
|
||||
2.23.0
|
||||
|
||||
@ -1,26 +0,0 @@
|
||||
From 4a8f3c9bd69320359d3b7f83f8849d54d8b68f94 Mon Sep 17 00:00:00 2001
|
||||
From: Zhipeng Xie <xiezhipeng1@huawei.com>
|
||||
Date: Sun, 12 Jun 2022 23:14:49 +0800
|
||||
Subject: [PATCH] Fix module 'collections' has no attribute 'MutableSequence'
|
||||
|
||||
Signed-off-by: Zhipeng Xie <xiezhipeng1@huawei.com>
|
||||
---
|
||||
com_google_protobuf/python/google/protobuf/pyext/message.cc | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/com_google_protobuf/python/google/protobuf/pyext/message.cc b/com_google_protobuf/python/google/protobuf/pyext/message.cc
|
||||
index 3530a9b37..1c4f33fcd 100755
|
||||
--- a/com_google_protobuf/python/google/protobuf/pyext/message.cc
|
||||
+++ b/com_google_protobuf/python/google/protobuf/pyext/message.cc
|
||||
@@ -2992,7 +2992,7 @@ bool InitProto2MessageModule(PyObject *m) {
|
||||
&RepeatedCompositeContainer_Type));
|
||||
|
||||
// Register them as collections.Sequence
|
||||
- ScopedPyObjectPtr collections(PyImport_ImportModule("collections"));
|
||||
+ ScopedPyObjectPtr collections(PyImport_ImportModule("collections.abc"));
|
||||
if (collections == NULL) {
|
||||
return false;
|
||||
}
|
||||
--
|
||||
2.27.0
|
||||
|
||||
@ -1,48 +0,0 @@
|
||||
From 75ea0b31477d6ba9e990e296bbbd8ca4e7eebadf Mon Sep 17 00:00:00 2001
|
||||
From: Christian Sigg <csigg@google.com>
|
||||
Date: Fri, 26 Jun 2020 05:08:10 -0700
|
||||
Subject: [PATCH] Provide overload to cope with const-ness change of NumPy's
|
||||
PyUFuncGenericFunction.
|
||||
|
||||
See https://github.com/tensorflow/tensorflow/issues/40688, https://github.com/tensorflow/tensorflow/pull/40654.
|
||||
|
||||
PiperOrigin-RevId: 318452381
|
||||
Change-Id: Icc5152f2b020ef19882a49e3c86ac80bbe048d64
|
||||
---
|
||||
tensorflow/python/lib/core/bfloat16.cc | 8 +++++++-
|
||||
1 file changed, 7 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/tensorflow/python/lib/core/bfloat16.cc b/tensorflow/python/lib/core/bfloat16.cc
|
||||
index feb01f11a1a..bb6b720febe 100644
|
||||
--- a/tensorflow/python/lib/core/bfloat16.cc
|
||||
+++ b/tensorflow/python/lib/core/bfloat16.cc
|
||||
@@ -517,7 +517,7 @@ bool RegisterBfloat16Cast(int numpy_type, bool cast_is_safe) {
|
||||
}
|
||||
|
||||
template <typename InType, typename OutType, typename Functor>
|
||||
-void BinaryUFunc(char** args, npy_intp* dimensions, npy_intp* steps,
|
||||
+void BinaryUFunc(char** args, const npy_intp* dimensions, const npy_intp* steps,
|
||||
void* data) {
|
||||
const char* i0 = args[0];
|
||||
const char* i1 = args[1];
|
||||
@@ -532,11 +532,17 @@ void BinaryUFunc(char** args, npy_intp* dimensions, npy_intp* steps,
|
||||
}
|
||||
}
|
||||
|
||||
+// Numpy changed const-ness of PyUFuncGenericFunction, provide overload.
|
||||
template <typename Functor>
|
||||
void CompareUFunc(char** args, npy_intp* dimensions, npy_intp* steps,
|
||||
void* data) {
|
||||
BinaryUFunc<bfloat16, npy_bool, Functor>(args, dimensions, steps, data);
|
||||
}
|
||||
+template <typename Functor>
|
||||
+void CompareUFunc(char** args, const npy_intp* dimensions,
|
||||
+ const npy_intp* steps, void* data) {
|
||||
+ BinaryUFunc<bfloat16, npy_bool, Functor>(args, dimensions, steps, data);
|
||||
+}
|
||||
|
||||
struct Bfloat16EqFunctor {
|
||||
npy_bool operator()(bfloat16 a, bfloat16 b) { return a == b; }
|
||||
--
|
||||
2.27.0
|
||||
|
||||
@ -1,30 +0,0 @@
|
||||
From 178fa5e11b78cf0900ab4a42a81807858c6a1f15 Mon Sep 17 00:00:00 2001
|
||||
From: KumaTea <KumaTea@outlook.com>
|
||||
Date: Wed, 1 Sep 2021 18:31:38 +0800
|
||||
Subject: [PATCH] `distutils` is deprecated in Python 3.10 #51776
|
||||
|
||||
The `distutils` is deprecated in Python 3.10.
|
||||
|
||||
As of #51776, In `python_configure.bzl`, the deprecation message will be printed prior to the include path, causing error on return.
|
||||
---
|
||||
third_party/py/python_configure.bzl | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/third_party/py/python_configure.bzl b/third_party/py/python_configure.bzl
|
||||
index 2f75262ea9f..b41f422e9bd 100644
|
||||
--- a/third_party/py/python_configure.bzl
|
||||
+++ b/third_party/py/python_configure.bzl
|
||||
@@ -155,8 +155,8 @@ def _get_python_include(repository_ctx, python_bin):
|
||||
python_bin,
|
||||
"-c",
|
||||
"from __future__ import print_function;" +
|
||||
- "from distutils import sysconfig;" +
|
||||
- "print(sysconfig.get_python_inc())",
|
||||
+ "import sysconfig;" +
|
||||
+ "print(sysconfig.get_path('include'))",
|
||||
],
|
||||
error_msg = "Problem getting python include path.",
|
||||
error_details = ("Is the Python binary path set up right? " +
|
||||
--
|
||||
2.27.0
|
||||
|
||||
@ -1,53 +0,0 @@
|
||||
From eccb7ec454e6617738554a255d77f08e60ee0808 Mon Sep 17 00:00:00 2001
|
||||
From: Mihai Maruseac <mihaimaruseac@google.com>
|
||||
Date: Mon, 19 Oct 2020 17:56:36 -0700
|
||||
Subject: [PATCH] Prevent segfault in `quantize_and_dequantize`
|
||||
|
||||
---
|
||||
.../core/kernels/quantize_and_dequantize_op.cc | 4 ++++
|
||||
tensorflow/python/kernel_tests/array_ops_test.py | 14 ++++++++++++++
|
||||
2 files changed, 18 insertions(+)
|
||||
|
||||
diff --git a/tensorflow/core/kernels/quantize_and_dequantize_op.cc b/tensorflow/core/kernels/quantize_and_dequantize_op.cc
|
||||
index 8f71d09c..fda54208 100644
|
||||
--- a/tensorflow/core/kernels/quantize_and_dequantize_op.cc
|
||||
+++ b/tensorflow/core/kernels/quantize_and_dequantize_op.cc
|
||||
@@ -71,6 +71,10 @@ class QuantizeAndDequantizeV2Op : public OpKernel {
|
||||
|
||||
void Compute(OpKernelContext* ctx) override {
|
||||
const Tensor& input = ctx->input(0);
|
||||
+ OP_REQUIRES(
|
||||
+ ctx, (axis_ == -1 || axis_ < input.shape().dims()),
|
||||
+ errors::InvalidArgument("Shape must be at least rank", axis_ + 1,
|
||||
+ " but is rank ", input.shape().dims()));
|
||||
const int depth = (axis_ == -1) ? 1 : input.dim_size(axis_);
|
||||
Tensor input_min_tensor;
|
||||
Tensor input_max_tensor;
|
||||
diff --git a/tensorflow/python/kernel_tests/array_ops_test.py b/tensorflow/python/kernel_tests/array_ops_test.py
|
||||
index dbff3a1b..c498ff62 100644
|
||||
--- a/tensorflow/python/kernel_tests/array_ops_test.py
|
||||
+++ b/tensorflow/python/kernel_tests/array_ops_test.py
|
||||
@@ -1541,6 +1541,20 @@ class QuantizeAndDequantizeTest(test_util.TensorFlowTestCase):
|
||||
axis=(axis - 4)))
|
||||
self.assertAllClose(fake_quantized, expected)
|
||||
|
||||
+ def testBadAxis(self):
|
||||
+ input_tensor = [2.5, 2.5]
|
||||
+ input_min = [0, 0]
|
||||
+ input_max = [1, 1]
|
||||
+ error_message_pattern = "Shape must be at least rank 11 but is rank 1"
|
||||
+ # TODO(b/171260356): Eager mode and graph mode throw different error types
|
||||
+ error = errors.InvalidArgumentError if context.executing_eagerly(
|
||||
+ ) else ValueError
|
||||
+ with self.assertRaisesRegex(error, error_message_pattern): self.evaluate(
|
||||
+ array_ops.quantize_and_dequantize_v2(
|
||||
+ input=input_tensor,
|
||||
+ input_min=input_min,
|
||||
+ input_max=input_max,
|
||||
+ axis=10))
|
||||
|
||||
@test_util.run_all_in_graph_and_eager_modes
|
||||
class SortedSearchTest(test_util.TensorFlowTestCase):
|
||||
--
|
||||
2.23.0
|
||||
|
||||
@ -1,67 +0,0 @@
|
||||
From 3ade2efec2e90c6237de32a19680caaa3ebc2845 Mon Sep 17 00:00:00 2001
|
||||
From: Yong Tang <yong.tang.github@outlook.com>
|
||||
Date: Sat, 8 Aug 2020 00:47:35 +0000
|
||||
Subject: [PATCH] Fix segmentation fault in tf.image.crop_and_resize when boxes
|
||||
|
||||
---
|
||||
tensorflow/core/kernels/crop_and_resize_op.cc | 13 +++++++++++++
|
||||
tensorflow/python/ops/image_ops_test.py | 12 ++++++++++++
|
||||
2 files changed, 25 insertions(+)
|
||||
|
||||
diff --git a/tensorflow/core/kernels/crop_and_resize_op.cc b/tensorflow/core/kernels/crop_and_resize_op.cc
|
||||
index 4ecd3bc0..e14f4e43 100644
|
||||
--- a/tensorflow/core/kernels/crop_and_resize_op.cc
|
||||
+++ b/tensorflow/core/kernels/crop_and_resize_op.cc
|
||||
@@ -71,6 +71,18 @@ static inline Status ParseAndCheckBoxSizes(const Tensor& boxes,
|
||||
if (boxes.dim_size(1) != 4) {
|
||||
return errors::InvalidArgument("boxes must have 4 columns");
|
||||
}
|
||||
+ for (int64 i = 0; i < *num_boxes; i++) {
|
||||
+ for (int64 j = 0; j < 4; j++) {
|
||||
+ if (!isfinite(boxes.tensor<float, 2>()(i, j))) {
|
||||
+ return errors::InvalidArgument(
|
||||
+ "boxes values must be finite, received boxes[", i, "]: ",
|
||||
+ boxes.tensor<float, 2>()(i, 0), ", ",
|
||||
+ boxes.tensor<float, 2>()(i, 1), ", ",
|
||||
+ boxes.tensor<float, 2>()(i, 2), ", ",
|
||||
+ boxes.tensor<float, 2>()(i, 3));
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
// The shape of 'box_index' is [num_boxes].
|
||||
if (box_index.dims() != 1) {
|
||||
return errors::InvalidArgument("box_index must be 1-D",
|
||||
@@ -256,6 +268,7 @@ struct CropAndResize<CPUDevice, T> {
|
||||
continue;
|
||||
}
|
||||
if (method_name == "bilinear") {
|
||||
+
|
||||
const int top_y_index = floorf(in_y);
|
||||
const int bottom_y_index = ceilf(in_y);
|
||||
const float y_lerp = in_y - top_y_index;
|
||||
diff --git a/tensorflow/python/ops/image_ops_test.py b/tensorflow/python/ops/image_ops_test.py
|
||||
index 0206ccf9..0630b6fc 100644
|
||||
--- a/tensorflow/python/ops/image_ops_test.py
|
||||
+++ b/tensorflow/python/ops/image_ops_test.py
|
||||
@@ -5275,6 +5275,18 @@ class DecodeImageTest(test_util.TensorFlowTestCase):
|
||||
self.assertAllEqual(list(image0.shape), [40, 20, 3])
|
||||
self.assertAllEqual(image0, image1)
|
||||
|
||||
+ def testImageCropAndResize(self):
|
||||
+ # Test case for GitHub issue 42129
|
||||
+ message = "boxes values must be finite"
|
||||
+ with self.assertRaisesRegex(
|
||||
+ (errors.InvalidArgumentError, ValueError), message):
|
||||
+ v = image_ops_impl.crop_and_resize_v2(
|
||||
+ image=array_ops.zeros((2, 1, 1, 1)),
|
||||
+ boxes=[[1.0e+40, 0, 0, 0]],
|
||||
+ box_indices=[1],
|
||||
+ crop_size=[1, 1])
|
||||
+ self.evaluate(v)
|
||||
+
|
||||
|
||||
if __name__ == "__main__":
|
||||
googletest.main()
|
||||
--
|
||||
2.23.0
|
||||
|
||||
@ -1,62 +0,0 @@
|
||||
From ace0c15a22f7f054abcc1f53eabbcb0a1239a9e2 Mon Sep 17 00:00:00 2001
|
||||
From: Mihai Maruseac <mihaimaruseac@google.com>
|
||||
Date: Tue, 24 Nov 2020 11:40:42 -0800
|
||||
Subject: [PATCH] Default initialize fixed point Eigen types.
|
||||
|
||||
In certain cases, tensors are filled with default values of the type. But, for these fixed point types, these values were uninitialized. Thus, we would have uninitialized memory access bugs, some of which were caught by MSAN.
|
||||
|
||||
PiperOrigin-RevId: 344101137
|
||||
Change-Id: I14555fda74dca3b5f1582da9008901937e3f14e2
|
||||
---
|
||||
.../Eigen/CXX11/src/FixedPoint/FixedPointTypes.h | 10 +++++-----
|
||||
1 file changed, 5 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/third_party/eigen3/unsupported/Eigen/CXX11/src/FixedPoint/FixedPointTypes.h b/third_party/eigen3/unsupported/Eigen/CXX11/src/FixedPoint/FixedPointTypes.h
|
||||
index ff359cedced96..fd35360da2820 100644
|
||||
--- a/third_party/eigen3/unsupported/Eigen/CXX11/src/FixedPoint/FixedPointTypes.h
|
||||
+++ b/third_party/eigen3/unsupported/Eigen/CXX11/src/FixedPoint/FixedPointTypes.h
|
||||
@@ -49,7 +49,7 @@ struct scalar_product_traits<QInt32, double> {
|
||||
// the compiler from silently type cast the mantissa into a bigger or a smaller
|
||||
// representation.
|
||||
struct QInt8 {
|
||||
- QInt8() {}
|
||||
+ QInt8() : value(0) {}
|
||||
QInt8(const int8_t v) : value(v) {}
|
||||
QInt8(const QInt32 v);
|
||||
|
||||
@@ -59,7 +59,7 @@ struct QInt8 {
|
||||
};
|
||||
|
||||
struct QUInt8 {
|
||||
- QUInt8() {}
|
||||
+ QUInt8() : value(0) {}
|
||||
QUInt8(const uint8_t v) : value(v) {}
|
||||
QUInt8(const QInt32 v);
|
||||
|
||||
@@ -69,7 +69,7 @@ struct QUInt8 {
|
||||
};
|
||||
|
||||
struct QInt16 {
|
||||
- QInt16() {}
|
||||
+ QInt16() : value(0) {}
|
||||
QInt16(const int16_t v) : value(v) {}
|
||||
QInt16(const QInt32 v);
|
||||
operator int() const { return static_cast<int>(value); }
|
||||
@@ -78,7 +78,7 @@ struct QInt16 {
|
||||
};
|
||||
|
||||
struct QUInt16 {
|
||||
- QUInt16() {}
|
||||
+ QUInt16() : value(0) {}
|
||||
QUInt16(const uint16_t v) : value(v) {}
|
||||
QUInt16(const QInt32 v);
|
||||
operator int() const { return static_cast<int>(value); }
|
||||
@@ -87,7 +87,7 @@ struct QUInt16 {
|
||||
};
|
||||
|
||||
struct QInt32 {
|
||||
- QInt32() {}
|
||||
+ QInt32() : value(0) {}
|
||||
QInt32(const int8_t v) : value(v) {}
|
||||
QInt32(const int32_t v) : value(v) {}
|
||||
QInt32(const uint32_t v) : value(static_cast<int32_t>(v)) {}
|
||||
@ -1,252 +0,0 @@
|
||||
From 1a11d01c1fdd6683e9aa210dccde81de127dbf3e Mon Sep 17 00:00:00 2001
|
||||
From: Kaixi Hou <kaixih@nvidia.com>
|
||||
Date: Mon, 14 Sep 2020 15:52:22 -0700
|
||||
Subject: [PATCH 1/1] support reduce ops for 5d tensors in layout optimizer
|
||||
|
||||
---
|
||||
.../generic_layout_optimizer_transposer.cc | 27 +++++++++-
|
||||
tensorflow/core/kernels/data_format_ops.cc | 10 ++--
|
||||
tensorflow/core/kernels/data_format_ops.h | 53 ++++++++++++++-----
|
||||
.../python/grappler/layout_optimizer_test.py | 39 ++++++++++++++
|
||||
tensorflow/python/ops/nn_test.py | 27 ++++++++++
|
||||
5 files changed, 136 insertions(+), 20 deletions(-)
|
||||
|
||||
diff --git a/tensorflow/core/grappler/optimizers/generic_layout_optimizer_transposer.cc b/tensorflow/core/grappler/optimizers/generic_layout_optimizer_transposer.cc
|
||||
index ab7d8fcd..fbbeffc7 100644
|
||||
--- a/tensorflow/core/grappler/optimizers/generic_layout_optimizer_transposer.cc
|
||||
+++ b/tensorflow/core/grappler/optimizers/generic_layout_optimizer_transposer.cc
|
||||
@@ -1283,11 +1283,31 @@ bool ReduceTransposer::IsReduceAxisSupported(
|
||||
Status ReduceTransposer::TransposeNode(TransposeContext* context,
|
||||
utils::MutableNodeView* node) {
|
||||
DCHECK(IsReduceOp(*node->node()));
|
||||
- if (!ShouldProcess(*context, *node) || !IsFaninPortRankN(*node, 0, 4) ||
|
||||
+ const auto* output_shape_attr = node->GetAttr(kAttrOutputShape);
|
||||
+ const auto& shape = output_shape_attr->list().shape(0);
|
||||
+ const int rank = shape.dim_size();
|
||||
+ std::string src_format = context->src_format;
|
||||
+ std::string dst_format = context->dst_format;
|
||||
+ // Update the format from 4D to 5D layout if necessary.
|
||||
+ if (rank == 5) {
|
||||
+ std::string src_format_3d = src_format == "NHWC" ? "NDHWC" : "NCDHW";
|
||||
+ std::string dst_format_3d = dst_format == "NHWC" ? "NDHWC" : "NCDHW";
|
||||
+ context->AssignDeviceAndDataFormats(context->target_device, src_format_3d,
|
||||
+ dst_format_3d);
|
||||
+ }
|
||||
+ if (!ShouldProcess(*context, *node) || !IsFaninPortRankN(*node, 0, rank) ||
|
||||
!IsReduceAxisSupported(*context, *node) ||
|
||||
!IsAfterDstToSrcTransform(*context, *node)) {
|
||||
+ // Change back to the original layout due to early exit.
|
||||
+ if (rank == 5) {
|
||||
+ context->AssignDeviceAndDataFormats(context->target_device, src_format,
|
||||
+ dst_format);
|
||||
+ }
|
||||
return Status::OK();
|
||||
}
|
||||
+ VLOG(3) << "GenericLayoutOptimizer: transforming node '" << node->GetName()
|
||||
+ << "' with op '" << node->GetOp() << "' from data format '"
|
||||
+ << context->src_format << "' to '" << context->dst_format << "'";
|
||||
TF_RETURN_IF_ERROR(UpdateFaninEdgesWithOp(context, {0}, node, kOpTranspose));
|
||||
TF_RETURN_IF_ERROR(
|
||||
UpdateFaninEdgesWithOp(context, {1}, node, kOpDataFormatDimMap));
|
||||
@@ -1295,6 +1315,11 @@ Status ReduceTransposer::TransposeNode(TransposeContext* context,
|
||||
TF_RETURN_IF_ERROR(
|
||||
UpdateFanoutEdgesWithOp(context, {0}, node, kOpTranspose));
|
||||
}
|
||||
+ // Change back the format from 5D to 4D layout.
|
||||
+ if (rank == 5) {
|
||||
+ context->AssignDeviceAndDataFormats(context->target_device, src_format,
|
||||
+ dst_format);
|
||||
+ }
|
||||
return context->graph_view->GetMutationBuilder()->Apply();
|
||||
}
|
||||
|
||||
diff --git a/tensorflow/core/kernels/data_format_ops.cc b/tensorflow/core/kernels/data_format_ops.cc
|
||||
index 181aa1b8..e9c71f17 100644
|
||||
--- a/tensorflow/core/kernels/data_format_ops.cc
|
||||
+++ b/tensorflow/core/kernels/data_format_ops.cc
|
||||
@@ -37,14 +37,14 @@ class DataFormatDimMapOp : public OpKernel {
|
||||
OP_REQUIRES_OK(context, context->GetAttr("src_format", &src_format));
|
||||
string dst_format;
|
||||
OP_REQUIRES_OK(context, context->GetAttr("dst_format", &dst_format));
|
||||
- OP_REQUIRES(context, src_format.size() == 4,
|
||||
+ OP_REQUIRES(context, src_format.size() == 4 || src_format.size() == 5,
|
||||
errors::InvalidArgument(strings::StrCat(
|
||||
- "Source format must of length 4, received src_format = ",
|
||||
- src_format)));
|
||||
+ "Source format must of length 4 or 5, received "
|
||||
+ "src_format = ", src_format)));
|
||||
OP_REQUIRES(
|
||||
- context, dst_format.size() == 4,
|
||||
+ context, dst_format.size() == 4 || dst_format.size() == 5,
|
||||
errors::InvalidArgument(strings::StrCat(
|
||||
- "Destination format must of length 4, received dst_format = ",
|
||||
+ "Destination format must of length 4 or 5, received dst_format = ",
|
||||
dst_format)));
|
||||
dst_idx_ = Tensor(DT_INT32, {static_cast<int64>(src_format.size())});
|
||||
for (int i = 0; i < src_format.size(); ++i) {
|
||||
diff --git a/tensorflow/core/kernels/data_format_ops.h b/tensorflow/core/kernels/data_format_ops.h
|
||||
index bc416fa7..89b54901 100644
|
||||
--- a/tensorflow/core/kernels/data_format_ops.h
|
||||
+++ b/tensorflow/core/kernels/data_format_ops.h
|
||||
@@ -28,24 +28,49 @@ template <typename Device, typename T>
|
||||
struct DataFormatDimMap {
|
||||
void operator()(const Device& d, typename TTypes<T>::ConstFlat x,
|
||||
typename TTypes<T>::Flat y, const TTypes<int>::Vec dst) {
|
||||
- auto zero = x.constant(0);
|
||||
- auto one = x.constant(1);
|
||||
- auto two = x.constant(2);
|
||||
+ if (dst.size() == 4) {
|
||||
+ auto zero = x.constant(0);
|
||||
+ auto one = x.constant(1);
|
||||
+ auto two = x.constant(2);
|
||||
|
||||
- auto f_zero = x.constant(dst(0));
|
||||
- auto f_one = x.constant(dst(1));
|
||||
- auto f_two = x.constant(dst(2));
|
||||
- auto f_three = x.constant(dst(3));
|
||||
+ auto f_zero = x.constant(dst(0));
|
||||
+ auto f_one = x.constant(dst(1));
|
||||
+ auto f_two = x.constant(dst(2));
|
||||
+ auto f_three = x.constant(dst(3));
|
||||
|
||||
- auto four = x.constant(4);
|
||||
- auto x_mod = (x + four) % 4;
|
||||
+ auto four = x.constant(4);
|
||||
+ auto x_mod = (x + four) % 4;
|
||||
|
||||
- auto is_zero = (x_mod == zero);
|
||||
- auto is_one = (x_mod == one);
|
||||
- auto is_two = (x_mod == two);
|
||||
+ auto is_zero = (x_mod == zero);
|
||||
+ auto is_one = (x_mod == one);
|
||||
+ auto is_two = (x_mod == two);
|
||||
|
||||
- y.device(d) = is_zero.select(
|
||||
- f_zero, is_one.select(f_one, is_two.select(f_two, f_three)));
|
||||
+ y.device(d) = is_zero.select(
|
||||
+ f_zero, is_one.select(f_one, is_two.select(f_two, f_three)));
|
||||
+ } else {
|
||||
+ auto zero = x.constant(0);
|
||||
+ auto one = x.constant(1);
|
||||
+ auto two = x.constant(2);
|
||||
+ auto three = x.constant(3);
|
||||
+
|
||||
+ auto f_zero = x.constant(dst(0));
|
||||
+ auto f_one = x.constant(dst(1));
|
||||
+ auto f_two = x.constant(dst(2));
|
||||
+ auto f_three = x.constant(dst(3));
|
||||
+ auto f_four = x.constant(dst(4));
|
||||
+
|
||||
+ auto five = x.constant(5);
|
||||
+ auto x_mod = (x + five) % 5;
|
||||
+
|
||||
+ auto is_zero = (x_mod == zero);
|
||||
+ auto is_one = (x_mod == one);
|
||||
+ auto is_two = (x_mod == two);
|
||||
+ auto is_three = (x_mod == three);
|
||||
+
|
||||
+ y.device(d) = is_zero.select(
|
||||
+ f_zero, is_one.select(f_one, is_two.select(f_two,
|
||||
+ is_three.select(f_three, f_four))));
|
||||
+ }
|
||||
}
|
||||
};
|
||||
|
||||
diff --git a/tensorflow/python/grappler/layout_optimizer_test.py b/tensorflow/python/grappler/layout_optimizer_test.py
|
||||
index 10f86980..f90da7ed 100644
|
||||
--- a/tensorflow/python/grappler/layout_optimizer_test.py
|
||||
+++ b/tensorflow/python/grappler/layout_optimizer_test.py
|
||||
@@ -215,6 +215,9 @@ class LayoutOptimizerTest(test.TestCase):
|
||||
def _assert_map_nhwc_to_nchw(self, name, nodes):
|
||||
self.assertIn(name + '-DimMapNHWCToNCHW-LayoutOptimizer', nodes)
|
||||
|
||||
+ def _assert_map_ndhwc_to_ncdhw(self, name, nodes):
|
||||
+ self.assertIn(name + '-DataFormatDimMapNDHWCToNCDHW-LayoutOptimizer', nodes)
|
||||
+
|
||||
def _assert_vec_nchw_to_nhwc(self, name, nodes):
|
||||
self.assertIn(name + '-VecPermuteNCHWToNHWC-LayoutOptimizer', nodes)
|
||||
|
||||
@@ -286,6 +289,42 @@ class LayoutOptimizerTest(test.TestCase):
|
||||
|
||||
self.assertAllClose(output_val_ref, output_val, atol=1e-3)
|
||||
|
||||
+ @test_util.deprecated_graph_mode_only
|
||||
+ def testReduceOpsFor5DTensors(self):
|
||||
+ if test.is_gpu_available(cuda_only=True):
|
||||
+ random_seed.set_random_seed(0)
|
||||
+ x = random_ops.truncated_normal([1, 4, 2, 3, 3], seed=0)
|
||||
+ w = random_ops.truncated_normal([2, 2, 2, 3, 3], seed=0)
|
||||
+ gamma = random_ops.truncated_normal([1, 1, 1, 1, 3], seed=0)
|
||||
+ beta = random_ops.truncated_normal([1, 1, 1, 1, 3], seed=0)
|
||||
+ conv3d = gen_nn_ops.conv3d(x, w, [1, 1, 1, 1, 1], 'SAME')
|
||||
+ y = math_ops.reduce_mean(conv3d, [0, 1, 2, 3], keepdims=True)
|
||||
+ output = array_ops.identity(y)
|
||||
+
|
||||
+ with session.Session(config=_get_config(False)) as sess:
|
||||
+ output_val_ref = sess.run(output)
|
||||
+
|
||||
+ with session.Session(config=_get_config()) as sess:
|
||||
+ metadata = config_pb2.RunMetadata()
|
||||
+ output_val = sess.run(output, run_metadata=metadata)
|
||||
+
|
||||
+ nodes = []
|
||||
+ num_transposes = 0
|
||||
+ for node in metadata.cost_graph.node:
|
||||
+ if _is_transpose(node.name):
|
||||
+ num_transposes += 1
|
||||
+ nodes.append(node.name)
|
||||
+ print(node.name)
|
||||
+
|
||||
+ # The reduce op Mean needs to dim map the input reduce index to NCDHW.
|
||||
+ # Then, the output needs to be tranposed back to NDHWC.
|
||||
+ expected_num_transposes = 2
|
||||
+ self.assertEqual(expected_num_transposes, num_transposes)
|
||||
+ self._assert_trans_ndhwc_to_ncdhw('Conv3D-0', nodes)
|
||||
+ self._assert_map_ndhwc_to_ncdhw('Mean-1', nodes)
|
||||
+ self._assert_trans_ncdhw_to_ndhwc('Mean-0-0', nodes)
|
||||
+ self.assertAllClose(output_val_ref, output_val, atol=1e-3)
|
||||
+
|
||||
@test_util.deprecated_graph_mode_only
|
||||
def testSplitWithNonConstAxis(self):
|
||||
if test.is_gpu_available(cuda_only=True):
|
||||
diff --git a/tensorflow/python/ops/nn_test.py b/tensorflow/python/ops/nn_test.py
|
||||
index bfe11b63..55d11a35 100644
|
||||
--- a/tensorflow/python/ops/nn_test.py
|
||||
+++ b/tensorflow/python/ops/nn_test.py
|
||||
@@ -1207,6 +1207,33 @@ class DataFormatDimMapTest(test_lib.TestCase):
|
||||
y_val = self.evaluate(y)
|
||||
self.assertAllEqual(y_val, y_val_expected)
|
||||
|
||||
+ def testNDHWCtoNCDHW(self):
|
||||
+ x_val = [1, -4, -3, -2]
|
||||
+ y_val_expected = [2, 2, 3, 4]
|
||||
+ x = constant_op.constant(x_val)
|
||||
+ y = nn_ops.data_format_dim_map(x, src_format="NDHWC", dst_format="NCDHW")
|
||||
+ with test_util.use_gpu():
|
||||
+ y_val = self.evaluate(y)
|
||||
+ self.assertAllEqual(y_val, y_val_expected)
|
||||
+
|
||||
+ def testNDHWCtoDHWNC(self):
|
||||
+ x_val = [-5, -4, -3, -2, -1, 0, 1, 2, 3, 4]
|
||||
+ y_val_expected = [3, 0, 1, 2, 4, 3, 0, 1, 2, 4]
|
||||
+ x = constant_op.constant(x_val)
|
||||
+ y = nn_ops.data_format_dim_map(x, src_format="NDHWC", dst_format="DHWNC")
|
||||
+ with test_util.use_gpu():
|
||||
+ y_val = self.evaluate(y)
|
||||
+ self.assertAllEqual(y_val, y_val_expected)
|
||||
+
|
||||
+ def testDNHWCtoWHDCN(self):
|
||||
+ x_val = [-5, -4, -3, -2, -1, 0, 1, 2, 3, 4]
|
||||
+ y_val_expected = [4, 2, 1, 0, 3, 4, 2, 1, 0, 3]
|
||||
+ x = constant_op.constant(x_val)
|
||||
+ y = nn_ops.data_format_dim_map(x, src_format="NDHWC", dst_format="WHDCN")
|
||||
+ with test_util.use_gpu():
|
||||
+ y_val = self.evaluate(y)
|
||||
+ self.assertAllEqual(y_val, y_val_expected)
|
||||
+
|
||||
def testArbitraryASCII(self):
|
||||
x_val = [-4, -3, -2, -1, 0, 1, 2, 3]
|
||||
y_val_expected = [3, 2, 1, 0, 3, 2, 1, 0]
|
||||
--
|
||||
2.27.0
|
||||
|
||||
@ -1,266 +0,0 @@
|
||||
From ebc70b7a592420d3d2f359e4b1694c236b82c7ae Mon Sep 17 00:00:00 2001
|
||||
From: Mihai Maruseac <mihaimaruseac@google.com>
|
||||
Date: Mon, 7 Dec 2020 11:15:21 -0800
|
||||
Subject: [PATCH] Validate that `DataFormat*` attributes form a permutation.
|
||||
|
||||
The `src_format` and `dst_format` attributes for the `DataFormatDimMap` and `DataFormatVecPermute` raw ops are supposed to determine a permutation. However, this was not validated and could result in unitialized memory accesses as well as writes outside of bounds and potential crashes.
|
||||
|
||||
While here, we also test that the format attributes have the needed length, add tests for all validation failure cases, remove unnecessary calls to `strings::StrCat`, and fix a few grammar errors.
|
||||
|
||||
This will be cherry-picked on the supported release branches.
|
||||
|
||||
PiperOrigin-RevId: 346135579
|
||||
Change-Id: I1c76392382c89ad8f072d5bc93d70669851eb404
|
||||
---
|
||||
tensorflow/core/kernels/data_format_ops.cc | 72 ++++++++++++++--
|
||||
tensorflow/python/ops/nn_test.py | 96 ++++++++++++++++++++++
|
||||
2 files changed, 161 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/tensorflow/core/kernels/data_format_ops.cc b/tensorflow/core/kernels/data_format_ops.cc
|
||||
index e9c71f17..abe2fbc3 100644
|
||||
--- a/tensorflow/core/kernels/data_format_ops.cc
|
||||
+++ b/tensorflow/core/kernels/data_format_ops.cc
|
||||
@@ -18,16 +18,52 @@ limitations under the License.
|
||||
#define EIGEN_USE_THREADS
|
||||
|
||||
#include "tensorflow/core/kernels/data_format_ops.h"
|
||||
+
|
||||
+#include <map>
|
||||
+
|
||||
#include "third_party/eigen3/unsupported/Eigen/CXX11/Tensor"
|
||||
#include "tensorflow/core/framework/op_kernel.h"
|
||||
#include "tensorflow/core/framework/register_types.h"
|
||||
#include "tensorflow/core/framework/tensor.h"
|
||||
+#include "tensorflow/core/platform/errors.h"
|
||||
|
||||
namespace tensorflow {
|
||||
|
||||
typedef Eigen::ThreadPoolDevice CPUDevice;
|
||||
typedef Eigen::GpuDevice GPUDevice;
|
||||
|
||||
+// Ensure that `src` and `dst` define a valid permutation.
|
||||
+// Ops defined in this file assume that user specifies a permutation via two
|
||||
+// string attributes. This check validates that these attributes properly define
|
||||
+// it to prevent security vulnerabilities.
|
||||
+static bool IsValidPermutation(const std::string& src, const std::string& dst) {
|
||||
+ if (src.size() != dst.size()) {
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ std::map<char, bool> characters;
|
||||
+
|
||||
+ // Every character in `src` must be present only once
|
||||
+ for (const auto c : src) {
|
||||
+ if (characters[c]) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ characters[c] = true;
|
||||
+ }
|
||||
+
|
||||
+ // Every character in `dst` must show up in `src` exactly once
|
||||
+ for (const auto c : dst) {
|
||||
+ if (!characters[c]) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ characters[c] = false;
|
||||
+ }
|
||||
+
|
||||
+ // At this point, characters[] has been switched to true and false exactly
|
||||
+ // once for all character in `src` (and `dst`) so we have a valid permutation
|
||||
+ return true;
|
||||
+}
|
||||
+
|
||||
template <typename Device, typename T>
|
||||
class DataFormatDimMapOp : public OpKernel {
|
||||
public:
|
||||
@@ -38,14 +74,18 @@ class DataFormatDimMapOp : public OpKernel {
|
||||
string dst_format;
|
||||
OP_REQUIRES_OK(context, context->GetAttr("dst_format", &dst_format));
|
||||
OP_REQUIRES(context, src_format.size() == 4 || src_format.size() == 5,
|
||||
- errors::InvalidArgument(strings::StrCat(
|
||||
- "Source format must of length 4 or 5, received "
|
||||
- "src_format = ", src_format)));
|
||||
+ errors::InvalidArgument(
|
||||
+ "Source format must be of length 4 or 5, received "
|
||||
+ "src_format = ", src_format));
|
||||
+ OP_REQUIRES(context, dst_format.size() == 4 || dst_format.size() == 5,
|
||||
+ errors::InvalidArgument("Destination format must be of length "
|
||||
+ "4 or 5, received dst_format = ",
|
||||
+ dst_format));
|
||||
OP_REQUIRES(
|
||||
- context, dst_format.size() == 4 || dst_format.size() == 5,
|
||||
- errors::InvalidArgument(strings::StrCat(
|
||||
- "Destination format must of length 4 or 5, received dst_format = ",
|
||||
- dst_format)));
|
||||
+ context, IsValidPermutation(src_format, dst_format),
|
||||
+ errors::InvalidArgument(
|
||||
+ "Destination and source format must determine a permutation, got ",
|
||||
+ src_format, " and ", dst_format));
|
||||
dst_idx_ = Tensor(DT_INT32, {static_cast<int64>(src_format.size())});
|
||||
for (int i = 0; i < src_format.size(); ++i) {
|
||||
for (int j = 0; j < dst_format.size(); ++j) {
|
||||
@@ -77,8 +117,22 @@ class DataFormatVecPermuteOp : public OpKernel {
|
||||
: OpKernel(context) {
|
||||
string src_format;
|
||||
OP_REQUIRES_OK(context, context->GetAttr("src_format", &src_format));
|
||||
+ OP_REQUIRES(context, src_format.size() == 4 || src_format.size() == 5,
|
||||
+ errors::InvalidArgument(
|
||||
+ "Source format must be of length 4 or 5, received "
|
||||
+ "src_format = ",
|
||||
+ src_format));
|
||||
string dst_format;
|
||||
OP_REQUIRES_OK(context, context->GetAttr("dst_format", &dst_format));
|
||||
+ OP_REQUIRES(context, dst_format.size() == 4 || dst_format.size() == 5,
|
||||
+ errors::InvalidArgument("Destination format must be of length "
|
||||
+ "4 or 5, received dst_format = ",
|
||||
+ dst_format));
|
||||
+ OP_REQUIRES(
|
||||
+ context, IsValidPermutation(src_format, dst_format),
|
||||
+ errors::InvalidArgument(
|
||||
+ "Destination and source format must determine a permutation, got ",
|
||||
+ src_format, " and ", dst_format));
|
||||
src_format_ = src_format;
|
||||
dst_format_ = dst_format;
|
||||
}
|
||||
@@ -124,6 +178,10 @@ class DataFormatVecPermuteOp : public OpKernel {
|
||||
};
|
||||
keep_only_spatial_dimensions(&src_format_str);
|
||||
keep_only_spatial_dimensions(&dst_format_str);
|
||||
+ OP_REQUIRES(context,
|
||||
+ src_format_str.size() == 2 && dst_format_str.size() == 2,
|
||||
+ errors::InvalidArgument(
|
||||
+ "Format specifier must contain H and W for 2D case"));
|
||||
}
|
||||
ComputeDstIndex(src_format_str, dst_format_str, input.dims(), &dst_idx);
|
||||
|
||||
diff --git a/tensorflow/python/ops/nn_test.py b/tensorflow/python/ops/nn_test.py
|
||||
index 55d11a35..d2094a7d 100644
|
||||
--- a/tensorflow/python/ops/nn_test.py
|
||||
+++ b/tensorflow/python/ops/nn_test.py
|
||||
@@ -27,6 +27,7 @@ from six.moves import xrange # pylint: disable=redefined-builtin
|
||||
from tensorflow.python.eager import def_function
|
||||
from tensorflow.python.framework import constant_op
|
||||
from tensorflow.python.framework import dtypes
|
||||
+from tensorflow.python.framework import errors
|
||||
from tensorflow.python.framework import ops
|
||||
from tensorflow.python.framework import tensor_spec
|
||||
from tensorflow.python.framework import test_util
|
||||
@@ -1234,6 +1235,7 @@ class DataFormatDimMapTest(test_lib.TestCase):
|
||||
y_val = self.evaluate(y)
|
||||
self.assertAllEqual(y_val, y_val_expected)
|
||||
|
||||
+ @test_util.disable_xla("XLA catches the error and rethrows as different one")
|
||||
def testArbitraryASCII(self):
|
||||
x_val = [-4, -3, -2, -1, 0, 1, 2, 3]
|
||||
y_val_expected = [3, 2, 1, 0, 3, 2, 1, 0]
|
||||
@@ -1243,6 +1245,46 @@ class DataFormatDimMapTest(test_lib.TestCase):
|
||||
y_val = self.evaluate(y)
|
||||
self.assertAllEqual(y_val, y_val_expected)
|
||||
|
||||
+ @test_util.disable_xla("XLA catches the error and rethrows as different one")
|
||||
+ def testInvalidLength(self):
|
||||
+ x = [-4, -3, -2, -1, 0, 1, 2, 3]
|
||||
+ with self.assertRaisesRegex(errors.InvalidArgumentError,
|
||||
+ "Source format must be of length 4 or 5"):
|
||||
+ op = nn_ops.data_format_dim_map(
|
||||
+ x, src_format="12345678", dst_format="87654321")
|
||||
+ with test_util.use_gpu():
|
||||
+ self.evaluate(op)
|
||||
+
|
||||
+ @test_util.disable_xla("XLA catches the error and rethrows as different one")
|
||||
+ def testDuplicateSrc(self):
|
||||
+ x = [-4, -3, -2, -1, 0, 1, 2, 3]
|
||||
+ with self.assertRaisesRegex(
|
||||
+ errors.InvalidArgumentError,
|
||||
+ "Destination and source format must determine a permutation"):
|
||||
+ op = nn_ops.data_format_dim_map(x, src_format="1233", dst_format="4321")
|
||||
+ with test_util.use_gpu():
|
||||
+ self.evaluate(op)
|
||||
+
|
||||
+ @test_util.disable_xla("XLA catches the error and rethrows as different one")
|
||||
+ def testDuplicateDst(self):
|
||||
+ x = [-4, -3, -2, -1, 0, 1, 2, 3]
|
||||
+ with self.assertRaisesRegex(
|
||||
+ errors.InvalidArgumentError,
|
||||
+ "Destination and source format must determine a permutation"):
|
||||
+ op = nn_ops.data_format_dim_map(x, src_format="1234", dst_format="3321")
|
||||
+ with test_util.use_gpu():
|
||||
+ self.evaluate(op)
|
||||
+
|
||||
+ @test_util.disable_xla("XLA catches the error and rethrows as different one")
|
||||
+ def testExtraSpecifiers(self):
|
||||
+ x = [-4, -3, -2, -1, 0, 1, 2, 3]
|
||||
+ with self.assertRaisesRegex(
|
||||
+ errors.InvalidArgumentError,
|
||||
+ "Destination and source format must determine a permutation"):
|
||||
+ op = nn_ops.data_format_dim_map(x, src_format="1234", dst_format="5321")
|
||||
+ with test_util.use_gpu():
|
||||
+ self.evaluate(op)
|
||||
+
|
||||
|
||||
class DataFormatVectorPermuteTest(test_lib.TestCase):
|
||||
|
||||
@@ -1344,6 +1386,60 @@ class DataFormatVectorPermuteTest(test_lib.TestCase):
|
||||
y_val = self.evaluate(y)
|
||||
self.assertAllEqual(y_val, [[7, 4], [4, 5], [5, 1], [9, 3]])
|
||||
|
||||
+ @test_util.disable_xla("XLA catches the error and rethrows as different one")
|
||||
+ def testInvalidLength(self):
|
||||
+ x = [0, 1, 2, 3]
|
||||
+ with self.assertRaisesRegex(errors.InvalidArgumentError,
|
||||
+ "Source format must be of length 4 or 5"):
|
||||
+ op = nn_ops.data_format_vec_permute(
|
||||
+ x, src_format="12345678", dst_format="87654321")
|
||||
+ with test_util.use_gpu():
|
||||
+ self.evaluate(op)
|
||||
+
|
||||
+ @test_util.disable_xla("XLA catches the error and rethrows as different one")
|
||||
+ def testDuplicateSrc(self):
|
||||
+ x = [0, 1, 2, 3]
|
||||
+ with self.assertRaisesRegex(
|
||||
+ errors.InvalidArgumentError,
|
||||
+ "Destination and source format must determine a permutation"):
|
||||
+ op = nn_ops.data_format_vec_permute(
|
||||
+ x, src_format="1233", dst_format="4321")
|
||||
+ with test_util.use_gpu():
|
||||
+ self.evaluate(op)
|
||||
+
|
||||
+ @test_util.disable_xla("XLA catches the error and rethrows as different one")
|
||||
+ def testDuplicateDst(self):
|
||||
+ x = [0, 1, 2, 3]
|
||||
+ with self.assertRaisesRegex(
|
||||
+ errors.InvalidArgumentError,
|
||||
+ "Destination and source format must determine a permutation"):
|
||||
+ op = nn_ops.data_format_vec_permute(
|
||||
+ x, src_format="1234", dst_format="3321")
|
||||
+ with test_util.use_gpu():
|
||||
+ self.evaluate(op)
|
||||
+
|
||||
+ @test_util.disable_xla("XLA catches the error and rethrows as different one")
|
||||
+ def testExtraSpecifiers(self):
|
||||
+ x = [0, 1, 2, 3]
|
||||
+ with self.assertRaisesRegex(
|
||||
+ errors.InvalidArgumentError,
|
||||
+ "Destination and source format must determine a permutation"):
|
||||
+ op = nn_ops.data_format_vec_permute(
|
||||
+ x, src_format="1234", dst_format="5321")
|
||||
+ with test_util.use_gpu():
|
||||
+ self.evaluate(op)
|
||||
+
|
||||
+ @test_util.disable_xla("XLA catches the error and rethrows as different one")
|
||||
+ def test2DNoWH(self):
|
||||
+ x = [[0, 1], [2, 3]]
|
||||
+ with self.assertRaisesRegex(
|
||||
+ errors.InvalidArgumentError,
|
||||
+ "Format specifier must contain H and W for 2D case"):
|
||||
+ op = nn_ops.data_format_vec_permute(
|
||||
+ x, src_format="1234", dst_format="4321")
|
||||
+ with test_util.use_gpu():
|
||||
+ self.evaluate(op)
|
||||
+
|
||||
|
||||
@test_util.run_all_in_graph_and_eager_modes
|
||||
class AvgPoolTest(test_lib.TestCase):
|
||||
--
|
||||
2.27.0
|
||||
|
||||
@ -1,32 +0,0 @@
|
||||
From c1e1fc899ad5f8c725dcbb6470069890b5060bc7 Mon Sep 17 00:00:00 2001
|
||||
From: Mihai Maruseac <mihaimaruseac@google.com>
|
||||
Date: Fri, 4 Dec 2020 17:06:23 -0800
|
||||
Subject: [PATCH] Mark `MemmappedTensorAllocator` as returning opaque handle.
|
||||
|
||||
This allocator is used for `ImmutableConstantOp` and it returns a handle to the contents of a memory mapped file which is supposed to represent a tensor.
|
||||
|
||||
For tensors of complex types (resources, variables and strings), allocators which are not marked as returning opaque handles will call placement new to initialize each element. This means writing to the buffer. However, in our case, the buffer is immutable and already contains the tensor data. Hence, writing to it is both destructive and causes a crash.
|
||||
|
||||
PiperOrigin-RevId: 345786451
|
||||
Change-Id: I46369c50fa60b3431709ffe068a728d3061f49c4
|
||||
---
|
||||
tensorflow/core/kernels/immutable_constant_op.cc | 6 ++++++
|
||||
1 file changed, 6 insertions(+)
|
||||
|
||||
diff --git a/tensorflow/core/kernels/immutable_constant_op.cc b/tensorflow/core/kernels/immutable_constant_op.cc
|
||||
index 0dd08c694eb6c..1cfbdb8277891 100644
|
||||
--- a/tensorflow/core/kernels/immutable_constant_op.cc
|
||||
+++ b/tensorflow/core/kernels/immutable_constant_op.cc
|
||||
@@ -62,6 +62,12 @@ class MemmappedTensorAllocator : public Allocator {
|
||||
|
||||
void set_delete_on_deallocate() { delete_on_deallocate_ = true; }
|
||||
|
||||
+ // Make sure tensors or complex types (strings, variants, resources) don't get
|
||||
+ // their constructor called via a placement new since that would require
|
||||
+ // writing to immutable data.
|
||||
+ // See also: tensorflow/core/framework/typed_allocator.h
|
||||
+ bool AllocatesOpaqueHandle() const override { return true; }
|
||||
+
|
||||
private:
|
||||
std::unique_ptr<ReadOnlyMemoryRegion> memory_region_;
|
||||
// If there is an error during allocation we keep it in this status.
|
||||
@ -1,40 +0,0 @@
|
||||
From 14755416e364f17fb1870882fa778c7fec7f16e3 Mon Sep 17 00:00:00 2001
|
||||
From: Mihai Maruseac <mihaimaruseac@google.com>
|
||||
Date: Mon, 7 Dec 2020 20:31:31 -0800
|
||||
Subject: [PATCH] Prevent CHECK-fail in LSTM/GRU with zero-length input.
|
||||
|
||||
PiperOrigin-RevId: 346239181
|
||||
Change-Id: I5f233dbc076aab7bb4e31ba24f5abd4eaf99ea4f
|
||||
---
|
||||
tensorflow/stream_executor/cuda/cuda_dnn.cc | 8 ++++++--
|
||||
1 file changed, 6 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/tensorflow/stream_executor/cuda/cuda_dnn.cc b/tensorflow/stream_executor/cuda/cuda_dnn.cc
|
||||
index a97850bd..5ae19f27 100644
|
||||
--- a/tensorflow/stream_executor/cuda/cuda_dnn.cc
|
||||
+++ b/tensorflow/stream_executor/cuda/cuda_dnn.cc
|
||||
@@ -1474,7 +1474,9 @@ class CudnnRnnSequenceTensorDescriptor
|
||||
static port::StatusOr<CudnnRnnSequenceTensorDescriptor> Create(
|
||||
GpuExecutor* parent, int max_seq_length, int batch_size, int data_size,
|
||||
cudnnDataType_t data_type) {
|
||||
- CHECK_GT(max_seq_length, 0);
|
||||
+ if (max_seq_length <= 0) {
|
||||
+ return port::Status(port::error::INVALID_ARGUMENT, "max_seq_length <= 0");
|
||||
+ }
|
||||
int dims[] = {batch_size, data_size, 1};
|
||||
int strides[] = {dims[1] * dims[2], dims[2], 1};
|
||||
TensorDescriptor tensor_desc = CreateTensorDescriptor();
|
||||
@@ -1495,7 +1497,9 @@ class CudnnRnnSequenceTensorDescriptor
|
||||
const absl::Span<const int>& seq_lengths, bool time_major,
|
||||
cudnnDataType_t data_type) {
|
||||
#if CUDNN_VERSION >= 7201
|
||||
- CHECK_GT(max_seq_length, 0);
|
||||
+ if (max_seq_length <= 0) {
|
||||
+ return port::Status(port::error::INVALID_ARGUMENT, "max_seq_length <= 0");
|
||||
+ }
|
||||
int dims[] = {batch_size, data_size, 1};
|
||||
int strides[] = {dims[1] * dims[2], dims[2], 1};
|
||||
TensorDescriptor tensor_desc = CreateTensorDescriptor();
|
||||
--
|
||||
2.27.0
|
||||
|
||||
@ -1,44 +0,0 @@
|
||||
From 0cc38aaa4064fd9e79101994ce9872c6d91f816b Mon Sep 17 00:00:00 2001
|
||||
From: Mihai Maruseac <mihaimaruseac@google.com>
|
||||
Date: Tue, 8 Dec 2020 09:31:57 -0800
|
||||
Subject: [PATCH] Prevent unitialized memory access in
|
||||
`GraphConstructor::MakeEdge`
|
||||
|
||||
The `MakeEdge` implementation assumes that there exists an output at `output_index` of `src` node and an input at `input_index` of `dst` node. However, if this is not the case this results in accessing data out of bounds. Because we are accessing an array that is a private member of a class and only in read only mode, this usually results only in unitialized memory access. However, it is reasonable to think that malicious users could manipulate these indexes to actually read data outside the class, thus resulting in information leakage and further exploits.
|
||||
|
||||
PiperOrigin-RevId: 346343288
|
||||
Change-Id: I2127da27c2023d27f26efd39afa6c853385cab6f
|
||||
---
|
||||
tensorflow/core/common_runtime/graph_constructor.cc | 12 ++++++++++++
|
||||
1 file changed, 12 insertions(+)
|
||||
|
||||
diff --git a/tensorflow/core/common_runtime/graph_constructor.cc b/tensorflow/core/common_runtime/graph_constructor.cc
|
||||
index 92b07682d76cd..639739e9cac8c 100644
|
||||
--- a/tensorflow/core/common_runtime/graph_constructor.cc
|
||||
+++ b/tensorflow/core/common_runtime/graph_constructor.cc
|
||||
@@ -44,6 +44,7 @@ limitations under the License.
|
||||
#include "tensorflow/core/lib/gtl/inlined_vector.h"
|
||||
#include "tensorflow/core/lib/strings/scanner.h"
|
||||
#include "tensorflow/core/lib/strings/str_util.h"
|
||||
+#include "tensorflow/core/platform/errors.h"
|
||||
#include "tensorflow/core/platform/logging.h"
|
||||
#include "tensorflow/core/platform/macros.h"
|
||||
#include "tensorflow/core/public/version.h"
|
||||
@@ -1425,6 +1426,17 @@ void GraphConstructor::Undo() {
|
||||
|
||||
Status GraphConstructor::MakeEdge(Node* src, int output_index, Node* dst,
|
||||
int input_index) {
|
||||
+ if (output_index >= src->num_outputs()) {
|
||||
+ return errors::InvalidArgument(
|
||||
+ "Output ", output_index, " of node ", src->name(),
|
||||
+ " does not exist. Node only has ", src->num_outputs(), " outputs.");
|
||||
+ }
|
||||
+ if (input_index >= dst->num_inputs()) {
|
||||
+ return errors::InvalidArgument(
|
||||
+ "Input ", input_index, " of node ", dst->name(),
|
||||
+ " does not exist. Node only has ", dst->num_inputs(), " inputs.");
|
||||
+ }
|
||||
+
|
||||
DataType src_out = src->output_type(output_index);
|
||||
DataType dst_in = dst->input_type(input_index);
|
||||
if (!TypesCompatible(dst_in, src_out)) {
|
||||
@ -1,32 +0,0 @@
|
||||
From eebb96c2830d48597d055d247c0e9aebaea94cd5 Mon Sep 17 00:00:00 2001
|
||||
From: Amit Patankar <amitpatankar@google.com>
|
||||
Date: Tue, 13 Apr 2021 14:18:51 -0700
|
||||
Subject: [PATCH] Fix an invalid address vulnerability in
|
||||
`tf.raw_ops.RaggedBincount`.
|
||||
|
||||
PiperOrigin-RevId: 368293153
|
||||
Change-Id: I4b4e493d3fd05e7dc55a55de3a041a80a4f275c3
|
||||
---
|
||||
tensorflow/core/kernels/bincount_op.cc | 9 +++++++++
|
||||
1 file changed, 9 insertions(+)
|
||||
|
||||
diff --git a/tensorflow/core/kernels/bincount_op.cc b/tensorflow/core/kernels/bincount_op.cc
|
||||
index 35911ee5d5540..258266ab29d33 100644
|
||||
--- a/tensorflow/core/kernels/bincount_op.cc
|
||||
+++ b/tensorflow/core/kernels/bincount_op.cc
|
||||
@@ -420,6 +420,15 @@ class RaggedBincountOp : public OpKernel {
|
||||
int num_values = values.size();
|
||||
int batch_idx = 0;
|
||||
|
||||
+ OP_REQUIRES(ctx, splits(0) == 0,
|
||||
+ errors::InvalidArgument("Splits must start with 0, not with ",
|
||||
+ splits(0)));
|
||||
+
|
||||
+ OP_REQUIRES(ctx, splits(num_rows) == num_values,
|
||||
+ errors::InvalidArgument(
|
||||
+ "Splits must end with the number of values, got ",
|
||||
+ splits(num_rows), " instead of ", num_values));
|
||||
+
|
||||
Tensor* out_t;
|
||||
OP_REQUIRES_OK(
|
||||
ctx, ctx->allocate_output(0, TensorShape({num_rows, size}), &out_t));
|
||||
@ -1,37 +0,0 @@
|
||||
From 030af767d357d1b4088c4a25c72cb3906abac489 Mon Sep 17 00:00:00 2001
|
||||
From: Amit Patankar <amitpatankar@google.com>
|
||||
Date: Tue, 13 Apr 2021 14:25:01 -0700
|
||||
Subject: [PATCH] Fix `tf.raw_ops.ResourceCountUpTo` null pointer dereference.
|
||||
|
||||
PiperOrigin-RevId: 368294347
|
||||
Change-Id: I2c16fbfc9b4966c402c3d8e311f0d665a9c852d8
|
||||
---
|
||||
tensorflow/python/lib/core/ndarray_tensor.cc | 8 ++++++++
|
||||
1 file changed, 8 insertions(+)
|
||||
|
||||
diff --git a/tensorflow/python/lib/core/ndarray_tensor.cc b/tensorflow/python/lib/core/ndarray_tensor.cc
|
||||
index 03fbea397485e..6cf51ceebbdaa 100644
|
||||
--- a/tensorflow/python/lib/core/ndarray_tensor.cc
|
||||
+++ b/tensorflow/python/lib/core/ndarray_tensor.cc
|
||||
@@ -16,6 +16,7 @@ limitations under the License.
|
||||
#include "tensorflow/python/lib/core/ndarray_tensor.h"
|
||||
|
||||
#include <cstring>
|
||||
+#include <optional>
|
||||
|
||||
#include "tensorflow/c/eager/tfe_context_internal.h"
|
||||
#include "tensorflow/c/tf_tensor_internal.h"
|
||||
@@ -74,6 +75,13 @@ Status PyArrayDescr_to_TF_DataType(PyArray_Descr* descr,
|
||||
PyObject* key;
|
||||
PyObject* value;
|
||||
Py_ssize_t pos = 0;
|
||||
+
|
||||
+ // Return an error if the fields attribute is null.
|
||||
+ // Occurs with an improper conversion attempt to resource.
|
||||
+ if (descr->fields == nullptr) {
|
||||
+ return errors::Internal("Unexpected numpy data type");
|
||||
+ }
|
||||
+
|
||||
if (PyDict_Next(descr->fields, &pos, &key, &value)) {
|
||||
// In Python 3, the keys of numpy custom struct types are unicode, unlike
|
||||
// Python 2, where the keys are bytes.
|
||||
@ -1,41 +0,0 @@
|
||||
From a7116dd3913c4a4afd2a3a938573aa7c785fdfc6 Mon Sep 17 00:00:00 2001
|
||||
From: Mihai Maruseac <mihaimaruseac@google.com>
|
||||
Date: Sat, 17 Apr 2021 20:55:53 -0700
|
||||
Subject: [PATCH] Validate `MatrixDiagV{2,3}` arguments to prevent breakage.
|
||||
|
||||
PiperOrigin-RevId: 369056033
|
||||
Change-Id: Ic2018c297d3dd6f252dc1dd3667f1ed5cb1eaa42
|
||||
---
|
||||
.../core/kernels/matrix_diag_op.cc | 19 ++++++++++++++++---
|
||||
1 file changed, 16 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/tensorflow/core/kernels/matrix_diag_op.cc b/tensorflow/core/kernels/matrix_diag_op.cc
|
||||
index 69cc8170793ae..d4eb589836a85 100644
|
||||
--- a/tensorflow/core/kernels/matrix_diag_op.cc
|
||||
+++ b/tensorflow/core/kernels/matrix_diag_op.cc
|
||||
@@ -192,9 +192,22 @@ class MatrixDiagOp : public OpKernel {
|
||||
upper_diag_index = diag_index.flat<int32>()(1);
|
||||
}
|
||||
}
|
||||
- num_rows = context->input(2).flat<int32>()(0);
|
||||
- num_cols = context->input(3).flat<int32>()(0);
|
||||
- padding_value = context->input(4).flat<T>()(0);
|
||||
+
|
||||
+ auto& num_rows_tensor = context->input(2);
|
||||
+ OP_REQUIRES(context, TensorShapeUtils::IsScalar(num_rows_tensor.shape()),
|
||||
+ errors::InvalidArgument("num_rows must be a scalar"));
|
||||
+ num_rows = num_rows_tensor.flat<int32>()(0);
|
||||
+
|
||||
+ auto& num_cols_tensor = context->input(3);
|
||||
+ OP_REQUIRES(context, TensorShapeUtils::IsScalar(num_cols_tensor.shape()),
|
||||
+ errors::InvalidArgument("num_cols must be a scalar"));
|
||||
+ num_cols = num_cols_tensor.flat<int32>()(0);
|
||||
+
|
||||
+ auto& padding_value_tensor = context->input(4);
|
||||
+ OP_REQUIRES(context,
|
||||
+ TensorShapeUtils::IsScalar(padding_value_tensor.shape()),
|
||||
+ errors::InvalidArgument("padding_value must be a scalar"));
|
||||
+ padding_value = padding_value_tensor.flat<T>()(0);
|
||||
}
|
||||
|
||||
// Size validations.
|
||||
@ -1,199 +0,0 @@
|
||||
From ce47a396ff795bdb6cf48eb53dbcba46cb51fa7d Mon Sep 17 00:00:00 2001
|
||||
From: Katherine Tian <kattian@google.com>
|
||||
Date: Tue, 30 Jun 2020 04:12:11 +0000
|
||||
Subject: [PATCH 1/1] TensorKey class and TensorMap tests
|
||||
|
||||
---
|
||||
tensorflow/core/BUILD | 1 +
|
||||
tensorflow/core/framework/BUILD | 70 ++++++++++++++++++++++++++
|
||||
tensorflow/core/framework/tensor_key.h | 64 +++++++++++++++++++++++
|
||||
tensorflow/core/kernels/BUILD | 1 +
|
||||
4 files changed, 136 insertions(+)
|
||||
create mode 100644 tensorflow/core/framework/tensor_key.h
|
||||
|
||||
diff --git a/tensorflow/core/BUILD b/tensorflow/core/BUILD
|
||||
index d0be6ee9..6e745b4e 100644
|
||||
--- a/tensorflow/core/BUILD
|
||||
+++ b/tensorflow/core/BUILD
|
||||
@@ -495,6 +495,7 @@ tf_cuda_library(
|
||||
"//tensorflow/core/framework:shared_ptr_variant.h",
|
||||
"//tensorflow/core/framework:stats_aggregator.h",
|
||||
"//tensorflow/core/framework:tensor.h",
|
||||
+ "//tensorflow/core/framework:tensor_key.h",
|
||||
"//tensorflow/core/framework:tensor_shape.h",
|
||||
"//tensorflow/core/framework:tensor_slice.h",
|
||||
"//tensorflow/core/framework:tensor_types.h",
|
||||
diff --git a/tensorflow/core/framework/BUILD b/tensorflow/core/framework/BUILD
|
||||
index 9b6ddb2a..093f0545 100644
|
||||
--- a/tensorflow/core/framework/BUILD
|
||||
+++ b/tensorflow/core/framework/BUILD
|
||||
@@ -209,6 +209,7 @@ filegroup(
|
||||
"shared_ptr_variant.h",
|
||||
"stats_aggregator.h",
|
||||
"tensor.h",
|
||||
+ "tensor_key.h",
|
||||
"tensor_reference.h",
|
||||
"tensor_shape.h",
|
||||
"tensor_slice.h",
|
||||
@@ -760,6 +761,75 @@ tf_cuda_library(
|
||||
alwayslink = 1,
|
||||
)
|
||||
|
||||
+tf_cuda_library(
|
||||
+ name = "tensor_key",
|
||||
+ srcs = [
|
||||
+ "log_memory.cc",
|
||||
+ "tensor.cc",
|
||||
+ "typed_allocator.cc",
|
||||
+ "types.cc",
|
||||
+ "variant.cc",
|
||||
+ "variant_op_registry.cc",
|
||||
+ "variant_tensor_data.cc",
|
||||
+ ],
|
||||
+ hdrs = [
|
||||
+ "log_memory.h",
|
||||
+ "register_types.h",
|
||||
+ "tensor.h",
|
||||
+ "tensor_key.h",
|
||||
+ "typed_allocator.h",
|
||||
+ "types.h",
|
||||
+ "variant.h",
|
||||
+ "variant_encode_decode.h",
|
||||
+ "variant_op_registry.h",
|
||||
+ "variant_tensor_data.h",
|
||||
+ ],
|
||||
+ visibility = [
|
||||
+ "//tensorflow/core:__pkg__",
|
||||
+ "//tensorflow/core/util:__pkg__",
|
||||
+ ],
|
||||
+ deps = [
|
||||
+ ":allocation_description_proto_cc",
|
||||
+ ":allocator",
|
||||
+ ":bfloat16",
|
||||
+ ":log_memory_proto_cc",
|
||||
+ ":numeric_types",
|
||||
+ ":resource_handle",
|
||||
+ ":resource_handle_proto_cc",
|
||||
+ ":tensor_description_proto_cc",
|
||||
+ ":tensor_proto_cc",
|
||||
+ ":tensor_shape",
|
||||
+ ":tensor_types",
|
||||
+ ":type_index",
|
||||
+ ":type_traits",
|
||||
+ ":types_proto_cc",
|
||||
+ "//tensorflow/core/lib/core:coding",
|
||||
+ "//tensorflow/core/lib/core:errors",
|
||||
+ "//tensorflow/core/lib/core:refcount",
|
||||
+ "//tensorflow/core/lib/core:status",
|
||||
+ "//tensorflow/core/lib/core:stringpiece",
|
||||
+ "//tensorflow/core/lib/gtl:array_slice",
|
||||
+ "//tensorflow/core/lib/gtl:flatmap",
|
||||
+ "//tensorflow/core/lib/gtl:inlined_vector",
|
||||
+ "//tensorflow/core/lib/hash",
|
||||
+ "//tensorflow/core/lib/strings:str_util",
|
||||
+ "//tensorflow/core/lib/strings:strcat",
|
||||
+ "//tensorflow/core/platform:abi",
|
||||
+ "//tensorflow/core/platform:logging",
|
||||
+ "//tensorflow/core/platform:macros",
|
||||
+ "//tensorflow/core/platform:platform_port",
|
||||
+ "//tensorflow/core/platform:protobuf",
|
||||
+ "//tensorflow/core/platform:strcat",
|
||||
+ "//tensorflow/core/platform:tensor_coding",
|
||||
+ "//tensorflow/core/platform:types",
|
||||
+ "//tensorflow/core/public:version",
|
||||
+ "//third_party/eigen3",
|
||||
+ "@com_google_absl//absl/memory",
|
||||
+ "@com_google_absl//absl/strings",
|
||||
+ ],
|
||||
+ alwayslink = 1,
|
||||
+)
|
||||
+
|
||||
cc_library(
|
||||
name = "shape_inference",
|
||||
srcs = ["shape_inference.cc"],
|
||||
diff --git a/tensorflow/core/framework/tensor_key.h b/tensorflow/core/framework/tensor_key.h
|
||||
new file mode 100644
|
||||
index 00000000..8eff58b2
|
||||
--- /dev/null
|
||||
+++ b/tensorflow/core/framework/tensor_key.h
|
||||
@@ -0,0 +1,64 @@
|
||||
+/* Copyright 2020 The TensorFlow Authors. All Rights Reserved.
|
||||
+
|
||||
+Licensed under the Apache License, Version 2.0 (the "License");
|
||||
+you may not use this file except in compliance with the License.
|
||||
+You may obtain a copy of the License at
|
||||
+
|
||||
+ http://www.apache.org/licenses/LICENSE-2.0
|
||||
+
|
||||
+Unless required by applicable law or agreed to in writing, software
|
||||
+distributed under the License is distributed on an "AS IS" BASIS,
|
||||
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
+See the License for the specific language governing permissions and
|
||||
+limitations under the License.
|
||||
+==============================================================================*/
|
||||
+
|
||||
+#include "tensorflow/core/framework/tensor.h"
|
||||
+
|
||||
+namespace tensorflow {
|
||||
+
|
||||
+class TensorKey : public Tensor {
|
||||
+ public:
|
||||
+ using Tensor::Tensor;
|
||||
+
|
||||
+ TensorKey(const Tensor& t) : Tensor(t) {}
|
||||
+
|
||||
+ // Equality operator. Needed for absl hashing.
|
||||
+ friend bool operator==(const TensorKey& t1, const TensorKey& t2) {
|
||||
+ if (t1.dtype() != t2.dtype() || t1.shape() != t2.shape()) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ if (DataTypeCanUseMemcpy(t1.dtype())) {
|
||||
+ return t1.tensor_data() == t2.tensor_data();
|
||||
+ }
|
||||
+ if (t1.dtype() == DT_STRING) {
|
||||
+ const auto s1 = t1.unaligned_flat<tstring>();
|
||||
+ const auto s2 = t2.unaligned_flat<tstring>();
|
||||
+ for (int64 i = 0, n = t1.NumElements(); i < n; ++i) {
|
||||
+ if (TF_PREDICT_FALSE(s1(i) != s2(i))) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ }
|
||||
+ return true;
|
||||
+ }
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ friend bool operator!=(const TensorKey& t1, const TensorKey& t2) {
|
||||
+ return !(t1==t2);
|
||||
+ }
|
||||
+
|
||||
+ // AbslHashValue() function, needed for absl hashing.
|
||||
+ template <typename H>
|
||||
+ friend H AbslHashValue(H h, const TensorKey& k) {
|
||||
+ uint8* d = (uint8*)(k.data());
|
||||
+ size_t s = k.AllocatedBytes();
|
||||
+ std::vector<uint8> vec;
|
||||
+ for (int i=0; i < s; i++) {
|
||||
+ vec.push_back(d[i]);
|
||||
+ }
|
||||
+ return H::combine(std::move(h), s);
|
||||
+ }
|
||||
+};
|
||||
+
|
||||
+} //namespace tensorflow
|
||||
\ No newline at end of file
|
||||
diff --git a/tensorflow/core/kernels/BUILD b/tensorflow/core/kernels/BUILD
|
||||
index f5a480b3..4ef86efb 100644
|
||||
--- a/tensorflow/core/kernels/BUILD
|
||||
+++ b/tensorflow/core/kernels/BUILD
|
||||
@@ -3219,6 +3219,7 @@ tf_cc_tests(
|
||||
],
|
||||
deps = [
|
||||
":eigen_helpers",
|
||||
+ "//tensorflow/core/framework:tensor_testutil",
|
||||
"//tensorflow/core:test",
|
||||
"//tensorflow/core:test_main",
|
||||
"@com_google_absl//absl/strings",
|
||||
--
|
||||
2.27.0
|
||||
|
||||
@ -1,70 +0,0 @@
|
||||
From b6a0cba2b381e83a1d0a19b675ca6f7459d2d2bc Mon Sep 17 00:00:00 2001
|
||||
From: Edward Loper <edloper@google.com>
|
||||
Date: Tue, 25 Aug 2020 08:12:53 -0700
|
||||
Subject: [PATCH 1/1] Fix segmentation fault in tf.map_fn when fn_output_spec
|
||||
is a RaggedTensorSpec and the input tensor has shape [0, ...].
|
||||
|
||||
PiperOrigin-RevId: 328332518
|
||||
Change-Id: I6aff03152bbc96507fb6c5f89b05722f3cc30164
|
||||
---
|
||||
.../kernels/ragged_tensor_from_variant_op.cc | 16 +++++++++++++++-
|
||||
.../python/ops/ragged/ragged_map_fn_op_test.py | 15 +++++++++++++++
|
||||
2 files changed, 30 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/tensorflow/core/kernels/ragged_tensor_from_variant_op.cc b/tensorflow/core/kernels/ragged_tensor_from_variant_op.cc
|
||||
index ad0712e6fd0..aa736ad7f60 100644
|
||||
--- a/tensorflow/core/kernels/ragged_tensor_from_variant_op.cc
|
||||
+++ b/tensorflow/core/kernels/ragged_tensor_from_variant_op.cc
|
||||
@@ -175,8 +175,22 @@ Status NestedStackRaggedTensors(
|
||||
}
|
||||
}
|
||||
|
||||
+ // If the variant tensor input is empty, then we have no way to determine
|
||||
+ // the correct shape for the dense_values. (It must have rank>=1, and its
|
||||
+ // outer dimension must be 0, but we don't know its shape beyond that.)
|
||||
+ // For now, we just use a shape of `[0]` in this case.
|
||||
+ // TODO(edloper): Update this op with an attribute containing information
|
||||
+ // about dense_values shape. If it's `None`, then we'll probably still have
|
||||
+ // to use shape=[0] here, but if we have more info, then we can use it.
|
||||
+ // E.g., in map_fn, we may have shape info from the RaggedTensorSpec.
|
||||
+ TensorShape component_values_shape;
|
||||
+ if (ragged_components.empty()) {
|
||||
+ component_values_shape = TensorShape({0});
|
||||
+ } else {
|
||||
+ component_values_shape = ragged_components[0].values.shape();
|
||||
+ }
|
||||
+
|
||||
// Populate values.
|
||||
- TensorShape component_values_shape = ragged_components[0].values.shape();
|
||||
int values_size = component_values_shape.dim_size(0);
|
||||
for (int i = 1; i < ragged_components.size(); i++) {
|
||||
if (ragged_components[i].values.dims() != component_values_shape.dims()) {
|
||||
diff --git a/tensorflow/python/ops/ragged/ragged_map_fn_op_test.py b/tensorflow/python/ops/ragged/ragged_map_fn_op_test.py
|
||||
index 8a40e396a68..bead4923a0a 100644
|
||||
--- a/tensorflow/python/ops/ragged/ragged_map_fn_op_test.py
|
||||
+++ b/tensorflow/python/ops/ragged/ragged_map_fn_op_test.py
|
||||
@@ -150,6 +150,21 @@ class RaggedMapOpTest(test_util.TensorFlowTestCase,
|
||||
result_dtype=ragged_tensor.RaggedTensorType(
|
||||
dtype=dtypes.int64, ragged_rank=4),
|
||||
),
|
||||
+ # [d1] -> [d1, (d2), (d3)]
|
||||
+ dict(
|
||||
+ fn=ragged_math_ops.range,
|
||||
+ elems=np.array([1, 2, 3], np.int64),
|
||||
+ expected_output=[[[0]], [[0, 1]], [[0, 1, 2]]],
|
||||
+ result_dtype=ragged_tensor.RaggedTensorType(
|
||||
+ dtype=dtypes.int64, ragged_rank=2)),
|
||||
+ # [0] -> [0, (d2), (d3)] (github issue #36232)
|
||||
+ dict(
|
||||
+ fn=ragged_math_ops.range,
|
||||
+ elems=np.zeros([0], np.int64),
|
||||
+ expected_output=[],
|
||||
+ expected_ragged_rank=2,
|
||||
+ result_dtype=ragged_tensor.RaggedTensorType(
|
||||
+ dtype=dtypes.int64, ragged_rank=2)),
|
||||
])
|
||||
|
||||
def testRaggedMap(
|
||||
--
|
||||
2.27.0
|
||||
|
||||
@ -1,904 +0,0 @@
|
||||
From be6b1fdb0699d4000b70ad32cc23d1503e5c7511 Mon Sep 17 00:00:00 2001
|
||||
From: Edward Loper <edloper@google.com>
|
||||
Date: Wed, 14 Oct 2020 09:41:17 -0700
|
||||
Subject: [PATCH 1/1] Added gradients for RaggedTensorToVariant and
|
||||
RaggedTensorFromVariant. (This allows gradients to pass through map_fn when
|
||||
it is applied to ragged tensors.)
|
||||
|
||||
PiperOrigin-RevId: 337108621
|
||||
Change-Id: I73d5f3296181877f0cc4c7a6273b693bcf8310ab
|
||||
---
|
||||
tensorflow/core/kernels/BUILD | 15 ++
|
||||
.../kernels/ragged_tensor_from_variant_op.cc | 164 +++++++---------
|
||||
.../kernels/ragged_tensor_to_variant_op.cc | 180 +++++++++++-------
|
||||
.../core/kernels/ragged_tensor_variant.cc | 86 +++++++++
|
||||
.../core/kernels/ragged_tensor_variant.h | 110 +++++++++++
|
||||
tensorflow/core/ops/ragged_conversion_ops.cc | 20 +-
|
||||
tensorflow/python/ops/ragged/BUILD | 1 +
|
||||
9 files changed, 478 insertions(+), 172 deletions(-)
|
||||
create mode 100644 tensorflow/core/framework/tensor_key.h
|
||||
create mode 100644 tensorflow/core/kernels/ragged_tensor_variant.cc
|
||||
create mode 100644 tensorflow/core/kernels/ragged_tensor_variant.h
|
||||
|
||||
diff --git a/tensorflow/core/kernels/BUILD b/tensorflow/core/kernels/BUILD
|
||||
index f5a480b3..12adb2b2 100644
|
||||
--- a/tensorflow/core/kernels/BUILD
|
||||
+++ b/tensorflow/core/kernels/BUILD
|
||||
@@ -1529,10 +1529,22 @@ tf_cc_test(
|
||||
],
|
||||
)
|
||||
|
||||
+cc_library(
|
||||
+ name = "ragged_tensor_variant",
|
||||
+ srcs = ["ragged_tensor_variant.cc"],
|
||||
+ hdrs = ["ragged_tensor_variant.h"],
|
||||
+ deps = [
|
||||
+ ":cwise_op",
|
||||
+ "//tensorflow/core:framework",
|
||||
+ ],
|
||||
+)
|
||||
+
|
||||
tf_kernel_library(
|
||||
name = "ragged_tensor_to_variant_op",
|
||||
srcs = ["ragged_tensor_to_variant_op.cc"],
|
||||
deps = [
|
||||
+ ":concat_lib",
|
||||
+ ":ragged_tensor_variant",
|
||||
"//tensorflow/core:framework",
|
||||
"//tensorflow/core:lib",
|
||||
],
|
||||
@@ -1542,6 +1554,7 @@ tf_kernel_library(
|
||||
name = "ragged_tensor_from_variant_op",
|
||||
srcs = ["ragged_tensor_from_variant_op.cc"],
|
||||
deps = [
|
||||
+ ":ragged_tensor_variant",
|
||||
"//tensorflow/core:framework",
|
||||
"//tensorflow/core:lib",
|
||||
],
|
||||
@@ -1554,6 +1567,7 @@ tf_cc_test(
|
||||
deps = [
|
||||
":ops_testutil",
|
||||
":ragged_tensor_to_variant_op",
|
||||
+ ":ragged_tensor_variant",
|
||||
"//tensorflow/core:framework",
|
||||
"//tensorflow/core:lib",
|
||||
"//tensorflow/core:test",
|
||||
@@ -1570,6 +1584,7 @@ tf_cc_test(
|
||||
deps = [
|
||||
":ops_testutil",
|
||||
":ragged_tensor_from_variant_op",
|
||||
+ ":ragged_tensor_variant",
|
||||
"//tensorflow/core:framework",
|
||||
"//tensorflow/core:lib",
|
||||
"//tensorflow/core:test",
|
||||
diff --git a/tensorflow/core/kernels/ragged_tensor_from_variant_op.cc b/tensorflow/core/kernels/ragged_tensor_from_variant_op.cc
|
||||
index d7b6a89a..fa8853af 100644
|
||||
--- a/tensorflow/core/kernels/ragged_tensor_from_variant_op.cc
|
||||
+++ b/tensorflow/core/kernels/ragged_tensor_from_variant_op.cc
|
||||
@@ -20,110 +20,76 @@ limitations under the License.
|
||||
#include "tensorflow/core/framework/tensor.h"
|
||||
#include "tensorflow/core/framework/variant.h"
|
||||
#include "tensorflow/core/framework/variant_encode_decode.h"
|
||||
+#include "tensorflow/core/kernels/ragged_tensor_variant.h"
|
||||
#include "tensorflow/core/lib/core/errors.h"
|
||||
#include "tensorflow/core/lib/core/status.h"
|
||||
|
||||
namespace tensorflow {
|
||||
namespace {
|
||||
|
||||
-struct RaggedTensor {
|
||||
- Tensor values;
|
||||
- std::vector<Tensor> nested_splits;
|
||||
-};
|
||||
-
|
||||
-Status RaggedComponentsFromVariant(const Tensor& encoded_variant,
|
||||
- int ragged_rank, DataType value_dtype,
|
||||
- DataType split_dtype,
|
||||
- std::vector<RaggedTensor>* decoded_ragged) {
|
||||
+Status RaggedComponentsFromVariant(
|
||||
+ const Tensor& encoded_variant, int ragged_rank, DataType value_dtype,
|
||||
+ DataType split_dtype, std::vector<RaggedTensorVariant>* decoded_ragged) {
|
||||
const auto& flat_variants = encoded_variant.flat<Variant>();
|
||||
- decoded_ragged->resize(flat_variants.size());
|
||||
- // Step 1: Extract the 1-D DT_VARIANT Tensor from each Variant element in the
|
||||
- // input.
|
||||
+ decoded_ragged->reserve(flat_variants.size());
|
||||
+
|
||||
for (int i = 0; i < flat_variants.size(); i++) {
|
||||
const auto& flat_variant = flat_variants(i);
|
||||
- const Tensor* encoded_list = flat_variant.get<Tensor>();
|
||||
- if (encoded_list == nullptr) {
|
||||
+ const RaggedTensorVariant* decoded =
|
||||
+ flat_variant.get<RaggedTensorVariant>();
|
||||
+ if (decoded == nullptr) {
|
||||
return errors::InvalidArgument(
|
||||
"Input Variant element at index ", i,
|
||||
- " doesn't hold a Tensor: ", flat_variant.DebugString());
|
||||
+ " doesn't hold a RaggedTensorVariant: ", flat_variant.DebugString());
|
||||
}
|
||||
- if (encoded_list->dims() != 1) {
|
||||
+ decoded_ragged->push_back(*decoded);
|
||||
+ decoded = &decoded_ragged->back();
|
||||
+ // Check ragged rank & types
|
||||
+ if (decoded->ragged_rank() != ragged_rank) {
|
||||
return errors::InvalidArgument(
|
||||
- "Encoded input Variant must have rank 1, but found rank: ",
|
||||
- encoded_list->dims(),
|
||||
- ". encoded input Variant: ", encoded_list->DebugString());
|
||||
+ "Encoded input RaggedTensorVariant has ragged_rank=",
|
||||
+ decoded->ragged_rank(), ". Expected ragged_rank=", ragged_rank, ".");
|
||||
}
|
||||
- if (encoded_list->NumElements() != (ragged_rank + 1) &&
|
||||
- encoded_list->NumElements() != 1) {
|
||||
+ if (decoded->values().dtype() != value_dtype) {
|
||||
return errors::InvalidArgument(
|
||||
- "Encoded input Variant must hold either input_ragged_rank + 1 "
|
||||
- "Tensors or an empty Tensor (zero splits Tensors, 1 values Tensor), "
|
||||
- "input_ragged_rank: ",
|
||||
- ragged_rank,
|
||||
- ", encoded input Variant: ", encoded_list->DebugString());
|
||||
+ "Expected values Tensor dtype: ", DataTypeString(value_dtype),
|
||||
+ ", found: ", DataTypeString(decoded->values().dtype()));
|
||||
}
|
||||
- const auto& input_vec = encoded_list->vec<Variant>();
|
||||
-
|
||||
- // Step 2: Get the splits and value Tensors from the 1-D DT_VARIANT Tensor
|
||||
- // to create the component RaggedTensors.
|
||||
- (*decoded_ragged)[i].nested_splits.reserve(ragged_rank);
|
||||
- for (int j = 0; j < ragged_rank; j++) {
|
||||
- const Tensor* split_tensor = input_vec(j).get<Tensor>();
|
||||
- if (split_tensor == nullptr) {
|
||||
- return errors::InvalidArgument(
|
||||
- "Encoded scalar element at index ", i,
|
||||
- " doesn't have a splits Tensor at split_index ", j, ": ",
|
||||
- input_vec(j).DebugString());
|
||||
- }
|
||||
- Tensor splits_tensor = *split_tensor;
|
||||
- if (splits_tensor.dtype() != split_dtype) {
|
||||
+ if (decoded->values().dims() < 1) {
|
||||
+ return errors::InvalidArgument(
|
||||
+ "Ragged values must have rank >= 1; encoded scalar element at index ",
|
||||
+ i, " has values Tensor: ", decoded->values().DebugString());
|
||||
+ }
|
||||
+ for (const auto& splits : decoded->nested_splits()) {
|
||||
+ if (splits.dtype() != split_dtype) {
|
||||
return errors::InvalidArgument(
|
||||
- "Expected splits Tensor dtype: ", split_dtype,
|
||||
- ", found: ", splits_tensor.dtype());
|
||||
+ "Expected row_splits Tensor dtype: ", DataTypeString(split_dtype),
|
||||
+ ", found: ", DataTypeString(splits.dtype()));
|
||||
}
|
||||
- if (splits_tensor.dims() != 1) {
|
||||
+ if (splits.dims() != 1) {
|
||||
return errors::InvalidArgument(
|
||||
"Ragged splits must have rank 1; encoded scalar element at index ",
|
||||
- i, " has splits Tensor at split_index ", j, ": ",
|
||||
- splits_tensor.DebugString());
|
||||
+ i, " has splits Tensor ", splits.DebugString());
|
||||
}
|
||||
- (*decoded_ragged)[i].nested_splits.push_back(splits_tensor);
|
||||
- }
|
||||
- const Tensor* values_tensor = input_vec(ragged_rank).get<Tensor>();
|
||||
- if (values_tensor == nullptr) {
|
||||
- return errors::InvalidArgument("Encoded scalar element at index ", i,
|
||||
- " doesn't have a values Tensor: ",
|
||||
- input_vec(ragged_rank).DebugString());
|
||||
- }
|
||||
- if (values_tensor->dtype() != value_dtype) {
|
||||
- return errors::InvalidArgument(
|
||||
- "Expected values Tensor dtype: ", DataTypeString(value_dtype),
|
||||
- ", found: ", DataTypeString(values_tensor->dtype()));
|
||||
- }
|
||||
- if (values_tensor->dims() < 1) {
|
||||
- return errors::InvalidArgument(
|
||||
- "Ragged values must have rank >= 1; encoded scalar element at index ",
|
||||
- i, " has values Tensor: ", values_tensor->DebugString());
|
||||
}
|
||||
- (*decoded_ragged)[i].values = *values_tensor;
|
||||
}
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
template <typename VALUE_TYPE, typename SPLIT_TYPE>
|
||||
Status NestedStackRaggedTensors(
|
||||
- const std::vector<RaggedTensor>& ragged_components,
|
||||
+ const std::vector<RaggedTensorVariant>& ragged_components,
|
||||
const std::vector<int>& nested_dim_sizes, const int input_ragged_rank,
|
||||
- const int output_ragged_rank, RaggedTensor* output_ragged) {
|
||||
- output_ragged->nested_splits.reserve(output_ragged_rank);
|
||||
+ const int output_ragged_rank, RaggedTensorVariant* output_ragged) {
|
||||
+ output_ragged->mutable_nested_splits()->reserve(output_ragged_rank);
|
||||
const int dims = nested_dim_sizes.size();
|
||||
|
||||
// Populate first `dims - 1` splits.
|
||||
for (int i = 0; i < dims - 1; i++) {
|
||||
int dims_splits_size = nested_dim_sizes[i] + 1;
|
||||
- output_ragged->nested_splits.push_back(Tensor(
|
||||
- DataTypeToEnum<SPLIT_TYPE>::value, TensorShape({dims_splits_size})));
|
||||
- auto splits_vec = output_ragged->nested_splits[i].vec<SPLIT_TYPE>();
|
||||
+ output_ragged->append_splits(Tensor(DataTypeToEnum<SPLIT_TYPE>::value,
|
||||
+ TensorShape({dims_splits_size})));
|
||||
+ auto splits_vec = output_ragged->mutable_splits(i)->vec<SPLIT_TYPE>();
|
||||
int split_diff = nested_dim_sizes[i + 1];
|
||||
for (int j = 0; j < dims_splits_size; j++) {
|
||||
splits_vec(j) = j * split_diff;
|
||||
@@ -132,15 +98,15 @@ Status NestedStackRaggedTensors(
|
||||
|
||||
// Populate `dims`-th split.
|
||||
int splits_size = ragged_components.size() + 1;
|
||||
- output_ragged->nested_splits.push_back(
|
||||
+ output_ragged->append_splits(
|
||||
Tensor(DataTypeToEnum<SPLIT_TYPE>::value, TensorShape({splits_size})));
|
||||
auto dims_splits_vec =
|
||||
- output_ragged->nested_splits[dims - 1].vec<SPLIT_TYPE>();
|
||||
+ output_ragged->mutable_splits(dims - 1)->vec<SPLIT_TYPE>();
|
||||
dims_splits_vec(0) = 0;
|
||||
for (int i = 0; i < ragged_components.size(); i++) {
|
||||
- int split_val = ragged_components[i].values.shape().dim_size(0);
|
||||
- if (input_ragged_rank != 0 && !ragged_components[i].nested_splits.empty()) {
|
||||
- split_val = ragged_components[i].nested_splits[0].NumElements() - 1;
|
||||
+ int split_val = ragged_components[i].values().shape().dim_size(0);
|
||||
+ if (input_ragged_rank != 0 && ragged_components[i].ragged_rank() > 0) {
|
||||
+ split_val = ragged_components[i].splits(0).NumElements() - 1;
|
||||
}
|
||||
dims_splits_vec(i + 1) = dims_splits_vec(i) + split_val;
|
||||
}
|
||||
@@ -150,24 +116,24 @@ Status NestedStackRaggedTensors(
|
||||
int split_index = dims + i;
|
||||
int split_size = 1;
|
||||
for (int j = 0; j < ragged_components.size(); j++) {
|
||||
- if (!ragged_components[j].nested_splits.empty()) {
|
||||
- split_size += ragged_components[j].nested_splits[i].NumElements() - 1;
|
||||
+ if (!ragged_components[j].nested_splits().empty()) {
|
||||
+ split_size += ragged_components[j].splits(i).NumElements() - 1;
|
||||
}
|
||||
}
|
||||
- output_ragged->nested_splits.push_back(
|
||||
+ output_ragged->append_splits(
|
||||
Tensor(DataTypeToEnum<SPLIT_TYPE>::value, TensorShape({split_size})));
|
||||
auto splits_vec =
|
||||
- output_ragged->nested_splits[split_index].vec<SPLIT_TYPE>();
|
||||
+ output_ragged->mutable_splits(split_index)->vec<SPLIT_TYPE>();
|
||||
splits_vec(0) = 0;
|
||||
SPLIT_TYPE last_split_value = 0;
|
||||
int index = 1;
|
||||
for (int j = 0; j < ragged_components.size(); j++) {
|
||||
- if (ragged_components[j].nested_splits.empty()) {
|
||||
+ if (ragged_components[j].nested_splits().empty()) {
|
||||
// Corner case: empty row. e.g [ [[x], [x]], [] ]
|
||||
continue;
|
||||
}
|
||||
auto component_splits_vec =
|
||||
- ragged_components[j].nested_splits[i].vec<SPLIT_TYPE>();
|
||||
+ ragged_components[j].splits(i).vec<SPLIT_TYPE>();
|
||||
for (int k = 1; k < component_splits_vec.size(); k++, index++) {
|
||||
splits_vec(index) = component_splits_vec(k) + last_split_value;
|
||||
}
|
||||
@@ -187,35 +153,35 @@ Status NestedStackRaggedTensors(
|
||||
if (ragged_components.empty()) {
|
||||
component_values_shape = TensorShape({0});
|
||||
} else {
|
||||
- component_values_shape = ragged_components[0].values.shape();
|
||||
+ component_values_shape = ragged_components[0].values().shape();
|
||||
}
|
||||
|
||||
// Populate values.
|
||||
int values_size = component_values_shape.dim_size(0);
|
||||
for (int i = 1; i < ragged_components.size(); i++) {
|
||||
- if (ragged_components[i].values.dims() != component_values_shape.dims()) {
|
||||
+ if (ragged_components[i].values().dims() != component_values_shape.dims()) {
|
||||
return errors::InvalidArgument(
|
||||
"Rank of values must match for all "
|
||||
"components; values shape at index 0: ",
|
||||
component_values_shape.DebugString(), ", values shape at index ", i,
|
||||
- ": ", ragged_components[i].values.shape().DebugString());
|
||||
+ ": ", ragged_components[i].values().shape().DebugString());
|
||||
}
|
||||
- values_size += ragged_components[i].values.shape().dim_size(0);
|
||||
+ values_size += ragged_components[i].values().shape().dim_size(0);
|
||||
}
|
||||
component_values_shape.set_dim(0, values_size);
|
||||
- output_ragged->values =
|
||||
- Tensor(DataTypeToEnum<VALUE_TYPE>::value, component_values_shape);
|
||||
+ output_ragged->set_values(
|
||||
+ Tensor(DataTypeToEnum<VALUE_TYPE>::value, component_values_shape));
|
||||
auto output_values_flat =
|
||||
- output_ragged->values.flat_outer_dims<VALUE_TYPE, 2>();
|
||||
+ output_ragged->mutable_values()->flat_outer_dims<VALUE_TYPE, 2>();
|
||||
int values_index = 0;
|
||||
for (int i = 0; i < ragged_components.size(); i++) {
|
||||
auto component_values_flat =
|
||||
- ragged_components[i].values.flat_outer_dims<VALUE_TYPE, 2>();
|
||||
- int num_inner_elements = ragged_components[i].values.NumElements();
|
||||
- if (ragged_components[i].values.dim_size(0) > 0) {
|
||||
- num_inner_elements /= ragged_components[i].values.dim_size(0);
|
||||
+ ragged_components[i].values().flat_outer_dims<VALUE_TYPE, 2>();
|
||||
+ int num_inner_elements = ragged_components[i].values().NumElements();
|
||||
+ if (ragged_components[i].values().dim_size(0) > 0) {
|
||||
+ num_inner_elements /= ragged_components[i].values().dim_size(0);
|
||||
}
|
||||
- for (int j = 0; j < ragged_components[i].values.dim_size(0);
|
||||
+ for (int j = 0; j < ragged_components[i].values().dim_size(0);
|
||||
j++, values_index++) {
|
||||
for (int k = 0; k < num_inner_elements; k++) {
|
||||
output_values_flat(values_index, k) = component_values_flat(j, k);
|
||||
@@ -265,7 +231,7 @@ class RaggedTensorFromVariantOp : public OpKernel {
|
||||
// Decode all variants.
|
||||
const auto value_dtype = DataTypeToEnum<VALUE_TYPE>::v();
|
||||
const auto split_dtype = DataTypeToEnum<SPLIT_TYPE>::v();
|
||||
- std::vector<RaggedTensor> decoded_components;
|
||||
+ std::vector<RaggedTensorVariant> decoded_components;
|
||||
OP_REQUIRES_OK(context, RaggedComponentsFromVariant(
|
||||
encoded_variant, input_ragged_rank_,
|
||||
value_dtype, split_dtype, &decoded_components));
|
||||
@@ -281,7 +247,7 @@ class RaggedTensorFromVariantOp : public OpKernel {
|
||||
for (int i = 0; i < encoded_variant.dims(); i++) {
|
||||
encoded_dim_sizes[i] = encoded_variant.dim_size(i);
|
||||
}
|
||||
- RaggedTensor output_ragged;
|
||||
+ RaggedTensorVariant output_ragged;
|
||||
OP_REQUIRES_OK(
|
||||
context, NestedStackRaggedTensors<VALUE_TYPE, SPLIT_TYPE>(
|
||||
decoded_components, encoded_dim_sizes, input_ragged_rank_,
|
||||
@@ -296,15 +262,15 @@ class RaggedTensorFromVariantOp : public OpKernel {
|
||||
int output_ragged_rank_;
|
||||
|
||||
void ReturnRaggedTensor(OpKernelContext* context,
|
||||
- RaggedTensor ragged_tensor) {
|
||||
- int ragged_rank = ragged_tensor.nested_splits.size();
|
||||
+ const RaggedTensorVariant& ragged_tensor) {
|
||||
+ int ragged_rank = ragged_tensor.ragged_rank();
|
||||
OpOutputList splits_out;
|
||||
OP_REQUIRES_OK(context,
|
||||
context->output_list("output_nested_splits", &splits_out));
|
||||
for (int i = 0; i < ragged_rank; i++) {
|
||||
- splits_out.set(i, ragged_tensor.nested_splits[i]);
|
||||
+ splits_out.set(i, ragged_tensor.splits(i));
|
||||
}
|
||||
- context->set_output(ragged_rank, ragged_tensor.values);
|
||||
+ context->set_output(ragged_rank, ragged_tensor.values());
|
||||
}
|
||||
};
|
||||
|
||||
diff --git a/tensorflow/core/kernels/ragged_tensor_to_variant_op.cc b/tensorflow/core/kernels/ragged_tensor_to_variant_op.cc
|
||||
index 3190534b..a60e5c62 100644
|
||||
--- a/tensorflow/core/kernels/ragged_tensor_to_variant_op.cc
|
||||
+++ b/tensorflow/core/kernels/ragged_tensor_to_variant_op.cc
|
||||
@@ -18,50 +18,38 @@ limitations under the License.
|
||||
#include "tensorflow/core/framework/op_kernel.h"
|
||||
#include "tensorflow/core/framework/register_types.h"
|
||||
#include "tensorflow/core/framework/tensor.h"
|
||||
+#include "tensorflow/core/framework/tensor_shape.h"
|
||||
#include "tensorflow/core/framework/variant.h"
|
||||
#include "tensorflow/core/framework/variant_encode_decode.h"
|
||||
+#include "tensorflow/core/framework/variant_op_registry.h"
|
||||
+#include "tensorflow/core/kernels/concat_lib.h"
|
||||
+#include "tensorflow/core/kernels/ragged_tensor_variant.h"
|
||||
#include "tensorflow/core/lib/core/errors.h"
|
||||
#include "tensorflow/core/lib/core/status.h"
|
||||
+#include "tensorflow/core/util/tensor_ops_util.h"
|
||||
|
||||
namespace tensorflow {
|
||||
namespace {
|
||||
|
||||
-struct RaggedTensor {
|
||||
- Tensor values;
|
||||
- std::vector<Tensor> nested_splits;
|
||||
-};
|
||||
-
|
||||
-Status RaggedToVariant(const RaggedTensor& ragged, Tensor* encoded_list) {
|
||||
- // Encode as a rank-1 Variant Tensor.
|
||||
- int ragged_rank = ragged.nested_splits.size();
|
||||
- *encoded_list = Tensor(DT_VARIANT, TensorShape({ragged_rank + 1}));
|
||||
- auto encoded_vec = encoded_list->vec<Variant>();
|
||||
- for (int i = 0; i < ragged_rank; i++) {
|
||||
- encoded_vec(i) = ragged.nested_splits[i];
|
||||
- }
|
||||
- encoded_vec(ragged_rank) = ragged.values;
|
||||
- return Status::OK();
|
||||
-}
|
||||
-
|
||||
template <typename VALUE_TYPE, typename SPLIT_TYPE>
|
||||
-Status UnbatchRaggedZerothDim(const RaggedTensor& batched_ragged,
|
||||
- std::vector<RaggedTensor>* ragged_components) {
|
||||
+Status UnbatchRaggedZerothDim(
|
||||
+ const RaggedTensorVariant& batched_ragged,
|
||||
+ std::vector<RaggedTensorVariant>* ragged_components) {
|
||||
// Set up the component Ragged Tensors.
|
||||
- int ragged_rank = batched_ragged.nested_splits.size();
|
||||
- auto batched_splits_top_vec =
|
||||
- batched_ragged.nested_splits[0].vec<SPLIT_TYPE>();
|
||||
+ int ragged_rank = batched_ragged.ragged_rank();
|
||||
+ auto batched_splits_top_vec = batched_ragged.splits(0).vec<SPLIT_TYPE>();
|
||||
int num_components = batched_splits_top_vec.size() - 1;
|
||||
int num_splits = ragged_rank - 1;
|
||||
ragged_components->resize(num_components);
|
||||
- for (RaggedTensor ragged_component : *ragged_components) {
|
||||
- ragged_component.nested_splits.reserve(num_splits);
|
||||
+ for (RaggedTensorVariant& ragged_component : *ragged_components) {
|
||||
+ ragged_component.mutable_nested_splits()->reserve(num_splits);
|
||||
}
|
||||
- const auto& batched_flat = batched_ragged.values.flat<VALUE_TYPE>();
|
||||
- int num_inner_elems = batched_ragged.values.NumElements();
|
||||
- if (batched_ragged.values.dim_size(0) > 1) {
|
||||
- num_inner_elems /= batched_ragged.values.dim_size(0);
|
||||
+ const auto& batched_flat = batched_ragged.values().flat<VALUE_TYPE>();
|
||||
+ int num_inner_elems = batched_ragged.values().NumElements();
|
||||
+ if (batched_ragged.values().dim_size(0) > 1) {
|
||||
+ num_inner_elems /= batched_ragged.values().dim_size(0);
|
||||
}
|
||||
- TensorShape values_shape = batched_ragged.values.shape();
|
||||
+ TensorShape values_shape = batched_ragged.values().shape();
|
||||
|
||||
// Corner case: ragged_rank == 1, e.g. [[1, 2, 3], [4, 5]]
|
||||
if (num_splits == 0) {
|
||||
@@ -70,10 +58,10 @@ Status UnbatchRaggedZerothDim(const RaggedTensor& batched_ragged,
|
||||
int limit = batched_splits_top_vec(i + 1);
|
||||
int num_values = limit - start;
|
||||
values_shape.set_dim(0, num_values);
|
||||
- (*ragged_components)[i].values =
|
||||
- Tensor(DataTypeToEnum<VALUE_TYPE>::value, values_shape);
|
||||
+ (*ragged_components)[i].set_values(
|
||||
+ Tensor(DataTypeToEnum<VALUE_TYPE>::value, values_shape));
|
||||
auto ragged_component_values_flat =
|
||||
- (*ragged_components)[i].values.flat<VALUE_TYPE>();
|
||||
+ (*ragged_components)[i].mutable_values()->flat<VALUE_TYPE>();
|
||||
for (int j = 0; j < num_values * num_inner_elems; j++) {
|
||||
ragged_component_values_flat(j) =
|
||||
batched_flat(j + start * num_inner_elems);
|
||||
@@ -86,8 +74,7 @@ Status UnbatchRaggedZerothDim(const RaggedTensor& batched_ragged,
|
||||
std::vector<typename TTypes<SPLIT_TYPE>::ConstVec> batched_splits_vec;
|
||||
batched_splits_vec.reserve(ragged_rank);
|
||||
for (int i = 0; i < ragged_rank; i++) {
|
||||
- batched_splits_vec.push_back(
|
||||
- batched_ragged.nested_splits[i].vec<SPLIT_TYPE>());
|
||||
+ batched_splits_vec.push_back(batched_ragged.splits(i).vec<SPLIT_TYPE>());
|
||||
}
|
||||
std::vector<int> index(num_splits, 1);
|
||||
std::vector<int> ragged_component_values_size(num_components, 0);
|
||||
@@ -104,10 +91,10 @@ Status UnbatchRaggedZerothDim(const RaggedTensor& batched_ragged,
|
||||
int last_index = ragged_component_splits_vec[j - 1].size() - 1;
|
||||
split_size = ragged_component_splits_vec[j - 1](last_index) + 1;
|
||||
}
|
||||
- (*ragged_components)[i].nested_splits.push_back(
|
||||
+ (*ragged_components)[i].append_splits(
|
||||
Tensor(DataTypeToEnum<SPLIT_TYPE>::value, TensorShape({split_size})));
|
||||
ragged_component_splits_vec.push_back(
|
||||
- (*ragged_components)[i].nested_splits[j].vec<SPLIT_TYPE>());
|
||||
+ (*ragged_components)[i].mutable_splits(j)->vec<SPLIT_TYPE>());
|
||||
SPLIT_TYPE last_split_value = batched_splits_vec[j + 1](index[j] - 1);
|
||||
ragged_component_splits_vec[j](0) = 0;
|
||||
for (int k = 1; k < split_size; k++, index[j]++) {
|
||||
@@ -125,10 +112,10 @@ Status UnbatchRaggedZerothDim(const RaggedTensor& batched_ragged,
|
||||
for (int i = 0; i < num_components; i++) {
|
||||
int num_values = ragged_component_values_size[i];
|
||||
values_shape.set_dim(0, num_values);
|
||||
- (*ragged_components)[i].values =
|
||||
- Tensor(DataTypeToEnum<VALUE_TYPE>::value, values_shape);
|
||||
+ (*ragged_components)[i].set_values(
|
||||
+ Tensor(DataTypeToEnum<VALUE_TYPE>::value, values_shape));
|
||||
auto ragged_component_values_flat =
|
||||
- (*ragged_components)[i].values.flat<VALUE_TYPE>();
|
||||
+ (*ragged_components)[i].mutable_values()->flat<VALUE_TYPE>();
|
||||
for (int j = 0; j < num_values * num_inner_elems; j++, value_index++) {
|
||||
ragged_component_values_flat(j) = batched_flat(value_index);
|
||||
}
|
||||
@@ -152,24 +139,21 @@ class RaggedTensorToVariantOp : public OpKernel {
|
||||
OP_REQUIRES_OK(context, context->input_list("rt_nested_splits",
|
||||
&ragged_nested_splits_in));
|
||||
const int ragged_nested_splits_len = ragged_nested_splits_in.size();
|
||||
- RaggedTensor batched_ragged_input;
|
||||
+ RaggedTensorVariant batched_ragged_input;
|
||||
// Read ragged_values input.
|
||||
- batched_ragged_input.values = context->input(ragged_nested_splits_len);
|
||||
- batched_ragged_input.nested_splits.reserve(ragged_nested_splits_len);
|
||||
+ batched_ragged_input.set_values(context->input(ragged_nested_splits_len));
|
||||
+ batched_ragged_input.mutable_nested_splits()->reserve(
|
||||
+ ragged_nested_splits_len);
|
||||
for (int i = 0; i < ragged_nested_splits_len; i++) {
|
||||
- batched_ragged_input.nested_splits.push_back(ragged_nested_splits_in[i]);
|
||||
+ batched_ragged_input.append_splits(ragged_nested_splits_in[i]);
|
||||
}
|
||||
|
||||
if (!batched_input_) {
|
||||
- // Encode the input as is.
|
||||
- Tensor encoded_list;
|
||||
- OP_REQUIRES_OK(context,
|
||||
- RaggedToVariant(batched_ragged_input, &encoded_list));
|
||||
// Encode as a Scalar Variant Tensor.
|
||||
Tensor* encoded_scalar;
|
||||
OP_REQUIRES_OK(context, context->allocate_output(0, TensorShape({}),
|
||||
&encoded_scalar));
|
||||
- encoded_scalar->scalar<Variant>()() = std::move(encoded_list);
|
||||
+ encoded_scalar->scalar<Variant>()() = std::move(batched_ragged_input);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -180,24 +164,19 @@ class RaggedTensorToVariantOp : public OpKernel {
|
||||
"received rt_nested_splits of length 0."));
|
||||
|
||||
// Unbatch the Ragged Tensor and encode the components.
|
||||
- std::vector<RaggedTensor> ragged_components;
|
||||
+ std::vector<RaggedTensorVariant> unbatched_ragged_input;
|
||||
OP_REQUIRES_OK(context, UnbatchRaggedZerothDim<VALUE_TYPE, SPLIT_TYPE>(
|
||||
- batched_ragged_input, &ragged_components));
|
||||
- std::vector<Tensor> encoded_components(ragged_components.size());
|
||||
- for (int i = 0; i < ragged_components.size(); i++) {
|
||||
- OP_REQUIRES_OK(context, RaggedToVariant(ragged_components[i],
|
||||
- &encoded_components[i]));
|
||||
- }
|
||||
+ batched_ragged_input, &unbatched_ragged_input));
|
||||
|
||||
// Bundle the encoded scalar Variant Tensors into a rank-1 Variant Tensor.
|
||||
- Tensor* encoded_ragged;
|
||||
- int output_size = ragged_components.size();
|
||||
+ Tensor* encoded_vector;
|
||||
+ int output_size = unbatched_ragged_input.size();
|
||||
OP_REQUIRES_OK(context,
|
||||
context->allocate_output(0, TensorShape({output_size}),
|
||||
- &encoded_ragged));
|
||||
- auto encoded_ragged_vec = encoded_ragged->vec<Variant>();
|
||||
+ &encoded_vector));
|
||||
+ auto encoded_vector_t = encoded_vector->vec<Variant>();
|
||||
for (int i = 0; i < output_size; i++) {
|
||||
- encoded_ragged_vec(i) = encoded_components[i];
|
||||
+ encoded_vector_t(i) = unbatched_ragged_input[i];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -205,12 +184,81 @@ class RaggedTensorToVariantOp : public OpKernel {
|
||||
bool batched_input_;
|
||||
};
|
||||
|
||||
-#define REGISTER_KERNELS_WITH_SPLIT_TYPE(value_type, split_type) \
|
||||
- REGISTER_KERNEL_BUILDER(Name("RaggedTensorToVariant") \
|
||||
- .Device(DEVICE_CPU) \
|
||||
- .TypeConstraint<value_type>("Tvalues") \
|
||||
- .TypeConstraint<split_type>("Tsplits"), \
|
||||
- RaggedTensorToVariantOp<value_type, split_type>);
|
||||
+template <typename VALUE_TYPE, typename SPLIT_TYPE>
|
||||
+class RaggedTensorToVariantGradientOp : public OpKernel {
|
||||
+ public:
|
||||
+ using OpKernel::OpKernel;
|
||||
+
|
||||
+ void Compute(OpKernelContext* context) override {
|
||||
+ // Read inputs.
|
||||
+ Tensor encoded_variant = context->input(0);
|
||||
+ Tensor row_splits = context->input(1);
|
||||
+ auto flat_row_splits = row_splits.flat<SPLIT_TYPE>();
|
||||
+ TensorShape dense_values_shape;
|
||||
+ OP_REQUIRES_OK(context,
|
||||
+ TensorShapeUtils::MakeShape(context->input(2).vec<int32>(),
|
||||
+ &dense_values_shape));
|
||||
+
|
||||
+ const auto& flat_variants = encoded_variant.flat<Variant>();
|
||||
+
|
||||
+ // Get a Tensor containing the flat_values for each variant.
|
||||
+ std::vector<Tensor> values;
|
||||
+ for (int i = 0; i < flat_variants.size(); ++i) {
|
||||
+ if (const auto* encoded = flat_variants(i).get<RaggedTensorVariant>()) {
|
||||
+ values.push_back(encoded->values());
|
||||
+ } else {
|
||||
+ // Missing value: this happens if only some of the variant values
|
||||
+ // generated by ragged_tensor_to_variant impacted the value that we're
|
||||
+ // calculating the gradient for. In this case, we will see a
|
||||
+ // default-constructed variant; so treat it as a zero tensor with the
|
||||
+ // appropriate shape.
|
||||
+ const auto value_dtype = DataTypeToEnum<VALUE_TYPE>::v();
|
||||
+ int piece_size = flat_row_splits(i + 1) - flat_row_splits(i);
|
||||
+ TensorShape zeros_shape = dense_values_shape;
|
||||
+ zeros_shape.set_dim(0, piece_size);
|
||||
+ Tensor zero(value_dtype, zeros_shape);
|
||||
+ zero.flat<VALUE_TYPE>() =
|
||||
+ zero.flat<VALUE_TYPE>().constant(VALUE_TYPE());
|
||||
+ values.push_back(zero);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (values.size() == 1) {
|
||||
+ // Just one flat_value tensor: return as-is.
|
||||
+ context->set_output(0, values[0]);
|
||||
+ } else {
|
||||
+ // Multiple flat_values tensors: concatenate them together.
|
||||
+ using Piece = typename TTypes<VALUE_TYPE, 2>::Matrix;
|
||||
+ using ConstPiece = typename TTypes<VALUE_TYPE, 2>::ConstMatrix;
|
||||
+ std::vector<std::unique_ptr<ConstPiece>> pieces;
|
||||
+ pieces.reserve(values.size());
|
||||
+ for (const Tensor& t : values) {
|
||||
+ pieces.emplace_back(
|
||||
+ new ConstPiece(t.shaped<VALUE_TYPE, 2>({1, t.NumElements()})));
|
||||
+ }
|
||||
+ Tensor* out = nullptr;
|
||||
+ OP_REQUIRES_OK(context,
|
||||
+ context->allocate_output(0, dense_values_shape, &out));
|
||||
+ Piece out_flat =
|
||||
+ out->shaped<VALUE_TYPE, 2>({1, dense_values_shape.num_elements()});
|
||||
+ ConcatCPU<VALUE_TYPE>(context->device(), pieces, &out_flat);
|
||||
+ }
|
||||
+ }
|
||||
+};
|
||||
+
|
||||
+#define REGISTER_KERNELS_WITH_SPLIT_TYPE(value_type, split_type) \
|
||||
+ REGISTER_KERNEL_BUILDER(Name("RaggedTensorToVariant") \
|
||||
+ .Device(DEVICE_CPU) \
|
||||
+ .TypeConstraint<value_type>("Tvalues") \
|
||||
+ .TypeConstraint<split_type>("Tsplits"), \
|
||||
+ RaggedTensorToVariantOp<value_type, split_type>); \
|
||||
+ REGISTER_KERNEL_BUILDER( \
|
||||
+ Name("RaggedTensorToVariantGradient") \
|
||||
+ .Device(DEVICE_CPU) \
|
||||
+ .TypeConstraint<value_type>("Tvalues") \
|
||||
+ .TypeConstraint<split_type>("Tsplits"), \
|
||||
+ RaggedTensorToVariantGradientOp<value_type, split_type>);
|
||||
+
|
||||
#define REGISTER_KERNELS(value_type) \
|
||||
REGISTER_KERNELS_WITH_SPLIT_TYPE(value_type, int32) \
|
||||
REGISTER_KERNELS_WITH_SPLIT_TYPE(value_type, int64)
|
||||
diff --git a/tensorflow/core/kernels/ragged_tensor_variant.cc b/tensorflow/core/kernels/ragged_tensor_variant.cc
|
||||
new file mode 100644
|
||||
index 00000000..94663138
|
||||
--- /dev/null
|
||||
+++ b/tensorflow/core/kernels/ragged_tensor_variant.cc
|
||||
@@ -0,0 +1,86 @@
|
||||
+/* Copyright 2020 The TensorFlow Authors. All Rights Reserved.
|
||||
+
|
||||
+Licensed under the Apache License, Version 2.0 (the "License");
|
||||
+you may not use this file except in compliance with the License.
|
||||
+You may obtain a copy of the License at
|
||||
+
|
||||
+ http://www.apache.org/licenses/LICENSE-2.0
|
||||
+
|
||||
+Unless required by applicable law or agreed to in writing, software
|
||||
+distributed under the License is distributed on an "AS IS" BASIS,
|
||||
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
+See the License for the specific language governing permissions and
|
||||
+limitations under the License.
|
||||
+==============================================================================*/
|
||||
+
|
||||
+#define EIGEN_USE_THREADS
|
||||
+#if GOOGLE_CUDA || TENSORFLOW_USE_ROCM
|
||||
+#define EIGEN_USE_GPU
|
||||
+#endif // GOOGLE_CUDA || TENSORFLOW_USE_ROCM
|
||||
+
|
||||
+#include "tensorflow/core/kernels/ragged_tensor_variant.h"
|
||||
+
|
||||
+namespace tensorflow {
|
||||
+
|
||||
+string RaggedTensorVariant::TypeName() const { return "RaggedTensorVariant"; }
|
||||
+
|
||||
+string RaggedTensorVariant::DebugString() const {
|
||||
+ return absl::StrCat(
|
||||
+ "RaggedTensorVariant(dtype=", DataTypeString(values_.dtype()),
|
||||
+ ", ragged_rank=", nested_splits_.size(), ", splits_dtype=",
|
||||
+ DataTypeString(nested_splits_.empty() ? DT_INVALID
|
||||
+ : nested_splits_.back().dtype()));
|
||||
+}
|
||||
+
|
||||
+void RaggedTensorVariant::Encode(VariantTensorData* data) const {
|
||||
+ data->set_type_name(TypeName());
|
||||
+ for (const auto& splits : nested_splits_) {
|
||||
+ *data->add_tensors() = splits;
|
||||
+ }
|
||||
+ *data->add_tensors() = values_;
|
||||
+}
|
||||
+
|
||||
+bool RaggedTensorVariant::Decode(const VariantTensorData& data) {
|
||||
+ if (data.tensors_size() < 1) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ nested_splits_.assign(data.tensors().begin(),
|
||||
+ std::prev(data.tensors().end()));
|
||||
+ values_ = data.tensors().back();
|
||||
+ return true;
|
||||
+}
|
||||
+
|
||||
+namespace {
|
||||
+
|
||||
+Status RaggedTensorVariantDeviceCopy(
|
||||
+ const RaggedTensorVariant& from, RaggedTensorVariant* to,
|
||||
+ const UnaryVariantOpRegistry::AsyncTensorDeviceCopyFn& copy) {
|
||||
+ TF_RETURN_IF_ERROR(copy(from.values(), to->mutable_values()));
|
||||
+ // TODO(b/170415165) Should we use `copy` to move splits from device<->host?
|
||||
+ *to->mutable_nested_splits() = from.nested_splits();
|
||||
+ return Status::OK();
|
||||
+}
|
||||
+
|
||||
+} // namespace
|
||||
+
|
||||
+REGISTER_UNARY_VARIANT_UNARY_OP_FUNCTION(
|
||||
+ ZEROS_LIKE_VARIANT_UNARY_OP, DEVICE_CPU, RaggedTensorVariant,
|
||||
+ RaggedTensorVariantZerosLike<CPUDevice>);
|
||||
+
|
||||
+REGISTER_UNARY_VARIANT_BINARY_OP_FUNCTION(
|
||||
+ ADD_VARIANT_BINARY_OP, DEVICE_CPU, RaggedTensorVariant,
|
||||
+ RaggedTensorVariantBinaryAdd<CPUDevice>);
|
||||
+
|
||||
+REGISTER_UNARY_VARIANT_DECODE_FUNCTION(RaggedTensorVariant,
|
||||
+ "RaggedTensorVariant");
|
||||
+
|
||||
+#define REGISTER_RAGGED_TENSOR_VARIANT_COPY(DIRECTION) \
|
||||
+ INTERNAL_REGISTER_UNARY_VARIANT_DEVICE_COPY_FUNCTION( \
|
||||
+ RaggedTensorVariant, DIRECTION, RaggedTensorVariantDeviceCopy)
|
||||
+
|
||||
+REGISTER_RAGGED_TENSOR_VARIANT_COPY(VariantDeviceCopyDirection::HOST_TO_DEVICE);
|
||||
+REGISTER_RAGGED_TENSOR_VARIANT_COPY(VariantDeviceCopyDirection::DEVICE_TO_HOST);
|
||||
+REGISTER_RAGGED_TENSOR_VARIANT_COPY(
|
||||
+ VariantDeviceCopyDirection::DEVICE_TO_DEVICE);
|
||||
+
|
||||
+} // namespace tensorflow
|
||||
diff --git a/tensorflow/core/kernels/ragged_tensor_variant.h b/tensorflow/core/kernels/ragged_tensor_variant.h
|
||||
new file mode 100644
|
||||
index 00000000..730758a3
|
||||
--- /dev/null
|
||||
+++ b/tensorflow/core/kernels/ragged_tensor_variant.h
|
||||
@@ -0,0 +1,110 @@
|
||||
+#include "tensorflow/core/framework/tensor_key.h"
|
||||
+/* Copyright 2020 The TensorFlow Authors. All Rights Reserved.
|
||||
+
|
||||
+Licensed under the Apache License, Version 2.0 (the "License");
|
||||
+you may not use this file except in compliance with the License.
|
||||
+You may obtain a copy of the License at
|
||||
+
|
||||
+ http://www.apache.org/licenses/LICENSE-2.0
|
||||
+
|
||||
+Unless required by applicable law or agreed to in writing, software
|
||||
+distributed under the License is distributed on an "AS IS" BASIS,
|
||||
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
+See the License for the specific language governing permissions and
|
||||
+limitations under the License.
|
||||
+==============================================================================*/
|
||||
+
|
||||
+#ifndef TENSORFLOW_CORE_KERNELS_RAGGED_TENSOR_VARIANT_H_
|
||||
+#define TENSORFLOW_CORE_KERNELS_RAGGED_TENSOR_VARIANT_H_
|
||||
+
|
||||
+#define EIGEN_USE_THREADS
|
||||
+#if GOOGLE_CUDA || TENSORFLOW_USE_ROCM
|
||||
+#define EIGEN_USE_GPU
|
||||
+#endif // GOOGLE_CUDA || TENSORFLOW_USE_ROCM
|
||||
+
|
||||
+#include <vector>
|
||||
+
|
||||
+#include "tensorflow/core/framework/tensor.h"
|
||||
+#include "tensorflow/core/framework/types.h"
|
||||
+#include "tensorflow/core/framework/variant_op_registry.h"
|
||||
+#include "tensorflow/core/framework/variant_tensor_data.h"
|
||||
+#include "tensorflow/core/kernels/cwise_ops_common.h"
|
||||
+#include "tensorflow/core/util/tensor_ops_util.h"
|
||||
+
|
||||
+namespace tensorflow {
|
||||
+
|
||||
+// Class used to store a RaggedTensor as a Variant scalar.
|
||||
+class RaggedTensorVariant {
|
||||
+ public:
|
||||
+ RaggedTensorVariant() {}
|
||||
+ RaggedTensorVariant(Tensor values, const std::vector<Tensor>& nested_splits)
|
||||
+ : values_(std::move(values)), nested_splits_(nested_splits) {}
|
||||
+
|
||||
+ // Variant support methods.
|
||||
+ string TypeName() const;
|
||||
+ string DebugString() const;
|
||||
+ void Encode(VariantTensorData* data) const;
|
||||
+ bool Decode(const VariantTensorData& data);
|
||||
+
|
||||
+ // The flat_values of the RaggedTensor.
|
||||
+ const Tensor& values() const { return values_; }
|
||||
+ Tensor* mutable_values() { return &values_; }
|
||||
+ void set_values(const Tensor& new_values) { values_ = new_values; }
|
||||
+
|
||||
+ // The nested row_splits of the RaggedTensor.
|
||||
+ int ragged_rank() const { return nested_splits_.size(); }
|
||||
+ const std::vector<Tensor>& nested_splits() const { return nested_splits_; }
|
||||
+ std::vector<Tensor>* mutable_nested_splits() { return &nested_splits_; }
|
||||
+ const Tensor& splits(int i) const { return nested_splits_[i]; }
|
||||
+ Tensor* mutable_splits(int i) { return &nested_splits_[i]; }
|
||||
+ void set_nested_splits(const std::vector<Tensor>& nested_splits) {
|
||||
+ nested_splits_ = nested_splits;
|
||||
+ }
|
||||
+ void append_splits(const Tensor& splits) { nested_splits_.push_back(splits); }
|
||||
+
|
||||
+ private:
|
||||
+ Tensor values_;
|
||||
+ std::vector<Tensor> nested_splits_;
|
||||
+};
|
||||
+
|
||||
+template <typename Device>
|
||||
+Status RaggedTensorVariantZerosLike(OpKernelContext* c,
|
||||
+ const RaggedTensorVariant& x,
|
||||
+ RaggedTensorVariant* y) {
|
||||
+ y->set_nested_splits(x.nested_splits());
|
||||
+ TF_RETURN_IF_ERROR(
|
||||
+ ZerosLikeTensor<Device>(c, x.values(), y->mutable_values()));
|
||||
+ return Status::OK();
|
||||
+}
|
||||
+
|
||||
+template <typename Device>
|
||||
+Status RaggedTensorVariantBinaryAdd(OpKernelContext* c,
|
||||
+ const RaggedTensorVariant& x,
|
||||
+ const RaggedTensorVariant& y,
|
||||
+ RaggedTensorVariant* out) {
|
||||
+ if (x.values().dtype() != y.values().dtype()) {
|
||||
+ return errors::InvalidArgument(
|
||||
+ "Can't add RaggedTensorVariants of different dtypes. One is ",
|
||||
+ DataTypeString(x.values().dtype()), " and the other is ",
|
||||
+ DataTypeString(y.values().dtype()));
|
||||
+ }
|
||||
+ if (x.ragged_rank() != y.ragged_rank()) {
|
||||
+ return errors::InvalidArgument(
|
||||
+ "Can't add RaggedTensorVariants of different ragged rank. ", "One is ",
|
||||
+ x.ragged_rank(), " and the other is ", y.ragged_rank());
|
||||
+ }
|
||||
+ for (int i = 0; i < x.ragged_rank(); ++i) {
|
||||
+ if (TensorKey(x.splits(i)) != TensorKey(y.splits(i))) {
|
||||
+ return errors::InvalidArgument(
|
||||
+ "Can't add RaggedTensorVariants with different row_splits.");
|
||||
+ }
|
||||
+ }
|
||||
+ out->set_nested_splits(x.nested_splits());
|
||||
+ TF_RETURN_IF_ERROR(BinaryAddTensors<Device>(c, x.values(), y.values(),
|
||||
+ out->mutable_values()));
|
||||
+ return Status::OK();
|
||||
+}
|
||||
+
|
||||
+} // namespace tensorflow
|
||||
+
|
||||
+#endif // TENSORFLOW_CORE_KERNELS_RAGGED_TENSOR_VARIANT_H_
|
||||
diff --git a/tensorflow/core/ops/ragged_conversion_ops.cc b/tensorflow/core/ops/ragged_conversion_ops.cc
|
||||
index 6bee189c..8512bcf3 100644
|
||||
--- a/tensorflow/core/ops/ragged_conversion_ops.cc
|
||||
+++ b/tensorflow/core/ops/ragged_conversion_ops.cc
|
||||
@@ -92,7 +92,8 @@ tensorflow::Status ValidateRowPartitionTypesAndShapes(
|
||||
Status RaggedTensorToSparseShapeFn(InferenceContext* c);
|
||||
Status RaggedTensorToVariantShapeFn(InferenceContext* c);
|
||||
Status RaggedTensorFromVariantShapeFn(InferenceContext* c);
|
||||
-tensorflow::Status RaggedTensorToTensorShapeFn(InferenceContext* c);
|
||||
+Status RaggedTensorToVariantGradientShapeFn(InferenceContext* c);
|
||||
+Status RaggedTensorToTensorShapeFn(InferenceContext* c);
|
||||
|
||||
//==============================================================================
|
||||
// Registered Ops
|
||||
@@ -129,6 +130,15 @@ REGISTER_OP("RaggedTensorFromVariant")
|
||||
.Attr("Tsplits: {int32, int64} = DT_INT64")
|
||||
.SetShapeFn(RaggedTensorFromVariantShapeFn);
|
||||
|
||||
+REGISTER_OP("RaggedTensorToVariantGradient")
|
||||
+ .Input("encoded_ragged_grad: variant")
|
||||
+ .Input("row_splits: Tsplits")
|
||||
+ .Input("dense_values_shape: int32")
|
||||
+ .Output("dense_values_grad: Tvalues")
|
||||
+ .Attr("Tvalues: type")
|
||||
+ .Attr("Tsplits: {int32, int64} = DT_INT64")
|
||||
+ .SetShapeFn(RaggedTensorToVariantGradientShapeFn);
|
||||
+
|
||||
REGISTER_OP("RaggedTensorToTensor")
|
||||
.Attr("T: type")
|
||||
.Attr("Tindex: {int64, int32}")
|
||||
@@ -201,6 +211,14 @@ Status RaggedTensorToVariantShapeFn(InferenceContext* c) {
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
+Status RaggedTensorToVariantGradientShapeFn(InferenceContext* c) {
|
||||
+ ShapeHandle shape;
|
||||
+ TF_RETURN_IF_ERROR(
|
||||
+ c->MakeShapeFromShapeTensorTreatScalarAsUnknownShape(2, &shape));
|
||||
+ c->set_output(0, shape);
|
||||
+ return Status::OK();
|
||||
+}
|
||||
+
|
||||
Status RaggedTensorFromVariantShapeFn(InferenceContext* c) {
|
||||
int64 input_ragged_rank;
|
||||
TF_RETURN_IF_ERROR(
|
||||
diff --git a/tensorflow/python/ops/ragged/BUILD b/tensorflow/python/ops/ragged/BUILD
|
||||
index 95e5602a..34372160 100644
|
||||
--- a/tensorflow/python/ops/ragged/BUILD
|
||||
+++ b/tensorflow/python/ops/ragged/BUILD
|
||||
@@ -507,6 +507,7 @@ py_test(
|
||||
"//tensorflow/python:framework_ops",
|
||||
"//tensorflow/python:framework_test_lib",
|
||||
"//tensorflow/python:platform_test",
|
||||
+ "//tensorflow/python:tensor_array_grad",
|
||||
"//tensorflow/python:tensor_shape",
|
||||
"//tensorflow/python:tensor_spec",
|
||||
"//tensorflow/python/data/ops:dataset_ops",
|
||||
--
|
||||
2.27.0
|
||||
|
||||
@ -1,30 +0,0 @@
|
||||
From b055b9c474cd376259dde8779908f9eeaf097d93 Mon Sep 17 00:00:00 2001
|
||||
From: Amit Patankar <amitpatankar@google.com>
|
||||
Date: Tue, 13 Apr 2021 14:49:50 -0700
|
||||
Subject: [PATCH] Fix `tf.raw_ops.RaggedTensorToVariant` invalid resize.
|
||||
|
||||
PiperOrigin-RevId: 368299574
|
||||
Change-Id: I751c186325aa0bab397928845e790e60c2d90918
|
||||
---
|
||||
tensorflow/core/kernels/ragged_tensor_to_variant_op.cc | 5 +++++
|
||||
1 file changed, 5 insertions(+)
|
||||
|
||||
diff --git a/tensorflow/core/kernels/ragged_tensor_to_variant_op.cc b/tensorflow/core/kernels/ragged_tensor_to_variant_op.cc
|
||||
index a60e5c62..fb1f25fc 100644
|
||||
--- a/tensorflow/core/kernels/ragged_tensor_to_variant_op.cc
|
||||
+++ b/tensorflow/core/kernels/ragged_tensor_to_variant_op.cc
|
||||
@@ -165,6 +165,11 @@ class RaggedTensorToVariantOp : public OpKernel {
|
||||
|
||||
// Unbatch the Ragged Tensor and encode the components.
|
||||
std::vector<RaggedTensorVariant> unbatched_ragged_input;
|
||||
+ auto batched_splits_top_vec =
|
||||
+ batched_ragged_input.splits(0).vec<SPLIT_TYPE>();
|
||||
+ int num_components = batched_splits_top_vec.size() - 1;
|
||||
+ OP_REQUIRES(context, num_components >= 0,
|
||||
+ errors::Internal("Invalid split argument."));
|
||||
OP_REQUIRES_OK(context, UnbatchRaggedZerothDim<VALUE_TYPE, SPLIT_TYPE>(
|
||||
batched_ragged_input, &unbatched_ragged_input));
|
||||
|
||||
--
|
||||
2.27.0
|
||||
|
||||
@ -1,611 +0,0 @@
|
||||
From cc5ea8469641b6680971eb76020407f81ab3f573 Mon Sep 17 00:00:00 2001
|
||||
From: Anna R <annarev@google.com>
|
||||
Date: Wed, 9 Dec 2020 16:13:53 -0800
|
||||
Subject: [PATCH] Remove changes made to support TFRT-based OpKernel classes in
|
||||
|
||||
---
|
||||
tensorflow/core/framework/BUILD | 3 -
|
||||
tensorflow/core/framework/numeric_op.h | 21 ++-
|
||||
tensorflow/core/framework/numeric_op_base.h | 49 -----
|
||||
tensorflow/core/kernels/BUILD | 47 +----
|
||||
tensorflow/core/kernels/conv_ops_3d.cc | 153 ++++++++++++++--
|
||||
tensorflow/core/kernels/conv_ops_3d.h | 187 --------------------
|
||||
6 files changed, 161 insertions(+), 299 deletions(-)
|
||||
|
||||
diff --git a/tensorflow/core/framework/BUILD b/tensorflow/core/framework/BUILD
|
||||
index d47c74a6..9b6ddb2a 100644
|
||||
--- a/tensorflow/core/framework/BUILD
|
||||
+++ b/tensorflow/core/framework/BUILD
|
||||
@@ -51,7 +51,6 @@ exports_files(
|
||||
"model.h",
|
||||
"node_def_builder.h",
|
||||
"numeric_op.h",
|
||||
- "numeric_op_base.h",
|
||||
"op_kernel.h",
|
||||
"op_requires.h",
|
||||
"op_segment.h",
|
||||
@@ -183,7 +182,6 @@ filegroup(
|
||||
"node_def_util.h",
|
||||
"node_properties.h",
|
||||
"numeric_op.h",
|
||||
- "numeric_op_base.h",
|
||||
"numeric_types.h",
|
||||
"op.h",
|
||||
"op_def_builder.h",
|
||||
@@ -280,7 +278,6 @@ filegroup(
|
||||
"kernel_shape_util.h",
|
||||
"log_memory.cc",
|
||||
"log_memory.h",
|
||||
- "numeric_op_base.h",
|
||||
"numeric_types.h",
|
||||
"op_requires.h",
|
||||
"ops_util.cc",
|
||||
diff --git a/tensorflow/core/framework/numeric_op.h b/tensorflow/core/framework/numeric_op.h
|
||||
index 9f8ceed2..ad452bcd 100644
|
||||
--- a/tensorflow/core/framework/numeric_op.h
|
||||
+++ b/tensorflow/core/framework/numeric_op.h
|
||||
@@ -15,19 +15,34 @@ limitations under the License.
|
||||
#ifndef TENSORFLOW_CORE_FRAMEWORK_NUMERIC_OP_H_
|
||||
#define TENSORFLOW_CORE_FRAMEWORK_NUMERIC_OP_H_
|
||||
|
||||
-#include "tensorflow/core/framework/numeric_op_base.h"
|
||||
#include "tensorflow/core/framework/op_kernel.h"
|
||||
#include "tensorflow/core/framework/tensor.h"
|
||||
+#include "tensorflow/core/framework/types.h"
|
||||
+#include "tensorflow/core/framework/types.pb.h"
|
||||
#include "tensorflow/core/lib/core/errors.h"
|
||||
#include "tensorflow/core/lib/core/status.h"
|
||||
|
||||
namespace tensorflow {
|
||||
|
||||
+// One input and one output, both the same type.
|
||||
template <class T>
|
||||
-using UnaryOp = UnaryOpBase<T, OpKernel, OpKernelConstruction>;
|
||||
+class UnaryOp : public OpKernel {
|
||||
+ public:
|
||||
+ explicit UnaryOp(OpKernelConstruction* context) : OpKernel(context) {
|
||||
+ const DataType dt = DataTypeToEnum<T>::v();
|
||||
+ OP_REQUIRES_OK(context, context->MatchSignature({dt}, {dt}));
|
||||
+ }
|
||||
+};
|
||||
|
||||
+// Two inputs and one output, all the same type.
|
||||
template <class T>
|
||||
-using BinaryOp = BinaryOpBase<T, OpKernel, OpKernelConstruction>;
|
||||
+class BinaryOp : public OpKernel {
|
||||
+ public:
|
||||
+ explicit BinaryOp(OpKernelConstruction* context) : OpKernel(context) {
|
||||
+ const DataType dt = DataTypeToEnum<T>::v();
|
||||
+ OP_REQUIRES_OK(context, context->MatchSignature({dt, dt}, {dt}));
|
||||
+ }
|
||||
+};
|
||||
|
||||
// For operations where the input and output are the same shape.
|
||||
//
|
||||
diff --git a/tensorflow/core/framework/numeric_op_base.h b/tensorflow/core/framework/numeric_op_base.h
|
||||
index be7d3bf8..e69de29b 100644
|
||||
--- a/tensorflow/core/framework/numeric_op_base.h
|
||||
+++ b/tensorflow/core/framework/numeric_op_base.h
|
||||
@@ -1,49 +0,0 @@
|
||||
-/* Copyright 2015 The TensorFlow Authors. All Rights Reserved.
|
||||
-
|
||||
-Licensed under the Apache License, Version 2.0 (the "License");
|
||||
-you may not use this file except in compliance with the License.
|
||||
-You may obtain a copy of the License at
|
||||
-
|
||||
- http://www.apache.org/licenses/LICENSE-2.0
|
||||
-
|
||||
-Unless required by applicable law or agreed to in writing, software
|
||||
-distributed under the License is distributed on an "AS IS" BASIS,
|
||||
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
-See the License for the specific language governing permissions and
|
||||
-limitations under the License.
|
||||
-==============================================================================*/
|
||||
-
|
||||
-#ifndef TENSORFLOW_CORE_FRAMEWORK_NUMERIC_OP_BASE_H_
|
||||
-#define TENSORFLOW_CORE_FRAMEWORK_NUMERIC_OP_BASE_H_
|
||||
-
|
||||
-#include "tensorflow/core/framework/op_requires.h"
|
||||
-#include "tensorflow/core/framework/types.h"
|
||||
-#include "tensorflow/core/framework/types.pb.h"
|
||||
-#include "tensorflow/core/lib/core/status.h"
|
||||
-
|
||||
-namespace tensorflow {
|
||||
-
|
||||
-// One input and one output, both the same type.
|
||||
-template <class T, class OpKernelT, class OpKernelConstructionT>
|
||||
-class UnaryOpBase : public OpKernelT {
|
||||
- public:
|
||||
- explicit UnaryOpBase(OpKernelConstructionT* construction) :
|
||||
- OpKernelT(construction) {
|
||||
- const DataType dt = DataTypeToEnum<T>::v();
|
||||
- OP_REQUIRES_OK(construction, construction->MatchSignature({dt}, {dt}));
|
||||
- }
|
||||
-};
|
||||
-
|
||||
-// Two inputs and one output, all the same type.
|
||||
-template <class T, class OpKernelT, class OpKernelConstructionT>
|
||||
-class BinaryOpBase : public OpKernelT {
|
||||
- public:
|
||||
- explicit BinaryOpBase(OpKernelConstructionT* construction) :
|
||||
- OpKernelT(construction) {
|
||||
- const DataType dt = DataTypeToEnum<T>::v();
|
||||
- OP_REQUIRES_OK(construction, construction->MatchSignature({dt, dt}, {dt}));
|
||||
- }
|
||||
-};
|
||||
-} // namespace tensorflow
|
||||
-
|
||||
-#endif // TENSORFLOW_CORE_FRAMEWORK_NUMERIC_OP_BASE_H_
|
||||
diff --git a/tensorflow/core/kernels/BUILD b/tensorflow/core/kernels/BUILD
|
||||
index 14f7d99b..5f8fa80b 100644
|
||||
--- a/tensorflow/core/kernels/BUILD
|
||||
+++ b/tensorflow/core/kernels/BUILD
|
||||
@@ -4048,48 +4048,6 @@ cc_library(
|
||||
}),
|
||||
)
|
||||
|
||||
-# TODO(annarev): conv_ops_3d_headers currently depends on android target build
|
||||
-# from selected sources. We should switch to use granular dependencies instead.
|
||||
-# Then, we can just depend on "conv3d".
|
||||
-cc_library(
|
||||
- name = "conv_3d_mobile",
|
||||
- hdrs = [
|
||||
- "conv_3d.h",
|
||||
- "eigen_backward_cuboid_convolutions.h",
|
||||
- "eigen_convolution_helpers.h",
|
||||
- "eigen_cuboid_convolution.h",
|
||||
- "eigen_volume_patch.h",
|
||||
- ],
|
||||
- deps = [
|
||||
- ":eigen_spatial_convolutions-inl",
|
||||
- ] + select({
|
||||
- "//tensorflow:android": [
|
||||
- "//tensorflow/core:portable_tensorflow_lib_lite", # TODO(annarev): exclude runtime srcs
|
||||
- ],
|
||||
- "//conditions:default": [
|
||||
- "//tensorflow/core:framework",
|
||||
- ],
|
||||
- }),
|
||||
-)
|
||||
-
|
||||
-cc_library(
|
||||
- name = "conv_ops_3d_headers",
|
||||
- hdrs = [
|
||||
- "conv_ops_3d.h",
|
||||
- ],
|
||||
- deps = select({
|
||||
- "//tensorflow:android": [
|
||||
- ":conv_3d_mobile",
|
||||
- "//tensorflow/core:portable_tensorflow_lib_lite", # TODO(annarev): exclude runtime srcs
|
||||
- ],
|
||||
- "//conditions:default": [
|
||||
- ":conv_3d",
|
||||
- "//third_party/eigen3",
|
||||
- "//tensorflow/core:framework",
|
||||
- ],
|
||||
- }),
|
||||
-)
|
||||
-
|
||||
tf_kernel_library(
|
||||
name = "argmax_op",
|
||||
prefix = "argmax_op",
|
||||
@@ -4673,6 +4631,7 @@ tf_kernel_library(
|
||||
"deep_conv2d.h",
|
||||
"gemm_functors.h",
|
||||
"winograd_transform.h",
|
||||
+ "conv_ops_fused_impl.h",
|
||||
] + select({
|
||||
":xsmm_convolutions": ["xsmm_conv2d.h"],
|
||||
"//conditions:default": [],
|
||||
@@ -4687,8 +4646,6 @@ tf_kernel_library(
|
||||
prefix = "conv_ops",
|
||||
deps = [
|
||||
":conv_grad_shape_utils",
|
||||
- ":conv_ops_3d_headers",
|
||||
- ":bounds_check",
|
||||
":conv_2d",
|
||||
":conv_3d",
|
||||
":eigen_contraction_kernel",
|
||||
@@ -6710,7 +6667,6 @@ filegroup(
|
||||
"conv_2d.h",
|
||||
"conv_3d.h",
|
||||
"conv_ops.h",
|
||||
- "conv_ops_3d.h",
|
||||
"conv_ops_gpu.h",
|
||||
"data_format_ops.h",
|
||||
"depthtospace_op.h",
|
||||
@@ -7160,7 +7116,6 @@ filegroup(
|
||||
"stateful_random_ops_cpu_gpu.h",
|
||||
# Allows conv_3d ops for android but excluded from *_3d* rule above.
|
||||
"conv_3d.h",
|
||||
- "conv_ops_3d.h",
|
||||
"conv_ops_3d.cc",
|
||||
"conv_ops_gpu.h",
|
||||
],
|
||||
diff --git a/tensorflow/core/kernels/conv_ops_3d.cc b/tensorflow/core/kernels/conv_ops_3d.cc
|
||||
index 289a083a..52356443 100644
|
||||
--- a/tensorflow/core/kernels/conv_ops_3d.cc
|
||||
+++ b/tensorflow/core/kernels/conv_ops_3d.cc
|
||||
@@ -16,8 +16,7 @@ limitations under the License.
|
||||
#define USE_EIGEN_TENSOR
|
||||
#define EIGEN_USE_THREADS
|
||||
|
||||
-#include "tensorflow/core/kernels/conv_ops_3d.h"
|
||||
-
|
||||
+#include "tensorflow/core/framework/kernel_shape_util.h"
|
||||
#include "tensorflow/core/framework/numeric_op.h"
|
||||
#include "tensorflow/core/framework/op_kernel.h"
|
||||
#include "tensorflow/core/framework/register_types.h"
|
||||
@@ -51,11 +50,146 @@ namespace tensorflow {
|
||||
typedef Eigen::ThreadPoolDevice CPUDevice;
|
||||
typedef Eigen::GpuDevice GPUDevice;
|
||||
|
||||
+template <typename Device, typename T>
|
||||
+ struct LaunchConvOp;
|
||||
+template <typename T>
|
||||
+struct LaunchConvOp<CPUDevice, T> {
|
||||
+ static void launch(OpKernelContext* context, bool cudnn_use_autotune,
|
||||
+ const Tensor& input, const Tensor& filter,
|
||||
+ const std::array<int64, 3>& dilations,
|
||||
+ const std::array<int64, 3>& strides, const Padding padding,
|
||||
+ TensorFormat data_format, Tensor* output) {
|
||||
+ OP_REQUIRES(context, data_format == FORMAT_NHWC,
|
||||
+ errors::InvalidArgument("CPU implementation of Conv3D "
|
||||
+ "currently only supports the NHWC "
|
||||
+ "tensor format."));
|
||||
+ OP_REQUIRES(context,
|
||||
+ dilations[0] == 1 && dilations[1] == 1 && dilations[2] == 1,
|
||||
+ errors::InvalidArgument("CPU implementation of Conv3D "
|
||||
+ "currently only supports dilated rates "
|
||||
+ "of 1."));
|
||||
+ functor::CuboidConvolution<CPUDevice, T>()(
|
||||
+ context->eigen_device<CPUDevice>(), output->tensor<T, 5>(),
|
||||
+ input.tensor<T, 5>(), filter.tensor<T, 5>(), strides[2], strides[1],
|
||||
+ strides[0], BrainPadding2EigenPadding(padding));
|
||||
+ }
|
||||
+};
|
||||
+
|
||||
+template <typename Device, typename T>
|
||||
+class Conv3DOp : public BinaryOp<T> {
|
||||
+ public:
|
||||
+ explicit Conv3DOp(OpKernelConstruction* context) : BinaryOp<T>(context) {
|
||||
+ string data_format;
|
||||
+ OP_REQUIRES_OK(context, context->GetAttr("data_format", &data_format));
|
||||
+ OP_REQUIRES(context, FormatFromString(data_format, &data_format_),
|
||||
+ errors::InvalidArgument("Invalid data format"));
|
||||
+ OP_REQUIRES_OK(context, context->GetAttr("strides", &stride_));
|
||||
+ OP_REQUIRES(context, stride_.size() == 5,
|
||||
+ errors::InvalidArgument("Sliding window strides field must "
|
||||
+ "specify 5 dimensions"));
|
||||
+ OP_REQUIRES(
|
||||
+ context,
|
||||
+ (GetTensorDim(stride_, data_format_, 'N') == 1 &&
|
||||
+ GetTensorDim(stride_, data_format_, 'C') == 1),
|
||||
+ errors::InvalidArgument("Current implementation does not yet support "
|
||||
+ "strides in the batch and depth dimensions."));
|
||||
+ OP_REQUIRES(
|
||||
+ context,
|
||||
+ (GetTensorDim(stride_, data_format_, '0') > 0 &&
|
||||
+ GetTensorDim(stride_, data_format_, '1') > 0 &&
|
||||
+ GetTensorDim(stride_, data_format_, '2') > 0),
|
||||
+ errors::InvalidArgument("Spatial strides should be larger than 0."));
|
||||
+ OP_REQUIRES_OK(context, context->GetAttr("dilations", &dilation_));
|
||||
+ OP_REQUIRES(context, dilation_.size() == 5,
|
||||
+ errors::InvalidArgument("Dilation rates field must "
|
||||
+ "specify 5 dimensions"));
|
||||
+ OP_REQUIRES(context,
|
||||
+ (GetTensorDim(dilation_, data_format_, 'N') == 1 &&
|
||||
+ GetTensorDim(dilation_, data_format_, 'C') == 1),
|
||||
+ errors::InvalidArgument(
|
||||
+ "Current implementation does not yet support "
|
||||
+ "dilation rates in the batch and depth dimensions."));
|
||||
+ OP_REQUIRES(
|
||||
+ context,
|
||||
+ (GetTensorDim(dilation_, data_format_, '0') > 0 &&
|
||||
+ GetTensorDim(dilation_, data_format_, '1') > 0 &&
|
||||
+ GetTensorDim(dilation_, data_format_, '2') > 0),
|
||||
+ errors::InvalidArgument("Dilated rates should be larger than 0."));
|
||||
+ OP_REQUIRES_OK(context, context->GetAttr("padding", &padding_));
|
||||
+ cudnn_use_autotune_ = CudnnUseAutotune();
|
||||
+ }
|
||||
+
|
||||
+ void Compute(OpKernelContext* context) override {
|
||||
+ // Input tensor is of the following dimensions:
|
||||
+ // [ batch, in_z, in_y, in_x, in_channels ]
|
||||
+ const Tensor& input = context->input(0);
|
||||
+
|
||||
+ // Input filter is of the following dimensions:
|
||||
+ // [ filter_z, filter_y, filter_x, in_channels, out_channels]
|
||||
+ const Tensor& filter = context->input(1);
|
||||
+
|
||||
+ // NOTE: The ordering of the spatial dimensions is arbitrary, but has to be
|
||||
+ // kept consistent between input/filter/output.
|
||||
+ OP_REQUIRES(context, input.dims() == 5,
|
||||
+ errors::InvalidArgument("input must be 5-dimensional"));
|
||||
+ OP_REQUIRES(context, filter.dims() == 5,
|
||||
+ errors::InvalidArgument("filter must be 5-dimensional"));
|
||||
+
|
||||
+ const int64 in_depth = GetTensorDim(input, data_format_, 'C');
|
||||
+ const int64 in_batch = GetTensorDim(input, data_format_, 'N');
|
||||
+
|
||||
+ const int64 filter_depth = filter.dim_size(3);
|
||||
+ const int64 out_depth = filter.dim_size(4);
|
||||
+
|
||||
+ OP_REQUIRES(context, in_depth % filter_depth == 0,
|
||||
+ errors::InvalidArgument(
|
||||
+ "Input depth must be evenly divisible by filter depth: ",
|
||||
+ in_depth, " vs ", filter_depth));
|
||||
+
|
||||
+ // Dimension order for these arrays is: z, y, x.
|
||||
+ std::array<int64, 3> input_size = {
|
||||
+ {GetTensorDim(input, data_format_, '0'),
|
||||
+ GetTensorDim(input, data_format_, '1'),
|
||||
+ GetTensorDim(input, data_format_, '2')}};
|
||||
+ std::array<int64, 3> filter_size = {
|
||||
+ {filter.dim_size(0), filter.dim_size(1), filter.dim_size(2)}};
|
||||
+ std::array<int64, 3> dilations = {
|
||||
+ {GetTensorDim(dilation_, data_format_, '0'),
|
||||
+ GetTensorDim(dilation_, data_format_, '1'),
|
||||
+ GetTensorDim(dilation_, data_format_, '2')}};
|
||||
+ std::array<int64, 3> strides = {{GetTensorDim(stride_, data_format_, '0'),
|
||||
+ GetTensorDim(stride_, data_format_, '1'),
|
||||
+ GetTensorDim(stride_, data_format_, '2')}};
|
||||
+ std::array<int64, 3> out, padding;
|
||||
+
|
||||
+ OP_REQUIRES_OK(
|
||||
+ context, Get3dOutputSizeV2(input_size, filter_size, dilations, strides,
|
||||
+ padding_, &out, &padding));
|
||||
+ TensorShape out_shape = ShapeFromFormat(
|
||||
+ data_format_, in_batch, {{out[0], out[1], out[2]}}, out_depth);
|
||||
+ Tensor* output;
|
||||
+ OP_REQUIRES_OK(context, context->allocate_output(0, out_shape, &output));
|
||||
+
|
||||
+ // Return early if nothing to do.
|
||||
+ if (out_shape.num_elements() == 0) return;
|
||||
+
|
||||
+ LaunchConvOp<Device, T>::launch(context, cudnn_use_autotune_, input, filter,
|
||||
+ dilations, strides, padding_, data_format_,
|
||||
+ output);
|
||||
+ }
|
||||
+
|
||||
+ private:
|
||||
+ std::vector<int32> dilation_;
|
||||
+ std::vector<int32> stride_;
|
||||
+ Padding padding_;
|
||||
+ TensorFormat data_format_;
|
||||
+ bool cudnn_use_autotune_;
|
||||
+};
|
||||
+
|
||||
#define REGISTER_CPU_KERNEL(T) \
|
||||
REGISTER_KERNEL_BUILDER( \
|
||||
Name("Conv3D").Device(DEVICE_CPU).TypeConstraint<T>("T"), \
|
||||
- Conv3DOp<CPUDevice, T, OpKernel, OpKernelConstruction, \
|
||||
- OpKernelContext>);
|
||||
+ Conv3DOp<CPUDevice, T>);
|
||||
TF_CALL_half(REGISTER_CPU_KERNEL);
|
||||
TF_CALL_float(REGISTER_CPU_KERNEL);
|
||||
TF_CALL_double(REGISTER_CPU_KERNEL);
|
||||
@@ -73,7 +207,7 @@ typedef AutoTuneSingleton<Conv3dAutoTuneGroup, ConvParameters,
|
||||
|
||||
// TODO(mjanusz): Share logic with 2d implementation as much as possible.
|
||||
template <typename T>
|
||||
-struct LaunchConvOp<GPUDevice, T, OpKernelContext> {
|
||||
+struct LaunchConvOp<GPUDevice, T> {
|
||||
static void launch(OpKernelContext* ctx, bool cudnn_use_autotune,
|
||||
const Tensor& input_param, const Tensor& filter,
|
||||
const std::array<int64, 3>& dilations,
|
||||
@@ -559,16 +693,13 @@ DECLARE_GPU_SPEC(double);
|
||||
// Registration of the GPU implementations.
|
||||
REGISTER_KERNEL_BUILDER(
|
||||
Name("Conv3D").Device(DEVICE_GPU).TypeConstraint<Eigen::half>("T"),
|
||||
- Conv3DOp<GPUDevice, Eigen::half, OpKernel, OpKernelConstruction,
|
||||
- OpKernelContext>);
|
||||
+ Conv3DOp<GPUDevice, Eigen::half>);
|
||||
REGISTER_KERNEL_BUILDER(
|
||||
Name("Conv3D").Device(DEVICE_GPU).TypeConstraint<float>("T"),
|
||||
- Conv3DOp<GPUDevice, float, OpKernel, OpKernelConstruction,
|
||||
- OpKernelContext>);
|
||||
+ Conv3DOp<GPUDevice, float>);
|
||||
REGISTER_KERNEL_BUILDER(
|
||||
Name("Conv3D").Device(DEVICE_GPU).TypeConstraint<double>("T"),
|
||||
- Conv3DOp<GPUDevice, double, OpKernel, OpKernelConstruction,
|
||||
- OpKernelContext>);
|
||||
+ Conv3DOp<GPUDevice, double>);
|
||||
#endif // GOOGLE_CUDA || TENSORFLOW_USE_ROCM
|
||||
|
||||
} // namespace tensorflow
|
||||
diff --git a/tensorflow/core/kernels/conv_ops_3d.h b/tensorflow/core/kernels/conv_ops_3d.h
|
||||
index 9dcdea5b..e69de29b 100644
|
||||
--- a/tensorflow/core/kernels/conv_ops_3d.h
|
||||
+++ b/tensorflow/core/kernels/conv_ops_3d.h
|
||||
@@ -1,187 +0,0 @@
|
||||
-/* Copyright 2020 The TensorFlow Authors. All Rights Reserved.
|
||||
-
|
||||
-Licensed under the Apache License, Version 2.0 (the "License");
|
||||
-you may not use this file except in compliance with the License.
|
||||
-You may obtain a copy of the License at
|
||||
-
|
||||
- http://www.apache.org/licenses/LICENSE-2.0
|
||||
-
|
||||
-Unless required by applicable law or agreed to in writing, software
|
||||
-distributed under the License is distributed on an "AS IS" BASIS,
|
||||
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
-See the License for the specific language governing permissions and
|
||||
-limitations under the License.
|
||||
-==============================================================================*/
|
||||
-#ifndef TENSORFLOW_CORE_KERNELS_CONV_OPS_3D_H_
|
||||
-#define TENSORFLOW_CORE_KERNELS_CONV_OPS_3D_H_
|
||||
-
|
||||
-#include <vector>
|
||||
-
|
||||
-#define USE_EIGEN_TENSOR
|
||||
-#define EIGEN_USE_THREADS
|
||||
-
|
||||
-#include "tensorflow/core/framework/numeric_op_base.h"
|
||||
-#include "tensorflow/core/framework/kernel_shape_util.h"
|
||||
-#include "tensorflow/core/framework/op_requires.h"
|
||||
-#include "tensorflow/core/framework/ops_util.h"
|
||||
-#include "tensorflow/core/framework/tensor.h"
|
||||
-#include "tensorflow/core/framework/tensor_shape.h"
|
||||
-#include "tensorflow/core/kernels/conv_3d.h"
|
||||
-#include "tensorflow/core/platform/errors.h"
|
||||
-#include "tensorflow/core/util/padding.h"
|
||||
-#include "tensorflow/core/util/tensor_format.h"
|
||||
-#if GOOGLE_CUDA
|
||||
-#include "tensorflow/core/util/use_cudnn.h"
|
||||
-#endif
|
||||
-
|
||||
-namespace tensorflow {
|
||||
-typedef Eigen::ThreadPoolDevice CPUDevice;
|
||||
-
|
||||
-template <typename Device, typename T, class OpKernelContextT>
|
||||
-struct LaunchConvOp;
|
||||
-
|
||||
-template <typename T, class OpKernelContextT>
|
||||
-struct LaunchConvOp<CPUDevice, T, OpKernelContextT> {
|
||||
- static void launch(OpKernelContextT* context, bool cudnn_use_autotune,
|
||||
- const Tensor& input, const Tensor& filter,
|
||||
- const std::array<int64, 3>& dilations,
|
||||
- const std::array<int64, 3>& strides, const Padding padding,
|
||||
- TensorFormat data_format, Tensor* output) {
|
||||
- OP_REQUIRES(context, data_format == FORMAT_NHWC,
|
||||
- errors::InvalidArgument("CPU implementation of Conv3D "
|
||||
- "currently only supports the NHWC "
|
||||
- "tensor format."));
|
||||
- OP_REQUIRES(context,
|
||||
- dilations[0] == 1 && dilations[1] == 1 && dilations[2] == 1,
|
||||
- errors::InvalidArgument("CPU implementation of Conv3D "
|
||||
- "currently only supports dilated rates "
|
||||
- "of 1."));
|
||||
- functor::CuboidConvolution<CPUDevice, T>()(
|
||||
- context->template eigen_device<CPUDevice>(), output->tensor<T, 5>(),
|
||||
- input.tensor<T, 5>(), filter.tensor<T, 5>(), strides[2], strides[1],
|
||||
- strides[0], BrainPadding2EigenPadding(padding));
|
||||
- }
|
||||
-};
|
||||
-
|
||||
-template <typename Device, typename T, class OpKernelT,
|
||||
- class OpKernelConstructionT, class OpKernelContextT>
|
||||
-class Conv3DOp : public BinaryOpBase<T, OpKernelT, OpKernelConstructionT> {
|
||||
- public:
|
||||
- explicit Conv3DOp(OpKernelConstructionT* context) :
|
||||
- BinaryOpBase<T, OpKernelT, OpKernelConstructionT>(context) {
|
||||
- string data_format;
|
||||
- OP_REQUIRES_OK(context, context->GetAttr("data_format", &data_format));
|
||||
- OP_REQUIRES(context, FormatFromString(data_format, &data_format_),
|
||||
- errors::InvalidArgument("Invalid data format"));
|
||||
- OP_REQUIRES_OK(context, context->GetAttr("strides", &stride_));
|
||||
- OP_REQUIRES(context, stride_.size() == 5,
|
||||
- errors::InvalidArgument("Sliding window strides field must "
|
||||
- "specify 5 dimensions"));
|
||||
- OP_REQUIRES(
|
||||
- context,
|
||||
- (GetTensorDim(stride_, data_format_, 'N') == 1 &&
|
||||
- GetTensorDim(stride_, data_format_, 'C') == 1),
|
||||
- errors::InvalidArgument("Current implementation does not yet support "
|
||||
- "strides in the batch and depth dimensions."));
|
||||
- OP_REQUIRES(
|
||||
- context,
|
||||
- (GetTensorDim(stride_, data_format_, '0') > 0 &&
|
||||
- GetTensorDim(stride_, data_format_, '1') > 0 &&
|
||||
- GetTensorDim(stride_, data_format_, '2') > 0),
|
||||
- errors::InvalidArgument("Spatial strides should be larger than 0."));
|
||||
- OP_REQUIRES_OK(context, context->GetAttr("dilations", &dilation_));
|
||||
- OP_REQUIRES(context, dilation_.size() == 5,
|
||||
- errors::InvalidArgument("Dilation rates field must "
|
||||
- "specify 5 dimensions"));
|
||||
- OP_REQUIRES(context,
|
||||
- (GetTensorDim(dilation_, data_format_, 'N') == 1 &&
|
||||
- GetTensorDim(dilation_, data_format_, 'C') == 1),
|
||||
- errors::InvalidArgument(
|
||||
- "Current implementation does not yet support "
|
||||
- "dilation rates in the batch and depth dimensions."));
|
||||
- OP_REQUIRES(
|
||||
- context,
|
||||
- (GetTensorDim(dilation_, data_format_, '0') > 0 &&
|
||||
- GetTensorDim(dilation_, data_format_, '1') > 0 &&
|
||||
- GetTensorDim(dilation_, data_format_, '2') > 0),
|
||||
- errors::InvalidArgument("Dilated rates should be larger than 0."));
|
||||
- OP_REQUIRES_OK(context, context->GetAttr("padding", &padding_));
|
||||
-#if GOOGLE_CUDA
|
||||
- cudnn_use_autotune_ = CudnnUseAutotune();
|
||||
-#else
|
||||
- cudnn_use_autotune_ = false;
|
||||
-#endif
|
||||
- }
|
||||
-
|
||||
- void Compute(OpKernelContextT* context) override {
|
||||
- // Input tensor is of the following dimensions:
|
||||
- // [ batch, in_z, in_y, in_x, in_channels ]
|
||||
- const Tensor& input = context->input(0);
|
||||
-
|
||||
- // Input filter is of the following dimensions:
|
||||
- // [ filter_z, filter_y, filter_x, in_channels, out_channels]
|
||||
- const Tensor& filter = context->input(1);
|
||||
-
|
||||
- // NOTE: The ordering of the spatial dimensions is arbitrary, but has to be
|
||||
- // kept consistent between input/filter/output.
|
||||
- OP_REQUIRES(context, input.dims() == 5,
|
||||
- errors::InvalidArgument("input must be 5-dimensional"));
|
||||
- OP_REQUIRES(context, filter.dims() == 5,
|
||||
- errors::InvalidArgument("filter must be 5-dimensional"));
|
||||
-
|
||||
- const int64 in_depth = GetTensorDim(input, data_format_, 'C');
|
||||
- const int64 in_batch = GetTensorDim(input, data_format_, 'N');
|
||||
-
|
||||
- const int64 filter_depth = filter.dim_size(3);
|
||||
- const int64 out_depth = filter.dim_size(4);
|
||||
-
|
||||
- OP_REQUIRES(context, in_depth % filter_depth == 0,
|
||||
- errors::InvalidArgument(
|
||||
- "Input depth must be evenly divisible by filter depth: ",
|
||||
- in_depth, " vs ", filter_depth));
|
||||
-
|
||||
- // Dimension order for these arrays is: z, y, x.
|
||||
- std::array<int64, 3> input_size = {
|
||||
- {GetTensorDim(input, data_format_, '0'),
|
||||
- GetTensorDim(input, data_format_, '1'),
|
||||
- GetTensorDim(input, data_format_, '2')}};
|
||||
- std::array<int64, 3> filter_size = {
|
||||
- {filter.dim_size(0), filter.dim_size(1), filter.dim_size(2)}};
|
||||
- std::array<int64, 3> dilations = {
|
||||
- {GetTensorDim(dilation_, data_format_, '0'),
|
||||
- GetTensorDim(dilation_, data_format_, '1'),
|
||||
- GetTensorDim(dilation_, data_format_, '2')}};
|
||||
- std::array<int64, 3> strides = {{GetTensorDim(stride_, data_format_, '0'),
|
||||
- GetTensorDim(stride_, data_format_, '1'),
|
||||
- GetTensorDim(stride_, data_format_, '2')}};
|
||||
- std::array<int64, 3> out, padding;
|
||||
-
|
||||
- OP_REQUIRES_OK(
|
||||
- context, Get3dOutputSizeV2(input_size, filter_size, dilations, strides,
|
||||
- padding_, &out, &padding));
|
||||
- TensorShape out_shape = ShapeFromFormat(
|
||||
- data_format_, in_batch, {{out[0], out[1], out[2]}}, out_depth);
|
||||
- Tensor* output;
|
||||
- OP_REQUIRES_OK(context, context->allocate_output(0, out_shape, &output));
|
||||
-
|
||||
- // Return early if nothing to do.
|
||||
- if (out_shape.num_elements() == 0) return;
|
||||
-
|
||||
- LaunchConvOp<Device, T, OpKernelContextT>::launch(
|
||||
- context, cudnn_use_autotune_, input, filter,
|
||||
- dilations, strides, padding_, data_format_,
|
||||
- output);
|
||||
- }
|
||||
-
|
||||
- private:
|
||||
- std::vector<int32> dilation_;
|
||||
- std::vector<int32> stride_;
|
||||
- Padding padding_;
|
||||
- TensorFormat data_format_;
|
||||
- bool cudnn_use_autotune_;
|
||||
-};
|
||||
-
|
||||
-} // namespace tensorflow
|
||||
-
|
||||
-
|
||||
-#endif // TENSORFLOW_CORE_KERNELS_CONV_OPS_3D_H_
|
||||
--
|
||||
2.23.0
|
||||
|
||||
@ -1,37 +0,0 @@
|
||||
From 799f835a3dfa00a4d852defa29b15841eea9d64f Mon Sep 17 00:00:00 2001
|
||||
From: Mihai Maruseac <mihaimaruseac@google.com>
|
||||
Date: Mon, 19 Apr 2021 09:56:46 -0700
|
||||
Subject: [PATCH] Fix 2 issues with `Conv3D`.
|
||||
|
||||
---
|
||||
tensorflow/core/kernels/conv_ops_3d.cc | 7 +++++++
|
||||
1 file changed, 7 insertions(+)
|
||||
|
||||
diff --git a/tensorflow/core/kernels/conv_ops_3d.cc b/tensorflow/core/kernels/conv_ops_3d.cc
|
||||
index 52356443..75a0a043 100644
|
||||
--- a/tensorflow/core/kernels/conv_ops_3d.cc
|
||||
+++ b/tensorflow/core/kernels/conv_ops_3d.cc
|
||||
@@ -68,6 +68,11 @@ struct LaunchConvOp<CPUDevice, T> {
|
||||
errors::InvalidArgument("CPU implementation of Conv3D "
|
||||
"currently only supports dilated rates "
|
||||
"of 1."));
|
||||
+ OP_REQUIRES(context, filter.dim_size(3) == input.dim_size(input.dims() - 1),
|
||||
+ errors::InvalidArgument(
|
||||
+ "Number of channels in filter (", filter.dim_size(3),
|
||||
+ ") must match last dimension of input (",
|
||||
+ input.dim_size(input.dims() - 1), ")"));
|
||||
functor::CuboidConvolution<CPUDevice, T>()(
|
||||
context->eigen_device<CPUDevice>(), output->tensor<T, 5>(),
|
||||
input.tensor<T, 5>(), filter.tensor<T, 5>(), strides[2], strides[1],
|
||||
@@ -141,6 +146,8 @@ class Conv3DOp : public BinaryOp<T> {
|
||||
const int64 filter_depth = filter.dim_size(3);
|
||||
const int64 out_depth = filter.dim_size(4);
|
||||
|
||||
+ OP_REQUIRES(context, filter_depth != 0,
|
||||
+ errors::InvalidArgument("filter_depth must be non-zero"));
|
||||
OP_REQUIRES(context, in_depth % filter_depth == 0,
|
||||
errors::InvalidArgument(
|
||||
"Input depth must be evenly divisible by filter depth: ",
|
||||
--
|
||||
2.23.0
|
||||
|
||||
@ -1,42 +0,0 @@
|
||||
From ff70c47a396ef1e3cb73c90513da4f5cb71bebba Mon Sep 17 00:00:00 2001
|
||||
From: Amit Patankar <amitpatankar@google.com>
|
||||
Date: Tue, 13 Apr 2021 14:24:00 -0700
|
||||
Subject: [PATCH] Fix `tf.raw_ops.GetSessionTensor` and
|
||||
`tf.raw_ops.DeleteSessionTensor` null pointer dereferences.
|
||||
|
||||
---
|
||||
tensorflow/core/kernels/session_ops.cc | 11 ++++++++++-
|
||||
1 file changed, 10 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/tensorflow/core/kernels/session_ops.cc b/tensorflow/core/kernels/session_ops.cc
|
||||
index e7e73549..dab59e70 100644
|
||||
--- a/tensorflow/core/kernels/session_ops.cc
|
||||
+++ b/tensorflow/core/kernels/session_ops.cc
|
||||
@@ -119,6 +119,11 @@ class GetSessionTensorOp : public OpKernel {
|
||||
const string& name = handle.scalar<tstring>()();
|
||||
Tensor val;
|
||||
OP_REQUIRES_OK(ctx, ctx->session_state()->GetTensor(name, &val));
|
||||
+ auto session_state = ctx->session_state();
|
||||
+ OP_REQUIRES(ctx, session_state != nullptr,
|
||||
+ errors::FailedPrecondition(
|
||||
+ "GetSessionTensor called on null session state"));
|
||||
+ OP_REQUIRES_OK(ctx, session_state->GetTensor(name, &val));
|
||||
ctx->set_output(0, val);
|
||||
}
|
||||
|
||||
@@ -160,7 +165,11 @@ class DeleteSessionTensorOp : public OpKernel {
|
||||
void Compute(OpKernelContext* ctx) override {
|
||||
const Tensor& handle = ctx->input(0);
|
||||
const string& name = handle.scalar<tstring>()();
|
||||
- OP_REQUIRES_OK(ctx, ctx->session_state()->DeleteTensor(name));
|
||||
+ auto session_state = ctx->session_state();
|
||||
+ OP_REQUIRES(ctx, session_state != nullptr,
|
||||
+ errors::FailedPrecondition(
|
||||
+ "DeleteSessionTensor called on null session state"));
|
||||
+ OP_REQUIRES_OK(ctx, session_state->DeleteTensor(name));
|
||||
}
|
||||
|
||||
TF_DISALLOW_COPY_AND_ASSIGN(DeleteSessionTensorOp);
|
||||
--
|
||||
2.23.0
|
||||
|
||||
@ -1,143 +0,0 @@
|
||||
From b1cc5e5a50e7cee09f2c6eb48eb40ee9c4125025 Mon Sep 17 00:00:00 2001
|
||||
From: Amit Patankar <amitpatankar@google.com>
|
||||
Date: Thu, 15 Apr 2021 13:03:19 -0700
|
||||
Subject: [PATCH] Fix `tf.raw_ops.SparseCross` failing CHECK.
|
||||
|
||||
PiperOrigin-RevId: 368701671
|
||||
Change-Id: Id805729dd9ba0bda36e4bb309408129b55fb649d
|
||||
---
|
||||
tensorflow/core/kernels/sparse_cross_op.cc | 55 +++++++++++++++++++---
|
||||
1 file changed, 48 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/tensorflow/core/kernels/sparse_cross_op.cc b/tensorflow/core/kernels/sparse_cross_op.cc
|
||||
index 583235b4a309b..43b3bedc74503 100644
|
||||
--- a/tensorflow/core/kernels/sparse_cross_op.cc
|
||||
+++ b/tensorflow/core/kernels/sparse_cross_op.cc
|
||||
@@ -27,6 +27,7 @@ limitations under the License.
|
||||
#include "tensorflow/core/framework/tensor.h"
|
||||
#include "tensorflow/core/framework/tensor_shape.h"
|
||||
#include "tensorflow/core/framework/types.h"
|
||||
+#include "tensorflow/core/framework/types.pb.h"
|
||||
#include "tensorflow/core/lib/core/stringpiece.h"
|
||||
#include "tensorflow/core/lib/strings/str_util.h"
|
||||
#include "tensorflow/core/platform/fingerprint.h"
|
||||
@@ -460,10 +461,19 @@ int64 CalculateBatchSize(const OpInputList& shapes_list_in,
|
||||
Status ValidateInput(const OpInputList& indices_list_in,
|
||||
const OpInputList& values_list_in,
|
||||
const OpInputList& shapes_list_in,
|
||||
- const OpInputList& dense_list_in) {
|
||||
+ const OpInputList& dense_list_in,
|
||||
+ const DataType& internal_type) {
|
||||
const auto size = indices_list_in.size();
|
||||
+ // Only perform internal_type check for SparseCrossOp.
|
||||
+ // Check if the internal_type is not invalid before doing so.
|
||||
+ bool check_type = internal_type != DT_INVALID;
|
||||
// Validates indices_list_in OpInputList.
|
||||
for (int i = 0; i < size; i++) {
|
||||
+ if (check_type && indices_list_in[i].dtype() != DT_INT64) {
|
||||
+ return errors::InvalidArgument("Input indices should be of type ",
|
||||
+ DT_INT64, " but received ",
|
||||
+ indices_list_in[i].dtype());
|
||||
+ }
|
||||
if (!TensorShapeUtils::IsMatrix(indices_list_in[i].shape())) {
|
||||
return errors::InvalidArgument(
|
||||
"Input indices should be a matrix but received shape ",
|
||||
@@ -482,6 +492,14 @@ Status ValidateInput(const OpInputList& indices_list_in,
|
||||
values_list_in.size());
|
||||
}
|
||||
for (int i = 0; i < size; i++) {
|
||||
+ // Make sure to avoid the expected type to be string, but input values to be
|
||||
+ // int64.
|
||||
+ if (check_type && internal_type == DT_STRING &&
|
||||
+ values_list_in[i].dtype() == DT_INT64) {
|
||||
+ return errors::InvalidArgument("Input values should be of internal type ",
|
||||
+ internal_type, " but received ",
|
||||
+ values_list_in[i].dtype());
|
||||
+ }
|
||||
if (!TensorShapeUtils::IsVector(values_list_in[i].shape())) {
|
||||
return errors::InvalidArgument(
|
||||
"Input values should be a vector but received shape ",
|
||||
@@ -502,6 +520,11 @@ Status ValidateInput(const OpInputList& indices_list_in,
|
||||
shapes_list_in.size());
|
||||
}
|
||||
for (int i = 0; i < size; i++) {
|
||||
+ if (check_type && shapes_list_in[i].dtype() != DT_INT64) {
|
||||
+ return errors::InvalidArgument("Input shape should be of type ", DT_INT64,
|
||||
+ " but received ",
|
||||
+ shapes_list_in[i].dtype());
|
||||
+ }
|
||||
if (!TensorShapeUtils::IsVector(shapes_list_in[i].shape())) {
|
||||
return errors::InvalidArgument(
|
||||
"Input shapes should be a vector but received shape ",
|
||||
@@ -517,6 +540,14 @@ Status ValidateInput(const OpInputList& indices_list_in,
|
||||
|
||||
// Validates dense_list_in OpInputList
|
||||
for (int i = 0; i < dense_list_in.size(); ++i) {
|
||||
+ // Make sure to avoid the expected type to be string, but input values to be
|
||||
+ // int64.
|
||||
+ if (check_type && internal_type == DT_STRING &&
|
||||
+ dense_list_in[i].dtype() == DT_INT64) {
|
||||
+ return errors::InvalidArgument("Dense inputs should be of internal type ",
|
||||
+ internal_type, " but received ",
|
||||
+ dense_list_in[i].dtype());
|
||||
+ }
|
||||
if (!TensorShapeUtils::IsMatrix(dense_list_in[i].shape())) {
|
||||
return errors::InvalidArgument(
|
||||
"Dense inputs should be a matrix but received shape ",
|
||||
@@ -698,6 +729,7 @@ class SparseCrossOp : public OpKernel {
|
||||
int64 signed_hash_key_;
|
||||
OP_REQUIRES_OK(context, context->GetAttr("hash_key", &signed_hash_key_));
|
||||
hash_key_ = static_cast<uint64>(signed_hash_key_);
|
||||
+ OP_REQUIRES_OK(context, context->GetAttr("internal_type", &internal_type_));
|
||||
}
|
||||
|
||||
void Compute(OpKernelContext* context) override {
|
||||
@@ -711,8 +743,10 @@ class SparseCrossOp : public OpKernel {
|
||||
OP_REQUIRES_OK(context,
|
||||
context->input_list("dense_inputs", &dense_list_in));
|
||||
|
||||
- OP_REQUIRES_OK(context, ValidateInput(indices_list_in, values_list_in,
|
||||
- shapes_list_in, dense_list_in));
|
||||
+ DataType internal_type = internal_type_;
|
||||
+ OP_REQUIRES_OK(
|
||||
+ context, ValidateInput(indices_list_in, values_list_in, shapes_list_in,
|
||||
+ dense_list_in, internal_type));
|
||||
|
||||
std::vector<std::unique_ptr<ColumnInterface<InternalType>>> columns =
|
||||
GenerateColumnsFromInput<InternalType>(indices_list_in, values_list_in,
|
||||
@@ -756,6 +790,7 @@ class SparseCrossOp : public OpKernel {
|
||||
private:
|
||||
int64 num_buckets_;
|
||||
uint64 hash_key_;
|
||||
+ DataType internal_type_;
|
||||
};
|
||||
|
||||
class SparseCrossV2Op : public OpKernel {
|
||||
@@ -773,8 +808,11 @@ class SparseCrossV2Op : public OpKernel {
|
||||
OP_REQUIRES_OK(context,
|
||||
context->input_list("dense_inputs", &dense_list_in));
|
||||
|
||||
- OP_REQUIRES_OK(context, ValidateInput(indices_list_in, values_list_in,
|
||||
- shapes_list_in, dense_list_in));
|
||||
+ // Set internal_type to invalid_type so that the check will be ignored.
|
||||
+ DataType internal_type = DT_INVALID;
|
||||
+ OP_REQUIRES_OK(
|
||||
+ context, ValidateInput(indices_list_in, values_list_in, shapes_list_in,
|
||||
+ dense_list_in, internal_type));
|
||||
|
||||
const Tensor* sep_t;
|
||||
OP_REQUIRES_OK(context, context->input("sep", &sep_t));
|
||||
@@ -832,8 +870,11 @@ class SparseCrossHashedOp : public OpKernel {
|
||||
OP_REQUIRES_OK(context,
|
||||
context->input_list("dense_inputs", &dense_list_in));
|
||||
|
||||
- OP_REQUIRES_OK(context, ValidateInput(indices_list_in, values_list_in,
|
||||
- shapes_list_in, dense_list_in));
|
||||
+ // Set internal_type to invalid_type so that the check will be ignored.
|
||||
+ DataType internal_type = DT_INVALID;
|
||||
+ OP_REQUIRES_OK(
|
||||
+ context, ValidateInput(indices_list_in, values_list_in, shapes_list_in,
|
||||
+ dense_list_in, internal_type));
|
||||
|
||||
const Tensor* num_buckets_t;
|
||||
OP_REQUIRES_OK(context, context->input("num_buckets", &num_buckets_t));
|
||||
@ -1,102 +0,0 @@
|
||||
From 8f37b52e1320d8d72a9529b2468277791a261197 Mon Sep 17 00:00:00 2001
|
||||
From: Mihai Maruseac <mihaimaruseac@google.com>
|
||||
Date: Mon, 19 Apr 2021 13:46:32 -0700
|
||||
Subject: [PATCH] Validate some shape requirements for `Conv3DBackpropFilter*`
|
||||
and `Conv3DBackpropInput*` ops.
|
||||
|
||||
Older versions of Eigen might otherwise crash / produce OOB read on specially crafted inputs.
|
||||
|
||||
PiperOrigin-RevId: 369293977
|
||||
Change-Id: I58f51445a93936d7cf8e616f75de17677df36718
|
||||
---
|
||||
tensorflow/core/kernels/conv_grad_ops_3d.cc | 56 +++++++++++++++++++++
|
||||
1 file changed, 56 insertions(+)
|
||||
|
||||
diff --git a/tensorflow/core/kernels/conv_grad_ops_3d.cc b/tensorflow/core/kernels/conv_grad_ops_3d.cc
|
||||
index f736a12fb1ca3..8c72d01578d6d 100644
|
||||
--- a/tensorflow/core/kernels/conv_grad_ops_3d.cc
|
||||
+++ b/tensorflow/core/kernels/conv_grad_ops_3d.cc
|
||||
@@ -239,6 +239,20 @@ class Conv3DBackpropInputOp : public OpKernel {
|
||||
input_shape = context->input(0).shape();
|
||||
}
|
||||
|
||||
+ OP_REQUIRES(
|
||||
+ context, input_shape.dim_size(4) == filter_shape.dim_size(3),
|
||||
+ errors::InvalidArgument("input and filter_sizes must have the same "
|
||||
+ "number of channels. Got ",
|
||||
+ input_shape.dim_size(4), " for input and ",
|
||||
+ filter_shape.dim_size(3), " for filter_sizes"));
|
||||
+ OP_REQUIRES(
|
||||
+ context, out_backprop_shape.dim_size(4) == filter_shape.dim_size(4),
|
||||
+ errors::InvalidArgument("out_backprop and filter_sizes must have the "
|
||||
+ "same number of channels. Got ",
|
||||
+ out_backprop_shape.dim_size(4),
|
||||
+ " for out_backprop and ",
|
||||
+ filter_shape.dim_size(4), " for filter_sizes"));
|
||||
+
|
||||
ConvBackpropDimensions dims;
|
||||
OP_REQUIRES_OK(context, ConvBackpropComputeDimensions(
|
||||
"Conv3DBackpropInputOp", /*num_spatial_dims=*/3,
|
||||
@@ -346,6 +360,20 @@ class Conv3DCustomBackpropInputOp : public OpKernel {
|
||||
input_shape = context->input(0).shape();
|
||||
}
|
||||
|
||||
+ OP_REQUIRES(
|
||||
+ context, input_shape.dim_size(4) == filter_shape.dim_size(3),
|
||||
+ errors::InvalidArgument("input and filter_sizes must have the same "
|
||||
+ "number of channels. Got ",
|
||||
+ input_shape.dim_size(4), " for input and ",
|
||||
+ filter_shape.dim_size(3), " for filter_sizes"));
|
||||
+ OP_REQUIRES(
|
||||
+ context, out_backprop_shape.dim_size(4) == filter_shape.dim_size(4),
|
||||
+ errors::InvalidArgument("out_backprop and filter_sizes must have the "
|
||||
+ "same number of channels. Got ",
|
||||
+ out_backprop_shape.dim_size(4),
|
||||
+ " for out_backprop and ",
|
||||
+ filter_shape.dim_size(4), " for filter_sizes"));
|
||||
+
|
||||
ConvBackpropDimensions dims;
|
||||
OP_REQUIRES_OK(context, ConvBackpropComputeDimensions(
|
||||
"Conv3DBackpropInputOp", /*num_spatial_dims=*/3,
|
||||
@@ -696,6 +724,20 @@ class Conv3DBackpropFilterOp : public OpKernel {
|
||||
filter_shape = context->input(1).shape();
|
||||
}
|
||||
|
||||
+ OP_REQUIRES(
|
||||
+ context, input_shape.dim_size(4) == filter_shape.dim_size(3),
|
||||
+ errors::InvalidArgument("input and filter_sizes must have the same "
|
||||
+ "number of channels. Got ",
|
||||
+ input_shape.dim_size(4), " for input and ",
|
||||
+ filter_shape.dim_size(3), " for filter_sizes"));
|
||||
+ OP_REQUIRES(
|
||||
+ context, out_backprop_shape.dim_size(4) == filter_shape.dim_size(4),
|
||||
+ errors::InvalidArgument("out_backprop and filter_sizes must have the "
|
||||
+ "same number of channels. Got ",
|
||||
+ out_backprop_shape.dim_size(4),
|
||||
+ " for out_backprop and ",
|
||||
+ filter_shape.dim_size(4), " for filter_sizes"));
|
||||
+
|
||||
ConvBackpropDimensions dims;
|
||||
OP_REQUIRES_OK(context,
|
||||
ConvBackpropComputeDimensions(
|
||||
@@ -808,6 +850,20 @@ class Conv3DCustomBackpropFilterOp : public OpKernel {
|
||||
filter_shape = context->input(1).shape();
|
||||
}
|
||||
|
||||
+ OP_REQUIRES(
|
||||
+ context, input_shape.dim_size(4) == filter_shape.dim_size(3),
|
||||
+ errors::InvalidArgument("input and filter_sizes must have the same "
|
||||
+ "number of channels. Got ",
|
||||
+ input_shape.dim_size(4), " for input and ",
|
||||
+ filter_shape.dim_size(3), " for filter_sizes"));
|
||||
+ OP_REQUIRES(
|
||||
+ context, out_backprop_shape.dim_size(4) == filter_shape.dim_size(4),
|
||||
+ errors::InvalidArgument("out_backprop and filter_sizes must have the "
|
||||
+ "same number of channels. Got ",
|
||||
+ out_backprop_shape.dim_size(4),
|
||||
+ " for out_backprop and ",
|
||||
+ filter_shape.dim_size(4), " for filter_sizes"));
|
||||
+
|
||||
ConvBackpropDimensions dims;
|
||||
OP_REQUIRES_OK(context,
|
||||
ConvBackpropComputeDimensions(
|
||||
@ -1,35 +0,0 @@
|
||||
From c57c0b9f3a4f8684f3489dd9a9ec627ad8b599f5 Mon Sep 17 00:00:00 2001
|
||||
From: Amit Patankar <amitpatankar@google.com>
|
||||
Date: Mon, 19 Apr 2021 11:33:50 -0700
|
||||
Subject: [PATCH] Fix the segfault in `tf.raw_ops.SparseCountSparseOutput`.
|
||||
|
||||
---
|
||||
tensorflow/core/kernels/count_ops.cc | 10 +++++++++-
|
||||
1 file changed, 9 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/tensorflow/core/kernels/count_ops.cc b/tensorflow/core/kernels/count_ops.cc
|
||||
index b7bb3ed9..67aafebe 100644
|
||||
--- a/tensorflow/core/kernels/count_ops.cc
|
||||
+++ b/tensorflow/core/kernels/count_ops.cc
|
||||
@@ -200,9 +200,17 @@ class SparseCount : public OpKernel {
|
||||
"The shape argument requires at least one element."));
|
||||
|
||||
bool is_1d = shape.NumElements() == 1;
|
||||
- int num_batches = is_1d ? 1 : shape.flat<int64>()(0);
|
||||
+ auto shape_vector = shape.flat<int64>();
|
||||
+ int num_batches = is_1d ? 1 : shape_vector(0);
|
||||
int num_values = values.NumElements();
|
||||
|
||||
+ for (int b = 0; b < shape_vector.size(); b++) {
|
||||
+ OP_REQUIRES(context, shape_vector(b) >= 0,
|
||||
+ errors::InvalidArgument(
|
||||
+ "Elements in dense_shape must be >= 0. Instead got:",
|
||||
+ shape.DebugString()));
|
||||
+ }
|
||||
+
|
||||
OP_REQUIRES(context, num_values == indices.shape().dim_size(0),
|
||||
errors::InvalidArgument(
|
||||
"Number of values must match first dimension of indices.",
|
||||
--
|
||||
2.23.0
|
||||
|
||||
@ -1,101 +0,0 @@
|
||||
From 311403edbc9816df80274bd1ea8b3c0c0f22c3fa Mon Sep 17 00:00:00 2001
|
||||
From: Mihai Maruseac <mihaimaruseac@google.com>
|
||||
Date: Mon, 19 Apr 2021 16:00:40 -0700
|
||||
Subject: [PATCH] Eliminate a division by 0 in 3D convolutions.
|
||||
|
||||
Also prevent a CHECK failed introduced in the most recent change.
|
||||
|
||||
PiperOrigin-RevId: 369322073
|
||||
Change-Id: I4f609c028f89565fb2b49c3fdd20b63496582bae
|
||||
---
|
||||
tensorflow/core/kernels/conv_grad_ops_3d.cc | 42 +++++++++++++++++++++
|
||||
1 file changed, 42 insertions(+)
|
||||
|
||||
diff --git a/tensorflow/core/kernels/conv_grad_ops_3d.cc b/tensorflow/core/kernels/conv_grad_ops_3d.cc
|
||||
index 8c72d01578d6d..c0b57a7ae5606 100644
|
||||
--- a/tensorflow/core/kernels/conv_grad_ops_3d.cc
|
||||
+++ b/tensorflow/core/kernels/conv_grad_ops_3d.cc
|
||||
@@ -239,6 +239,14 @@ class Conv3DBackpropInputOp : public OpKernel {
|
||||
input_shape = context->input(0).shape();
|
||||
}
|
||||
|
||||
+ OP_REQUIRES(context, input_shape.dims() == 5,
|
||||
+ errors::InvalidArgument("input tensor must have 5 dimensions"));
|
||||
+ OP_REQUIRES(
|
||||
+ context, filter_shape.dims() == 5,
|
||||
+ errors::InvalidArgument("filter_sizes tensor must have 5 dimensions"));
|
||||
+ OP_REQUIRES(
|
||||
+ context, out_backprop_shape.dims() == 5,
|
||||
+ errors::InvalidArgument("out_backprop tensor must have 5 dimensions"));
|
||||
OP_REQUIRES(
|
||||
context, input_shape.dim_size(4) == filter_shape.dim_size(3),
|
||||
errors::InvalidArgument("input and filter_sizes must have the same "
|
||||
@@ -360,6 +368,14 @@ class Conv3DCustomBackpropInputOp : public OpKernel {
|
||||
input_shape = context->input(0).shape();
|
||||
}
|
||||
|
||||
+ OP_REQUIRES(context, input_shape.dims() == 5,
|
||||
+ errors::InvalidArgument("input tensor must have 5 dimensions"));
|
||||
+ OP_REQUIRES(
|
||||
+ context, filter_shape.dims() == 5,
|
||||
+ errors::InvalidArgument("filter_sizes tensor must have 5 dimensions"));
|
||||
+ OP_REQUIRES(
|
||||
+ context, out_backprop_shape.dims() == 5,
|
||||
+ errors::InvalidArgument("out_backprop tensor must have 5 dimensions"));
|
||||
OP_REQUIRES(
|
||||
context, input_shape.dim_size(4) == filter_shape.dim_size(3),
|
||||
errors::InvalidArgument("input and filter_sizes must have the same "
|
||||
@@ -444,6 +460,11 @@ class Conv3DCustomBackpropInputOp : public OpKernel {
|
||||
// contraction compared to sharding and matmuls.
|
||||
const bool use_parallel_contraction = dims.batch_size == 1;
|
||||
|
||||
+ OP_REQUIRES(
|
||||
+ context, work_unit_size > 0,
|
||||
+ errors::InvalidArgument("input, filter_sizes and out_backprop tensors "
|
||||
+ "must all have at least 1 element"));
|
||||
+
|
||||
const size_t shard_size =
|
||||
use_parallel_contraction
|
||||
? 1
|
||||
@@ -724,6 +745,14 @@ class Conv3DBackpropFilterOp : public OpKernel {
|
||||
filter_shape = context->input(1).shape();
|
||||
}
|
||||
|
||||
+ OP_REQUIRES(context, input_shape.dims() == 5,
|
||||
+ errors::InvalidArgument("input tensor must have 5 dimensions"));
|
||||
+ OP_REQUIRES(
|
||||
+ context, filter_shape.dims() == 5,
|
||||
+ errors::InvalidArgument("filter_sizes tensor must have 5 dimensions"));
|
||||
+ OP_REQUIRES(
|
||||
+ context, out_backprop_shape.dims() == 5,
|
||||
+ errors::InvalidArgument("out_backprop tensor must have 5 dimensions"));
|
||||
OP_REQUIRES(
|
||||
context, input_shape.dim_size(4) == filter_shape.dim_size(3),
|
||||
errors::InvalidArgument("input and filter_sizes must have the same "
|
||||
@@ -850,6 +879,14 @@ class Conv3DCustomBackpropFilterOp : public OpKernel {
|
||||
filter_shape = context->input(1).shape();
|
||||
}
|
||||
|
||||
+ OP_REQUIRES(context, input_shape.dims() == 5,
|
||||
+ errors::InvalidArgument("input tensor must have 5 dimensions"));
|
||||
+ OP_REQUIRES(
|
||||
+ context, filter_shape.dims() == 5,
|
||||
+ errors::InvalidArgument("filter_sizes tensor must have 5 dimensions"));
|
||||
+ OP_REQUIRES(
|
||||
+ context, out_backprop_shape.dims() == 5,
|
||||
+ errors::InvalidArgument("out_backprop tensor must have 5 dimensions"));
|
||||
OP_REQUIRES(
|
||||
context, input_shape.dim_size(4) == filter_shape.dim_size(3),
|
||||
errors::InvalidArgument("input and filter_sizes must have the same "
|
||||
@@ -936,6 +973,11 @@ class Conv3DCustomBackpropFilterOp : public OpKernel {
|
||||
|
||||
const int64 work_unit_size = size_A + size_B + size_C;
|
||||
|
||||
+ OP_REQUIRES(
|
||||
+ context, work_unit_size > 0,
|
||||
+ errors::InvalidArgument("input, filter_sizes and out_backprop tensors "
|
||||
+ "must all have at least 1 element"));
|
||||
+
|
||||
const size_t shard_size =
|
||||
(target_working_set_size + work_unit_size - 1) / work_unit_size;
|
||||
|
||||
@ -1,26 +0,0 @@
|
||||
From fca9874a9b42a2134f907d2fb46ab774a831404a Mon Sep 17 00:00:00 2001
|
||||
From: Mihai Maruseac <mihaimaruseac@google.com>
|
||||
Date: Mon, 19 Apr 2021 17:33:11 -0700
|
||||
Subject: [PATCH] Prevent another division by zero.
|
||||
|
||||
PiperOrigin-RevId: 369338598
|
||||
Change-Id: I55471d363e401fdcf8d259670ad4eef672b731e2
|
||||
---
|
||||
tensorflow/core/kernels/conv_grad_shape_utils.cc | 4 ++++
|
||||
1 file changed, 4 insertions(+)
|
||||
|
||||
diff --git a/tensorflow/core/kernels/conv_grad_shape_utils.cc b/tensorflow/core/kernels/conv_grad_shape_utils.cc
|
||||
index 7543ce669923a..805f5809a472e 100644
|
||||
--- a/tensorflow/core/kernels/conv_grad_shape_utils.cc
|
||||
+++ b/tensorflow/core/kernels/conv_grad_shape_utils.cc
|
||||
@@ -127,6 +127,10 @@ Status ConvBackpropComputeDimensionsV2(
|
||||
// dimensions of the filter Tensor.
|
||||
VLOG(2) << "input vs filter_in depth " << dims->in_depth << " "
|
||||
<< filter_shape.dim_size(num_dims - 2);
|
||||
+ if (filter_shape.dim_size(num_dims - 2) <= 0) {
|
||||
+ return errors ::InvalidArgument(
|
||||
+ label, ": filter depth must be strictly greated than zero");
|
||||
+ }
|
||||
if (dims->in_depth % filter_shape.dim_size(num_dims - 2)) {
|
||||
return errors::InvalidArgument(
|
||||
label, ": input depth must be evenly divisible by filter depth");
|
||||
@ -1,322 +0,0 @@
|
||||
From 7b8db6083b34520688dbc71f341f7aeaf156bf17 Mon Sep 17 00:00:00 2001
|
||||
From: Eugene Zhulenev <ezhulenev@google.com>
|
||||
Date: Fri, 19 Mar 2021 16:16:41 -0700
|
||||
Subject: [PATCH] Implement grouped convolution on CPU
|
||||
|
||||
To get better compute resources utilization group-compute loop has to be parallelized, but it involves a lot of changes in Conv2D primitives. Will address that later if it will be critical for some of the users.
|
||||
|
||||
Fix for: https://github.com/tensorflow/tensorflow/issues/29005
|
||||
|
||||
PiperOrigin-RevId: 363991782
|
||||
Change-Id: I97f375b1133833c4de5181199316be7cbf4ebee0
|
||||
---
|
||||
tensorflow/core/kernels/BUILD | 1 +
|
||||
tensorflow/core/kernels/conv_2d.h | 54 +++++++
|
||||
tensorflow/core/kernels/conv_ops.cc | 133 ++++++++++++++++--
|
||||
.../python/kernel_tests/conv_ops_test.py | 20 +--
|
||||
4 files changed, 189 insertions(+), 19 deletions(-)
|
||||
|
||||
diff --git a/tensorflow/core/kernels/BUILD b/tensorflow/core/kernels/BUILD
|
||||
index 8e49f1e0a5caf..bc455626f4322 100644
|
||||
--- a/tensorflow/core/kernels/BUILD
|
||||
+++ b/tensorflow/core/kernels/BUILD
|
||||
@@ -3818,6 +3818,7 @@ tf_kernel_library(
|
||||
":ops_util",
|
||||
"@com_google_absl//absl/base:dynamic_annotations",
|
||||
"@com_google_absl//absl/strings",
|
||||
+ "@com_google_absl//absl/synchronization",
|
||||
"//third_party/eigen3",
|
||||
"//tensorflow/core:core_cpu",
|
||||
"//tensorflow/core:framework",
|
||||
diff --git a/tensorflow/core/kernels/conv_2d.h b/tensorflow/core/kernels/conv_2d.h
|
||||
index b9a8c977e11ee..87df4a848dd56 100644
|
||||
--- a/tensorflow/core/kernels/conv_2d.h
|
||||
+++ b/tensorflow/core/kernels/conv_2d.h
|
||||
@@ -43,6 +43,9 @@ void SpatialConvolutionFunc(const Device& d, Output output, Input input,
|
||||
padding_bottom);
|
||||
}
|
||||
|
||||
+// TODO(ezhulenev): Non-templated `operator()` are required by explicit template
|
||||
+// instantiations for the GPU device. However they are almost certainly not used
|
||||
+// in any of the kernel implementation. Check if they can be removed.
|
||||
template <typename Device, typename T,
|
||||
typename OutputKernel = const Eigen::NoOpOutputKernel>
|
||||
struct SpatialConvolution {
|
||||
@@ -55,6 +58,16 @@ struct SpatialConvolution {
|
||||
SpatialConvolutionFunc(d, output, input, filter, row_stride, col_stride,
|
||||
row_dilation, col_dilation, padding, output_kernel);
|
||||
}
|
||||
+
|
||||
+ template <typename Input, typename Filter, typename Output>
|
||||
+ void operator()(const Device& d, Output output, Input input, Filter filter,
|
||||
+ int row_stride, int col_stride, int row_dilation,
|
||||
+ int col_dilation, const Eigen::PaddingType& padding,
|
||||
+ const OutputKernel& output_kernel = OutputKernel()) {
|
||||
+ SpatialConvolutionFunc(d, output, input, filter, row_stride, col_stride,
|
||||
+ row_dilation, col_dilation, padding, output_kernel);
|
||||
+ }
|
||||
+
|
||||
void operator()(const Device& d, typename TTypes<T, 4>::Tensor output,
|
||||
typename TTypes<T, 4>::ConstTensor input,
|
||||
typename TTypes<T, 4>::ConstTensor filter, int row_stride,
|
||||
@@ -67,6 +80,18 @@ struct SpatialConvolution {
|
||||
col_dilation, Eigen::PaddingType::PADDING_VALID, output_kernel,
|
||||
padding_top, padding_bottom, padding_left, padding_right);
|
||||
}
|
||||
+
|
||||
+ template <typename Input, typename Filter, typename Output>
|
||||
+ void operator()(const Device& d, Output output, Input input, Filter filter,
|
||||
+ int row_stride, int col_stride, int row_dilation,
|
||||
+ int col_dilation, int padding_top, int padding_bottom,
|
||||
+ int padding_left, int padding_right,
|
||||
+ const OutputKernel& output_kernel = OutputKernel()) {
|
||||
+ SpatialConvolutionFunc(
|
||||
+ d, output, input, filter, row_stride, col_stride, row_dilation,
|
||||
+ col_dilation, Eigen::PaddingType::PADDING_VALID, output_kernel,
|
||||
+ padding_top, padding_bottom, padding_left, padding_right);
|
||||
+ }
|
||||
};
|
||||
|
||||
template <typename Device, typename OutputKernel>
|
||||
@@ -84,6 +109,20 @@ struct SpatialConvolution<Device, Eigen::half, OutputKernel> {
|
||||
row_dilation, output_kernel)
|
||||
.template cast<Eigen::half>();
|
||||
}
|
||||
+
|
||||
+ template <typename Input, typename Filter, typename Output>
|
||||
+ void operator()(const Device& d, Output output, Input input, Filter filter,
|
||||
+ int row_stride, int col_stride, int row_dilation,
|
||||
+ int col_dilation, const Eigen::PaddingType& padding,
|
||||
+ const OutputKernel& output_kernel = OutputKernel()) {
|
||||
+ output.device(d) =
|
||||
+ Eigen::SpatialConvolution(input.template cast<float>(),
|
||||
+ filter.template cast<float>(), col_stride,
|
||||
+ row_stride, padding, col_dilation,
|
||||
+ row_dilation, output_kernel)
|
||||
+ .template cast<Eigen::half>();
|
||||
+ }
|
||||
+
|
||||
void operator()(const Device& d,
|
||||
typename TTypes<Eigen::half, 4>::Tensor output,
|
||||
typename TTypes<Eigen::half, 4>::ConstTensor input,
|
||||
@@ -100,6 +139,21 @@ struct SpatialConvolution<Device, Eigen::half, OutputKernel> {
|
||||
padding_bottom)
|
||||
.template cast<Eigen::half>();
|
||||
}
|
||||
+
|
||||
+ template <typename Input, typename Filter, typename Output>
|
||||
+ void operator()(const Device& d, Output output, Input input, Filter filter,
|
||||
+ int row_stride, int col_stride, int row_dilation,
|
||||
+ int col_dilation, int padding_top, int padding_bottom,
|
||||
+ int padding_left, int padding_right,
|
||||
+ const OutputKernel& output_kernel = OutputKernel()) {
|
||||
+ output.device(d) =
|
||||
+ Eigen::SpatialConvolution(
|
||||
+ input.template cast<float>(), filter.template cast<float>(),
|
||||
+ col_stride, row_stride, Eigen::PaddingType::PADDING_VALID,
|
||||
+ col_dilation, row_dilation, output_kernel, padding_left,
|
||||
+ padding_right, padding_top, padding_bottom)
|
||||
+ .template cast<Eigen::half>();
|
||||
+ }
|
||||
};
|
||||
|
||||
template <typename Device, typename T>
|
||||
diff --git a/tensorflow/core/kernels/conv_ops.cc b/tensorflow/core/kernels/conv_ops.cc
|
||||
index 025a8e37a94e9..8fdfe04bd1c67 100644
|
||||
--- a/tensorflow/core/kernels/conv_ops.cc
|
||||
+++ b/tensorflow/core/kernels/conv_ops.cc
|
||||
@@ -30,6 +30,7 @@ limitations under the License.
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
+#include "absl/synchronization/blocking_counter.h"
|
||||
#include "tensorflow/core/framework/allocator.h"
|
||||
#include "tensorflow/core/framework/bounds_check.h"
|
||||
#include "tensorflow/core/framework/kernel_shape_util.h"
|
||||
@@ -138,6 +139,98 @@ struct LaunchGeneric {
|
||||
}
|
||||
}
|
||||
};
|
||||
+
|
||||
+// Compute grouped 2D convolutions on CPU. Unlike grouped convolution
|
||||
+// implementation in cuDNN this is faaaaaar from optimal and needs more work
|
||||
+// to deliver competitive performance. Currently it exists to close the feature
|
||||
+// parity gap between convolution operations on different devices.
|
||||
+template <typename T>
|
||||
+struct LaunchGrouped {
|
||||
+ void operator()(OpKernelContext* ctx, const Tensor& input,
|
||||
+ const Tensor& filter, int row_stride, int col_stride,
|
||||
+ int row_dilation, int col_dilation, const Padding& padding,
|
||||
+ const std::vector<int64>& explicit_paddings, Tensor* output,
|
||||
+ TensorFormat data_format) {
|
||||
+ DCHECK(data_format == FORMAT_NHWC)
|
||||
+ << "Grouped conv implementation only "
|
||||
+ "supports NHWC tensor format for now.";
|
||||
+
|
||||
+ const int64 in_depth = input.dim_size(3);
|
||||
+ const int64 patch_depth = filter.dim_size(2);
|
||||
+ const int64 num_groups = in_depth / patch_depth;
|
||||
+
|
||||
+ // Shuffle input/filter tensors to have group as a leading dimension.
|
||||
+ std::array<int64, 5> shuffle({3, 0, 1, 2, 4});
|
||||
+
|
||||
+ // Compute pre shuffle dimemnsions.
|
||||
+ auto pre_shuffle = [&](const Tensor& tensor) -> std::array<int64, 5> {
|
||||
+ return {tensor.dim_size(0), tensor.dim_size(1), tensor.dim_size(2),
|
||||
+ num_groups, tensor.dim_size(3) / num_groups};
|
||||
+ };
|
||||
+
|
||||
+ // Compute post shuffle dimemnsions.
|
||||
+ auto post_shuffle = [&](const Tensor& tensor) -> std::array<int64, 5> {
|
||||
+ return {num_groups, tensor.dim_size(0), tensor.dim_size(1),
|
||||
+ tensor.dim_size(2), tensor.dim_size(3) / num_groups};
|
||||
+ };
|
||||
+
|
||||
+ auto& device = ctx->eigen_device<CPUDevice>();
|
||||
+
|
||||
+ absl::BlockingCounter shuffles_completed(2);
|
||||
+ auto on_shuffled = [&]() { shuffles_completed.DecrementCount(); };
|
||||
+
|
||||
+ // Shuffle input into temporary tensor.
|
||||
+ Tensor input_shuffled(input.dtype(), TensorShape(post_shuffle(input)));
|
||||
+ input_shuffled.tensor<T, 5>().device(device, on_shuffled) =
|
||||
+ input.shaped<T, 5>(pre_shuffle(input)).shuffle(shuffle);
|
||||
+
|
||||
+ // Shuffle filter into temporary tensor.
|
||||
+ Tensor filter_shuffled(filter.dtype(), TensorShape(post_shuffle(filter)));
|
||||
+ filter_shuffled.tensor<T, 5>().device(device, on_shuffled) =
|
||||
+ filter.shaped<T, 5>(pre_shuffle(filter)).shuffle(shuffle);
|
||||
+
|
||||
+ // Wait for the completion of input/filter shuffles.
|
||||
+ shuffles_completed.Wait();
|
||||
+
|
||||
+ // Write group convolution results into temporary output tensor.
|
||||
+ Tensor output_shuffled(output->dtype(), TensorShape(post_shuffle(*output)));
|
||||
+
|
||||
+ for (int64 i = 0; i < num_groups; ++i) {
|
||||
+ // TODO(ezhulenev): Run this loop using `parallelFor` (regular parallelFor
|
||||
+ // will lead to deadlock, SpatialConvolution has to use async Eigen
|
||||
+ // assignment). This requires small changes to Eigen to support async
|
||||
+ // exeuction for tensor chipping operation.
|
||||
+
|
||||
+ // TODO(ezhulenev): Grouped convolution should also support 1x1 filter
|
||||
+ // optimization.
|
||||
+
|
||||
+ auto input_slice = input_shuffled.tensor<T, 5>().template chip<0>(i);
|
||||
+ auto filter_slice = filter_shuffled.tensor<T, 5>().template chip<0>(i);
|
||||
+ auto output_slice = output_shuffled.tensor<T, 5>().template chip<0>(i);
|
||||
+
|
||||
+ if (padding == EXPLICIT) {
|
||||
+ functor::SpatialConvolution<CPUDevice, T>()(
|
||||
+ ctx->eigen_device<CPUDevice>(), output_slice, input_slice,
|
||||
+ filter_slice, row_stride, col_stride, row_dilation, col_dilation,
|
||||
+ static_cast<int>(explicit_paddings[2]),
|
||||
+ static_cast<int>(explicit_paddings[3]),
|
||||
+ static_cast<int>(explicit_paddings[4]),
|
||||
+ static_cast<int>(explicit_paddings[5]));
|
||||
+ } else {
|
||||
+ functor::SpatialConvolution<CPUDevice, T>()(
|
||||
+ ctx->eigen_device<CPUDevice>(), output_slice, input_slice,
|
||||
+ filter_slice, row_stride, col_stride, row_dilation, col_dilation,
|
||||
+ BrainPadding2EigenPadding(padding));
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ // Shuffle temporary output back into pre-shuffled shape.
|
||||
+ std::array<int64, 5> rev_shuffle({1, 2, 3, 0, 4});
|
||||
+ output->shaped<T, 5>(pre_shuffle(*output)).device(device) =
|
||||
+ output_shuffled.tensor<T, 5>().shuffle(rev_shuffle);
|
||||
+ }
|
||||
+};
|
||||
+
|
||||
} // namespace
|
||||
|
||||
template <typename T>
|
||||
@@ -155,14 +248,6 @@ struct LaunchConv2DOp<CPUDevice, T> {
|
||||
ToString(data_format)));
|
||||
return;
|
||||
}
|
||||
- const int64 in_depth = GetTensorDim(input, data_format, 'C');
|
||||
- OP_REQUIRES(ctx, in_depth == filter.dim_size(2),
|
||||
- errors::Unimplemented(
|
||||
- "The Conv2D op currently does not support grouped "
|
||||
- "convolutions on the CPU. A grouped convolution was "
|
||||
- "attempted to be run because the input depth of ",
|
||||
- in_depth, " does not match the filter input depth of ",
|
||||
- filter.dim_size(2)));
|
||||
|
||||
for (int64 explicit_padding : explicit_paddings) {
|
||||
if (!FastBoundsCheck(explicit_padding, std::numeric_limits<int>::max())) {
|
||||
@@ -170,9 +255,35 @@ struct LaunchConv2DOp<CPUDevice, T> {
|
||||
return;
|
||||
}
|
||||
}
|
||||
- LaunchGeneric<CPUDevice, T>()(ctx, input, filter, row_stride, col_stride,
|
||||
- row_dilation, col_dilation, padding,
|
||||
- explicit_paddings, output, data_format);
|
||||
+
|
||||
+ const int64 in_depth = input.dim_size(3);
|
||||
+ const int64 out_depth = output->dim_size(3);
|
||||
+ const int64 patch_depth = filter.dim_size(2);
|
||||
+
|
||||
+ if (in_depth % patch_depth != 0) {
|
||||
+ ctx->SetStatus(errors::InvalidArgument(
|
||||
+ "input depth must be evenly divisible by filter depth: ", in_depth,
|
||||
+ " vs ", patch_depth));
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ const int64 num_groups = in_depth / patch_depth;
|
||||
+ if (out_depth % num_groups != 0 || out_depth < num_groups) {
|
||||
+ ctx->SetStatus(errors::InvalidArgument(
|
||||
+ "output depth must be evenly divisible by number of groups: ",
|
||||
+ out_depth, " vs ", num_groups));
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ if (in_depth != patch_depth) {
|
||||
+ LaunchGrouped<T>()(ctx, input, filter, row_stride, col_stride,
|
||||
+ row_dilation, col_dilation, padding, explicit_paddings,
|
||||
+ output, data_format);
|
||||
+ } else {
|
||||
+ LaunchGeneric<CPUDevice, T>()(ctx, input, filter, row_stride, col_stride,
|
||||
+ row_dilation, col_dilation, padding,
|
||||
+ explicit_paddings, output, data_format);
|
||||
+ }
|
||||
}
|
||||
};
|
||||
|
||||
diff --git a/tensorflow/python/kernel_tests/conv_ops_test.py b/tensorflow/python/kernel_tests/conv_ops_test.py
|
||||
index 44a67ccc55f0a..92af04359caa9 100644
|
||||
--- a/tensorflow/python/kernel_tests/conv_ops_test.py
|
||||
+++ b/tensorflow/python/kernel_tests/conv_ops_test.py
|
||||
@@ -834,17 +834,21 @@ def MakeConv2d(inputs, filters):
|
||||
results[0], results[1], atol=tol_to_use, rtol=tol_to_use)
|
||||
|
||||
@test_util.run_in_graph_and_eager_modes
|
||||
- @test_util.run_cuda_only
|
||||
def testConv2DGroupConvFwd(self):
|
||||
- for data_format in ["NHWC", "NCHW"]:
|
||||
+ if test.is_gpu_available(cuda_only=True):
|
||||
+ data_formats = ["NHWC", "NCHW"]
|
||||
+ else:
|
||||
+ data_formats = ["NHWC"]
|
||||
+ for data_format in data_formats:
|
||||
for dilation in [1, 2]:
|
||||
for stride in [1, 2]:
|
||||
- self._VerifyGroupConvFwd([10, 32, 32, 16], [3, 3, 4, 8],
|
||||
- dilations=[dilation, dilation],
|
||||
- strides=[stride, stride],
|
||||
- padding="SAME",
|
||||
- data_format=data_format,
|
||||
- dtype=dtypes.float32)
|
||||
+ for filter_dims in [[3, 3, 4, 8], [1, 1, 2, 16]]:
|
||||
+ self._VerifyGroupConvFwd([10, 32, 32, 16], filter_dims,
|
||||
+ dilations=[dilation, dilation],
|
||||
+ strides=[stride, stride],
|
||||
+ padding="SAME",
|
||||
+ data_format=data_format,
|
||||
+ dtype=dtypes.float32)
|
||||
|
||||
@test_util.deprecated_graph_mode_only
|
||||
@test_util.run_cuda_only
|
||||
@ -1,50 +0,0 @@
|
||||
From b12aa1d44352de21d1a6faaf04172d8c2508b42b Mon Sep 17 00:00:00 2001
|
||||
From: Mihai Maruseac <mihaimaruseac@google.com>
|
||||
Date: Mon, 19 Apr 2021 18:32:56 -0700
|
||||
Subject: [PATCH] Fix one more FPE.
|
||||
|
||||
---
|
||||
tensorflow/core/kernels/conv_ops.cc | 13 +++++++++++++
|
||||
1 file changed, 13 insertions(+)
|
||||
|
||||
diff --git a/tensorflow/core/kernels/conv_ops.cc b/tensorflow/core/kernels/conv_ops.cc
|
||||
index ef13eb3f..2d357710 100644
|
||||
--- a/tensorflow/core/kernels/conv_ops.cc
|
||||
+++ b/tensorflow/core/kernels/conv_ops.cc
|
||||
@@ -260,6 +260,11 @@ struct LaunchConv2DOp<CPUDevice, T> {
|
||||
const int64 out_depth = output->dim_size(3);
|
||||
const int64 patch_depth = filter.dim_size(2);
|
||||
|
||||
+ if (patch_depth <= 0) {
|
||||
+ ctx->SetStatus(errors::InvalidArgument(
|
||||
+ "filter depth must be stricly positive, got ", patch_depth));
|
||||
+ return;
|
||||
+ }
|
||||
if (in_depth % patch_depth != 0) {
|
||||
ctx->SetStatus(errors::InvalidArgument(
|
||||
"input depth must be evenly divisible by filter depth: ", in_depth,
|
||||
@@ -268,6 +273,11 @@ struct LaunchConv2DOp<CPUDevice, T> {
|
||||
}
|
||||
|
||||
const int64 num_groups = in_depth / patch_depth;
|
||||
+ if (num_groups <= 0) {
|
||||
+ ctx->SetStatus(errors::InvalidArgument(
|
||||
+ "number of groups must be stricly positive, got ", num_groups));
|
||||
+ return;
|
||||
+ }
|
||||
if (out_depth % num_groups != 0 || out_depth < num_groups) {
|
||||
ctx->SetStatus(errors::InvalidArgument(
|
||||
"output depth must be evenly divisible by number of groups: ",
|
||||
@@ -536,6 +546,9 @@ Status ComputeConv2DDimension(const Conv2DParameters& params,
|
||||
errors::InvalidArgument("Patch depth too large"));
|
||||
const int in_depth = static_cast<int>(in_depth_raw);
|
||||
const int patch_depth = static_cast<int>(patch_depth_raw);
|
||||
+ TF_REQUIRES(patch_depth > 0,
|
||||
+ errors::InvalidArgument(
|
||||
+ "filter depth must be stricly positive, got", patch_depth));
|
||||
TF_REQUIRES(in_depth % patch_depth == 0,
|
||||
errors::InvalidArgument(
|
||||
"input depth must be evenly divisible by filter depth: ",
|
||||
--
|
||||
2.23.0
|
||||
|
||||
@ -1,49 +0,0 @@
|
||||
From cfa91be9863a91d5105a3b4941096044ab32036b Mon Sep 17 00:00:00 2001
|
||||
From: Mihai Maruseac <mihaimaruseac@google.com>
|
||||
Date: Mon, 19 Apr 2021 18:58:47 -0700
|
||||
Subject: [PATCH] Fix one FPE and remove two CHECK-fails.
|
||||
|
||||
PiperOrigin-RevId: 369349640
|
||||
Change-Id: I1fedbfc2b5bab635c5cb51f103d7c9176f79831a
|
||||
---
|
||||
tensorflow/core/kernels/quantized_conv_ops.cc | 13 +++++++++++--
|
||||
1 file changed, 11 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/tensorflow/core/kernels/quantized_conv_ops.cc b/tensorflow/core/kernels/quantized_conv_ops.cc
|
||||
index a4d36cca3e408..a339de8cfc8fa 100644
|
||||
--- a/tensorflow/core/kernels/quantized_conv_ops.cc
|
||||
+++ b/tensorflow/core/kernels/quantized_conv_ops.cc
|
||||
@@ -18,6 +18,8 @@ limitations under the License.
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
+#include "tensorflow/core/platform/errors.h"
|
||||
+
|
||||
#define EIGEN_USE_THREADS
|
||||
|
||||
#define GEMMLOWP_ALLOW_SLOW_SCALAR_FALLBACK
|
||||
@@ -227,8 +229,12 @@ class Im2ColConvFunctor {
|
||||
return;
|
||||
}
|
||||
|
||||
- CHECK_GT(output_width, 0);
|
||||
- CHECK_GT(output_height, 0);
|
||||
+ OP_REQUIRES(
|
||||
+ context, output_width > 0,
|
||||
+ errors::InvalidArgument("output_width must be strictly positive"));
|
||||
+ OP_REQUIRES(
|
||||
+ context, output_height > 0,
|
||||
+ errors::InvalidArgument("output_height must be strictly positive"));
|
||||
int filter_left_offset;
|
||||
int filter_top_offset;
|
||||
if (padding == VALID) {
|
||||
@@ -255,6 +261,9 @@ class Im2ColConvFunctor {
|
||||
// by the width, then the height. This is the standard memory order in the
|
||||
// image world if it helps to visualize it.
|
||||
const int filter_value_count = filter_width * filter_height * input_depth;
|
||||
+ OP_REQUIRES(context, filter_value_count > 0,
|
||||
+ errors::InvalidArgument(
|
||||
+ "filter patch must contain at least one element"));
|
||||
const int64 patches_per_chunk =
|
||||
kMaxChunkSize / (filter_value_count * sizeof(T1));
|
||||
const int64 chunk_value_count =
|
||||
@ -1,27 +0,0 @@
|
||||
From a1b11d2fdd1e51bfe18bb1ede804f60abfa92da6 Mon Sep 17 00:00:00 2001
|
||||
From: Mihai Maruseac <mihaimaruseac@google.com>
|
||||
Date: Tue, 20 Apr 2021 10:52:46 -0700
|
||||
Subject: [PATCH] Fix one division by zero
|
||||
|
||||
PiperOrigin-RevId: 369474832
|
||||
Change-Id: I1082858ed78d9b2e4738ce30b231955973d49e1e
|
||||
---
|
||||
tensorflow/core/kernels/quantized_mul_op.cc | 5 +++++
|
||||
1 file changed, 5 insertions(+)
|
||||
|
||||
diff --git a/tensorflow/core/kernels/quantized_mul_op.cc b/tensorflow/core/kernels/quantized_mul_op.cc
|
||||
index 4e191f162662b..fb56f68bf14db 100644
|
||||
--- a/tensorflow/core/kernels/quantized_mul_op.cc
|
||||
+++ b/tensorflow/core/kernels/quantized_mul_op.cc
|
||||
@@ -347,6 +347,11 @@ class QuantizedMulOp : public OpKernel {
|
||||
tensor_num_elements = x.NumElements();
|
||||
tensor_offset = offset_x;
|
||||
}
|
||||
+ if (vector_num_elements == 0) {
|
||||
+ context->SetStatus(
|
||||
+ errors::InvalidArgument("vector must have at least 1 element"));
|
||||
+ return;
|
||||
+ }
|
||||
VectorTensorMultiply<T, Toutput>(
|
||||
vector_data, vector_offset, vector_num_elements, tensor_data,
|
||||
tensor_offset, tensor_num_elements, z_data);
|
||||
@ -1,26 +0,0 @@
|
||||
From f851613f8f0fb0c838d160ced13c134f778e3ce7 Mon Sep 17 00:00:00 2001
|
||||
From: Mihai Maruseac <mihaimaruseac@google.com>
|
||||
Date: Wed, 21 Apr 2021 16:20:48 -0700
|
||||
Subject: [PATCH] Fix heap buffer overflow caused by rounding.
|
||||
|
||||
This was hard to fix. Due to the way we compute the pixels that influence an output pixel in resized images, for certain input configuration we might have issued a read to a pixel that is outside of boundary of the original image. This is because of floating errors that affected truncation results.
|
||||
|
||||
PiperOrigin-RevId: 369757871
|
||||
Change-Id: If89425fff930983829a2168203c11858883eebc9
|
||||
---
|
||||
tensorflow/core/kernels/quantized_resize_bilinear_op.cc | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
diff --git a/tensorflow/core/kernels/quantized_resize_bilinear_op.cc b/tensorflow/core/kernels/quantized_resize_bilinear_op.cc
|
||||
index 07453c7e73284..2fd807f6df961 100644
|
||||
--- a/tensorflow/core/kernels/quantized_resize_bilinear_op.cc
|
||||
+++ b/tensorflow/core/kernels/quantized_resize_bilinear_op.cc
|
||||
@@ -64,6 +64,8 @@ inline void ComputeInterpolationWeights(
|
||||
std::max(static_cast<int64>(in_f), static_cast<int64>(0));
|
||||
interpolation->upper[i] =
|
||||
std::min(static_cast<int64>(std::ceil(in)), in_size - 1);
|
||||
+ interpolation->lower[i] =
|
||||
+ std::min(interpolation->lower[i], interpolation->upper[i]);
|
||||
interpolation->lerp[i] = in - in_f;
|
||||
interpolation->ilerp[i] =
|
||||
static_cast<T_SCALE>((in - in_f) * (1 << resolution));
|
||||
@ -1,117 +0,0 @@
|
||||
From e6a7c7cc18c3aaad1ae0872cb0a959f5c923d2bd Mon Sep 17 00:00:00 2001
|
||||
From: Mihai Maruseac <mihaimaruseac@google.com>
|
||||
Date: Tue, 20 Apr 2021 14:45:33 -0700
|
||||
Subject: [PATCH] Remove `OP_REQUIRES` call from helper function.
|
||||
|
||||
Since `OP_REQUIRES` macro expands to a `return;` (among other), calling it in a helper function only ends the helper function's execution earlier, but the kernel will still run from start to end. Thus, all the expected validations are actually broken/useless as the code ploughs through the next crash anyway.
|
||||
|
||||
PiperOrigin-RevId: 369524386
|
||||
Change-Id: I54f6cf9328445675ccc392e661b04336b229c9da
|
||||
---
|
||||
.../core/kernels/sparse/sparse_cholesky_op.cc | 67 ++++++++++---------
|
||||
1 file changed, 34 insertions(+), 33 deletions(-)
|
||||
|
||||
diff --git a/tensorflow/core/kernels/sparse/sparse_cholesky_op.cc b/tensorflow/core/kernels/sparse/sparse_cholesky_op.cc
|
||||
index 9a939276f0b6c..47ab252317de5 100644
|
||||
--- a/tensorflow/core/kernels/sparse/sparse_cholesky_op.cc
|
||||
+++ b/tensorflow/core/kernels/sparse/sparse_cholesky_op.cc
|
||||
@@ -17,6 +17,8 @@ limitations under the License.
|
||||
#include <numeric>
|
||||
#include <vector>
|
||||
|
||||
+#include "tensorflow/core/framework/op_requires.h"
|
||||
+
|
||||
#define EIGEN_USE_THREADS
|
||||
|
||||
#include "third_party/eigen3/Eigen/Core"
|
||||
@@ -82,8 +84,8 @@ class CSRSparseCholeskyCPUOp : public OpKernel {
|
||||
|
||||
int64 num_rows;
|
||||
int batch_size;
|
||||
- ValidateInputs(ctx, *input_matrix, input_permutation_indices, &batch_size,
|
||||
- &num_rows);
|
||||
+ OP_REQUIRES_OK(ctx, ValidateInputs(*input_matrix, input_permutation_indices,
|
||||
+ &batch_size, &num_rows));
|
||||
|
||||
// Allocate batch pointers.
|
||||
Tensor batch_ptr(cpu_allocator(), DT_INT32, TensorShape({batch_size + 1}));
|
||||
@@ -226,49 +228,48 @@ class CSRSparseCholeskyCPUOp : public OpKernel {
|
||||
}
|
||||
|
||||
private:
|
||||
- void ValidateInputs(OpKernelContext* ctx,
|
||||
- const CSRSparseMatrix& sparse_matrix,
|
||||
- const Tensor& permutation_indices, int* batch_size,
|
||||
- int64* num_rows) {
|
||||
- OP_REQUIRES(ctx, sparse_matrix.dtype() == DataTypeToEnum<T>::value,
|
||||
- errors::InvalidArgument(
|
||||
- "Asked for a CSRSparseMatrix of type ",
|
||||
- DataTypeString(DataTypeToEnum<T>::value),
|
||||
- " but saw dtype: ", DataTypeString(sparse_matrix.dtype())));
|
||||
+ Status ValidateInputs(const CSRSparseMatrix& sparse_matrix,
|
||||
+ const Tensor& permutation_indices, int* batch_size,
|
||||
+ int64* num_rows) {
|
||||
+ if (sparse_matrix.dtype() != DataTypeToEnum<T>::value)
|
||||
+ return errors::InvalidArgument(
|
||||
+ "Asked for a CSRSparseMatrix of type ",
|
||||
+ DataTypeString(DataTypeToEnum<T>::value),
|
||||
+ " but saw dtype: ", DataTypeString(sparse_matrix.dtype()));
|
||||
|
||||
const Tensor& dense_shape = sparse_matrix.dense_shape();
|
||||
const int rank = dense_shape.dim_size(0);
|
||||
- OP_REQUIRES(ctx, rank == 2 || rank == 3,
|
||||
- errors::InvalidArgument("sparse matrix must have rank 2 or 3; ",
|
||||
- "but dense_shape has size ", rank));
|
||||
+ if (rank < 2 || rank > 3)
|
||||
+ return errors::InvalidArgument("sparse matrix must have rank 2 or 3; ",
|
||||
+ "but dense_shape has size ", rank);
|
||||
const int row_dim = (rank == 2) ? 0 : 1;
|
||||
auto dense_shape_vec = dense_shape.vec<int64>();
|
||||
*num_rows = dense_shape_vec(row_dim);
|
||||
const int64 num_cols = dense_shape_vec(row_dim + 1);
|
||||
- OP_REQUIRES(ctx, *num_rows == num_cols,
|
||||
- errors::InvalidArgument("sparse matrix must be square; got: ",
|
||||
- *num_rows, " != ", num_cols));
|
||||
+ if (*num_rows != num_cols)
|
||||
+ return errors::InvalidArgument(
|
||||
+ "sparse matrix must be square; got: ", *num_rows, " != ", num_cols);
|
||||
const TensorShape& perm_shape = permutation_indices.shape();
|
||||
- OP_REQUIRES(
|
||||
- ctx, perm_shape.dims() + 1 == rank,
|
||||
- errors::InvalidArgument(
|
||||
- "sparse matrix must have the same rank as permutation; got: ", rank,
|
||||
- " != ", perm_shape.dims(), " + 1."));
|
||||
- OP_REQUIRES(
|
||||
- ctx, perm_shape.dim_size(rank - 2) == *num_rows,
|
||||
- errors::InvalidArgument(
|
||||
- "permutation must have the same number of elements in each batch "
|
||||
- "as the number of rows in sparse matrix; got: ",
|
||||
- perm_shape.dim_size(rank - 2), " != ", *num_rows));
|
||||
+ if (perm_shape.dims() + 1 != rank)
|
||||
+ return errors::InvalidArgument(
|
||||
+ "sparse matrix must have the same rank as permutation; got: ", rank,
|
||||
+ " != ", perm_shape.dims(), " + 1.");
|
||||
+ if (perm_shape.dim_size(rank - 2) != *num_rows)
|
||||
+ return errors::InvalidArgument(
|
||||
+ "permutation must have the same number of elements in each batch "
|
||||
+ "as the number of rows in sparse matrix; got: ",
|
||||
+ perm_shape.dim_size(rank - 2), " != ", *num_rows);
|
||||
|
||||
*batch_size = sparse_matrix.batch_size();
|
||||
if (*batch_size > 1) {
|
||||
- OP_REQUIRES(
|
||||
- ctx, perm_shape.dim_size(0) == *batch_size,
|
||||
- errors::InvalidArgument("permutation must have the same batch size "
|
||||
- "as sparse matrix; got: ",
|
||||
- perm_shape.dim_size(0), " != ", *batch_size));
|
||||
+ if (perm_shape.dim_size(0) != *batch_size)
|
||||
+ return errors::InvalidArgument(
|
||||
+ "permutation must have the same batch size "
|
||||
+ "as sparse matrix; got: ",
|
||||
+ perm_shape.dim_size(0), " != ", *batch_size);
|
||||
}
|
||||
+
|
||||
+ return Status::OK();
|
||||
}
|
||||
};
|
||||
|
||||
@ -1,69 +0,0 @@
|
||||
From 44b7f486c0143f68b56c34e2d01e146ee445134a Mon Sep 17 00:00:00 2001
|
||||
From: Mihai Maruseac <mihaimaruseac@google.com>
|
||||
Date: Wed, 21 Apr 2021 16:19:54 -0700
|
||||
Subject: [PATCH] Fix out of bounds read in `ragged_cross_op.cc`.
|
||||
|
||||
PiperOrigin-RevId: 369757702
|
||||
Change-Id: Ie6e5d2c21513a8d56bf41fcf35960caf76e890f9
|
||||
---
|
||||
tensorflow/core/kernels/ragged_cross_op.cc | 30 ++++++++++++++++++++++
|
||||
1 file changed, 30 insertions(+)
|
||||
|
||||
diff --git a/tensorflow/core/kernels/ragged_cross_op.cc b/tensorflow/core/kernels/ragged_cross_op.cc
|
||||
index ea65c0ee2b5b2..5dfe93f416659 100644
|
||||
--- a/tensorflow/core/kernels/ragged_cross_op.cc
|
||||
+++ b/tensorflow/core/kernels/ragged_cross_op.cc
|
||||
@@ -21,6 +21,7 @@ limitations under the License.
|
||||
#include "tensorflow/core/framework/register_types.h"
|
||||
#include "tensorflow/core/framework/tensor.h"
|
||||
#include "tensorflow/core/framework/tensor_shape.h"
|
||||
+#include "tensorflow/core/platform/errors.h"
|
||||
#include "tensorflow/core/platform/fingerprint.h"
|
||||
#include "tensorflow/core/util/util.h"
|
||||
#include "tensorflow/core/util/work_sharder.h"
|
||||
@@ -466,16 +467,45 @@ class RaggedCrossOp : public OpKernel {
|
||||
int next_dense = 0;
|
||||
for (char c : input_order_) {
|
||||
if (c == 'R') {
|
||||
+ if (next_ragged >= ragged_values_list.size())
|
||||
+ return errors::InvalidArgument(
|
||||
+ "input_order \"", input_order_,
|
||||
+ "\" specifies reading a ragged tensor value at index ",
|
||||
+ next_ragged, " from a list of ", ragged_values_list.size(),
|
||||
+ " values.");
|
||||
+ if (next_ragged >= ragged_splits_list.size())
|
||||
+ return errors::InvalidArgument(
|
||||
+ "input_order \"", input_order_,
|
||||
+ "\" specifies reading a ragged tensor split at index ",
|
||||
+ next_ragged, " from a list of ", ragged_splits_list.size(),
|
||||
+ " splits.");
|
||||
TF_RETURN_IF_ERROR(BuildRaggedFeatureReader(
|
||||
ragged_values_list[next_ragged], ragged_splits_list[next_ragged],
|
||||
features));
|
||||
next_ragged++;
|
||||
} else if (c == 'S') {
|
||||
+ if (next_sparse >= sparse_values_list.size())
|
||||
+ return errors::InvalidArgument(
|
||||
+ "input_order \"", input_order_,
|
||||
+ "\" specifies reading a sparse tensor value at index ",
|
||||
+ next_sparse, " from a list of ", sparse_values_list.size(),
|
||||
+ " values.");
|
||||
+ if (next_sparse >= sparse_indices_list.size())
|
||||
+ return errors::InvalidArgument(
|
||||
+ "input_order \"", input_order_,
|
||||
+ "\" specifies reading a sparse tensor index at index ",
|
||||
+ next_sparse, " from a list of ", sparse_indices_list.size(),
|
||||
+ " indices.");
|
||||
TF_RETURN_IF_ERROR(BuildSparseFeatureReader(
|
||||
sparse_indices_list[next_sparse], sparse_values_list[next_sparse],
|
||||
batch_size, features));
|
||||
next_sparse++;
|
||||
} else if (c == 'D') {
|
||||
+ if (next_dense >= dense_list.size())
|
||||
+ return errors::InvalidArgument(
|
||||
+ "input_order \"", input_order_,
|
||||
+ "\" specifies reading a dense tensor at index ", next_dense,
|
||||
+ " from a list of ", dense_list.size(), " tensors.");
|
||||
TF_RETURN_IF_ERROR(
|
||||
BuildDenseFeatureReader(dense_list[next_dense++], features));
|
||||
} else {
|
||||
@ -1,76 +0,0 @@
|
||||
From b432a38fe0e1b4b904a6c222cbce794c39703e87 Mon Sep 17 00:00:00 2001
|
||||
From: Amit Patankar <amitpatankar@google.com>
|
||||
Date: Wed, 21 Apr 2021 15:57:36 -0700
|
||||
Subject: [PATCH] Fix overflow CHECK issue with `tf.raw_ops.DrawBoundingBoxes`.
|
||||
|
||||
---
|
||||
.../core/kernels/draw_bounding_box_op.cc | 49 ++++++++++++++-----
|
||||
1 file changed, 37 insertions(+), 12 deletions(-)
|
||||
|
||||
diff --git a/tensorflow/core/kernels/draw_bounding_box_op.cc b/tensorflow/core/kernels/draw_bounding_box_op.cc
|
||||
index 30de99b7..39519523 100644
|
||||
--- a/tensorflow/core/kernels/draw_bounding_box_op.cc
|
||||
+++ b/tensorflow/core/kernels/draw_bounding_box_op.cc
|
||||
@@ -147,22 +147,47 @@ class DrawBoundingBoxesOp : public OpKernel {
|
||||
|
||||
// At this point, {min,max}_box_{row,col}_clamp are inside the
|
||||
// image.
|
||||
- CHECK_GE(min_box_row_clamp, 0);
|
||||
- CHECK_GE(max_box_row_clamp, 0);
|
||||
- CHECK_LT(min_box_row_clamp, height);
|
||||
- CHECK_LT(max_box_row_clamp, height);
|
||||
- CHECK_GE(min_box_col_clamp, 0);
|
||||
- CHECK_GE(max_box_col_clamp, 0);
|
||||
- CHECK_LT(min_box_col_clamp, width);
|
||||
- CHECK_LT(max_box_col_clamp, width);
|
||||
+
|
||||
+ OP_REQUIRES(
|
||||
+ context, min_box_row_clamp >= 0,
|
||||
+ errors::InvalidArgument("Min box row clamp is less than 0."));
|
||||
+ OP_REQUIRES(
|
||||
+ context, max_box_row_clamp >= 0,
|
||||
+ errors::InvalidArgument("Max box row clamp is less than 0."));
|
||||
+ OP_REQUIRES(context, min_box_row_clamp <= height,
|
||||
+ errors::InvalidArgument(
|
||||
+ "Min box row clamp is greater than height."));
|
||||
+ OP_REQUIRES(context, max_box_row_clamp <= height,
|
||||
+ errors::InvalidArgument(
|
||||
+ "Max box row clamp is greater than height."));
|
||||
+
|
||||
+ OP_REQUIRES(
|
||||
+ context, min_box_col_clamp >= 0,
|
||||
+ errors::InvalidArgument("Min box col clamp is less than 0."));
|
||||
+ OP_REQUIRES(
|
||||
+ context, max_box_col_clamp >= 0,
|
||||
+ errors::InvalidArgument("Max box col clamp is less than 0."));
|
||||
+ OP_REQUIRES(context, min_box_col_clamp <= width,
|
||||
+ errors::InvalidArgument(
|
||||
+ "Min box col clamp is greater than width."));
|
||||
+ OP_REQUIRES(context, max_box_col_clamp <= width,
|
||||
+ errors::InvalidArgument(
|
||||
+ "Max box col clamp is greater than width."));
|
||||
|
||||
// At this point, the min_box_row and min_box_col are either
|
||||
// in the image or above/left of it, and max_box_row and
|
||||
// max_box_col are either in the image or below/right or it.
|
||||
- CHECK_LT(min_box_row, height);
|
||||
- CHECK_GE(max_box_row, 0);
|
||||
- CHECK_LT(min_box_col, width);
|
||||
- CHECK_GE(max_box_col, 0);
|
||||
+
|
||||
+ OP_REQUIRES(
|
||||
+ context, min_box_row <= height,
|
||||
+ errors::InvalidArgument("Min box row is greater than height."));
|
||||
+ OP_REQUIRES(context, max_box_row >= 0,
|
||||
+ errors::InvalidArgument("Max box row is less than 0."));
|
||||
+ OP_REQUIRES(
|
||||
+ context, min_box_col <= width,
|
||||
+ errors::InvalidArgument("Min box col is greater than width."));
|
||||
+ OP_REQUIRES(context, max_box_col >= 0,
|
||||
+ errors::InvalidArgument("Max box col is less than 0."));
|
||||
|
||||
// Draw top line.
|
||||
if (min_box_row >= 0) {
|
||||
--
|
||||
2.23.0
|
||||
|
||||
@ -1,64 +0,0 @@
|
||||
diff -Nur a/tensorflow/core/kernels/sparse_tensors_map_ops.cc b/tensorflow/core/kernels/sparse_tensors_map_ops.cc
|
||||
--- a/tensorflow/core/kernels/sparse_tensors_map_ops.cc 2020-09-22 09:57:17.000000000 +0800
|
||||
+++ b/tensorflow/core/kernels/sparse_tensors_map_ops.cc 2021-06-28 22:53:37.005305788 +0800
|
||||
@@ -21,16 +21,12 @@
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
-#include "tensorflow/core/framework/op_kernel.h"
|
||||
-#include "tensorflow/core/framework/register_types.h"
|
||||
-
|
||||
-#include "tensorflow/core/framework/op_kernel.h"
|
||||
-#include "tensorflow/core/framework/register_types.h"
|
||||
#include "tensorflow/core/framework/resource_mgr.h"
|
||||
#include "tensorflow/core/framework/tensor.h"
|
||||
#include "tensorflow/core/framework/tensor_util.h"
|
||||
#include "tensorflow/core/framework/types.h"
|
||||
#include "tensorflow/core/lib/gtl/inlined_vector.h"
|
||||
+#include "tensorflow/core/util/overflow.h"
|
||||
#include "tensorflow/core/util/sparse/sparse_tensor.h"
|
||||
|
||||
namespace tensorflow {
|
||||
@@ -254,7 +250,22 @@
|
||||
errors::InvalidArgument(
|
||||
"Rank of input SparseTensor should be > 1, but saw rank: ", rank));
|
||||
|
||||
- TensorShape tensor_input_shape(input_shape->vec<int64>());
|
||||
+ auto input_shape_vec = input_shape->vec<int64>();
|
||||
+ int new_num_elements = 1;
|
||||
+ bool overflow_ocurred = false;
|
||||
+ for (int i = 0; i < input_shape_vec.size(); i++) {
|
||||
+ new_num_elements =
|
||||
+ MultiplyWithoutOverflow(new_num_elements, input_shape_vec(i));
|
||||
+ if (new_num_elements < 0) {
|
||||
+ overflow_ocurred = true;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ OP_REQUIRES(
|
||||
+ context, !overflow_ocurred,
|
||||
+ errors::Internal("Encountered overflow from large input shape."));
|
||||
+
|
||||
+ TensorShape tensor_input_shape(input_shape_vec);
|
||||
gtl::InlinedVector<int64, 8> std_order(rank);
|
||||
std::iota(std_order.begin(), std_order.end(), 0);
|
||||
SparseTensor input_st;
|
||||
@@ -262,8 +273,7 @@
|
||||
tensor_input_shape, std_order,
|
||||
&input_st));
|
||||
|
||||
- auto input_shape_t = input_shape->vec<int64>();
|
||||
- const int64 N = input_shape_t(0);
|
||||
+ const int64 N = input_shape_vec(0);
|
||||
|
||||
Tensor sparse_handles(DT_INT64, TensorShape({N}));
|
||||
auto sparse_handles_t = sparse_handles.vec<int64>();
|
||||
@@ -274,7 +284,7 @@
|
||||
// minibatch entries.
|
||||
TensorShape output_shape;
|
||||
OP_REQUIRES_OK(context, TensorShapeUtils::MakeShape(
|
||||
- input_shape_t.data() + 1,
|
||||
+ input_shape_vec.data() + 1,
|
||||
input_shape->NumElements() - 1, &output_shape));
|
||||
|
||||
// Get groups by minibatch dimension
|
||||
@ -1,42 +0,0 @@
|
||||
From efea03b38fb8d3b81762237dc85e579cc5fc6e87 Mon Sep 17 00:00:00 2001
|
||||
From: Mihai Maruseac <mihaimaruseac@google.com>
|
||||
Date: Wed, 21 Apr 2021 16:15:46 -0700
|
||||
Subject: [PATCH] Validate inputs to `QuantizedMul`
|
||||
|
||||
PiperOrigin-RevId: 369756982
|
||||
Change-Id: I00d960cc3b9316fd7a86bd37a44e341c96e17624
|
||||
---
|
||||
tensorflow/core/kernels/quantized_mul_op.cc | 20 ++++++++++++++++----
|
||||
1 file changed, 16 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/tensorflow/core/kernels/quantized_mul_op.cc b/tensorflow/core/kernels/quantized_mul_op.cc
|
||||
index fb56f68bf14db..22cff8939449a 100644
|
||||
--- a/tensorflow/core/kernels/quantized_mul_op.cc
|
||||
+++ b/tensorflow/core/kernels/quantized_mul_op.cc
|
||||
@@ -284,10 +284,22 @@ class QuantizedMulOp : public OpKernel {
|
||||
void Compute(OpKernelContext* context) override {
|
||||
const Tensor& x = context->input(0);
|
||||
const Tensor& y = context->input(1);
|
||||
- const float min_x = context->input(2).flat<float>()(0);
|
||||
- const float max_x = context->input(3).flat<float>()(0);
|
||||
- const float min_y = context->input(4).flat<float>()(0);
|
||||
- const float max_y = context->input(5).flat<float>()(0);
|
||||
+ auto& min_x_tensor = context->input(2);
|
||||
+ OP_REQUIRES(context, TensorShapeUtils::IsScalar(min_x_tensor.shape()),
|
||||
+ errors::InvalidArgument("min_x must be a scalar"));
|
||||
+ const float min_x = min_x_tensor.flat<float>()(0);
|
||||
+ auto& max_x_tensor = context->input(3);
|
||||
+ OP_REQUIRES(context, TensorShapeUtils::IsScalar(max_x_tensor.shape()),
|
||||
+ errors::InvalidArgument("max_x must be a scalar"));
|
||||
+ const float max_x = max_x_tensor.flat<float>()(0);
|
||||
+ auto& min_y_tensor = context->input(4);
|
||||
+ OP_REQUIRES(context, TensorShapeUtils::IsScalar(min_y_tensor.shape()),
|
||||
+ errors::InvalidArgument("min_y must be a scalar"));
|
||||
+ const float min_y = min_y_tensor.flat<float>()(0);
|
||||
+ auto& max_y_tensor = context->input(5);
|
||||
+ OP_REQUIRES(context, TensorShapeUtils::IsScalar(max_y_tensor.shape()),
|
||||
+ errors::InvalidArgument("max_y must be a scalar"));
|
||||
+ const float max_y = max_y_tensor.flat<float>()(0);
|
||||
|
||||
BCast bcast(BCast::FromShape(x.shape()), BCast::FromShape(y.shape()));
|
||||
if (!bcast.IsValid()) {
|
||||
@ -1,57 +0,0 @@
|
||||
From a324ac84e573fba362a5e53d4e74d5de6729933e Mon Sep 17 00:00:00 2001
|
||||
From: Mihai Maruseac <mihaimaruseac@google.com>
|
||||
Date: Wed, 21 Apr 2021 18:11:15 -0700
|
||||
Subject: [PATCH] Validate arguments to `QuantizedReshape`.
|
||||
|
||||
Ensure that validations from `Reshape` also terminate `QuantizedReshape` on failure.
|
||||
|
||||
PiperOrigin-RevId: 369775421
|
||||
Change-Id: If8c5342267aceea65b7cb83a4b183304886f1ce8
|
||||
---
|
||||
.../core/kernels/quantized_reshape_op.cc | 25 +++++++++++++++++--
|
||||
1 file changed, 23 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/tensorflow/core/kernels/quantized_reshape_op.cc b/tensorflow/core/kernels/quantized_reshape_op.cc
|
||||
index bd76c94edeea7..682f4aaa1f79e 100644
|
||||
--- a/tensorflow/core/kernels/quantized_reshape_op.cc
|
||||
+++ b/tensorflow/core/kernels/quantized_reshape_op.cc
|
||||
@@ -17,6 +17,7 @@ limitations under the License.
|
||||
|
||||
#include "tensorflow/core/framework/op_kernel.h"
|
||||
#include "tensorflow/core/framework/register_types.h"
|
||||
+#include "tensorflow/core/framework/tensor_shape.h"
|
||||
#include "tensorflow/core/framework/tensor_types.h"
|
||||
#include "tensorflow/core/framework/types.h"
|
||||
#include "tensorflow/core/kernels/reshape_op.h"
|
||||
@@ -30,9 +31,29 @@ class QuantizedReshapeOp : public ReshapeOp {
|
||||
void Compute(OpKernelContext* ctx) override {
|
||||
// This call processes inputs 1 and 2 to write output 0.
|
||||
ReshapeOp::Compute(ctx);
|
||||
+ if (!ctx->status().ok()) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ const auto& input_min_float_tensor = ctx->input(2);
|
||||
+ const auto& input_min_float_shape = input_min_float_tensor.shape();
|
||||
+ OP_REQUIRES(ctx,
|
||||
+ TensorShapeUtils::IsScalar(input_min_float_shape) ||
|
||||
+ (TensorShapeUtils::IsVector(input_min_float_shape) &&
|
||||
+ (input_min_float_shape.dim_size(0) == 1)),
|
||||
+ errors::InvalidArgument(
|
||||
+ "input_min must be a scalar or a vector of 1 element"));
|
||||
+ const float input_min_float = input_min_float_tensor.flat<float>()(0);
|
||||
+ const auto& input_max_float_tensor = ctx->input(3);
|
||||
+ const auto& input_max_float_shape = input_max_float_tensor.shape();
|
||||
+ OP_REQUIRES(ctx,
|
||||
+ TensorShapeUtils::IsScalar(input_max_float_shape) ||
|
||||
+ (TensorShapeUtils::IsVector(input_max_float_shape) &&
|
||||
+ (input_max_float_shape.dim_size(0) == 1)),
|
||||
+ errors::InvalidArgument(
|
||||
+ "input_max must be a scalar or a vector of 1 element"));
|
||||
+ const float input_max_float = input_max_float_tensor.flat<float>()(0);
|
||||
|
||||
- const float input_min_float = ctx->input(2).flat<float>()(0);
|
||||
- const float input_max_float = ctx->input(3).flat<float>()(0);
|
||||
Tensor* output_min = nullptr;
|
||||
OP_REQUIRES_OK(ctx, ctx->allocate_output(1, TensorShape({}), &output_min));
|
||||
output_min->flat<float>()(0) = input_min_float;
|
||||
@ -1,33 +0,0 @@
|
||||
From f6c40f0c6cbf00d46c7717a26419f2062f2f8694 Mon Sep 17 00:00:00 2001
|
||||
From: Mihai Maruseac <mihaimaruseac@google.com>
|
||||
Date: Wed, 21 Apr 2021 17:00:39 -0700
|
||||
Subject: [PATCH] Validate min and max arguments to `QuantizedResizeBilinear`.
|
||||
|
||||
---
|
||||
.../core/kernels/quantized_resize_bilinear_op.cc | 10 ++++++++--
|
||||
1 file changed, 8 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/tensorflow/core/kernels/quantized_resize_bilinear_op.cc b/tensorflow/core/kernels/quantized_resize_bilinear_op.cc
|
||||
index 8270fc11..a94f56a5 100644
|
||||
--- a/tensorflow/core/kernels/quantized_resize_bilinear_op.cc
|
||||
+++ b/tensorflow/core/kernels/quantized_resize_bilinear_op.cc
|
||||
@@ -703,8 +703,14 @@ class QuantizedResizeBilinearOp : public OpKernel {
|
||||
|
||||
void Compute(OpKernelContext* context) override {
|
||||
const Tensor& input = context->input(0);
|
||||
- const float in_min = context->input(2).flat<float>()(0);
|
||||
- const float in_max = context->input(3).flat<float>()(0);
|
||||
+ const auto& in_min_tensor = context->input(2);
|
||||
+ OP_REQUIRES(context, TensorShapeUtils::IsScalar(in_min_tensor.shape()),
|
||||
+ errors::InvalidArgument("min must be a scalar"));
|
||||
+ const float in_min = in_min_tensor.flat<float>()(0);
|
||||
+ const auto& in_max_tensor = context->input(3);
|
||||
+ OP_REQUIRES(context, TensorShapeUtils::IsScalar(in_max_tensor.shape()),
|
||||
+ errors::InvalidArgument("max must be a scalar"));
|
||||
+ const float in_max = in_max_tensor.flat<float>()(0);
|
||||
|
||||
ImageResizerState st(align_corners_, false);
|
||||
st.ValidateAndCreateOutput(context, input);
|
||||
--
|
||||
2.23.0
|
||||
|
||||
@ -1,42 +0,0 @@
|
||||
From c570e2ecfc822941335ad48f6e10df4e21f11c96 Mon Sep 17 00:00:00 2001
|
||||
From: Mihai Maruseac <mihaimaruseac@google.com>
|
||||
Date: Wed, 21 Apr 2021 17:50:10 -0700
|
||||
Subject: [PATCH] Fix issues in Conv2DBackpropFilter.
|
||||
|
||||
PiperOrigin-RevId: 369772454
|
||||
Change-Id: I49b465f2ae2ce91def61b56cea8000197d5177d8
|
||||
---
|
||||
tensorflow/core/kernels/conv_grad_filter_ops.cc | 13 +++++++++++++
|
||||
1 file changed, 13 insertions(+)
|
||||
|
||||
diff --git a/tensorflow/core/kernels/conv_grad_filter_ops.cc b/tensorflow/core/kernels/conv_grad_filter_ops.cc
|
||||
index fb48e3e285a27..2645d850ab7cf 100644
|
||||
--- a/tensorflow/core/kernels/conv_grad_filter_ops.cc
|
||||
+++ b/tensorflow/core/kernels/conv_grad_filter_ops.cc
|
||||
@@ -495,6 +495,14 @@ class Conv2DCustomBackpropFilterOp : public OpKernel {
|
||||
const int filter_total_size = dims.spatial_dims[0].filter_size *
|
||||
dims.spatial_dims[1].filter_size *
|
||||
dims.in_depth;
|
||||
+ OP_REQUIRES(
|
||||
+ context,
|
||||
+ filter_total_size * dims.out_depth == filter_backprop->NumElements(),
|
||||
+ errors::InvalidArgument(
|
||||
+ "filter_size does not have enough elements, requested ",
|
||||
+ filter_total_size * dims.out_depth, ", got ",
|
||||
+ filter_backprop->NumElements()));
|
||||
+
|
||||
// The output image size is the spatial size of the output.
|
||||
const int output_image_size =
|
||||
dims.spatial_dims[0].output_size * dims.spatial_dims[1].output_size;
|
||||
@@ -518,6 +526,11 @@ class Conv2DCustomBackpropFilterOp : public OpKernel {
|
||||
|
||||
const size_t work_unit_size = size_A + size_B + size_C;
|
||||
|
||||
+ OP_REQUIRES(
|
||||
+ context, work_unit_size != 0,
|
||||
+ errors::InvalidArgument(
|
||||
+ "Work size for convolution would be 0, which is not acceptable"));
|
||||
+
|
||||
const size_t shard_size =
|
||||
(target_working_set_size + work_unit_size - 1) / work_unit_size;
|
||||
|
||||
@ -1,34 +0,0 @@
|
||||
From 4f663d4b8f0bec1b48da6fa091a7d29609980fa4 Mon Sep 17 00:00:00 2001
|
||||
From: Amit Patankar <amitpatankar@google.com>
|
||||
Date: Mon, 8 Feb 2021 12:29:30 -0800
|
||||
Subject: [PATCH] Allowlist certain data types to avoid a seg fault.
|
||||
|
||||
PiperOrigin-RevId: 356326671
|
||||
Change-Id: I23b65b52e93798cb5a6744632d31b0f88c6b6b31
|
||||
---
|
||||
tensorflow/core/kernels/immutable_constant_op.cc | 5 +++++
|
||||
1 file changed, 5 insertions(+)
|
||||
|
||||
diff --git a/tensorflow/core/kernels/immutable_constant_op.cc b/tensorflow/core/kernels/immutable_constant_op.cc
|
||||
index 1cfbdb8277891..19aa865c1fbe4 100644
|
||||
--- a/tensorflow/core/kernels/immutable_constant_op.cc
|
||||
+++ b/tensorflow/core/kernels/immutable_constant_op.cc
|
||||
@@ -17,6 +17,8 @@ limitations under the License.
|
||||
|
||||
#include <unordered_set>
|
||||
|
||||
+#include "tensorflow/core/framework/types.pb.h"
|
||||
+
|
||||
namespace tensorflow {
|
||||
|
||||
namespace {
|
||||
@@ -86,6 +88,9 @@ ImmutableConstantOp::ImmutableConstantOp(OpKernelConstruction* context)
|
||||
OP_REQUIRES_OK(context,
|
||||
context->GetAttr(kMemoryRegionNameAttr, ®ion_name_));
|
||||
OP_REQUIRES_OK(context, context->GetAttr(kDTypeAttr, &dtype_));
|
||||
+ OP_REQUIRES(context, dtype_ != DT_RESOURCE && dtype_ != DT_VARIANT,
|
||||
+ errors::InvalidArgument(
|
||||
+ "Resource and variant dtypes are invalid for this op."));
|
||||
OP_REQUIRES_OK(context, context->GetAttr(kShapeAttr, &shape_));
|
||||
}
|
||||
|
||||
@ -1,133 +0,0 @@
|
||||
From ba424dd8f16f7110eea526a8086f1a155f14f22b Mon Sep 17 00:00:00 2001
|
||||
From: Mihai Maruseac <mihaimaruseac@google.com>
|
||||
Date: Thu, 22 Apr 2021 13:29:54 -0700
|
||||
Subject: [PATCH] Enhance validation of ngram op and handle case of 0 tokens.
|
||||
|
||||
PiperOrigin-RevId: 369940178
|
||||
Change-Id: Ia82f42c09d14efe76e7dc013505b832a42282f0b
|
||||
---
|
||||
tensorflow/core/kernels/string_ngrams_op.cc | 52 +++++++++++++++----
|
||||
.../core/kernels/string_ngrams_op_test.cc | 34 ++++++++++++
|
||||
2 files changed, 75 insertions(+), 11 deletions(-)
|
||||
|
||||
diff --git a/tensorflow/core/kernels/string_ngrams_op.cc b/tensorflow/core/kernels/string_ngrams_op.cc
|
||||
index 8aed2b3831a2f..7008a1d766af2 100644
|
||||
--- a/tensorflow/core/kernels/string_ngrams_op.cc
|
||||
+++ b/tensorflow/core/kernels/string_ngrams_op.cc
|
||||
@@ -61,16 +61,28 @@ class StringNGramsOp : public tensorflow::OpKernel {
|
||||
OP_REQUIRES_OK(context, context->input("data_splits", &splits));
|
||||
const auto& splits_vec = splits->flat<SPLITS_TYPE>();
|
||||
|
||||
- // Validate that the splits are valid indices into data
|
||||
+ // Validate that the splits are valid indices into data, only if there are
|
||||
+ // splits specified.
|
||||
const int input_data_size = data->flat<tstring>().size();
|
||||
const int splits_vec_size = splits_vec.size();
|
||||
- for (int i = 0; i < splits_vec_size; ++i) {
|
||||
- bool valid_splits = splits_vec(i) >= 0;
|
||||
- valid_splits = valid_splits && (splits_vec(i) <= input_data_size);
|
||||
- OP_REQUIRES(
|
||||
- context, valid_splits,
|
||||
- errors::InvalidArgument("Invalid split value ", splits_vec(i),
|
||||
- ", must be in [0,", input_data_size, "]"));
|
||||
+ if (splits_vec_size > 0) {
|
||||
+ int prev_split = splits_vec(0);
|
||||
+ OP_REQUIRES(context, prev_split == 0,
|
||||
+ errors::InvalidArgument("First split value must be 0, got ",
|
||||
+ prev_split));
|
||||
+ for (int i = 1; i < splits_vec_size; ++i) {
|
||||
+ bool valid_splits = splits_vec(i) >= prev_split;
|
||||
+ valid_splits = valid_splits && (splits_vec(i) <= input_data_size);
|
||||
+ OP_REQUIRES(context, valid_splits,
|
||||
+ errors::InvalidArgument(
|
||||
+ "Invalid split value ", splits_vec(i), ", must be in [",
|
||||
+ prev_split, ", ", input_data_size, "]"));
|
||||
+ prev_split = splits_vec(i);
|
||||
+ }
|
||||
+ OP_REQUIRES(context, prev_split == input_data_size,
|
||||
+ errors::InvalidArgument(
|
||||
+ "Last split value must be data size. Expected ",
|
||||
+ input_data_size, ", got ", prev_split));
|
||||
}
|
||||
|
||||
int num_batch_items = splits_vec.size() - 1;
|
||||
@@ -174,13 +186,31 @@ class StringNGramsOp : public tensorflow::OpKernel {
|
||||
ngram->append(left_pad_);
|
||||
ngram->append(separator_);
|
||||
}
|
||||
+ // Only output first num_tokens - 1 pairs of data and separator
|
||||
for (int n = 0; n < num_tokens - 1; ++n) {
|
||||
ngram->append(data[data_start_index + n]);
|
||||
ngram->append(separator_);
|
||||
}
|
||||
- ngram->append(data[data_start_index + num_tokens - 1]);
|
||||
- for (int n = 0; n < right_padding; ++n) {
|
||||
- ngram->append(separator_);
|
||||
+ // Handle case when there are no tokens or no right padding as these can
|
||||
+ // result in consecutive separators.
|
||||
+ if (num_tokens > 0) {
|
||||
+ // If we have tokens, then output last and then pair each separator with
|
||||
+ // the right padding that follows, to ensure ngram ends either with the
|
||||
+ // token or with the right pad.
|
||||
+ ngram->append(data[data_start_index + num_tokens - 1]);
|
||||
+ for (int n = 0; n < right_padding; ++n) {
|
||||
+ ngram->append(separator_);
|
||||
+ ngram->append(right_pad_);
|
||||
+ }
|
||||
+ } else {
|
||||
+ // If we don't have tokens, then the last item inserted into the ngram
|
||||
+ // has been the separator from the left padding loop above. Hence,
|
||||
+ // output right pad and separator and make sure to finish with a
|
||||
+ // padding, not a separator.
|
||||
+ for (int n = 0; n < right_padding - 1; ++n) {
|
||||
+ ngram->append(right_pad_);
|
||||
+ ngram->append(separator_);
|
||||
+ }
|
||||
ngram->append(right_pad_);
|
||||
}
|
||||
|
||||
diff --git a/tensorflow/core/kernels/string_ngrams_op_test.cc b/tensorflow/core/kernels/string_ngrams_op_test.cc
|
||||
index b89de9ad16dab..0d52283bd8fb9 100644
|
||||
--- a/tensorflow/core/kernels/string_ngrams_op_test.cc
|
||||
+++ b/tensorflow/core/kernels/string_ngrams_op_test.cc
|
||||
@@ -542,6 +542,40 @@ TEST_F(NgramKernelTest, TestEmptyInput) {
|
||||
assert_int64_equal(expected_splits, *GetOutput(1));
|
||||
}
|
||||
|
||||
+TEST_F(NgramKernelTest, TestNoTokens) {
|
||||
+ MakeOp("|", {3}, "L", "R", -1, false);
|
||||
+ // Batch items are:
|
||||
+ // 0:
|
||||
+ // 1: "a"
|
||||
+ AddInputFromArray<tstring>(TensorShape({1}), {"a"});
|
||||
+ AddInputFromArray<int64>(TensorShape({3}), {0, 0, 1});
|
||||
+ TF_ASSERT_OK(RunOpKernel());
|
||||
+
|
||||
+ std::vector<tstring> expected_values(
|
||||
+ {"L|L|R", "L|R|R", // no input in first split
|
||||
+ "L|L|a", "L|a|R", "a|R|R"}); // second split
|
||||
+ std::vector<int64> expected_splits({0, 2, 5});
|
||||
+
|
||||
+ assert_string_equal(expected_values, *GetOutput(0));
|
||||
+ assert_int64_equal(expected_splits, *GetOutput(1));
|
||||
+}
|
||||
+
|
||||
+TEST_F(NgramKernelTest, TestNoTokensNoPad) {
|
||||
+ MakeOp("|", {3}, "", "", 0, false);
|
||||
+ // Batch items are:
|
||||
+ // 0:
|
||||
+ // 1: "a"
|
||||
+ AddInputFromArray<tstring>(TensorShape({1}), {"a"});
|
||||
+ AddInputFromArray<int64>(TensorShape({3}), {0, 0, 1});
|
||||
+ TF_ASSERT_OK(RunOpKernel());
|
||||
+
|
||||
+ std::vector<tstring> expected_values({});
|
||||
+ std::vector<int64> expected_splits({0, 0, 0});
|
||||
+
|
||||
+ assert_string_equal(expected_values, *GetOutput(0));
|
||||
+ assert_int64_equal(expected_splits, *GetOutput(1));
|
||||
+}
|
||||
+
|
||||
TEST_F(NgramKernelTest, ShapeFn) {
|
||||
ShapeInferenceTestOp op("StringNGrams");
|
||||
INFER_OK(op, "?;?", "[?];[?]");
|
||||
@ -1,24 +0,0 @@
|
||||
From ea3b43e98c32c97b35d52b4c66f9107452ca8fb2 Mon Sep 17 00:00:00 2001
|
||||
From: Amit Patankar <amitpatankar@google.com>
|
||||
Date: Thu, 22 Apr 2021 15:11:05 -0700
|
||||
Subject: [PATCH] Fix `tf.raw_ops.CTCGreedyDecoder` CHECK failure.
|
||||
|
||||
PiperOrigin-RevId: 369960465
|
||||
Change-Id: If0b8b3264d5a47a24ac0970ed7b81ce6b4921fae
|
||||
---
|
||||
tensorflow/core/kernels/ctc_decoder_ops.cc | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
diff --git a/tensorflow/core/kernels/ctc_decoder_ops.cc b/tensorflow/core/kernels/ctc_decoder_ops.cc
|
||||
index d62aef2d03b98..22681f97437f0 100644
|
||||
--- a/tensorflow/core/kernels/ctc_decoder_ops.cc
|
||||
+++ b/tensorflow/core/kernels/ctc_decoder_ops.cc
|
||||
@@ -232,6 +232,8 @@ class CTCGreedyDecoderOp : public OpKernel {
|
||||
int prev_indices = -1;
|
||||
for (int t = 0; t < seq_len_t(b); ++t) {
|
||||
int max_class_indices;
|
||||
+ OP_REQUIRES(ctx, input_list_t[t].dimension(1) > 0,
|
||||
+ errors::InvalidArgument("Invalid input dimensions."));
|
||||
log_prob_t(b, 0) +=
|
||||
-RowMax<T>(input_list_t[t], b, &max_class_indices);
|
||||
if (max_class_indices != blank_index &&
|
||||
@ -1,919 +0,0 @@
|
||||
From 52df91c5634e6c666843849a1c6ff29b3d2676be Mon Sep 17 00:00:00 2001
|
||||
From: Pankaj Kanwar <pkanwar@google.com>
|
||||
Date: Mon, 12 Oct 2020 10:30:20 -0700
|
||||
Subject: [PATCH] Create a V2 Op to stop the gradient when the input is out of
|
||||
range.
|
||||
|
||||
PiperOrigin-RevId: 336692325
|
||||
Change-Id: I36fd3fcfc58a30d5218beca512fbfc7c24b8b5cb
|
||||
---
|
||||
tensorflow/cc/gradients/array_grad.cc | 29 ++--
|
||||
tensorflow/compiler/tests/unary_ops_test.py | 6 +-
|
||||
.../api_def_QuantizeAndDequantizeV4.pbtxt | 8 ++
|
||||
.../api_def_QuantizeAndDequantizeV4Grad.pbtxt | 8 ++
|
||||
.../api_def_QuantizeAndDequantizeV4.pbtxt | 3 +
|
||||
.../api_def_QuantizeAndDequantizeV4Grad.pbtxt | 3 +
|
||||
.../api_def_QuantizeAndDequantizeV4.pbtxt | 4 +
|
||||
.../api_def_QuantizeAndDequantizeV4Grad.pbtxt | 4 +
|
||||
.../kernels/quantize_and_dequantize_op.cc | 126 ++++++++++++++++++
|
||||
.../core/kernels/quantize_and_dequantize_op.h | 71 ++++++++++
|
||||
.../quantize_and_dequantize_op_gpu.cu.cc | 40 ++++++
|
||||
.../quantize_and_dequantize_op_test.cc | 48 +++++++
|
||||
tensorflow/core/ops/array_ops.cc | 64 +++++++++
|
||||
.../python/kernel_tests/array_ops_test.py | 21 ++-
|
||||
tensorflow/python/ops/array_ops.py | 113 +++++++++++++++-
|
||||
.../tools/api/golden/v1/tensorflow.pbtxt | 4 +
|
||||
.../golden/v1/tensorflow.quantization.pbtxt | 4 +
|
||||
.../api/golden/v1/tensorflow.raw_ops.pbtxt | 8 ++
|
||||
.../tools/api/golden/v2/tensorflow.pbtxt | 4 +
|
||||
.../golden/v2/tensorflow.quantization.pbtxt | 4 +
|
||||
.../api/golden/v2/tensorflow.raw_ops.pbtxt | 8 ++
|
||||
21 files changed, 564 insertions(+), 16 deletions(-)
|
||||
create mode 100644 tensorflow/core/api_def/base_api/api_def_QuantizeAndDequantizeV4.pbtxt
|
||||
create mode 100644 tensorflow/core/api_def/base_api/api_def_QuantizeAndDequantizeV4Grad.pbtxt
|
||||
create mode 100644 tensorflow/core/api_def/java_api/api_def_QuantizeAndDequantizeV4.pbtxt
|
||||
create mode 100644 tensorflow/core/api_def/java_api/api_def_QuantizeAndDequantizeV4Grad.pbtxt
|
||||
create mode 100644 tensorflow/core/api_def/python_api/api_def_QuantizeAndDequantizeV4.pbtxt
|
||||
create mode 100644 tensorflow/core/api_def/python_api/api_def_QuantizeAndDequantizeV4Grad.pbtxt
|
||||
|
||||
diff --git a/tensorflow/cc/gradients/array_grad.cc b/tensorflow/cc/gradients/array_grad.cc
|
||||
index e9173227..480243a2 100644
|
||||
--- a/tensorflow/cc/gradients/array_grad.cc
|
||||
+++ b/tensorflow/cc/gradients/array_grad.cc
|
||||
@@ -15,13 +15,12 @@ limitations under the License.
|
||||
|
||||
#include <vector>
|
||||
|
||||
+#include "tensorflow/cc/framework/grad_op_registry.h"
|
||||
+#include "tensorflow/cc/framework/gradients.h"
|
||||
#include "tensorflow/cc/ops/array_ops_internal.h"
|
||||
#include "tensorflow/cc/ops/standard_ops.h"
|
||||
#include "tensorflow/core/lib/strings/strcat.h"
|
||||
|
||||
-#include "tensorflow/cc/framework/grad_op_registry.h"
|
||||
-#include "tensorflow/cc/framework/gradients.h"
|
||||
-
|
||||
namespace tensorflow {
|
||||
namespace ops {
|
||||
namespace {
|
||||
@@ -90,15 +89,25 @@ Status QuantizeAndDequantizeGrad(const Scope& scope, const Operation& op,
|
||||
}
|
||||
REGISTER_GRADIENT_OP("QuantizeAndDequantize", QuantizeAndDequantizeGrad);
|
||||
|
||||
-Status QuantizeAndDequantizeV2Grad(const Scope& scope, const Operation& op,
|
||||
- const std::vector<Output>& grad_inputs,
|
||||
- std::vector<Output>* grad_outputs) {
|
||||
- grad_outputs->push_back(Identity(scope, grad_inputs[0]));
|
||||
- grad_outputs->push_back(NoGradient());
|
||||
- grad_outputs->push_back(NoGradient());
|
||||
+Status QuantizeAndDequantizeV4GradHelper(const Scope& scope,
|
||||
+ const Operation& op,
|
||||
+ const std::vector<Output>& grad_inputs,
|
||||
+ std::vector<Output>* grad_outputs) {
|
||||
+ Input input = Shape(scope, op.input(0));
|
||||
+ Input input_min = op.input(1);
|
||||
+ Input input_max = op.input(2);
|
||||
+ int64 axis;
|
||||
+ TF_RETURN_IF_ERROR(GetNodeAttr(op.node()->attrs(), "axis", &axis));
|
||||
+ auto qdq_v4_grad = QuantizeAndDequantizeV4Grad(
|
||||
+ scope, grad_inputs[0], input, input_min, input_max,
|
||||
+ QuantizeAndDequantizeV4Grad::Axis(axis));
|
||||
+ grad_outputs->push_back(qdq_v4_grad.input_backprop);
|
||||
+ grad_outputs->push_back(qdq_v4_grad.input_min_backprop);
|
||||
+ grad_outputs->push_back(qdq_v4_grad.input_max_backprop);
|
||||
return scope.status();
|
||||
}
|
||||
-REGISTER_GRADIENT_OP("QuantizeAndDequantizeV2", QuantizeAndDequantizeV2Grad);
|
||||
+REGISTER_GRADIENT_OP("QuantizeAndDequantizeV4",
|
||||
+ QuantizeAndDequantizeV4GradHelper);
|
||||
|
||||
Status QuantizeAndDequantizeV3Grad(const Scope& scope, const Operation& op,
|
||||
const std::vector<Output>& grad_inputs,
|
||||
diff --git a/tensorflow/compiler/tests/unary_ops_test.py b/tensorflow/compiler/tests/unary_ops_test.py
|
||||
index 162693a9..dacd7232 100644
|
||||
--- a/tensorflow/compiler/tests/unary_ops_test.py
|
||||
+++ b/tensorflow/compiler/tests/unary_ops_test.py
|
||||
@@ -535,7 +535,7 @@ class UnaryOpsTest(xla_test.XLATestCase):
|
||||
for dtype in self.float_types:
|
||||
|
||||
def quantize_and_dequantize_v2(x):
|
||||
- return array_ops.quantize_and_dequantize_v2(
|
||||
+ return array_ops.quantize_and_dequantize(
|
||||
x, -127, 127, signed_input=True, num_bits=8)
|
||||
|
||||
self._assertOpOutputMatchesExpected(
|
||||
@@ -544,7 +544,7 @@ class UnaryOpsTest(xla_test.XLATestCase):
|
||||
expected=np.array([-1., -0.5, 0., 0.296875], dtype=dtype))
|
||||
|
||||
def quantize_and_dequantize_v2_round_half_up(x):
|
||||
- return array_ops.quantize_and_dequantize_v2(
|
||||
+ return array_ops.quantize_and_dequantize(
|
||||
x,
|
||||
-1,
|
||||
1.0,
|
||||
@@ -568,7 +568,7 @@ class UnaryOpsTest(xla_test.XLATestCase):
|
||||
dtype=dtype))
|
||||
|
||||
def quantize_and_dequantize_v2_round_half_to_even(x):
|
||||
- return array_ops.quantize_and_dequantize_v2(
|
||||
+ return array_ops.quantize_and_dequantize(
|
||||
x,
|
||||
-1.0,
|
||||
1.0,
|
||||
diff --git a/tensorflow/core/api_def/base_api/api_def_QuantizeAndDequantizeV4.pbtxt b/tensorflow/core/api_def/base_api/api_def_QuantizeAndDequantizeV4.pbtxt
|
||||
new file mode 100644
|
||||
index 00000000..a84ccb78
|
||||
--- /dev/null
|
||||
+++ b/tensorflow/core/api_def/base_api/api_def_QuantizeAndDequantizeV4.pbtxt
|
||||
@@ -0,0 +1,8 @@
|
||||
+op {
|
||||
+ graph_op_name: "QuantizeAndDequantizeV4"
|
||||
+ summary: "Returns the gradient of `QuantizeAndDequantizeV4`."
|
||||
+ description: <<END
|
||||
+This is almost identical to QuantizeAndDequantizeV2, except that it returns a
|
||||
+gradient of 1 for inputs that are within the quantization range, or 0 otherwise.
|
||||
+END
|
||||
+}
|
||||
diff --git a/tensorflow/core/api_def/base_api/api_def_QuantizeAndDequantizeV4Grad.pbtxt b/tensorflow/core/api_def/base_api/api_def_QuantizeAndDequantizeV4Grad.pbtxt
|
||||
new file mode 100644
|
||||
index 00000000..88ba0ea8
|
||||
--- /dev/null
|
||||
+++ b/tensorflow/core/api_def/base_api/api_def_QuantizeAndDequantizeV4Grad.pbtxt
|
||||
@@ -0,0 +1,8 @@
|
||||
+op {
|
||||
+ graph_op_name: "QuantizeAndDequantizeV4Grad"
|
||||
+ summary: "Returns the gradient of `QuantizeAndDequantizeV4`."
|
||||
+ description: <<END
|
||||
+Returns a gradient of 1 for inputs that are within the quantization range,
|
||||
+or 0 otherwise.
|
||||
+END
|
||||
+}
|
||||
diff --git a/tensorflow/core/api_def/java_api/api_def_QuantizeAndDequantizeV4.pbtxt b/tensorflow/core/api_def/java_api/api_def_QuantizeAndDequantizeV4.pbtxt
|
||||
new file mode 100644
|
||||
index 00000000..80544053
|
||||
--- /dev/null
|
||||
+++ b/tensorflow/core/api_def/java_api/api_def_QuantizeAndDequantizeV4.pbtxt
|
||||
@@ -0,0 +1,3 @@
|
||||
+op {
|
||||
+ graph_op_name: "QuantizeAndDequantizeV4Grad"
|
||||
+}
|
||||
diff --git a/tensorflow/core/api_def/java_api/api_def_QuantizeAndDequantizeV4Grad.pbtxt b/tensorflow/core/api_def/java_api/api_def_QuantizeAndDequantizeV4Grad.pbtxt
|
||||
new file mode 100644
|
||||
index 00000000..80544053
|
||||
--- /dev/null
|
||||
+++ b/tensorflow/core/api_def/java_api/api_def_QuantizeAndDequantizeV4Grad.pbtxt
|
||||
@@ -0,0 +1,3 @@
|
||||
+op {
|
||||
+ graph_op_name: "QuantizeAndDequantizeV4Grad"
|
||||
+}
|
||||
diff --git a/tensorflow/core/api_def/python_api/api_def_QuantizeAndDequantizeV4.pbtxt b/tensorflow/core/api_def/python_api/api_def_QuantizeAndDequantizeV4.pbtxt
|
||||
new file mode 100644
|
||||
index 00000000..0ed576f0
|
||||
--- /dev/null
|
||||
+++ b/tensorflow/core/api_def/python_api/api_def_QuantizeAndDequantizeV4.pbtxt
|
||||
@@ -0,0 +1,4 @@
|
||||
+op {
|
||||
+ graph_op_name: "QuantizeAndDequantizeV4Grad"
|
||||
+ visibility: HIDDEN
|
||||
+}
|
||||
diff --git a/tensorflow/core/api_def/python_api/api_def_QuantizeAndDequantizeV4Grad.pbtxt b/tensorflow/core/api_def/python_api/api_def_QuantizeAndDequantizeV4Grad.pbtxt
|
||||
new file mode 100644
|
||||
index 00000000..0ed576f0
|
||||
--- /dev/null
|
||||
+++ b/tensorflow/core/api_def/python_api/api_def_QuantizeAndDequantizeV4Grad.pbtxt
|
||||
@@ -0,0 +1,4 @@
|
||||
+op {
|
||||
+ graph_op_name: "QuantizeAndDequantizeV4Grad"
|
||||
+ visibility: HIDDEN
|
||||
+}
|
||||
diff --git a/tensorflow/core/kernels/quantize_and_dequantize_op.cc b/tensorflow/core/kernels/quantize_and_dequantize_op.cc
|
||||
index 408196a2..a2e0fe33 100644
|
||||
--- a/tensorflow/core/kernels/quantize_and_dequantize_op.cc
|
||||
+++ b/tensorflow/core/kernels/quantize_and_dequantize_op.cc
|
||||
@@ -139,6 +139,75 @@ class QuantizeAndDequantizeV2Op : public OpKernel {
|
||||
bool narrow_range_;
|
||||
};
|
||||
|
||||
+// Implementation of QuantizeAndDequantizeV4GradientOp.
|
||||
+// When back-propagating the error through a quantized layer, the following
|
||||
+// paper gives evidence that clipped-ReLU is better than non-clipped:
|
||||
+// "Deep Learning with Low Precision by Half-wave Gaussian Quantization"
|
||||
+// http://zpascal.net/cvpr2017/Cai_Deep_Learning_With_CVPR_2017_paper.pdf
|
||||
+template <typename Device, typename T>
|
||||
+class QuantizeAndDequantizeV4GradientOp : public OpKernel {
|
||||
+ public:
|
||||
+ explicit QuantizeAndDequantizeV4GradientOp(OpKernelConstruction* ctx)
|
||||
+ : OpKernel::OpKernel(ctx) {
|
||||
+ OP_REQUIRES_OK(ctx, ctx->GetAttr("axis", &axis_));
|
||||
+ }
|
||||
+
|
||||
+ void Compute(OpKernelContext* ctx) override {
|
||||
+ const Tensor& gradient = ctx->input(0);
|
||||
+ const Tensor& input = ctx->input(1);
|
||||
+ Tensor* input_backprop = nullptr;
|
||||
+ OP_REQUIRES_OK(ctx,
|
||||
+ ctx->allocate_output(0, input.shape(), &input_backprop));
|
||||
+
|
||||
+ OP_REQUIRES(
|
||||
+ ctx, input.IsSameSize(gradient),
|
||||
+ errors::InvalidArgument("gradient and input must be the same size"));
|
||||
+ const int depth = (axis_ == -1) ? 1 : input.dim_size(axis_);
|
||||
+ const Tensor& input_min_tensor = ctx->input(2);
|
||||
+ const Tensor& input_max_tensor = ctx->input(3);
|
||||
+ if (axis_ != -1) {
|
||||
+ OP_REQUIRES(
|
||||
+ ctx, input_min_tensor.dim_size(0) == depth,
|
||||
+ errors::InvalidArgument("min has incorrect size, expected ", depth,
|
||||
+ " was ", input_min_tensor.dim_size(0)));
|
||||
+ OP_REQUIRES(
|
||||
+ ctx, input_max_tensor.dim_size(0) == depth,
|
||||
+ errors::InvalidArgument("max has incorrect size, expected ", depth,
|
||||
+ " was ", input_max_tensor.dim_size(0)));
|
||||
+ }
|
||||
+
|
||||
+ TensorShape min_max_shape(input_min_tensor.shape());
|
||||
+ Tensor* input_min_backprop;
|
||||
+ OP_REQUIRES_OK(ctx,
|
||||
+ ctx->allocate_output(1, min_max_shape, &input_min_backprop));
|
||||
+
|
||||
+ Tensor* input_max_backprop;
|
||||
+ OP_REQUIRES_OK(ctx,
|
||||
+ ctx->allocate_output(2, min_max_shape, &input_max_backprop));
|
||||
+
|
||||
+ if (axis_ == -1) {
|
||||
+ functor::QuantizeAndDequantizeOneScaleGradientFunctor<Device, T> f;
|
||||
+ f(ctx->eigen_device<Device>(), gradient.template flat<T>(),
|
||||
+ input.template flat<T>(), input_min_tensor.scalar<T>(),
|
||||
+ input_max_tensor.scalar<T>(), input_backprop->template flat<T>(),
|
||||
+ input_min_backprop->template scalar<T>(),
|
||||
+ input_max_backprop->template scalar<T>());
|
||||
+ } else {
|
||||
+ functor::QuantizeAndDequantizePerChannelGradientFunctor<Device, T> f;
|
||||
+ f(ctx->eigen_device<Device>(),
|
||||
+ gradient.template flat_inner_outer_dims<T, 3>(axis_ - 1),
|
||||
+ input.template flat_inner_outer_dims<T, 3>(axis_ - 1),
|
||||
+ &input_min_tensor, &input_max_tensor,
|
||||
+ input_backprop->template flat_inner_outer_dims<T, 3>(axis_ - 1),
|
||||
+ input_min_backprop->template flat<T>(),
|
||||
+ input_max_backprop->template flat<T>());
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private:
|
||||
+ int axis_;
|
||||
+};
|
||||
+
|
||||
// Simulate quantization precision loss in a float tensor by:
|
||||
// 1. Quantize the tensor to fixed point numbers, which should match the target
|
||||
// quantization method when it is used in inference.
|
||||
@@ -307,6 +376,43 @@ struct QuantizeAndDequantizePerChannelFunctor<CPUDevice, T> {
|
||||
input_max_tensor, round_mode, narrow_range, out);
|
||||
}
|
||||
};
|
||||
+
|
||||
+template <typename T>
|
||||
+struct QuantizeAndDequantizeOneScaleGradientFunctor<CPUDevice, T> {
|
||||
+ void operator()(const CPUDevice& d, typename TTypes<T>::ConstFlat gradient,
|
||||
+ typename TTypes<T>::ConstFlat input,
|
||||
+ typename TTypes<T>::ConstScalar input_min_tensor,
|
||||
+ typename TTypes<T>::ConstScalar input_max_tensor,
|
||||
+ typename TTypes<T>::Flat input_backprop,
|
||||
+ typename TTypes<T>::Scalar input_min_backprop,
|
||||
+ typename TTypes<T>::Scalar input_max_backprop) {
|
||||
+ QuantizeAndDequantizeOneScaleGradientImpl<CPUDevice, T>::Compute(
|
||||
+ d, gradient, input, input_min_tensor, input_max_tensor, input_backprop,
|
||||
+ input_min_backprop, input_max_backprop);
|
||||
+ }
|
||||
+};
|
||||
+
|
||||
+template <typename T>
|
||||
+struct QuantizeAndDequantizePerChannelGradientFunctor<CPUDevice, T> {
|
||||
+ void operator()(const CPUDevice& d,
|
||||
+ typename TTypes<T, 3>::ConstTensor gradient,
|
||||
+ typename TTypes<T, 3>::ConstTensor input,
|
||||
+ const Tensor* input_min_tensor,
|
||||
+ const Tensor* input_max_tensor,
|
||||
+ typename TTypes<T, 3>::Tensor input_backprop,
|
||||
+ typename TTypes<T>::Flat input_min_backprop,
|
||||
+ typename TTypes<T>::Flat input_max_backprop) {
|
||||
+ QuantizeAndDequantizePerChannelGradientImpl<CPUDevice, T>::Compute(
|
||||
+ d, gradient, input, input_min_tensor, input_max_tensor, input_backprop,
|
||||
+ input_min_backprop, input_max_backprop);
|
||||
+ }
|
||||
+};
|
||||
+
|
||||
+template struct functor::QuantizeAndDequantizeOneScaleGradientFunctor<CPUDevice,
|
||||
+ float>;
|
||||
+template struct functor::QuantizeAndDequantizePerChannelGradientFunctor<
|
||||
+ CPUDevice, double>;
|
||||
+
|
||||
} // namespace functor
|
||||
|
||||
#define REGISTER_CPU_KERNEL(T) \
|
||||
@@ -318,6 +424,14 @@ struct QuantizeAndDequantizePerChannelFunctor<CPUDevice, T> {
|
||||
.Device(DEVICE_CPU) \
|
||||
.TypeConstraint<T>("T"), \
|
||||
QuantizeAndDequantizeV3Op<CPUDevice, T>); \
|
||||
+ REGISTER_KERNEL_BUILDER(Name("QuantizeAndDequantizeV4") \
|
||||
+ .Device(DEVICE_CPU) \
|
||||
+ .TypeConstraint<T>("T"), \
|
||||
+ QuantizeAndDequantizeV2Op<CPUDevice, T>); \
|
||||
+ REGISTER_KERNEL_BUILDER(Name("QuantizeAndDequantizeV4Grad") \
|
||||
+ .Device(DEVICE_CPU) \
|
||||
+ .TypeConstraint<T>("T"), \
|
||||
+ QuantizeAndDequantizeV4GradientOp<CPUDevice, T>); \
|
||||
REGISTER_KERNEL_BUILDER( \
|
||||
Name("QuantizeAndDequantize").Device(DEVICE_CPU).TypeConstraint<T>("T"), \
|
||||
QuantizeAndDequantizeOp<CPUDevice, T>);
|
||||
@@ -341,6 +455,18 @@ TF_CALL_double(REGISTER_CPU_KERNEL);
|
||||
.HostMemory("num_bits") \
|
||||
.TypeConstraint<T>("T"), \
|
||||
QuantizeAndDequantizeV3Op<GPUDevice, T>); \
|
||||
+ REGISTER_KERNEL_BUILDER(Name("QuantizeAndDequantizeV4") \
|
||||
+ .Device(DEVICE_GPU) \
|
||||
+ .HostMemory("input_min") \
|
||||
+ .HostMemory("input_max") \
|
||||
+ .TypeConstraint<T>("T"), \
|
||||
+ QuantizeAndDequantizeV2Op<GPUDevice, T>); \
|
||||
+ REGISTER_KERNEL_BUILDER(Name("QuantizeAndDequantizeV4Grad") \
|
||||
+ .Device(DEVICE_GPU) \
|
||||
+ .HostMemory("input_min") \
|
||||
+ .HostMemory("input_max") \
|
||||
+ .TypeConstraint<T>("T"), \
|
||||
+ QuantizeAndDequantizeV4GradientOp<GPUDevice, T>); \
|
||||
REGISTER_KERNEL_BUILDER( \
|
||||
Name("QuantizeAndDequantize").Device(DEVICE_GPU).TypeConstraint<T>("T"), \
|
||||
QuantizeAndDequantizeOp<GPUDevice, T>);
|
||||
diff --git a/tensorflow/core/kernels/quantize_and_dequantize_op.h b/tensorflow/core/kernels/quantize_and_dequantize_op.h
|
||||
index 4dd6e5c8..c286a10a 100644
|
||||
--- a/tensorflow/core/kernels/quantize_and_dequantize_op.h
|
||||
+++ b/tensorflow/core/kernels/quantize_and_dequantize_op.h
|
||||
@@ -60,6 +60,28 @@ struct QuantizeAndDequantizePerChannelFunctor {
|
||||
typename TTypes<T, 3>::Tensor output);
|
||||
};
|
||||
|
||||
+template <typename Device, typename T>
|
||||
+struct QuantizeAndDequantizeOneScaleGradientFunctor {
|
||||
+ void operator()(const Device& d, typename TTypes<T>::ConstFlat gradient,
|
||||
+ typename TTypes<T>::ConstFlat input,
|
||||
+ typename TTypes<T>::ConstScalar input_min,
|
||||
+ typename TTypes<T>::ConstScalar input_max,
|
||||
+ typename TTypes<T>::Flat input_backprop,
|
||||
+ typename TTypes<T>::Scalar input_min_backprop,
|
||||
+ typename TTypes<T>::Scalar input_max_backprop);
|
||||
+};
|
||||
+
|
||||
+template <typename Device, typename T>
|
||||
+struct QuantizeAndDequantizePerChannelGradientFunctor {
|
||||
+ void operator()(const Device& d, typename TTypes<T, 3>::ConstTensor gradient,
|
||||
+ typename TTypes<T, 3>::ConstTensor input,
|
||||
+ const Tensor* input_min_tensor,
|
||||
+ const Tensor* input_max_tensor,
|
||||
+ typename TTypes<T, 3>::Tensor input_backprop,
|
||||
+ typename TTypes<T>::Flat input_min_backprop,
|
||||
+ typename TTypes<T>::Flat input_max_backprop);
|
||||
+};
|
||||
+
|
||||
// The implementation below runs on both CPU and GPU.
|
||||
template <typename Device, typename T, typename Func,
|
||||
typename Vec = typename TTypes<T>::Vec,
|
||||
@@ -249,6 +271,55 @@ struct QuantizeAndDequantizePerChannelImpl {
|
||||
}
|
||||
};
|
||||
|
||||
+template <typename Device, typename T>
|
||||
+struct QuantizeAndDequantizeOneScaleGradientImpl {
|
||||
+ static void Compute(const Device& d, typename TTypes<T>::ConstFlat gradient,
|
||||
+ typename TTypes<T>::ConstFlat input,
|
||||
+ typename TTypes<T>::ConstScalar input_min,
|
||||
+ typename TTypes<T>::ConstScalar input_max,
|
||||
+ typename TTypes<T>::Flat input_backprop,
|
||||
+ typename TTypes<T>::Scalar input_min_backprop,
|
||||
+ typename TTypes<T>::Scalar input_max_backprop) {
|
||||
+ const T min_val = input_min();
|
||||
+ const T max_val = input_max();
|
||||
+ const auto in_range =
|
||||
+ (input >= min_val && input <= max_val)
|
||||
+ .select(input.constant(1.0f), input.constant(0.0f));
|
||||
+ input_backprop.device(d) = gradient * in_range;
|
||||
+ input_min_backprop.device(d) = input_min_backprop.constant(0.0f);
|
||||
+ input_max_backprop.device(d) = input_max_backprop.constant(0.0f);
|
||||
+ }
|
||||
+};
|
||||
+
|
||||
+template <typename Device, typename T>
|
||||
+struct QuantizeAndDequantizePerChannelGradientImpl {
|
||||
+ static void Compute(const Device& d,
|
||||
+ typename TTypes<T, 3>::ConstTensor gradient,
|
||||
+ typename TTypes<T, 3>::ConstTensor input,
|
||||
+ const Tensor* input_min_tensor,
|
||||
+ const Tensor* input_max_tensor,
|
||||
+ typename TTypes<T, 3>::Tensor input_backprop,
|
||||
+ typename TTypes<T>::Flat input_min_backprop,
|
||||
+ typename TTypes<T>::Flat input_max_backprop) {
|
||||
+ using Index = typename tensorflow::TTypes<T>::ConstTensor::Index;
|
||||
+ auto input_min = input_min_tensor->vec<T>();
|
||||
+ auto input_max = input_max_tensor->vec<T>();
|
||||
+ int num_channels = input.dimension(1);
|
||||
+ for (Index i = 0; i < num_channels; ++i) {
|
||||
+ const auto gradient_chip = gradient.template chip<1>(i);
|
||||
+ const auto input_chip = input.template chip<1>(i);
|
||||
+ const T min_val = input_min(i);
|
||||
+ const T max_val = input_max(i);
|
||||
+ const auto in_range =
|
||||
+ (input_chip >= min_val && input_chip <= max_val)
|
||||
+ .select(input_chip.constant(1.0f), input_chip.constant(0.0f));
|
||||
+ input_backprop.template chip<1>(i).device(d) = gradient_chip * in_range;
|
||||
+ }
|
||||
+ input_min_backprop.device(d) = input_min_backprop.constant(0.0f);
|
||||
+ input_max_backprop.device(d) = input_max_backprop.constant(0.0f);
|
||||
+ }
|
||||
+};
|
||||
+
|
||||
} // end of namespace functor
|
||||
} // end of namespace tensorflow
|
||||
|
||||
diff --git a/tensorflow/core/kernels/quantize_and_dequantize_op_gpu.cu.cc b/tensorflow/core/kernels/quantize_and_dequantize_op_gpu.cu.cc
|
||||
index f3bb4107..9f074535 100644
|
||||
--- a/tensorflow/core/kernels/quantize_and_dequantize_op_gpu.cu.cc
|
||||
+++ b/tensorflow/core/kernels/quantize_and_dequantize_op_gpu.cu.cc
|
||||
@@ -53,6 +53,37 @@ struct QuantizeAndDequantizePerChannelFunctor<GPUDevice, T> {
|
||||
}
|
||||
};
|
||||
|
||||
+template <typename T>
|
||||
+struct QuantizeAndDequantizeOneScaleGradientFunctor<GPUDevice, T> {
|
||||
+ void operator()(const GPUDevice& d, typename TTypes<T>::ConstFlat gradient,
|
||||
+ typename TTypes<T>::ConstFlat input,
|
||||
+ typename TTypes<T>::ConstScalar input_min_tensor,
|
||||
+ typename TTypes<T>::ConstScalar input_max_tensor,
|
||||
+ typename TTypes<T>::Flat input_backprop,
|
||||
+ typename TTypes<T>::Scalar input_min_backprop,
|
||||
+ typename TTypes<T>::Scalar input_max_backprop) {
|
||||
+ QuantizeAndDequantizeOneScaleGradientImpl<GPUDevice, T>::Compute(
|
||||
+ d, gradient, input, input_min_tensor, input_max_tensor, input_backprop,
|
||||
+ input_min_backprop, input_max_backprop);
|
||||
+ }
|
||||
+};
|
||||
+
|
||||
+template <typename T>
|
||||
+struct QuantizeAndDequantizePerChannelGradientFunctor<GPUDevice, T> {
|
||||
+ void operator()(const GPUDevice& d,
|
||||
+ typename TTypes<T, 3>::ConstTensor gradient,
|
||||
+ typename TTypes<T, 3>::ConstTensor input,
|
||||
+ const Tensor* input_min_tensor,
|
||||
+ const Tensor* input_max_tensor,
|
||||
+ typename TTypes<T, 3>::Tensor input_backprop,
|
||||
+ typename TTypes<T>::Flat input_min_backprop,
|
||||
+ typename TTypes<T>::Flat input_max_backprop) {
|
||||
+ QuantizeAndDequantizePerChannelGradientImpl<GPUDevice, T>::Compute(
|
||||
+ d, gradient, input, input_min_tensor, input_max_tensor, input_backprop,
|
||||
+ input_min_backprop, input_max_backprop);
|
||||
+ }
|
||||
+};
|
||||
+
|
||||
} // end namespace functor
|
||||
|
||||
// Instantiate the GPU implementation for float and double.
|
||||
@@ -65,6 +96,15 @@ template struct functor::QuantizeAndDequantizePerChannelFunctor<GPUDevice,
|
||||
template struct functor::QuantizeAndDequantizePerChannelFunctor<GPUDevice,
|
||||
double>;
|
||||
|
||||
+template struct functor::QuantizeAndDequantizeOneScaleGradientFunctor<GPUDevice,
|
||||
+ float>;
|
||||
+template struct functor::QuantizeAndDequantizeOneScaleGradientFunctor<GPUDevice,
|
||||
+ double>;
|
||||
+template struct functor::QuantizeAndDequantizePerChannelGradientFunctor<
|
||||
+ GPUDevice, float>;
|
||||
+template struct functor::QuantizeAndDequantizePerChannelGradientFunctor<
|
||||
+ GPUDevice, double>;
|
||||
+
|
||||
} // end namespace tensorflow
|
||||
|
||||
#endif // GOOGLE_CUDA || TENSORFLOW_USE_ROCM
|
||||
diff --git a/tensorflow/core/kernels/quantize_and_dequantize_op_test.cc b/tensorflow/core/kernels/quantize_and_dequantize_op_test.cc
|
||||
index 90764b0f..596ab135 100644
|
||||
--- a/tensorflow/core/kernels/quantize_and_dequantize_op_test.cc
|
||||
+++ b/tensorflow/core/kernels/quantize_and_dequantize_op_test.cc
|
||||
@@ -362,6 +362,54 @@ TEST_P(ParameterizedQuantizeAndDequantizeTest,
|
||||
}
|
||||
}
|
||||
|
||||
+// Verifies the Gradient.
|
||||
+TEST_P(ParameterizedQuantizeAndDequantizeTest, GradientV4_op) {
|
||||
+ const int axis = GetParam();
|
||||
+ TF_ASSERT_OK(NodeDefBuilder("qdq_v4_grad_op", "QuantizeAndDequantizeV4Grad")
|
||||
+ .Input(FakeInput(DT_FLOAT))
|
||||
+ .Input(FakeInput(DT_FLOAT))
|
||||
+ .Input(FakeInput(DT_FLOAT))
|
||||
+ .Input(FakeInput(DT_FLOAT))
|
||||
+ .Attr("axis", axis)
|
||||
+ .Finalize(node_def()));
|
||||
+ TF_ASSERT_OK(InitOp());
|
||||
+ const std::vector<int64> dims = {2, 3, 4, 5};
|
||||
+ // Input gradient. (repeating 11 values multiplied by (slice_idx + 1))
|
||||
+ auto gradients = ScalePerSliceAlongAxis<float>(
|
||||
+ dims, axis, {1, -2, -3, 4, 5, 6, -7, -8, -9, -10, 11});
|
||||
+ AddInputFromArray<float>(TensorShape(dims), gradients);
|
||||
+ // Forward op inputs. (repeating 7 values multiplied by (slice_idx + 1)).
|
||||
+ auto inputs = ScalePerSliceAlongAxis<float>(
|
||||
+ dims, axis, {-1, -0.5, 0, 0.3, 0.8, 0.55, 0.6});
|
||||
+ AddInputFromArray<float>(TensorShape(dims), inputs);
|
||||
+ const int num_slices = (axis == -1) ? 1 : dims[axis];
|
||||
+ const TensorShape range_shape =
|
||||
+ (axis == -1) ? TensorShape({}) : TensorShape({num_slices});
|
||||
+ std::vector<float> input_min_values(num_slices), input_max_values(num_slices);
|
||||
+ for (int i = 0; i < num_slices; ++i) {
|
||||
+ input_max_values[i] = 0.8f + i * 0.4f;
|
||||
+ input_min_values[i] = -input_max_values[i];
|
||||
+ }
|
||||
+ AddInputFromArray<float>(range_shape, input_min_values);
|
||||
+ AddInputFromArray<float>(range_shape, input_max_values);
|
||||
+ std::vector<float> expected_vals(inputs.size());
|
||||
+ int minor_size = 1;
|
||||
+ for (int i = axis + 1; i < dims.size(); ++i) {
|
||||
+ minor_size *= dims[i];
|
||||
+ }
|
||||
+ for (int i = 0; i < inputs.size(); ++i) {
|
||||
+ int slice_idx = (i / minor_size) % num_slices;
|
||||
+ expected_vals[i] = ((inputs[i] >= input_min_values[slice_idx]) &&
|
||||
+ (inputs[i] <= input_max_values[slice_idx]))
|
||||
+ ? gradients[i]
|
||||
+ : 0;
|
||||
+ }
|
||||
+ TF_ASSERT_OK(RunOpKernel());
|
||||
+ Tensor expected(allocator(), DT_FLOAT, TensorShape(dims));
|
||||
+ test::FillValues<float>(&expected, expected_vals);
|
||||
+ test::ExpectTensorNear<float>(expected, *GetOutput(0), 1e-5);
|
||||
+}
|
||||
+
|
||||
// Instantiate parameterized tests for axis = -1, 1, 3.
|
||||
INSTANTIATE_TEST_SUITE_P(All, ParameterizedQuantizeAndDequantizeTest,
|
||||
::testing::Values(-1, 1, 3));
|
||||
diff --git a/tensorflow/core/ops/array_ops.cc b/tensorflow/core/ops/array_ops.cc
|
||||
index ad11e0b7..17258bc1 100644
|
||||
--- a/tensorflow/core/ops/array_ops.cc
|
||||
+++ b/tensorflow/core/ops/array_ops.cc
|
||||
@@ -2802,6 +2802,70 @@ REGISTER_OP("QuantizeAndDequantizeV2")
|
||||
return Status::OK();
|
||||
});
|
||||
|
||||
+REGISTER_OP("QuantizeAndDequantizeV4")
|
||||
+ .Input("input: T")
|
||||
+ .Input("input_min: T")
|
||||
+ .Input("input_max: T")
|
||||
+ .Attr("signed_input: bool = true")
|
||||
+ .Attr("num_bits: int = 8")
|
||||
+ .Attr("range_given: bool = false")
|
||||
+ .Output("output: T")
|
||||
+ .Attr("T: {bfloat16, half, float, double}")
|
||||
+ .Attr(
|
||||
+ "round_mode: {'HALF_TO_EVEN', 'HALF_UP'} = "
|
||||
+ "'HALF_TO_EVEN'")
|
||||
+ .Attr("narrow_range: bool = false")
|
||||
+ .Attr("axis: int = -1")
|
||||
+ .SetShapeFn([](InferenceContext* c) {
|
||||
+ int axis;
|
||||
+ TF_RETURN_IF_ERROR(c->GetAttr("axis", &axis));
|
||||
+ const int minmax_rank = (axis == -1) ? 0 : 1;
|
||||
+ ShapeHandle minmax;
|
||||
+ TF_RETURN_IF_ERROR(c->WithRank(c->input(1), minmax_rank, &minmax));
|
||||
+ TF_RETURN_IF_ERROR(c->Merge(c->input(2), minmax, &minmax));
|
||||
+ if (axis != -1) {
|
||||
+ ShapeHandle input;
|
||||
+ TF_RETURN_IF_ERROR(c->WithRankAtLeast(c->input(0), axis + 1, &input));
|
||||
+ DimensionHandle depth;
|
||||
+ TF_RETURN_IF_ERROR(
|
||||
+ c->Merge(c->Dim(minmax, 0), c->Dim(input, axis), &depth));
|
||||
+ }
|
||||
+ c->set_output(0, c->input(0));
|
||||
+ return Status::OK();
|
||||
+ });
|
||||
+
|
||||
+REGISTER_OP("QuantizeAndDequantizeV4Grad")
|
||||
+ .Input("gradients: T")
|
||||
+ .Input("input: T")
|
||||
+ .Input("input_min: T")
|
||||
+ .Input("input_max: T")
|
||||
+ .Output("input_backprop: T")
|
||||
+ .Output("input_min_backprop: T")
|
||||
+ .Output("input_max_backprop: T")
|
||||
+ .Attr("T: {bfloat16, half, float, double}")
|
||||
+ .Attr("axis: int = -1")
|
||||
+ .SetShapeFn([](InferenceContext* c) {
|
||||
+ int axis;
|
||||
+ TF_RETURN_IF_ERROR(c->GetAttr("axis", &axis));
|
||||
+ const int minmax_rank = (axis == -1) ? 0 : 1;
|
||||
+ ShapeHandle minmax;
|
||||
+ TF_RETURN_IF_ERROR(c->WithRank(c->input(2), minmax_rank, &minmax));
|
||||
+ TF_RETURN_IF_ERROR(c->Merge(c->input(3), minmax, &minmax));
|
||||
+ if (axis != -1) {
|
||||
+ ShapeHandle input;
|
||||
+ TF_RETURN_IF_ERROR(c->WithRankAtLeast(c->input(0), axis + 1, &input));
|
||||
+ DimensionHandle depth;
|
||||
+ TF_RETURN_IF_ERROR(
|
||||
+ c->Merge(c->Dim(minmax, 0), c->Dim(input, axis), &depth));
|
||||
+ }
|
||||
+ ShapeHandle inputs;
|
||||
+ TF_RETURN_IF_ERROR(c->Merge(c->input(0), c->input(1), &inputs));
|
||||
+ c->set_output(0, inputs);
|
||||
+ c->set_output(1, minmax);
|
||||
+ c->set_output(2, minmax);
|
||||
+ return Status::OK();
|
||||
+ });
|
||||
+
|
||||
REGISTER_OP("QuantizeAndDequantizeV3")
|
||||
.Input("input: T")
|
||||
.Input("input_min: T")
|
||||
diff --git a/tensorflow/python/kernel_tests/array_ops_test.py b/tensorflow/python/kernel_tests/array_ops_test.py
|
||||
index 97a1184f..a3097fe2 100644
|
||||
--- a/tensorflow/python/kernel_tests/array_ops_test.py
|
||||
+++ b/tensorflow/python/kernel_tests/array_ops_test.py
|
||||
@@ -1523,7 +1523,7 @@ class QuantizeAndDequantizeTest(test_util.TensorFlowTestCase):
|
||||
expected = self._scale_per_slice(shape, axis, quant_values)
|
||||
unused_minmax_value = 0 if axis is None else [0] * shape[axis]
|
||||
fake_quantized = self.evaluate(
|
||||
- array_ops.quantize_and_dequantize(
|
||||
+ array_ops.quantize_and_dequantize_v2(
|
||||
inputs,
|
||||
unused_minmax_value,
|
||||
unused_minmax_value,
|
||||
@@ -1533,7 +1533,7 @@ class QuantizeAndDequantizeTest(test_util.TensorFlowTestCase):
|
||||
self.assertAllEqual(fake_quantized, expected)
|
||||
if axis is not None:
|
||||
fake_quantized = self.evaluate(
|
||||
- array_ops.quantize_and_dequantize(
|
||||
+ array_ops.quantize_and_dequantize_v2(
|
||||
inputs,
|
||||
unused_minmax_value,
|
||||
unused_minmax_value,
|
||||
@@ -1541,6 +1541,23 @@ class QuantizeAndDequantizeTest(test_util.TensorFlowTestCase):
|
||||
axis=(axis - 4)))
|
||||
self.assertAllClose(fake_quantized, expected)
|
||||
|
||||
+ def testQuantizeDequantizeGrad(self):
|
||||
+ shape = (2, 2)
|
||||
+ max_threshold = 0
|
||||
+ min_threshold = -10
|
||||
+ input_value = np.random.rand(2, 2) * 40.0 - 20.0
|
||||
+ input_tensor = constant_op.constant(input_value, shape=shape,
|
||||
+ name="input_tensor")
|
||||
+ with self.cached_session():
|
||||
+ def f(a):
|
||||
+ return array_ops.quantize_and_dequantize_v2(
|
||||
+ a,
|
||||
+ input_min=min_threshold,
|
||||
+ input_max=max_threshold,
|
||||
+ range_given=True)
|
||||
+ output_grad = gradient_checker_v2.compute_gradient(f, [input_tensor])
|
||||
+ self.assertAllClose(output_grad[0], np.zeros([1, 4, 4]))
|
||||
+
|
||||
def testBadAxis(self):
|
||||
input_tensor = [2.5, 2.5]
|
||||
input_min = [0, 0]
|
||||
diff --git a/tensorflow/python/ops/array_ops.py b/tensorflow/python/ops/array_ops.py
|
||||
index cb97b8f9..19a2a0c2 100644
|
||||
--- a/tensorflow/python/ops/array_ops.py
|
||||
+++ b/tensorflow/python/ops/array_ops.py
|
||||
@@ -3654,6 +3654,23 @@ def _FakeQuantWithMinMaxVarsPerChannelGradient(op, grad):
|
||||
narrow_range=op.get_attr("narrow_range"))
|
||||
|
||||
|
||||
+@ops.RegisterGradient("QuantizeAndDequantizeV4")
|
||||
+def _QuantizeAndDequantizeV4Grad(op, grad):
|
||||
+ """Gradient for QuantizeAndDequantizeV4 op."""
|
||||
+ return quantize_and_dequantize_v4_grad(
|
||||
+ grad,
|
||||
+ op.inputs[0],
|
||||
+ op.inputs[1],
|
||||
+ op.inputs[2],
|
||||
+ axis=op.get_attr("axis"))
|
||||
+
|
||||
+
|
||||
+@ops.RegisterGradient("QuantizeAndDequantizeV4Grad")
|
||||
+def _QuantizeAndDequantizeV4GradGrad(op, grad):
|
||||
+ """Gradient for QuantizeAndDequantizeV4Grad op."""
|
||||
+ return _QuantizeAndDequantizeV4Grad(op, grad)
|
||||
+
|
||||
+
|
||||
@tf_export("required_space_to_batch_paddings")
|
||||
def required_space_to_batch_paddings(input_shape,
|
||||
block_shape,
|
||||
@@ -5223,6 +5240,13 @@ dequantize.__doc__ = gen_array_ops.dequantize.__doc__
|
||||
|
||||
@tf_export("quantization.quantize_and_dequantize")
|
||||
@dispatch.add_dispatch_support
|
||||
+@deprecation.deprecated(None,
|
||||
+ "This Op has been deprecated, use" +
|
||||
+ "`quantize_and_dequantize_v2` instead. To " +
|
||||
+ "To simulate the V1 the behavior of " +
|
||||
+ "tf.quantization.quantize_and_dequantize(...) use " +
|
||||
+ "tf.grad_pass_through(" +
|
||||
+ "tf.quantization.quantize_and_dequantize_v2)(...).")
|
||||
def quantize_and_dequantize(
|
||||
input, # pylint: disable=redefined-builtin
|
||||
input_min,
|
||||
@@ -5281,6 +5305,93 @@ def quantize_and_dequantize(
|
||||
name=name)
|
||||
|
||||
|
||||
+@tf_export("quantization.quantize_and_dequantize_v2")
|
||||
+@dispatch.add_dispatch_support
|
||||
+def quantize_and_dequantize_v2(
|
||||
+ input, # pylint: disable=redefined-builtin
|
||||
+ input_min,
|
||||
+ input_max,
|
||||
+ signed_input=True,
|
||||
+ num_bits=8,
|
||||
+ range_given=False,
|
||||
+ round_mode="HALF_TO_EVEN",
|
||||
+ name=None,
|
||||
+ narrow_range=False,
|
||||
+ axis=None):
|
||||
+ """Quantizes then dequantizes a tensor.
|
||||
+
|
||||
+ Updates the gradient definition for quantization that is outside the range to
|
||||
+ be 0.To simulate the V1 the behavior of
|
||||
+ tf.quantization.quantize_and_dequantize(...) use
|
||||
+ tf.grad_pass_through(tf.quantization.quantize_and_dequantize_v2)(...).
|
||||
+
|
||||
+ Example usage:
|
||||
+
|
||||
+ ```python
|
||||
+ def getQuantizeOp(input):
|
||||
+ input_tensor = tf.placeholder(tf.float32, shape=[4, 4])
|
||||
+ net = tf.quantization.quantize_and_dequantize(input,
|
||||
+ input_min=min_threshold,
|
||||
+ input_max=max_threshold,
|
||||
+ range_given=True)
|
||||
+
|
||||
+ To simulate v1 behavior:
|
||||
+
|
||||
+ def testDecomposeQuantizeDequantize(self):
|
||||
+ def f(input_tensor):
|
||||
+ return tf.quantization.quantize_and_dequantize_v2(input_tensor,
|
||||
+ input_min = 5.0,
|
||||
+ input_max= -10.0,
|
||||
+ range_given=True)
|
||||
+ input_tensor = tf.placeholder(tf.float32, shape=[4, 4])
|
||||
+ net = tf.grad_pass_through(f)(input_tensor)
|
||||
+ ```
|
||||
+
|
||||
+ Args:
|
||||
+ input: A `Tensor` to quantize and dequantize.
|
||||
+ input_min: If range_given=True, the minimum input value, that needs to be
|
||||
+ represented in the quantized representation. If axis is specified, this
|
||||
+ should be a vector of minimum values for each slice along axis.
|
||||
+ input_max: If range_given=True, the maximum input value that needs to be
|
||||
+ represented in the quantized representation. If axis is specified, this
|
||||
+ should be a vector of maximum values for each slice along axis.
|
||||
+ signed_input: True if the quantization is signed or unsigned.
|
||||
+ num_bits: The bitwidth of the quantization.
|
||||
+ range_given: If true use `input_min` and `input_max` for the range of the
|
||||
+ input, otherwise determine min and max from the input `Tensor`.
|
||||
+ round_mode: Rounding mode when rounding from float values to quantized ones.
|
||||
+ one of ['HALF_TO_EVEN', 'HALF_UP']
|
||||
+ name: Optional name for the operation.
|
||||
+ narrow_range: If true, then the absolute value of the quantized minimum
|
||||
+ value is the same as the quantized maximum value, instead of 1 greater.
|
||||
+ i.e. for 8 bit quantization, the minimum value is -127 instead of -128.
|
||||
+ axis: Integer. If specified, refers to a dimension of the input tensor, such
|
||||
+ that quantization will be per slice along that dimension.
|
||||
+
|
||||
+ Returns:
|
||||
+ A `Tensor`. Each element is the result of quantizing and dequantizing the
|
||||
+ corresponding element of `input`.
|
||||
+ """
|
||||
+ if axis is None:
|
||||
+ axis = -1
|
||||
+ elif axis < 0:
|
||||
+ if input.shape.ndims is None:
|
||||
+ raise ValueError("input should have known rank to use negative axis.")
|
||||
+ axis %= input.shape.ndims
|
||||
+
|
||||
+ return gen_array_ops.quantize_and_dequantize_v4(
|
||||
+ input,
|
||||
+ input_min=input_min,
|
||||
+ input_max=input_max,
|
||||
+ signed_input=signed_input,
|
||||
+ num_bits=num_bits,
|
||||
+ range_given=range_given,
|
||||
+ round_mode=round_mode,
|
||||
+ narrow_range=narrow_range,
|
||||
+ axis=axis,
|
||||
+ name=name)
|
||||
+
|
||||
+
|
||||
@tf_export("searchsorted")
|
||||
@dispatch.add_dispatch_support
|
||||
def searchsorted(sorted_sequence,
|
||||
@@ -5768,7 +5879,7 @@ def _with_nonzero_rank(data):
|
||||
@dispatch.add_dispatch_support
|
||||
def repeat(input, repeats, axis=None, name=None): # pylint: disable=redefined-builtin
|
||||
"""Repeat elements of `input`.
|
||||
-
|
||||
+
|
||||
See also `tf.concat`, `tf.stack`, `tf.tile`.
|
||||
|
||||
Args:
|
||||
diff --git a/tensorflow/tools/api/golden/v1/tensorflow.pbtxt b/tensorflow/tools/api/golden/v1/tensorflow.pbtxt
|
||||
index 1fe3c40d..0b944f56 100644
|
||||
--- a/tensorflow/tools/api/golden/v1/tensorflow.pbtxt
|
||||
+++ b/tensorflow/tools/api/golden/v1/tensorflow.pbtxt
|
||||
@@ -1820,6 +1820,10 @@ tf_module {
|
||||
name: "quantize"
|
||||
argspec: "args=[\'input\', \'min_range\', \'max_range\', \'T\', \'mode\', \'round_mode\', \'name\', \'narrow_range\', \'axis\', \'ensure_minimum_range\'], varargs=None, keywords=None, defaults=[\'MIN_COMBINED\', \'HALF_AWAY_FROM_ZERO\', \'None\', \'False\', \'None\', \'0.01\'], "
|
||||
}
|
||||
+ member_method {
|
||||
+ name: "quantize_and_dequantize_v4"
|
||||
+ argspec: "args=[\'input\', \'input_min\', \'input_max\', \'signed_input\', \'num_bits\', \'range_given\', \'round_mode\', \'narrow_range\', \'axis\', \'name\'], varargs=None, keywords=None, defaults=[\'True\', \'8\', \'False\', \'HALF_TO_EVEN\', \'False\', \'-1\', \'None\'], "
|
||||
+ }
|
||||
member_method {
|
||||
name: "quantize_v2"
|
||||
argspec: "args=[\'input\', \'min_range\', \'max_range\', \'T\', \'mode\', \'name\', \'round_mode\', \'narrow_range\', \'axis\', \'ensure_minimum_range\'], varargs=None, keywords=None, defaults=[\'MIN_COMBINED\', \'None\', \'HALF_AWAY_FROM_ZERO\', \'False\', \'None\', \'0.01\'], "
|
||||
diff --git a/tensorflow/tools/api/golden/v1/tensorflow.quantization.pbtxt b/tensorflow/tools/api/golden/v1/tensorflow.quantization.pbtxt
|
||||
index 047fb4de..269873c6 100644
|
||||
--- a/tensorflow/tools/api/golden/v1/tensorflow.quantization.pbtxt
|
||||
+++ b/tensorflow/tools/api/golden/v1/tensorflow.quantization.pbtxt
|
||||
@@ -36,6 +36,10 @@ tf_module {
|
||||
name: "quantize_and_dequantize"
|
||||
argspec: "args=[\'input\', \'input_min\', \'input_max\', \'signed_input\', \'num_bits\', \'range_given\', \'round_mode\', \'name\', \'narrow_range\', \'axis\'], varargs=None, keywords=None, defaults=[\'True\', \'8\', \'False\', \'HALF_TO_EVEN\', \'None\', \'False\', \'None\'], "
|
||||
}
|
||||
+ member_method {
|
||||
+ name: "quantize_and_dequantize_v2"
|
||||
+ argspec: "args=[\'input\', \'input_min\', \'input_max\', \'signed_input\', \'num_bits\', \'range_given\', \'round_mode\', \'name\', \'narrow_range\', \'axis\'], varargs=None, keywords=None, defaults=[\'True\', \'8\', \'False\', \'HALF_TO_EVEN\', \'None\', \'False\', \'None\'], "
|
||||
+ }
|
||||
member_method {
|
||||
name: "quantized_concat"
|
||||
argspec: "args=[\'concat_dim\', \'values\', \'input_mins\', \'input_maxes\', \'name\'], varargs=None, keywords=None, defaults=[\'None\'], "
|
||||
diff --git a/tensorflow/tools/api/golden/v1/tensorflow.raw_ops.pbtxt b/tensorflow/tools/api/golden/v1/tensorflow.raw_ops.pbtxt
|
||||
index 8e5303cb..136d86f7 100644
|
||||
--- a/tensorflow/tools/api/golden/v1/tensorflow.raw_ops.pbtxt
|
||||
+++ b/tensorflow/tools/api/golden/v1/tensorflow.raw_ops.pbtxt
|
||||
@@ -2900,6 +2900,14 @@ tf_module {
|
||||
name: "QuantizeAndDequantizeV3"
|
||||
argspec: "args=[\'input\', \'input_min\', \'input_max\', \'num_bits\', \'signed_input\', \'range_given\', \'narrow_range\', \'axis\', \'name\'], varargs=None, keywords=None, defaults=[\'True\', \'True\', \'False\', \'-1\', \'None\'], "
|
||||
}
|
||||
+ member_method {
|
||||
+ name: "QuantizeAndDequantizeV4"
|
||||
+ argspec: "args=[\'input\', \'input_min\', \'input_max\', \'signed_input\', \'num_bits\', \'range_given\', \'round_mode\', \'narrow_range\', \'axis\', \'name\'], varargs=None, keywords=None, defaults=[\'True\', \'8\', \'False\', \'HALF_TO_EVEN\', \'False\', \'-1\', \'None\'], "
|
||||
+ }
|
||||
+ member_method {
|
||||
+ name: "QuantizeAndDequantizeV4Grad"
|
||||
+ argspec: "args=[\'gradients\', \'input\', \'input_min\', \'input_max\', \'axis\', \'name\'], varargs=None, keywords=None, defaults=[\'-1\', \'None\'], "
|
||||
+ }
|
||||
member_method {
|
||||
name: "QuantizeDownAndShrinkRange"
|
||||
argspec: "args=[\'input\', \'input_min\', \'input_max\', \'out_type\', \'name\'], varargs=None, keywords=None, defaults=[\'None\'], "
|
||||
diff --git a/tensorflow/tools/api/golden/v2/tensorflow.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.pbtxt
|
||||
index 1d56969b..5f358a7b 100644
|
||||
--- a/tensorflow/tools/api/golden/v2/tensorflow.pbtxt
|
||||
+++ b/tensorflow/tools/api/golden/v2/tensorflow.pbtxt
|
||||
@@ -872,6 +872,10 @@ tf_module {
|
||||
name: "py_function"
|
||||
argspec: "args=[\'func\', \'inp\', \'Tout\', \'name\'], varargs=None, keywords=None, defaults=[\'None\'], "
|
||||
}
|
||||
+ member_method {
|
||||
+ name: "quantize_and_dequantize_v4"
|
||||
+ argspec: "args=[\'input\', \'input_min\', \'input_max\', \'signed_input\', \'num_bits\', \'range_given\', \'round_mode\', \'narrow_range\', \'axis\', \'name\'], varargs=None, keywords=None, defaults=[\'True\', \'8\', \'False\', \'HALF_TO_EVEN\', \'False\', \'-1\', \'None\'], "
|
||||
+ }
|
||||
member_method {
|
||||
name: "range"
|
||||
argspec: "args=[\'start\', \'limit\', \'delta\', \'dtype\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'1\', \'None\', \'range\'], "
|
||||
diff --git a/tensorflow/tools/api/golden/v2/tensorflow.quantization.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.quantization.pbtxt
|
||||
index 047fb4de..269873c6 100644
|
||||
--- a/tensorflow/tools/api/golden/v2/tensorflow.quantization.pbtxt
|
||||
+++ b/tensorflow/tools/api/golden/v2/tensorflow.quantization.pbtxt
|
||||
@@ -36,6 +36,10 @@ tf_module {
|
||||
name: "quantize_and_dequantize"
|
||||
argspec: "args=[\'input\', \'input_min\', \'input_max\', \'signed_input\', \'num_bits\', \'range_given\', \'round_mode\', \'name\', \'narrow_range\', \'axis\'], varargs=None, keywords=None, defaults=[\'True\', \'8\', \'False\', \'HALF_TO_EVEN\', \'None\', \'False\', \'None\'], "
|
||||
}
|
||||
+ member_method {
|
||||
+ name: "quantize_and_dequantize_v2"
|
||||
+ argspec: "args=[\'input\', \'input_min\', \'input_max\', \'signed_input\', \'num_bits\', \'range_given\', \'round_mode\', \'name\', \'narrow_range\', \'axis\'], varargs=None, keywords=None, defaults=[\'True\', \'8\', \'False\', \'HALF_TO_EVEN\', \'None\', \'False\', \'None\'], "
|
||||
+ }
|
||||
member_method {
|
||||
name: "quantized_concat"
|
||||
argspec: "args=[\'concat_dim\', \'values\', \'input_mins\', \'input_maxes\', \'name\'], varargs=None, keywords=None, defaults=[\'None\'], "
|
||||
diff --git a/tensorflow/tools/api/golden/v2/tensorflow.raw_ops.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.raw_ops.pbtxt
|
||||
index 8e5303cb..136d86f7 100644
|
||||
--- a/tensorflow/tools/api/golden/v2/tensorflow.raw_ops.pbtxt
|
||||
+++ b/tensorflow/tools/api/golden/v2/tensorflow.raw_ops.pbtxt
|
||||
@@ -2900,6 +2900,14 @@ tf_module {
|
||||
name: "QuantizeAndDequantizeV3"
|
||||
argspec: "args=[\'input\', \'input_min\', \'input_max\', \'num_bits\', \'signed_input\', \'range_given\', \'narrow_range\', \'axis\', \'name\'], varargs=None, keywords=None, defaults=[\'True\', \'True\', \'False\', \'-1\', \'None\'], "
|
||||
}
|
||||
+ member_method {
|
||||
+ name: "QuantizeAndDequantizeV4"
|
||||
+ argspec: "args=[\'input\', \'input_min\', \'input_max\', \'signed_input\', \'num_bits\', \'range_given\', \'round_mode\', \'narrow_range\', \'axis\', \'name\'], varargs=None, keywords=None, defaults=[\'True\', \'8\', \'False\', \'HALF_TO_EVEN\', \'False\', \'-1\', \'None\'], "
|
||||
+ }
|
||||
+ member_method {
|
||||
+ name: "QuantizeAndDequantizeV4Grad"
|
||||
+ argspec: "args=[\'gradients\', \'input\', \'input_min\', \'input_max\', \'axis\', \'name\'], varargs=None, keywords=None, defaults=[\'-1\', \'None\'], "
|
||||
+ }
|
||||
member_method {
|
||||
name: "QuantizeDownAndShrinkRange"
|
||||
argspec: "args=[\'input\', \'input_min\', \'input_max\', \'out_type\', \'name\'], varargs=None, keywords=None, defaults=[\'None\'], "
|
||||
--
|
||||
2.27.0
|
||||
|
||||
@ -1,33 +0,0 @@
|
||||
From 20431e9044cf2ad3c0323c34888b192f3289af6b Mon Sep 17 00:00:00 2001
|
||||
From: Amit Patankar <amitpatankar@google.com>
|
||||
Date: Mon, 26 Apr 2021 13:43:59 -0700
|
||||
Subject: [PATCH] Fix `tf.raw_ops.QuantizeAndDequantizeV4Grad` CHECK failure.
|
||||
|
||||
PiperOrigin-RevId: 370532425
|
||||
Change-Id: I767721be266851b63d8fe55e7ac6be0af6017f6c
|
||||
---
|
||||
tensorflow/core/kernels/quantize_and_dequantize_op.cc | 10 ++++++++++
|
||||
1 file changed, 10 insertions(+)
|
||||
|
||||
diff --git a/tensorflow/core/kernels/quantize_and_dequantize_op.cc b/tensorflow/core/kernels/quantize_and_dequantize_op.cc
|
||||
index 675bdaec225bd..c2a7a90d8713d 100644
|
||||
--- a/tensorflow/core/kernels/quantize_and_dequantize_op.cc
|
||||
+++ b/tensorflow/core/kernels/quantize_and_dequantize_op.cc
|
||||
@@ -164,7 +164,17 @@ class QuantizeAndDequantizeV4GradientOp : public OpKernel {
|
||||
errors::InvalidArgument("gradient and input must be the same size"));
|
||||
const int depth = (axis_ == -1) ? 1 : input.dim_size(axis_);
|
||||
const Tensor& input_min_tensor = ctx->input(2);
|
||||
+ OP_REQUIRES(ctx,
|
||||
+ input_min_tensor.dims() == 0 || input_min_tensor.dims() == 1,
|
||||
+ errors::InvalidArgument(
|
||||
+ "Input min tensor must have dimension 1. Recieved ",
|
||||
+ input_min_tensor.dims(), "."));
|
||||
const Tensor& input_max_tensor = ctx->input(3);
|
||||
+ OP_REQUIRES(ctx,
|
||||
+ input_max_tensor.dims() == 0 || input_max_tensor.dims() == 1,
|
||||
+ errors::InvalidArgument(
|
||||
+ "Input max tensor must have dimension 1. Recieved ",
|
||||
+ input_max_tensor.dims(), "."));
|
||||
if (axis_ != -1) {
|
||||
OP_REQUIRES(
|
||||
ctx, input_min_tensor.dim_size(0) == depth,
|
||||
@ -1,35 +0,0 @@
|
||||
From 1e922ccdf6bf46a3a52641f99fd47d54c1decd13 Mon Sep 17 00:00:00 2001
|
||||
From: Mihai Maruseac <mihaimaruseac@google.com>
|
||||
Date: Fri, 23 Apr 2021 10:41:12 -0700
|
||||
Subject: [PATCH] Fix crash in `SparseTensorToCSRSparseMatrixCPUFunctor`
|
||||
|
||||
PiperOrigin-RevId: 370110290
|
||||
Change-Id: I4451e92661a55c2180f80d38b67a9b50bf5edec5
|
||||
---
|
||||
tensorflow/core/kernels/sparse/kernels.cc | 6 ++++++
|
||||
1 file changed, 6 insertions(+)
|
||||
|
||||
diff --git a/tensorflow/core/kernels/sparse/kernels.cc b/tensorflow/core/kernels/sparse/kernels.cc
|
||||
index 0eea9f1feed5c..dff9aeb83ccfe 100644
|
||||
--- a/tensorflow/core/kernels/sparse/kernels.cc
|
||||
+++ b/tensorflow/core/kernels/sparse/kernels.cc
|
||||
@@ -22,6 +22,7 @@ limitations under the License.
|
||||
#include "tensorflow/core/framework/tensor_types.h"
|
||||
#include "tensorflow/core/lib/core/errors.h"
|
||||
#include "tensorflow/core/lib/core/status.h"
|
||||
+#include "tensorflow/core/platform/errors.h"
|
||||
|
||||
namespace tensorflow {
|
||||
namespace functor {
|
||||
@@ -63,6 +64,11 @@ Status SparseTensorToCSRSparseMatrixCPUFunctor::operator()(
|
||||
|
||||
for (int64 i = 0; i < total_nnz; ++i) {
|
||||
// For now, the rows pointers store the corresponding row counts.
|
||||
+ int64 ix = indices(i, 0) + 1;
|
||||
+ if (ix >= csr_row_ptr.size()) {
|
||||
+ return errors::InvalidArgument("Got an index ", ix,
|
||||
+ " that is outside of csr_row_ptr");
|
||||
+ }
|
||||
csr_row_ptr(indices(i, 0) + 1) += 1;
|
||||
csr_col_ind(i) = indices(i, 1);
|
||||
}
|
||||
@ -1,24 +0,0 @@
|
||||
From 67784700869470d65d5f2ef20aeb5e97c31673cb Mon Sep 17 00:00:00 2001
|
||||
From: Mihai Maruseac <mihaimaruseac@google.com>
|
||||
Date: Fri, 23 Apr 2021 11:11:39 -0700
|
||||
Subject: [PATCH] Prevent division by 0 in `QuantizedBiasAdd`.
|
||||
|
||||
PiperOrigin-RevId: 370117454
|
||||
Change-Id: I3804e2ac8dcc6d3afcc92e27853e2325a017ca4d
|
||||
---
|
||||
tensorflow/core/kernels/quantized_bias_add_op.cc | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
diff --git a/tensorflow/core/kernels/quantized_bias_add_op.cc b/tensorflow/core/kernels/quantized_bias_add_op.cc
|
||||
index 5457d290c2559..db0e21a498011 100644
|
||||
--- a/tensorflow/core/kernels/quantized_bias_add_op.cc
|
||||
+++ b/tensorflow/core/kernels/quantized_bias_add_op.cc
|
||||
@@ -56,6 +56,8 @@ class QuantizedBiasAddOp : public OpKernel {
|
||||
"Must provide as many biases as the last dimension "
|
||||
"of the input tensor: ",
|
||||
bias.shape().DebugString(), " vs. ", input.shape().DebugString()));
|
||||
+ OP_REQUIRES(context, bias.NumElements() > 0,
|
||||
+ errors::InvalidArgument("Must provide at least 1 bias"));
|
||||
|
||||
Tensor* output = nullptr;
|
||||
OP_REQUIRES_OK(context,
|
||||
@ -1,111 +0,0 @@
|
||||
From d6ed5bcfe1dcab9e85a4d39931bd18d99018e75b Mon Sep 17 00:00:00 2001
|
||||
From: Mihai Maruseac <mihaimaruseac@google.com>
|
||||
Date: Fri, 23 Apr 2021 11:40:06 -0700
|
||||
Subject: [PATCH] Add missing validation in
|
||||
`QuantizedBatchNormWithGlobalNormalization`
|
||||
|
||||
PiperOrigin-RevId: 370123451
|
||||
Change-Id: Id234d6dab1ec21230bb8e503dba30f899af87f33
|
||||
---
|
||||
.../core/kernels/quantized_batch_norm_op.cc | 77 ++++++++++++++++---
|
||||
1 file changed, 67 insertions(+), 10 deletions(-)
|
||||
|
||||
diff --git a/tensorflow/core/kernels/quantized_batch_norm_op.cc b/tensorflow/core/kernels/quantized_batch_norm_op.cc
|
||||
index b03da7ad17fab..6dfe07f97a400 100644
|
||||
--- a/tensorflow/core/kernels/quantized_batch_norm_op.cc
|
||||
+++ b/tensorflow/core/kernels/quantized_batch_norm_op.cc
|
||||
@@ -173,20 +173,50 @@ class QuantizedBatchNormOp : public OpKernel {
|
||||
|
||||
void Compute(OpKernelContext* context) override {
|
||||
const Tensor& input = context->input(0);
|
||||
- const float input_min = context->input(1).flat<float>()(0);
|
||||
- const float input_max = context->input(2).flat<float>()(0);
|
||||
+ const auto& input_min_tensor = context->input(1);
|
||||
+ OP_REQUIRES(context, input_min_tensor.NumElements() == 1,
|
||||
+ errors::InvalidArgument("input_min must have 1 element"));
|
||||
+ const float input_min = input_min_tensor.flat<float>()(0);
|
||||
+ const auto& input_max_tensor = context->input(2);
|
||||
+ OP_REQUIRES(context, input_max_tensor.NumElements() == 1,
|
||||
+ errors::InvalidArgument("input_max must have 1 element"));
|
||||
+ const float input_max = input_max_tensor.flat<float>()(0);
|
||||
const Tensor& mean = context->input(3);
|
||||
- const float mean_min = context->input(4).flat<float>()(0);
|
||||
- const float mean_max = context->input(5).flat<float>()(0);
|
||||
+ const auto& mean_min_tensor = context->input(4);
|
||||
+ OP_REQUIRES(context, mean_min_tensor.NumElements() == 1,
|
||||
+ errors::InvalidArgument("mean_min must have 1 element"));
|
||||
+ const float mean_min = mean_min_tensor.flat<float>()(0);
|
||||
+ const auto& mean_max_tensor = context->input(5);
|
||||
+ OP_REQUIRES(context, mean_max_tensor.NumElements() == 1,
|
||||
+ errors::InvalidArgument("mean_max must have 1 element"));
|
||||
+ const float mean_max = mean_max_tensor.flat<float>()(0);
|
||||
const Tensor& var = context->input(6);
|
||||
- const float var_min = context->input(7).flat<float>()(0);
|
||||
- const float var_max = context->input(8).flat<float>()(0);
|
||||
+ const auto& var_min_tensor = context->input(7);
|
||||
+ OP_REQUIRES(context, var_min_tensor.NumElements() == 1,
|
||||
+ errors::InvalidArgument("var_min must have 1 element"));
|
||||
+ const float var_min = var_min_tensor.flat<float>()(0);
|
||||
+ const auto& var_max_tensor = context->input(8);
|
||||
+ OP_REQUIRES(context, var_max_tensor.NumElements() == 1,
|
||||
+ errors::InvalidArgument("var_max must have 1 element"));
|
||||
+ const float var_max = var_max_tensor.flat<float>()(0);
|
||||
const Tensor& beta = context->input(9);
|
||||
- const float beta_min = context->input(10).flat<float>()(0);
|
||||
- const float beta_max = context->input(11).flat<float>()(0);
|
||||
+ const auto& beta_min_tensor = context->input(10);
|
||||
+ OP_REQUIRES(context, beta_min_tensor.NumElements() == 1,
|
||||
+ errors::InvalidArgument("beta_min must have 1 element"));
|
||||
+ const float beta_min = beta_min_tensor.flat<float>()(0);
|
||||
+ const auto& beta_max_tensor = context->input(11);
|
||||
+ OP_REQUIRES(context, beta_max_tensor.NumElements() == 1,
|
||||
+ errors::InvalidArgument("beta_max must have 1 element"));
|
||||
+ const float beta_max = beta_max_tensor.flat<float>()(0);
|
||||
const Tensor& gamma = context->input(12);
|
||||
- const float gamma_min = context->input(13).flat<float>()(0);
|
||||
- const float gamma_max = context->input(14).flat<float>()(0);
|
||||
+ const auto& gamma_min_tensor = context->input(13);
|
||||
+ OP_REQUIRES(context, gamma_min_tensor.NumElements() == 1,
|
||||
+ errors::InvalidArgument("gamma_min must have 1 element"));
|
||||
+ const float gamma_min = gamma_min_tensor.flat<float>()(0);
|
||||
+ const auto& gamma_max_tensor = context->input(14);
|
||||
+ OP_REQUIRES(context, gamma_max_tensor.NumElements() == 1,
|
||||
+ errors::InvalidArgument("gamma_max must have 1 element"));
|
||||
+ const float gamma_max = gamma_max_tensor.flat<float>()(0);
|
||||
|
||||
OP_REQUIRES(context, input.dims() == 4,
|
||||
errors::InvalidArgument("input must be 4-dimensional",
|
||||
@@ -203,6 +233,33 @@ class QuantizedBatchNormOp : public OpKernel {
|
||||
OP_REQUIRES(context, gamma.dims() == 1,
|
||||
errors::InvalidArgument("gamma must be 1-dimensional",
|
||||
gamma.shape().DebugString()));
|
||||
+ OP_REQUIRES(context, mean.NumElements() > 1,
|
||||
+ errors::InvalidArgument("Must have at least a mean value",
|
||||
+ gamma.shape().DebugString()));
|
||||
+ OP_REQUIRES(context, mean.NumElements() > 1,
|
||||
+ errors::InvalidArgument("Must have at least a mean value"));
|
||||
+ const auto last_dim = input.shape().dims() - 1;
|
||||
+ OP_REQUIRES(context,
|
||||
+ mean.shape().dim_size(0) == input.shape().dim_size(last_dim),
|
||||
+ errors::InvalidArgument("Must provide as many means as the "
|
||||
+ "last dimension of the input tensor: ",
|
||||
+ mean.shape().DebugString(), " vs. ",
|
||||
+ input.shape().DebugString()));
|
||||
+ OP_REQUIRES(
|
||||
+ context, mean.shape().dim_size(0) == var.shape().dim_size(0),
|
||||
+ errors::InvalidArgument(
|
||||
+ "Mean and variance tensors must have the same shape: ",
|
||||
+ mean.shape().DebugString(), " vs. ", var.shape().DebugString()));
|
||||
+ OP_REQUIRES(
|
||||
+ context, mean.shape().dim_size(0) == beta.shape().dim_size(0),
|
||||
+ errors::InvalidArgument(
|
||||
+ "Mean and beta tensors must have the same shape: ",
|
||||
+ mean.shape().DebugString(), " vs. ", beta.shape().DebugString()));
|
||||
+ OP_REQUIRES(
|
||||
+ context, mean.shape().dim_size(0) == gamma.shape().dim_size(0),
|
||||
+ errors::InvalidArgument(
|
||||
+ "Mean and gamma tensors must have the same shape: ",
|
||||
+ mean.shape().DebugString(), " vs. ", gamma.shape().DebugString()));
|
||||
|
||||
Tensor* output = nullptr;
|
||||
OP_REQUIRES_OK(context,
|
||||
@ -1,24 +0,0 @@
|
||||
From 744009c9e5cc5d0447f0dc39d055f917e1fd9e16 Mon Sep 17 00:00:00 2001
|
||||
From: Mihai Maruseac <mihaimaruseac@google.com>
|
||||
Date: Fri, 23 Apr 2021 12:00:12 -0700
|
||||
Subject: [PATCH] Validate work in `QuantizedAdd`, ensure at least one element.
|
||||
|
||||
PiperOrigin-RevId: 370127996
|
||||
Change-Id: I57c6f3e01afdeada84737820a131590137463855
|
||||
---
|
||||
tensorflow/core/kernels/quantized_add_op.cc | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
diff --git a/tensorflow/core/kernels/quantized_add_op.cc b/tensorflow/core/kernels/quantized_add_op.cc
|
||||
index 55c69de7d3ea6..b186f00f15c06 100644
|
||||
--- a/tensorflow/core/kernels/quantized_add_op.cc
|
||||
+++ b/tensorflow/core/kernels/quantized_add_op.cc
|
||||
@@ -538,6 +538,8 @@ class QuantizedAddOp : public OpKernel {
|
||||
tensor_min = min_x;
|
||||
tensor_max = max_x;
|
||||
}
|
||||
+ OP_REQUIRES(context, vector_num_elements > 0,
|
||||
+ errors::InvalidArgument("Must have some elements to add"));
|
||||
VectorTensorAddition<T, Toutput>(
|
||||
vector_data, vector_min, vector_max, vector_num_elements, tensor_data,
|
||||
tensor_min, tensor_max, tensor_num_elements, min_z_value, max_z_value,
|
||||
@ -1,26 +0,0 @@
|
||||
From 548b5eaf23685d86f722233d8fbc21d0a4aecb96 Mon Sep 17 00:00:00 2001
|
||||
From: Laura Pak <lpak@google.com>
|
||||
Date: Thu, 29 Apr 2021 08:38:16 -0700
|
||||
Subject: [PATCH] Fix divide by zero error in `fractional_pool_common.cc`.
|
||||
|
||||
PiperOrigin-RevId: 371126221
|
||||
Change-Id: Iea4b2f363aaeb116ab460e3bc592c687484af344
|
||||
---
|
||||
tensorflow/core/kernels/fractional_avg_pool_op.cc | 4 ++++
|
||||
1 file changed, 4 insertions(+)
|
||||
|
||||
diff --git a/tensorflow/core/kernels/fractional_avg_pool_op.cc b/tensorflow/core/kernels/fractional_avg_pool_op.cc
|
||||
index dfc2382624e3f..b8a5083e5340f 100644
|
||||
--- a/tensorflow/core/kernels/fractional_avg_pool_op.cc
|
||||
+++ b/tensorflow/core/kernels/fractional_avg_pool_op.cc
|
||||
@@ -80,6 +80,10 @@ class FractionalAvgPoolOp : public OpKernel {
|
||||
std::vector<int> output_size(tensor_in_and_out_dims);
|
||||
for (int i = 0; i < tensor_in_and_out_dims; ++i) {
|
||||
input_size[i] = tensor_in.dim_size(i);
|
||||
+ OP_REQUIRES(
|
||||
+ context, pooling_ratio_[i] <= input_size[i],
|
||||
+ errors::InvalidArgument(
|
||||
+ "Pooling ratio cannot be bigger than input tensor dim size."));
|
||||
}
|
||||
// Output size.
|
||||
for (int i = 0; i < tensor_in_and_out_dims; ++i) {
|
||||
@ -1,53 +0,0 @@
|
||||
From 480641e3599775a8895254ffbc0fc45621334f68 Mon Sep 17 00:00:00 2001
|
||||
From: Mihai Maruseac <mihaimaruseac@google.com>
|
||||
Date: Sat, 24 Apr 2021 16:47:25 -0700
|
||||
Subject: [PATCH] Validate (and ensure validation sticks) inputs for
|
||||
`MatrixTriangularSolve`.
|
||||
|
||||
PiperOrigin-RevId: 370282444
|
||||
Change-Id: Iaed61a0b0727cc42c830658b72eb69f785f48dc5
|
||||
---
|
||||
.../matrix_triangular_solve_op_impl.h | 20 +++++++++++++++----
|
||||
1 file changed, 16 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/tensorflow/core/kernels/matrix_triangular_solve_op_impl.h b/tensorflow/core/kernels/matrix_triangular_solve_op_impl.h
|
||||
index 99249f792b6ed..ce5392e62b9fa 100644
|
||||
--- a/tensorflow/core/kernels/matrix_triangular_solve_op_impl.h
|
||||
+++ b/tensorflow/core/kernels/matrix_triangular_solve_op_impl.h
|
||||
@@ -162,6 +162,9 @@ class BaseMatrixTriangularSolveOp : public OpKernel {
|
||||
const Tensor& in1 = ctx->input(1);
|
||||
|
||||
ValidateInputTensors(ctx, in0, in1);
|
||||
+ if (!ctx->status().ok()) {
|
||||
+ return;
|
||||
+ }
|
||||
|
||||
MatMulBCast bcast(in0.shape().dim_sizes(), in1.shape().dim_sizes());
|
||||
OP_REQUIRES(
|
||||
@@ -230,13 +233,22 @@ class MatrixTriangularSolveOp
|
||||
private:
|
||||
void ValidateInputTensors(OpKernelContext* ctx, const Tensor& in0,
|
||||
const Tensor& in1) override {
|
||||
+ const auto in0_num_dims = in0.dims();
|
||||
OP_REQUIRES(
|
||||
- ctx, in0.dims() >= 2,
|
||||
- errors::InvalidArgument("In[0] ndims must be >= 2: ", in0.dims()));
|
||||
+ ctx, in0_num_dims >= 2,
|
||||
+ errors::InvalidArgument("In[0] ndims must be >= 2: ", in0_num_dims));
|
||||
|
||||
+ const auto in1_num_dims = in1.dims();
|
||||
OP_REQUIRES(
|
||||
- ctx, in1.dims() >= 2,
|
||||
- errors::InvalidArgument("In[0] ndims must be >= 2: ", in1.dims()));
|
||||
+ ctx, in1_num_dims >= 2,
|
||||
+ errors::InvalidArgument("In[1] ndims must be >= 2: ", in1_num_dims));
|
||||
+
|
||||
+ const auto in0_last_dim = in0.dim_size(in0_num_dims - 1);
|
||||
+ const auto in0_prev_dim = in0.dim_size(in0_num_dims - 2);
|
||||
+ OP_REQUIRES(ctx, in0_last_dim == in0_prev_dim,
|
||||
+ errors::InvalidArgument(
|
||||
+ "In[0] matrices in the last dimensions must be square (",
|
||||
+ in0_last_dim, " =/= ", in0_prev_dim, ")"));
|
||||
}
|
||||
};
|
||||
|
||||
@ -1,25 +0,0 @@
|
||||
From 704866eabe03a9aeda044ec91a8d0c83fc1ebdbe Mon Sep 17 00:00:00 2001
|
||||
From: Amit Patankar <amitpatankar@google.com>
|
||||
Date: Tue, 27 Apr 2021 14:41:40 -0700
|
||||
Subject: [PATCH] Fix overflow CHECK issue with
|
||||
`tf.raw_ops.UnsortedSegmentJoin`.
|
||||
|
||||
PiperOrigin-RevId: 370766155
|
||||
Change-Id: I33e7c6626224e1060a8a4ab51ad5d861c6d4c63e
|
||||
---
|
||||
tensorflow/core/kernels/unsorted_segment_join_op.cc | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
diff --git a/tensorflow/core/kernels/unsorted_segment_join_op.cc b/tensorflow/core/kernels/unsorted_segment_join_op.cc
|
||||
index 7464e165e46c8..9acfe7fb1e495 100644
|
||||
--- a/tensorflow/core/kernels/unsorted_segment_join_op.cc
|
||||
+++ b/tensorflow/core/kernels/unsorted_segment_join_op.cc
|
||||
@@ -90,6 +90,8 @@ class UnsortedSegmentJoinOp : public OpKernel {
|
||||
const int32 segment_dims = segment_id_shape.dims();
|
||||
|
||||
const Tensor& num_segments_tensor = context->input(2);
|
||||
+ OP_REQUIRES(context, num_segments_tensor.NumElements() != 0,
|
||||
+ errors::InvalidArgument("Number of segments cannot be empty."));
|
||||
auto num_segments = num_segments_tensor.scalar<NUM_SEGMENTS_TYPE>()();
|
||||
|
||||
OP_REQUIRES(context, segment_dims != 0,
|
||||
@ -1,34 +0,0 @@
|
||||
From 99085e8ff02c3763a0ec2263e44daec416f6a387 Mon Sep 17 00:00:00 2001
|
||||
From: Amit Patankar <amitpatankar@google.com>
|
||||
Date: Mon, 26 Apr 2021 17:32:41 -0700
|
||||
Subject: [PATCH] Fix `tf.raw_ops.QuantizeAndDequantizeV3` array index failure.
|
||||
|
||||
PiperOrigin-RevId: 370577691
|
||||
Change-Id: Ifeae64212f6bcd139435824fa2748d1329213c4c
|
||||
---
|
||||
tensorflow/core/kernels/quantize_and_dequantize_op.cc | 5 +++++
|
||||
1 file changed, 5 insertions(+)
|
||||
|
||||
diff --git a/tensorflow/core/kernels/quantize_and_dequantize_op.cc b/tensorflow/core/kernels/quantize_and_dequantize_op.cc
|
||||
index c2a7a90d8713d..f01a70114591b 100644
|
||||
--- a/tensorflow/core/kernels/quantize_and_dequantize_op.cc
|
||||
+++ b/tensorflow/core/kernels/quantize_and_dequantize_op.cc
|
||||
@@ -13,6 +13,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
==============================================================================*/
|
||||
|
||||
+#include "tensorflow/core/framework/op_requires.h"
|
||||
#define EIGEN_USE_THREADS
|
||||
|
||||
#if (defined(GOOGLE_CUDA) && GOOGLE_CUDA) || \
|
||||
@@ -234,6 +235,10 @@ class QuantizeAndDequantizeV3Op : public OpKernel {
|
||||
|
||||
void Compute(OpKernelContext* ctx) override {
|
||||
const Tensor& input = ctx->input(0);
|
||||
+ OP_REQUIRES(ctx, axis_ < input.dims(),
|
||||
+ errors::InvalidArgument(
|
||||
+ "Axis requested is larger than input dimensions. Axis: ",
|
||||
+ axis_, " Input Dimensions: ", input.dims()));
|
||||
const int depth = (axis_ == -1) ? 1 : input.dim_size(axis_);
|
||||
Tensor* output = nullptr;
|
||||
OP_REQUIRES_OK(ctx, ctx->allocate_output(0, input.shape(), &output));
|
||||
@ -1,25 +0,0 @@
|
||||
From da5ff2daf618591f64b2b62d9d9803951b945e9f Mon Sep 17 00:00:00 2001
|
||||
From: Amit Patankar <amitpatankar@google.com>
|
||||
Date: Wed, 28 Apr 2021 11:24:45 -0700
|
||||
Subject: [PATCH] Fix FPE issue with `tf.raw_ops.DenseCountSparseOutput`.
|
||||
|
||||
PiperOrigin-RevId: 370946862
|
||||
Change-Id: I3752584ad04aaecb327ff6793a9640ac56acfe7a
|
||||
---
|
||||
tensorflow/core/kernels/count_ops.cc | 3 +++
|
||||
1 file changed, 3 insertions(+)
|
||||
|
||||
diff --git a/tensorflow/core/kernels/count_ops.cc b/tensorflow/core/kernels/count_ops.cc
|
||||
index eeb0b853c7aad..40aa1fe458c1e 100644
|
||||
--- a/tensorflow/core/kernels/count_ops.cc
|
||||
+++ b/tensorflow/core/kernels/count_ops.cc
|
||||
@@ -122,6 +122,9 @@ class DenseCount : public OpKernel {
|
||||
|
||||
int num_batch_elements = 1;
|
||||
for (int i = 0; i < num_batch_dimensions; ++i) {
|
||||
+ OP_REQUIRES(context, data.shape().dim_size(i) != 0,
|
||||
+ errors::InvalidArgument(
|
||||
+ "Invalid input: Shapes dimension cannot be 0."));
|
||||
num_batch_elements *= data.shape().dim_size(i);
|
||||
}
|
||||
int num_value_elements = data.shape().num_elements() / num_batch_elements;
|
||||
@ -1,25 +0,0 @@
|
||||
From 1a2a87229d1d61e23a39373777c056161eb4084d Mon Sep 17 00:00:00 2001
|
||||
From: Amit Patankar <amitpatankar@google.com>
|
||||
Date: Wed, 28 Apr 2021 11:30:28 -0700
|
||||
Subject: [PATCH] Fix FPE issue with `tf.raw_ops.FusedBatchNorm`.
|
||||
|
||||
PiperOrigin-RevId: 370948185
|
||||
Change-Id: If0c8e0320062ed6363e94ff5fe38e6a301f69ac2
|
||||
---
|
||||
tensorflow/core/kernels/fused_batch_norm_op.cc | 3 +++
|
||||
1 file changed, 3 insertions(+)
|
||||
|
||||
diff --git a/tensorflow/core/kernels/fused_batch_norm_op.cc b/tensorflow/core/kernels/fused_batch_norm_op.cc
|
||||
index 9b917348e2afa..e564b19857c38 100644
|
||||
--- a/tensorflow/core/kernels/fused_batch_norm_op.cc
|
||||
+++ b/tensorflow/core/kernels/fused_batch_norm_op.cc
|
||||
@@ -293,6 +293,9 @@ struct FusedBatchNorm<CPUDevice, T, U, /* is_training= */ false> {
|
||||
const CPUDevice& d = context->eigen_device<CPUDevice>();
|
||||
|
||||
const int depth = x.dimension(3);
|
||||
+ OP_REQUIRES(
|
||||
+ context, depth != 0,
|
||||
+ errors::Internal("The 4th element in the input shape cannot be 0."));
|
||||
const int size = x.size();
|
||||
const int rest_size = size / depth;
|
||||
Eigen::DSizes<Eigen::Index, 2> rest_by_depth(rest_size, depth);
|
||||
@ -1,28 +0,0 @@
|
||||
From 4071d8e2f6c45c1955a811fee757ca2adbe462c1 Mon Sep 17 00:00:00 2001
|
||||
From: Amit Patankar <amitpatankar@google.com>
|
||||
Date: Thu, 29 Apr 2021 12:24:18 -0700
|
||||
Subject: [PATCH] Fix FPE issue with `tf.raw_ops.Reverse`.
|
||||
|
||||
PiperOrigin-RevId: 371176973
|
||||
Change-Id: Ic6d483bfc95313ec2299c2d1c956cfe96c96626c
|
||||
---
|
||||
tensorflow/core/kernels/reverse_op.cc | 6 ++++++
|
||||
1 file changed, 6 insertions(+)
|
||||
|
||||
diff --git a/tensorflow/core/kernels/reverse_op.cc b/tensorflow/core/kernels/reverse_op.cc
|
||||
index 5555a141b6c7b..560fac7133667 100644
|
||||
--- a/tensorflow/core/kernels/reverse_op.cc
|
||||
+++ b/tensorflow/core/kernels/reverse_op.cc
|
||||
@@ -155,6 +155,12 @@ class ReverseOp : public OpKernel {
|
||||
|
||||
void Compute(OpKernelContext* context) override {
|
||||
const Tensor& input = context->input(0);
|
||||
+ // If input is provided, check to make sure the first dimension is valid.
|
||||
+ if (input.dims() > 0) {
|
||||
+ OP_REQUIRES(
|
||||
+ context, input.dim_size(0) != 0,
|
||||
+ errors::InvalidArgument("Invalid input first dimension. Found 0."));
|
||||
+ }
|
||||
const Tensor& dims = context->input(1);
|
||||
|
||||
if (TensorShapeUtils::IsScalar(input.shape())) {
|
||||
@ -1,27 +0,0 @@
|
||||
From 7f283ff806b2031f407db64c4d3edcda8fb9f9f5 Mon Sep 17 00:00:00 2001
|
||||
From: Amit Patankar <amitpatankar@google.com>
|
||||
Date: Wed, 28 Apr 2021 15:00:39 -0700
|
||||
Subject: [PATCH] Fix FPE issue in external Eigen source code issue with
|
||||
`tf.raw_ops.SparseMatMul`.
|
||||
|
||||
PiperOrigin-RevId: 370992919
|
||||
Change-Id: Icfb276fef5fb40928b27c3e44608d2aca72c9fd7
|
||||
---
|
||||
tensorflow/core/kernels/sparse_matmul_op.cc | 4 ++++
|
||||
1 file changed, 4 insertions(+)
|
||||
|
||||
diff --git a/tensorflow/core/kernels/sparse_matmul_op.cc b/tensorflow/core/kernels/sparse_matmul_op.cc
|
||||
index f5747854093c9..a02afafa33e3a 100644
|
||||
--- a/tensorflow/core/kernels/sparse_matmul_op.cc
|
||||
+++ b/tensorflow/core/kernels/sparse_matmul_op.cc
|
||||
@@ -1039,6 +1039,10 @@ class SparseMatMulOp : public OpKernel {
|
||||
if (transpose_b) {
|
||||
// TODO(agarwal): avoid transposing the matrix here and directly handle
|
||||
// transpose in CreateDenseSlices.
|
||||
+ OP_REQUIRES(ctx, right->dim_size(0) != 0,
|
||||
+ errors::InvalidArgument("b has an entry 0 in it's shape."));
|
||||
+ OP_REQUIRES(ctx, right->dim_size(1) != 0,
|
||||
+ errors::InvalidArgument("b has an entry 0 in it's shape."));
|
||||
right_tr.reset(
|
||||
new Tensor(right->dtype(),
|
||||
TensorShape({right->dim_size(1), right->dim_size(0)})));
|
||||
@ -1,26 +0,0 @@
|
||||
From 8ba6fa29cd8bf9cef9b718dc31c78c73081f5b31 Mon Sep 17 00:00:00 2001
|
||||
From: Amit Patankar <amitpatankar@google.com>
|
||||
Date: Thu, 29 Apr 2021 17:58:08 -0700
|
||||
Subject: [PATCH] Fix heap-buffer-overflow issue with `tf.raw_ops.SparseSplit`.
|
||||
|
||||
PiperOrigin-RevId: 371242872
|
||||
Change-Id: I482bb3d12602c7c3cc9446f97fb9f584bb98e9a4
|
||||
---
|
||||
tensorflow/core/util/sparse/sparse_tensor.h | 4 ++++
|
||||
1 file changed, 4 insertions(+)
|
||||
|
||||
diff --git a/tensorflow/core/util/sparse/sparse_tensor.h b/tensorflow/core/util/sparse/sparse_tensor.h
|
||||
index 062226d7699bc..341290dbbc698 100644
|
||||
--- a/tensorflow/core/util/sparse/sparse_tensor.h
|
||||
+++ b/tensorflow/core/util/sparse/sparse_tensor.h
|
||||
@@ -527,6 +527,10 @@ inline Status SparseTensor::Split(const SparseTensor& input_tensor,
|
||||
for (int i = 0; i < input_tensor.indices().dim_size(0); ++i) {
|
||||
const int dim = input_tensor.indices().matrix<int64>()(i, split_dim);
|
||||
int slice_index = GetSliceIndex(dim, split_size, residual);
|
||||
+ if (slice_index >= num_values.size()) {
|
||||
+ return errors::InvalidArgument("Slice index ", slice_index,
|
||||
+ " is larger than num_split.");
|
||||
+ }
|
||||
num_values[slice_index]++;
|
||||
}
|
||||
|
||||
@ -1,48 +0,0 @@
|
||||
From 51300ba1cc2f487aefec6e6631fef03b0e08b298 Mon Sep 17 00:00:00 2001
|
||||
From: Laura Pak <lpak@google.com>
|
||||
Date: Mon, 3 May 2021 09:53:26 -0700
|
||||
Subject: [PATCH] Fix heap buffer overflow in tf.raw_ops.UnicodeEncode.
|
||||
|
||||
PiperOrigin-RevId: 371717714
|
||||
Change-Id: If33443b28f158e58078f1268f6b92f2728d219e0
|
||||
---
|
||||
tensorflow/core/kernels/unicode_ops.cc | 19 +++++++++++++++++++
|
||||
1 file changed, 19 insertions(+)
|
||||
|
||||
diff --git a/tensorflow/core/kernels/unicode_ops.cc b/tensorflow/core/kernels/unicode_ops.cc
|
||||
index d3a7ad7b2866f..e6c8f4dfc4228 100644
|
||||
--- a/tensorflow/core/kernels/unicode_ops.cc
|
||||
+++ b/tensorflow/core/kernels/unicode_ops.cc
|
||||
@@ -533,6 +533,17 @@ class UnicodeEncodeOp : public OpKernel {
|
||||
const Tensor& input_splits = context->input(1);
|
||||
const auto input_splits_flat = input_splits.flat<SPLITS_TYPE>();
|
||||
|
||||
+ // Operation will treat first argument in input_splits as if it were zero
|
||||
+ // regardless of its actual value since splits should begin with zero and
|
||||
+ // end with the length of the input values vector.
|
||||
+ OP_REQUIRES(
|
||||
+ context, input_splits_flat(0) == 0,
|
||||
+ errors::InvalidArgument("First value in input_splits must be zero."));
|
||||
+ OP_REQUIRES(context,
|
||||
+ input_splits_flat(input_splits_flat.size() - 1) ==
|
||||
+ input_tensor_flat.size(),
|
||||
+ errors::InvalidArgument("Last value in input_splits must be "
|
||||
+ "equal to length of input_tensor."));
|
||||
// Since we limit to a 2-D input (flat_values of rank 1 and a single splits
|
||||
// tensor), our output dimension will be 1 with it's size equal to the
|
||||
// number of splits (outer dimension or ragged tensor).
|
||||
@@ -548,6 +559,14 @@ class UnicodeEncodeOp : public OpKernel {
|
||||
for (int i = 1; i < input_splits_flat.size(); ++i) {
|
||||
icu::UnicodeString unicode_string;
|
||||
icu::UnicodeStringAppendable appendable_unicode_string(unicode_string);
|
||||
+ OP_REQUIRES(
|
||||
+ context, input_splits_flat(i - 1) <= input_splits_flat(i),
|
||||
+ errors::InvalidArgument(
|
||||
+ "Values in input_splits must be equal or in ascending order."));
|
||||
+ OP_REQUIRES(
|
||||
+ context, input_splits_flat(i) <= input_tensor_flat.size(),
|
||||
+ errors::InvalidArgument("Values in input_splits must be less than or "
|
||||
+ "equal to input_tensor length."));
|
||||
for (; idx < input_splits_flat(i); ++idx) {
|
||||
int32 code_point = input_tensor_flat(idx);
|
||||
// Check for invalid code point
|
||||
@ -1,30 +0,0 @@
|
||||
From a84358aa12f0b1518e606095ab9cfddbf597c121 Mon Sep 17 00:00:00 2001
|
||||
From: Amit Patankar <amitpatankar@google.com>
|
||||
Date: Tue, 4 May 2021 13:45:57 -0700
|
||||
Subject: [PATCH] Fix heap-buffer-overflow issue with
|
||||
`tf.raw_ops.RaggedTensorToTensor`.
|
||||
|
||||
---
|
||||
tensorflow/core/kernels/ragged_tensor_to_tensor_op.cc | 6 ++++++
|
||||
1 file changed, 6 insertions(+)
|
||||
|
||||
diff --git a/tensorflow/core/kernels/ragged_tensor_to_tensor_op.cc b/tensorflow/core/kernels/ragged_tensor_to_tensor_op.cc
|
||||
index 988a3333..38cb4257 100644
|
||||
--- a/tensorflow/core/kernels/ragged_tensor_to_tensor_op.cc
|
||||
+++ b/tensorflow/core/kernels/ragged_tensor_to_tensor_op.cc
|
||||
@@ -313,6 +313,12 @@ class RaggedTensorToTensorBaseOp : public OpKernel {
|
||||
output_index_multiplier, output_size, result);
|
||||
return tensorflow::Status::OK();
|
||||
case RowPartitionType::ROW_SPLITS:
|
||||
+ if (row_partition_tensor.size() - 1 > parent_output_index.size()) {
|
||||
+ return errors::InvalidArgument(
|
||||
+ "Row partition size is greater than output size: ",
|
||||
+ row_partition_tensor.size() - 1, " > ",
|
||||
+ parent_output_index.size());
|
||||
+ }
|
||||
CalculateOutputIndexRowSplit(
|
||||
context, row_partition_tensor, parent_output_index,
|
||||
output_index_multiplier, output_size, result);
|
||||
--
|
||||
2.23.0
|
||||
|
||||
@ -1,27 +0,0 @@
|
||||
From 77dd114513d7796e1e2b8aece214a380af26fbf4 Mon Sep 17 00:00:00 2001
|
||||
From: Mihai Maruseac <mihaimaruseac@google.com>
|
||||
Date: Tue, 4 May 2021 15:46:30 -0700
|
||||
Subject: [PATCH] Fix a check fail
|
||||
|
||||
PiperOrigin-RevId: 372011072
|
||||
Change-Id: I1062cfaed0aa16884e9a16312483794d188db76f
|
||||
---
|
||||
tensorflow/core/kernels/load_and_remap_matrix_op.cc | 5 +++++
|
||||
1 file changed, 5 insertions(+)
|
||||
|
||||
diff --git a/tensorflow/core/kernels/load_and_remap_matrix_op.cc b/tensorflow/core/kernels/load_and_remap_matrix_op.cc
|
||||
index cb0245a9b6126..5ec28c7035813 100644
|
||||
--- a/tensorflow/core/kernels/load_and_remap_matrix_op.cc
|
||||
+++ b/tensorflow/core/kernels/load_and_remap_matrix_op.cc
|
||||
@@ -123,6 +123,11 @@ class LoadAndRemapMatrixOp : public OpKernel {
|
||||
// Processes the checkpoint source and the provided Tensor name.
|
||||
const Tensor* ckpt_path_t;
|
||||
OP_REQUIRES_OK(context, context->input("ckpt_path", &ckpt_path_t));
|
||||
+ OP_REQUIRES(
|
||||
+ context, ckpt_path_t->NumElements() == 1,
|
||||
+ errors::InvalidArgument("The `ckpt_path` tensor must have exactly one "
|
||||
+ "element, got tensor of shape ",
|
||||
+ ckpt_path_t->shape().DebugString()));
|
||||
const string& ckpt_path = ckpt_path_t->scalar<tstring>()();
|
||||
const Tensor* old_tensor_name_t;
|
||||
OP_REQUIRES_OK(context,
|
||||
@ -1,33 +0,0 @@
|
||||
From 1c56f53be0b722ca657cbc7df461ed676c8642a2 Mon Sep 17 00:00:00 2001
|
||||
From: Mihai Maruseac <mihaimaruseac@google.com>
|
||||
Date: Tue, 4 May 2021 17:11:46 -0700
|
||||
Subject: [PATCH] Fix a check fail in Fast Fourier implementation
|
||||
|
||||
PiperOrigin-RevId: 372026629
|
||||
Change-Id: Id05c3362aa575271bc3e06b16316c9037085fc11
|
||||
---
|
||||
tensorflow/core/kernels/fft_ops.cc | 4 ++++
|
||||
1 file changed, 4 insertions(+)
|
||||
|
||||
diff --git a/tensorflow/core/kernels/fft_ops.cc b/tensorflow/core/kernels/fft_ops.cc
|
||||
index c3235c1547ff0..29ca0d2f546a0 100644
|
||||
--- a/tensorflow/core/kernels/fft_ops.cc
|
||||
+++ b/tensorflow/core/kernels/fft_ops.cc
|
||||
@@ -13,6 +13,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
==============================================================================*/
|
||||
|
||||
+#include "tensorflow/core/platform/errors.h"
|
||||
#define EIGEN_USE_THREADS
|
||||
|
||||
// See docs in ../ops/fft_ops.cc.
|
||||
@@ -261,6 +262,9 @@ class FFTCPU : public FFTBase {
|
||||
i == FFTRank ? fft_shape[i - 1] / 2 + 1 : fft_shape[i - 1];
|
||||
full_fft_shape.AddDim(fft_shape[i - 1]);
|
||||
}
|
||||
+ OP_REQUIRES(ctx, full_fft_shape.num_elements() > 0,
|
||||
+ errors::InvalidArgument("Obtained a FFT shape of 0 elements: ",
|
||||
+ full_fft_shape.DebugString()));
|
||||
|
||||
Tensor temp;
|
||||
OP_REQUIRES_OK(ctx, ctx->allocate_temp(DataTypeToEnum<ComplexT>::v(),
|
||||
@ -1,25 +0,0 @@
|
||||
From 31bd5026304677faa8a0b77602c6154171b9aec1 Mon Sep 17 00:00:00 2001
|
||||
From: Mihai Maruseac <mihaimaruseac@google.com>
|
||||
Date: Tue, 4 May 2021 17:42:54 -0700
|
||||
Subject: [PATCH] Prevent check fail in FFT
|
||||
|
||||
PiperOrigin-RevId: 372031044
|
||||
Change-Id: I50994e3e8a5d1342d01bde80256f6bf2730ca299
|
||||
---
|
||||
tensorflow/core/kernels/fft_ops.cc | 3 +++
|
||||
1 file changed, 3 insertions(+)
|
||||
|
||||
diff --git a/tensorflow/core/kernels/fft_ops.cc b/tensorflow/core/kernels/fft_ops.cc
|
||||
index 29ca0d2f546a0..fc29f49d223be 100644
|
||||
--- a/tensorflow/core/kernels/fft_ops.cc
|
||||
+++ b/tensorflow/core/kernels/fft_ops.cc
|
||||
@@ -222,6 +222,9 @@ class FFTCPU : public FFTBase {
|
||||
input_slice_sizes[i] = fft_shape[i - 1];
|
||||
temp_shape.AddDim(fft_shape[i - 1]);
|
||||
}
|
||||
+ OP_REQUIRES(ctx, temp_shape.num_elements() > 0,
|
||||
+ errors::InvalidArgument("Obtained a FFT shape of 0 elements: ",
|
||||
+ temp_shape.DebugString()));
|
||||
|
||||
auto output = out->flat_inner_dims<ComplexT, FFTRank + 1>();
|
||||
const Eigen::DSizes<Eigen::DenseIndex, FFTRank + 1> zero_start_indices;
|
||||
@ -1,118 +0,0 @@
|
||||
From f4c364a5d6880557f6f5b6eb5cee2c407f0186b3 Mon Sep 17 00:00:00 2001
|
||||
From: Mihai Maruseac <mihaimaruseac@google.com>
|
||||
Date: Tue, 4 May 2021 18:06:03 -0700
|
||||
Subject: [PATCH] Fix multiple issues in EditDistance
|
||||
|
||||
PiperOrigin-RevId: 372033948
|
||||
Change-Id: Ieb957c29894af05bdfeb1a0402fced808dfcfd7b
|
||||
---
|
||||
tensorflow/core/kernels/edit_distance_op.cc | 47 +++++++++++++++++++++
|
||||
1 file changed, 47 insertions(+)
|
||||
|
||||
diff --git a/tensorflow/core/kernels/edit_distance_op.cc b/tensorflow/core/kernels/edit_distance_op.cc
|
||||
index 4aecdc9e414d3..386a1af08409f 100644
|
||||
--- a/tensorflow/core/kernels/edit_distance_op.cc
|
||||
+++ b/tensorflow/core/kernels/edit_distance_op.cc
|
||||
@@ -64,6 +64,12 @@ Status ValidateShapes(OpKernelContext* ctx, const Tensor& hypothesis_indices,
|
||||
return errors::InvalidArgument(
|
||||
"truth_shape should be a vector, but got shape: ",
|
||||
truth_shape.shape().DebugString());
|
||||
+ if (hypothesis_values.NumElements() != hypothesis_indices.dim_size(0))
|
||||
+ return errors::InvalidArgument(
|
||||
+ "Expected hypothesis_values.NumElements == "
|
||||
+ "#rows(hypothesis_indices), their shapes are: ",
|
||||
+ hypothesis_values.shape().DebugString(), " and ",
|
||||
+ hypothesis_indices.shape().DebugString());
|
||||
if (hypothesis_shape.NumElements() != hypothesis_indices.dim_size(1))
|
||||
return errors::InvalidArgument(
|
||||
"Expected hypothesis_shape.NumElements == "
|
||||
@@ -75,6 +81,12 @@ Status ValidateShapes(OpKernelContext* ctx, const Tensor& hypothesis_indices,
|
||||
"Input SparseTensors must have rank at least 2, but truth_shape "
|
||||
"rank is: ",
|
||||
truth_shape.NumElements());
|
||||
+ if (truth_values.NumElements() != truth_indices.dim_size(0))
|
||||
+ return errors::InvalidArgument(
|
||||
+ "Expected truth_values.NumElements == "
|
||||
+ "#rows(truth_indices), their shapes are: ",
|
||||
+ truth_values.shape().DebugString(), " and ",
|
||||
+ truth_indices.shape().DebugString());
|
||||
if (truth_shape.NumElements() != truth_indices.dim_size(1))
|
||||
return errors::InvalidArgument(
|
||||
"Expected truth_shape.NumElements == "
|
||||
@@ -153,6 +165,11 @@ class EditDistanceOp : public OpKernel {
|
||||
output_shape.AddDim(std::max(hypothesis_st_shape.dim_size(d),
|
||||
truth_st_shape.dim_size(d)));
|
||||
}
|
||||
+ const auto output_elements = output_shape.num_elements();
|
||||
+ OP_REQUIRES(
|
||||
+ ctx, output_elements > 0,
|
||||
+ errors::InvalidArgument("Got output shape ", output_shape.DebugString(),
|
||||
+ " which has 0 elements"));
|
||||
|
||||
Tensor* output = nullptr;
|
||||
OP_REQUIRES_OK(ctx, ctx->allocate_output("output", output_shape, &output));
|
||||
@@ -185,6 +202,12 @@ class EditDistanceOp : public OpKernel {
|
||||
if (g_truth == g_hypothesis) {
|
||||
auto loc = std::inner_product(g_truth.begin(), g_truth.end(),
|
||||
output_strides.begin(), int64{0});
|
||||
+ OP_REQUIRES(
|
||||
+ ctx, loc < output_elements,
|
||||
+ errors::Internal("Got an inner product ", loc,
|
||||
+ " which would require in writing to outside of "
|
||||
+ "the buffer for the output tensor (max elements ",
|
||||
+ output_elements, ")"));
|
||||
output_t(loc) =
|
||||
gtl::LevenshteinDistance<T>(truth_seq, hypothesis_seq, cmp);
|
||||
if (normalize_) output_t(loc) /= truth_seq.size();
|
||||
@@ -194,6 +217,12 @@ class EditDistanceOp : public OpKernel {
|
||||
} else if (g_truth > g_hypothesis) { // zero-length truth
|
||||
auto loc = std::inner_product(g_hypothesis.begin(), g_hypothesis.end(),
|
||||
output_strides.begin(), int64{0});
|
||||
+ OP_REQUIRES(
|
||||
+ ctx, loc < output_elements,
|
||||
+ errors::Internal("Got an inner product ", loc,
|
||||
+ " which would require in writing to outside of "
|
||||
+ "the buffer for the output tensor (max elements ",
|
||||
+ output_elements, ")"));
|
||||
output_t(loc) = hypothesis_seq.size();
|
||||
if (normalize_ && output_t(loc) != 0.0f) {
|
||||
output_t(loc) = std::numeric_limits<float>::infinity();
|
||||
@@ -202,6 +231,12 @@ class EditDistanceOp : public OpKernel {
|
||||
} else { // zero-length hypothesis
|
||||
auto loc = std::inner_product(g_truth.begin(), g_truth.end(),
|
||||
output_strides.begin(), int64{0});
|
||||
+ OP_REQUIRES(
|
||||
+ ctx, loc < output_elements,
|
||||
+ errors::Internal("Got an inner product ", loc,
|
||||
+ " which would require in writing to outside of "
|
||||
+ "the buffer for the output tensor (max elements ",
|
||||
+ output_elements, ")"));
|
||||
output_t(loc) = (normalize_) ? 1.0 : truth_seq.size();
|
||||
++truth_iter;
|
||||
}
|
||||
@@ -212,6 +247,12 @@ class EditDistanceOp : public OpKernel {
|
||||
auto hypothesis_seq = hypothesis_j.values<T>();
|
||||
auto loc = std::inner_product(g_hypothesis.begin(), g_hypothesis.end(),
|
||||
output_strides.begin(), int64{0});
|
||||
+ OP_REQUIRES(
|
||||
+ ctx, loc < output_elements,
|
||||
+ errors::Internal("Got an inner product ", loc,
|
||||
+ " which would require in writing to outside of the "
|
||||
+ "buffer for the output tensor (max elements ",
|
||||
+ output_elements, ")"));
|
||||
output_t(loc) = hypothesis_seq.size();
|
||||
if (normalize_ && output_t(loc) != 0.0f) {
|
||||
output_t(loc) = std::numeric_limits<float>::infinity();
|
||||
@@ -224,6 +265,12 @@ class EditDistanceOp : public OpKernel {
|
||||
auto truth_seq = truth_i.values<T>();
|
||||
auto loc = std::inner_product(g_truth.begin(), g_truth.end(),
|
||||
output_strides.begin(), int64{0});
|
||||
+ OP_REQUIRES(
|
||||
+ ctx, loc < output_elements,
|
||||
+ errors::Internal("Got an inner product ", loc,
|
||||
+ " which would require in writing to outside of the "
|
||||
+ "buffer for the output tensor (max elements ",
|
||||
+ output_elements, ")"));
|
||||
output_t(loc) = (normalize_) ? 1.0 : truth_seq.size();
|
||||
++truth_iter;
|
||||
}
|
||||
@ -1,65 +0,0 @@
|
||||
From 3f6fe4dfef6f57e768260b48166c27d148f3015f Mon Sep 17 00:00:00 2001
|
||||
From: Mihai Maruseac <mihaimaruseac@google.com>
|
||||
Date: Tue, 4 May 2021 18:33:28 -0700
|
||||
Subject: [PATCH] Add missing validations in dillation ops.
|
||||
|
||||
PiperOrigin-RevId: 372037158
|
||||
Change-Id: I4ee304c84a02550c030288a6534000b934fc1599
|
||||
---
|
||||
tensorflow/core/kernels/dilation_ops.cc | 15 +++++++++++----
|
||||
1 file changed, 11 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/tensorflow/core/kernels/dilation_ops.cc b/tensorflow/core/kernels/dilation_ops.cc
|
||||
index 738ea31d555d5..996ddb62bfefe 100644
|
||||
--- a/tensorflow/core/kernels/dilation_ops.cc
|
||||
+++ b/tensorflow/core/kernels/dilation_ops.cc
|
||||
@@ -130,6 +130,7 @@ class DilationOp : public OpKernel {
|
||||
ParseSizes(context, strides_, rates_, padding_, &stride_rows, &stride_cols,
|
||||
&rate_rows, &rate_cols, &pad_top, &pad_left, &out_rows,
|
||||
&out_cols);
|
||||
+ if (!context->status().ok()) return;
|
||||
|
||||
// Output tensor is of the following dimensions:
|
||||
// [ batch, out_rows, out_cols, depth ]
|
||||
@@ -229,6 +230,7 @@ class DilationBackpropInputOp : public OpKernel {
|
||||
ParseSizes(context, strides_, rates_, padding_, &stride_rows, &stride_cols,
|
||||
&rate_rows, &rate_cols, &pad_top, &pad_left, &out_rows,
|
||||
&out_cols);
|
||||
+ if (!context->status().ok()) return;
|
||||
|
||||
// Verify that the incoming gradient tensor has the expected size
|
||||
// [ batch, out_rows, out_cols, depth ]
|
||||
@@ -318,8 +320,10 @@ struct DilationBackpropInput<CPUDevice, T> {
|
||||
}
|
||||
}
|
||||
}
|
||||
- in_backprop(b, h_in_max, w_in_max, d) +=
|
||||
- out_backprop(b, h_out, w_out, d);
|
||||
+ if (h_in_max < input_rows && w_in_max < input_cols) {
|
||||
+ in_backprop(b, h_in_max, w_in_max, d) +=
|
||||
+ out_backprop(b, h_out, w_out, d);
|
||||
+ }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -349,6 +353,7 @@ class DilationBackpropFilterOp : public OpKernel {
|
||||
ParseSizes(context, strides_, rates_, padding_, &stride_rows, &stride_cols,
|
||||
&rate_rows, &rate_cols, &pad_top, &pad_left, &out_rows,
|
||||
&out_cols);
|
||||
+ if (!context->status().ok()) return;
|
||||
|
||||
// Verify that the incoming gradient tensor has the expected size
|
||||
// [ batch, out_rows, out_cols, depth ]
|
||||
@@ -438,8 +443,10 @@ struct DilationBackpropFilter<CPUDevice, T> {
|
||||
}
|
||||
}
|
||||
}
|
||||
- filter_backprop(h_max, w_max, d) +=
|
||||
- out_backprop(b, h_out, w_out, d);
|
||||
+ if (h_max < filter_rows && w_max < filter_cols) {
|
||||
+ filter_backprop(h_max, w_max, d) +=
|
||||
+ out_backprop(b, h_out, w_out, d);
|
||||
+ }
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,28 +0,0 @@
|
||||
From 7ae2af34087fb4b5c8915279efd03da3b81028bc Mon Sep 17 00:00:00 2001
|
||||
From: Amit Patankar <amitpatankar@google.com>
|
||||
Date: Tue, 4 May 2021 21:30:50 -0700
|
||||
Subject: [PATCH] Fix heap-buffer-overflow issue with
|
||||
`tf.raw_ops.SparseDenseCwiseMul`.
|
||||
|
||||
PiperOrigin-RevId: 372054410
|
||||
Change-Id: Ifcce0491e2e3816838c87e73be30a1e61b65174d
|
||||
---
|
||||
tensorflow/core/kernels/sparse_dense_binary_op_shared.cc | 5 +++++
|
||||
1 file changed, 5 insertions(+)
|
||||
|
||||
diff --git a/tensorflow/core/kernels/sparse_dense_binary_op_shared.cc b/tensorflow/core/kernels/sparse_dense_binary_op_shared.cc
|
||||
index 3a5e66a0e73ea..dac4a3d3e6bfc 100644
|
||||
--- a/tensorflow/core/kernels/sparse_dense_binary_op_shared.cc
|
||||
+++ b/tensorflow/core/kernels/sparse_dense_binary_op_shared.cc
|
||||
@@ -78,6 +78,11 @@ class SparseDenseBinaryOpShared : public OpKernel {
|
||||
"but received shapes: ",
|
||||
values_t->shape().DebugString(), " and ",
|
||||
shape_t->shape().DebugString()));
|
||||
+ OP_REQUIRES(
|
||||
+ ctx, values_t->dim_size(0) == indices_t->dim_size(0),
|
||||
+ errors::InvalidArgument(
|
||||
+ "The first dimension of values and indices should match. (",
|
||||
+ values_t->dim_size(0), " vs. ", indices_t->dim_size(0), ")"));
|
||||
|
||||
const auto indices_mat = indices_t->matrix<int64>();
|
||||
const auto shape_vec = shape_t->vec<int64>();
|
||||
@ -1,25 +0,0 @@
|
||||
From 5e52ef5a461570cfb68f3bdbbebfe972cb4e0fd8 Mon Sep 17 00:00:00 2001
|
||||
From: Mihai Maruseac <mihaimaruseac@google.com>
|
||||
Date: Tue, 4 May 2021 19:14:24 -0700
|
||||
Subject: [PATCH] Fix breakage in parameterized_truncated_normal_op.cc
|
||||
|
||||
PiperOrigin-RevId: 372041718
|
||||
Change-Id: Iff79e77a2bb27032423eefcb84211627b27dfe81
|
||||
---
|
||||
tensorflow/core/kernels/parameterized_truncated_normal_op.cc | 3 +++
|
||||
1 file changed, 3 insertions(+)
|
||||
|
||||
diff --git a/tensorflow/core/kernels/parameterized_truncated_normal_op.cc b/tensorflow/core/kernels/parameterized_truncated_normal_op.cc
|
||||
index a63457551ac29..116df3541d7cf 100644
|
||||
--- a/tensorflow/core/kernels/parameterized_truncated_normal_op.cc
|
||||
+++ b/tensorflow/core/kernels/parameterized_truncated_normal_op.cc
|
||||
@@ -627,6 +627,9 @@ class ParameterizedTruncatedNormalOp : public OpKernel {
|
||||
ctx, TensorShapeUtils::IsVector(shape_tensor.shape()),
|
||||
errors::InvalidArgument("Input shape should be a vector, got shape: ",
|
||||
shape_tensor.shape().DebugString()));
|
||||
+ OP_REQUIRES(ctx, shape_tensor.NumElements() > 0,
|
||||
+ errors::InvalidArgument("Shape tensor must not be empty, got ",
|
||||
+ shape_tensor.DebugString()));
|
||||
int32 num_batches = shape_tensor.flat<int32>()(0);
|
||||
|
||||
int32 samples_per_batch = 1;
|
||||
@ -1,26 +0,0 @@
|
||||
From ef0c008ee84bad91ec6725ddc42091e19a30cf0e Mon Sep 17 00:00:00 2001
|
||||
From: Laura Pak <lpak@google.com>
|
||||
Date: Wed, 5 May 2021 08:16:13 -0700
|
||||
Subject: [PATCH] Fix out of bound read in requantization_range_op.cc
|
||||
|
||||
PiperOrigin-RevId: 372129031
|
||||
Change-Id: Ie684ab98a3840c5186ead3eafffc0e0ed0e8030d
|
||||
---
|
||||
tensorflow/core/kernels/requantization_range_op.cc | 4 ++++
|
||||
1 file changed, 4 insertions(+)
|
||||
|
||||
diff --git a/tensorflow/core/kernels/requantization_range_op.cc b/tensorflow/core/kernels/requantization_range_op.cc
|
||||
index cc6e891a6b352..f6e217499d198 100644
|
||||
--- a/tensorflow/core/kernels/requantization_range_op.cc
|
||||
+++ b/tensorflow/core/kernels/requantization_range_op.cc
|
||||
@@ -46,6 +46,10 @@ class RequantizationRangeOp : public OpKernel {
|
||||
|
||||
void Compute(OpKernelContext* ctx) override {
|
||||
const Tensor& input = ctx->input(0);
|
||||
+ OP_REQUIRES(ctx, ctx->input(1).NumElements() > 0,
|
||||
+ errors::InvalidArgument("Input min must not be empty."));
|
||||
+ OP_REQUIRES(ctx, ctx->input(2).NumElements() > 0,
|
||||
+ errors::InvalidArgument("Input max must not be empty."));
|
||||
const float input_min_float = ctx->input(1).flat<float>()(0);
|
||||
const float input_max_float = ctx->input(2).flat<float>()(0);
|
||||
Tensor* output_min = nullptr;
|
||||
@ -1,25 +0,0 @@
|
||||
From dcd7867de0fea4b72a2b34bd41eb74548dc23886 Mon Sep 17 00:00:00 2001
|
||||
From: Mihai Maruseac <mihaimaruseac@google.com>
|
||||
Date: Wed, 5 May 2021 08:38:03 -0700
|
||||
Subject: [PATCH] Fix heap buffer overflow
|
||||
|
||||
PiperOrigin-RevId: 372132844
|
||||
Change-Id: Idef9895efaf145f2b1c23d31983601ec980cd5e4
|
||||
---
|
||||
tensorflow/core/kernels/maxpooling_op.cc | 3 +++
|
||||
1 file changed, 3 insertions(+)
|
||||
|
||||
diff --git a/tensorflow/core/kernels/maxpooling_op.cc b/tensorflow/core/kernels/maxpooling_op.cc
|
||||
index b60d54533be68..003d2e94b99cd 100644
|
||||
--- a/tensorflow/core/kernels/maxpooling_op.cc
|
||||
+++ b/tensorflow/core/kernels/maxpooling_op.cc
|
||||
@@ -1014,6 +1014,9 @@ struct LaunchMaxPoolingGradWithArgmax<CPUDevice, T> {
|
||||
const int input_start = start * input_size_per_batch;
|
||||
const int input_end = limit * input_size_per_batch;
|
||||
for (int64 index = input_start; index < input_end; index++) {
|
||||
+ if (index >= argmax.NumElements()) {
|
||||
+ break;
|
||||
+ }
|
||||
int64 grad_out_index = argmax_flat(index);
|
||||
if (!include_batch_in_index) {
|
||||
const int64 cur_batch = index / input_size_per_batch;
|
||||
@ -1,30 +0,0 @@
|
||||
From 79865b542f9ffdc9caeb255631f7c56f1d4b6517 Mon Sep 17 00:00:00 2001
|
||||
From: Amit Patankar <amitpatankar@google.com>
|
||||
Date: Tue, 4 May 2021 18:05:46 -0700
|
||||
Subject: [PATCH] Fix memory corruption issue with
|
||||
`tf.raw_ops.DrawBoundingBoxesV2`.
|
||||
|
||||
---
|
||||
tensorflow/core/kernels/draw_bounding_box_op.cc | 6 ++++++
|
||||
1 file changed, 6 insertions(+)
|
||||
|
||||
diff --git a/tensorflow/core/kernels/draw_bounding_box_op.cc b/tensorflow/core/kernels/draw_bounding_box_op.cc
|
||||
index 30de99b7..1e866325 100644
|
||||
--- a/tensorflow/core/kernels/draw_bounding_box_op.cc
|
||||
+++ b/tensorflow/core/kernels/draw_bounding_box_op.cc
|
||||
@@ -73,6 +73,12 @@ class DrawBoundingBoxesOp : public OpKernel {
|
||||
errors::InvalidArgument("Channel depth should be either 1 (GRY), "
|
||||
"3 (RGB), or 4 (RGBA)"));
|
||||
|
||||
+ OP_REQUIRES(
|
||||
+ context, boxes.dim_size(2) == 4,
|
||||
+ errors::InvalidArgument(
|
||||
+ "The size of the third dimension of the box mustbe 4. Received: ",
|
||||
+ boxes.dim_size(2)));
|
||||
+
|
||||
const int64 batch_size = images.dim_size(0);
|
||||
const int64 height = images.dim_size(1);
|
||||
const int64 width = images.dim_size(2);
|
||||
--
|
||||
2.23.0
|
||||
|
||||
@ -1,90 +0,0 @@
|
||||
From f7cc8755ac6683131fdfa7a8a121f9d7a9dec6fb Mon Sep 17 00:00:00 2001
|
||||
From: Mihai Maruseac <mihaimaruseac@google.com>
|
||||
Date: Wed, 5 May 2021 11:40:50 -0700
|
||||
Subject: [PATCH] Add several missing validations in SDCA
|
||||
|
||||
PiperOrigin-RevId: 372172877
|
||||
Change-Id: Id366da962432e18dcbfac847d11e98488bebb70a
|
||||
---
|
||||
tensorflow/core/kernels/sdca_internal.cc | 36 ++++++++++++++++++++++++
|
||||
1 file changed, 36 insertions(+)
|
||||
|
||||
diff --git a/tensorflow/core/kernels/sdca_internal.cc b/tensorflow/core/kernels/sdca_internal.cc
|
||||
index cbc754af0e9bb..11a3be8bf46a7 100644
|
||||
--- a/tensorflow/core/kernels/sdca_internal.cc
|
||||
+++ b/tensorflow/core/kernels/sdca_internal.cc
|
||||
@@ -99,6 +99,10 @@ Status ModelWeights::Initialize(OpKernelContext* const context) {
|
||||
OpInputList sparse_weights_inputs;
|
||||
TF_RETURN_IF_ERROR(
|
||||
context->input_list("sparse_weights", &sparse_weights_inputs));
|
||||
+ if (sparse_indices_inputs.size() != sparse_weights_inputs.size())
|
||||
+ return errors::InvalidArgument(
|
||||
+ "sparse_indices and sparse_weights must have the same length, got ",
|
||||
+ sparse_indices_inputs.size(), " and ", sparse_weights_inputs.size());
|
||||
OpInputList dense_weights_inputs;
|
||||
TF_RETURN_IF_ERROR(
|
||||
context->input_list("dense_weights", &dense_weights_inputs));
|
||||
@@ -106,10 +110,20 @@ Status ModelWeights::Initialize(OpKernelContext* const context) {
|
||||
OpOutputList sparse_weights_outputs;
|
||||
TF_RETURN_IF_ERROR(context->output_list("out_delta_sparse_weights",
|
||||
&sparse_weights_outputs));
|
||||
+ if (sparse_weights_outputs.size() != sparse_weights_inputs.size())
|
||||
+ return errors::InvalidArgument(
|
||||
+ "out_delta_sparse_weights and sparse_weights must have the same "
|
||||
+ "length, got ",
|
||||
+ sparse_weights_outputs.size(), " and ", sparse_weights_inputs.size());
|
||||
|
||||
OpOutputList dense_weights_outputs;
|
||||
TF_RETURN_IF_ERROR(
|
||||
context->output_list("out_delta_dense_weights", &dense_weights_outputs));
|
||||
+ if (dense_weights_outputs.size() != dense_weights_inputs.size())
|
||||
+ return errors::InvalidArgument(
|
||||
+ "out_delta_dense_weights and dense_weights must have the same length, "
|
||||
+ "got ",
|
||||
+ dense_weights_outputs.size(), " and ", dense_weights_inputs.size());
|
||||
|
||||
for (int i = 0; i < sparse_weights_inputs.size(); ++i) {
|
||||
Tensor* delta_t;
|
||||
@@ -327,13 +341,28 @@ Status Examples::Initialize(OpKernelContext* const context,
|
||||
OpInputList sparse_example_indices_inputs;
|
||||
TF_RETURN_IF_ERROR(context->input_list("sparse_example_indices",
|
||||
&sparse_example_indices_inputs));
|
||||
+ if (sparse_example_indices_inputs.size() != num_sparse_features)
|
||||
+ return errors::InvalidArgument(
|
||||
+ "Expected ", num_sparse_features,
|
||||
+ " tensors in sparse_example_indices but got ",
|
||||
+ sparse_example_indices_inputs.size());
|
||||
OpInputList sparse_feature_indices_inputs;
|
||||
TF_RETURN_IF_ERROR(context->input_list("sparse_feature_indices",
|
||||
&sparse_feature_indices_inputs));
|
||||
+ if (sparse_feature_indices_inputs.size() != num_sparse_features)
|
||||
+ return errors::InvalidArgument(
|
||||
+ "Expected ", num_sparse_features,
|
||||
+ " tensors in sparse_feature_indices but got ",
|
||||
+ sparse_feature_indices_inputs.size());
|
||||
OpInputList sparse_feature_values_inputs;
|
||||
if (num_sparse_features_with_values > 0) {
|
||||
TF_RETURN_IF_ERROR(context->input_list("sparse_feature_values",
|
||||
&sparse_feature_values_inputs));
|
||||
+ if (sparse_feature_values_inputs.size() != num_sparse_features_with_values)
|
||||
+ return errors::InvalidArgument(
|
||||
+ "Expected ", num_sparse_features_with_values,
|
||||
+ " tensors in sparse_feature_values but got ",
|
||||
+ sparse_feature_values_inputs.size());
|
||||
}
|
||||
|
||||
const Tensor* example_weights_t;
|
||||
@@ -400,6 +429,13 @@ Status Examples::CreateSparseFeatureRepresentation(
|
||||
sparse_example_indices_inputs[i].template flat<int64>();
|
||||
auto feature_indices =
|
||||
sparse_feature_indices_inputs[i].template flat<int64>();
|
||||
+ if (example_indices.size() != feature_indices.size()) {
|
||||
+ mutex_lock l(mu);
|
||||
+ result = errors::InvalidArgument(
|
||||
+ "Found mismatched example_indices and feature_indices [",
|
||||
+ example_indices, "] vs [", feature_indices, "]");
|
||||
+ return;
|
||||
+ }
|
||||
|
||||
// Parse features for each example. Features for a particular example
|
||||
// are at the offsets (start_id, end_id]
|
||||
@ -1,24 +0,0 @@
|
||||
From 376c352a37ce5a68b721406dc7e77ac4b6cf483d Mon Sep 17 00:00:00 2001
|
||||
From: Mihai Maruseac <mihaimaruseac@google.com>
|
||||
Date: Wed, 5 May 2021 14:34:54 -0700
|
||||
Subject: [PATCH] Don't do any work if output tensor is null (prevent div by 0)
|
||||
|
||||
PiperOrigin-RevId: 372208700
|
||||
Change-Id: Iea6b6293e887ade8538facfdb50fb931e17f511e
|
||||
---
|
||||
tensorflow/core/kernels/maxpooling_op.cc | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
diff --git a/tensorflow/core/kernels/maxpooling_op.cc b/tensorflow/core/kernels/maxpooling_op.cc
|
||||
index 003d2e94b99cd..ceb6694ed665d 100644
|
||||
--- a/tensorflow/core/kernels/maxpooling_op.cc
|
||||
+++ b/tensorflow/core/kernels/maxpooling_op.cc
|
||||
@@ -1088,6 +1088,8 @@ class MaxPoolingGradWithArgmaxOp : public OpKernel {
|
||||
OP_REQUIRES_OK(context, context->forward_input_or_allocate_output(
|
||||
{0}, 0, out_shape, &grad_out));
|
||||
|
||||
+ if (out_shape.num_elements() == 0) return; // nothing to be done
|
||||
+
|
||||
LaunchMaxPoolingGradWithArgmax<Device, T>::launch(
|
||||
context, params, grad_in, argmax, grad_out, include_batch_in_index_);
|
||||
}
|
||||
@ -1,35 +0,0 @@
|
||||
From a3d9f9be9ac2296615644061b40cefcee341dcc4 Mon Sep 17 00:00:00 2001
|
||||
From: Mihai Maruseac <mihaimaruseac@google.com>
|
||||
Date: Wed, 5 May 2021 15:20:14 -0700
|
||||
Subject: [PATCH] Add missing validation to pooling_ops_3d
|
||||
|
||||
PiperOrigin-RevId: 372218727
|
||||
Change-Id: I6b9ed4266aa7286c02f1f230d7bea922c1be547e
|
||||
---
|
||||
tensorflow/core/kernels/pooling_ops_3d.cc | 13 +++++++++++++
|
||||
1 file changed, 13 insertions(+)
|
||||
|
||||
diff --git a/tensorflow/core/kernels/pooling_ops_3d.cc b/tensorflow/core/kernels/pooling_ops_3d.cc
|
||||
index 1114e6931ecf9..7d133b66a1ebd 100644
|
||||
--- a/tensorflow/core/kernels/pooling_ops_3d.cc
|
||||
+++ b/tensorflow/core/kernels/pooling_ops_3d.cc
|
||||
@@ -698,6 +698,19 @@ class MaxPooling3dGradGradOp : public OpKernel {
|
||||
OP_REQUIRES_OK(context, context->forward_input_or_allocate_output(
|
||||
{2}, 0, tensor_out.shape(), &output));
|
||||
|
||||
+ // Given access patterns in LaunchMaxPooling3dGradGradOp, these tensors must
|
||||
+ // have elements.
|
||||
+ OP_REQUIRES(context, tensor_in.NumElements() > 0,
|
||||
+ errors::InvalidArgument("received empty tensor tensor_in: ",
|
||||
+ tensor_in.DebugString()));
|
||||
+ OP_REQUIRES(context, tensor_out.NumElements() > 0,
|
||||
+ errors::InvalidArgument("received empty tensor tensor_out: ",
|
||||
+ tensor_out.DebugString()));
|
||||
+ OP_REQUIRES(
|
||||
+ context, out_grad_backprop.NumElements() > 0,
|
||||
+ errors::InvalidArgument("received empty tensor out_grad_backprop: ",
|
||||
+ out_grad_backprop.DebugString()));
|
||||
+
|
||||
LaunchMaxPooling3dGradGradOp<Device, T>::launch(
|
||||
context, params, tensor_in, tensor_out, out_grad_backprop, output);
|
||||
}
|
||||
@ -1,26 +0,0 @@
|
||||
From ecf768cbe50cedc0a45ce1ee223146a3d3d26d23 Mon Sep 17 00:00:00 2001
|
||||
From: Mihai Maruseac <mihaimaruseac@google.com>
|
||||
Date: Wed, 5 May 2021 12:07:57 -0700
|
||||
Subject: [PATCH] Add missing validations to reverse_sequence_op
|
||||
|
||||
PiperOrigin-RevId: 372178683
|
||||
Change-Id: Iac97ebab5b342f1262c77a7d9bcb4267b305ce5b
|
||||
---
|
||||
tensorflow/core/kernels/reverse_sequence_op.cc | 4 ++++
|
||||
1 file changed, 4 insertions(+)
|
||||
|
||||
diff --git a/tensorflow/core/kernels/reverse_sequence_op.cc b/tensorflow/core/kernels/reverse_sequence_op.cc
|
||||
index b5b62bc76ca52..1282deb26e8cd 100644
|
||||
--- a/tensorflow/core/kernels/reverse_sequence_op.cc
|
||||
+++ b/tensorflow/core/kernels/reverse_sequence_op.cc
|
||||
@@ -115,6 +115,10 @@ class ReverseSequenceOp : public OpKernel {
|
||||
: OpKernel(context) {
|
||||
OP_REQUIRES_OK(context, context->GetAttr("batch_dim", &batch_dim_));
|
||||
OP_REQUIRES_OK(context, context->GetAttr("seq_dim", &seq_dim_));
|
||||
+ OP_REQUIRES(context, batch_dim_ >= 0,
|
||||
+ errors::InvalidArgument("Invalid batch_dim ", batch_dim_));
|
||||
+ OP_REQUIRES(context, seq_dim_ >= 0,
|
||||
+ errors::InvalidArgument("Invalid seq_dim ", seq_dim_));
|
||||
}
|
||||
|
||||
void Compute(OpKernelContext* context) override {
|
||||
@ -1,41 +0,0 @@
|
||||
From 63c6a29d0f2d692b247f7bf81f8732d6442fad09 Mon Sep 17 00:00:00 2001
|
||||
From: Mihai Maruseac <mihaimaruseac@google.com>
|
||||
Date: Wed, 5 May 2021 18:07:02 -0700
|
||||
Subject: [PATCH] Add missing validation, prevent heap OOB
|
||||
|
||||
PiperOrigin-RevId: 372246723
|
||||
Change-Id: I1a454a643810e77d7d14821b342098c56a09fbbf
|
||||
---
|
||||
tensorflow/core/kernels/pooling_ops_3d.cc | 12 ++++++++++++
|
||||
1 file changed, 12 insertions(+)
|
||||
|
||||
diff --git a/tensorflow/core/kernels/pooling_ops_3d.cc b/tensorflow/core/kernels/pooling_ops_3d.cc
|
||||
index 7d133b66a1ebd..9da2d62b0a21d 100644
|
||||
--- a/tensorflow/core/kernels/pooling_ops_3d.cc
|
||||
+++ b/tensorflow/core/kernels/pooling_ops_3d.cc
|
||||
@@ -693,6 +693,7 @@ class MaxPooling3dGradGradOp : public OpKernel {
|
||||
|
||||
Pool3dParameters params{context, ksize_, stride_,
|
||||
padding_, data_format_, tensor_in.shape()};
|
||||
+ if (!context->status().ok()) return; // params is invalid
|
||||
|
||||
Tensor* output = nullptr;
|
||||
OP_REQUIRES_OK(context, context->forward_input_or_allocate_output(
|
||||
@@ -710,6 +711,17 @@ class MaxPooling3dGradGradOp : public OpKernel {
|
||||
context, out_grad_backprop.NumElements() > 0,
|
||||
errors::InvalidArgument("received empty tensor out_grad_backprop: ",
|
||||
out_grad_backprop.DebugString()));
|
||||
+ OP_REQUIRES(context,
|
||||
+ tensor_in.NumElements() == out_grad_backprop.NumElements(),
|
||||
+ errors::InvalidArgument("tensor_in and out_grad_backprop must "
|
||||
+ "have same number of elements, got <",
|
||||
+ tensor_in.DebugString(), "> and <",
|
||||
+ out_grad_backprop.DebugString(), ">"));
|
||||
+ OP_REQUIRES(
|
||||
+ context, tensor_out.NumElements() == output->NumElements(),
|
||||
+ errors::InvalidArgument(
|
||||
+ "tensor_out and output must have same number of elements, got <",
|
||||
+ tensor_out.DebugString(), "> and <", output->DebugString(), ">"));
|
||||
|
||||
LaunchMaxPooling3dGradGradOp<Device, T>::launch(
|
||||
context, params, tensor_in, tensor_out, out_grad_backprop, output);
|
||||
@ -1,35 +0,0 @@
|
||||
From 6fc9141f42f6a72180ecd24021c3e6b36165fe0d Mon Sep 17 00:00:00 2001
|
||||
From: Mihai Maruseac <mihaimaruseac@google.com>
|
||||
Date: Thu, 6 May 2021 09:51:26 -0700
|
||||
Subject: [PATCH] Fix assertion failure in pooling_ops_3d
|
||||
|
||||
PiperOrigin-RevId: 372364504
|
||||
Change-Id: Iecde4fe26b47a8fa935d6e2611b5585ed5777781
|
||||
---
|
||||
tensorflow/core/kernels/pooling_ops_3d.cc | 13 +++++++++++++
|
||||
1 file changed, 13 insertions(+)
|
||||
|
||||
diff --git a/tensorflow/core/kernels/pooling_ops_3d.cc b/tensorflow/core/kernels/pooling_ops_3d.cc
|
||||
index 9da2d62b0a21d..56a55bc2ec87b 100644
|
||||
--- a/tensorflow/core/kernels/pooling_ops_3d.cc
|
||||
+++ b/tensorflow/core/kernels/pooling_ops_3d.cc
|
||||
@@ -383,6 +383,19 @@ struct LaunchAvgPooling3dGradOp<CPUDevice, T> {
|
||||
const std::array<int64, 3>& output_shape,
|
||||
const std::array<int64, 3>& padding,
|
||||
TensorFormat data_format, Tensor* output) {
|
||||
+ OP_REQUIRES(
|
||||
+ context, tensor_in_shape.dim_size(0) == out_backprop.dim_size(0),
|
||||
+ errors::InvalidArgument(
|
||||
+ "Expected first dimension of tensor_in_shape and "
|
||||
+ "out_backprop to match, got ",
|
||||
+ tensor_in_shape.dim_size(0), " and ", out_backprop.dim_size(0)));
|
||||
+ OP_REQUIRES(
|
||||
+ context, tensor_in_shape.dim_size(4) == out_backprop.dim_size(4),
|
||||
+ errors::InvalidArgument(
|
||||
+ "Expected last dimension of tensor_in_shape and "
|
||||
+ "out_backprop to match, got ",
|
||||
+ tensor_in_shape.dim_size(4), " and ", out_backprop.dim_size(4)));
|
||||
+
|
||||
output->flat<T>().setZero();
|
||||
std::array<int64, 3> input_size = {{tensor_in_shape.dim_size(3),
|
||||
tensor_in_shape.dim_size(2),
|
||||
@ -1,35 +0,0 @@
|
||||
From 12c727cee857fa19be717f336943d95fca4ffe4f Mon Sep 17 00:00:00 2001
|
||||
From: Mihai Maruseac <mihaimaruseac@google.com>
|
||||
Date: Thu, 6 May 2021 14:02:47 -0700
|
||||
Subject: [PATCH] Validate inputs of `FractionalAvgPoolGrad`.
|
||||
|
||||
PiperOrigin-RevId: 372420640
|
||||
Change-Id: Icc583928e6cdc3062e12498e4d2337a8fe3da016
|
||||
---
|
||||
tensorflow/core/kernels/fractional_avg_pool_op.cc | 13 +++++++++++++
|
||||
1 file changed, 13 insertions(+)
|
||||
|
||||
diff --git a/tensorflow/core/kernels/fractional_avg_pool_op.cc b/tensorflow/core/kernels/fractional_avg_pool_op.cc
|
||||
index b8a5083e5340f..0452638a06679 100644
|
||||
--- a/tensorflow/core/kernels/fractional_avg_pool_op.cc
|
||||
+++ b/tensorflow/core/kernels/fractional_avg_pool_op.cc
|
||||
@@ -250,6 +250,19 @@ class FractionalAvgPoolGradOp : public OpKernel {
|
||||
const int64 out_cols = out_backprop.dim_size(2);
|
||||
const int64 out_depth = out_backprop.dim_size(3);
|
||||
|
||||
+ OP_REQUIRES(context, row_seq_tensor.NumElements() > out_rows,
|
||||
+ errors::InvalidArgument("Given out_backprop shape ",
|
||||
+ out_backprop.shape().DebugString(),
|
||||
+ ", row_seq_tensor must have at least ",
|
||||
+ out_rows + 1, " elements, but got ",
|
||||
+ row_seq_tensor.NumElements()));
|
||||
+ OP_REQUIRES(context, col_seq_tensor.NumElements() > out_cols,
|
||||
+ errors::InvalidArgument("Given out_backprop shape ",
|
||||
+ out_backprop.shape().DebugString(),
|
||||
+ ", col_seq_tensor must have at least ",
|
||||
+ out_cols + 1, " elements, but got ",
|
||||
+ col_seq_tensor.NumElements()));
|
||||
+
|
||||
auto row_seq_tensor_flat = row_seq_tensor.flat<int64>();
|
||||
auto col_seq_tensor_flat = col_seq_tensor.flat<int64>();
|
||||
auto orig_input_tensor_shape_flat = orig_input_tensor_shape.flat<int64>();
|
||||
@ -1,26 +0,0 @@
|
||||
From a74768f8e4efbda4def9f16ee7e13cf3922ac5f7 Mon Sep 17 00:00:00 2001
|
||||
From: Mihai Maruseac <mihaimaruseac@google.com>
|
||||
Date: Thu, 6 May 2021 14:24:09 -0700
|
||||
Subject: [PATCH] Prevent heap OOB error in `MaxPoolGrad`
|
||||
|
||||
PiperOrigin-RevId: 372424854
|
||||
Change-Id: Idac0f23867ad8b0601cafbaaa52d5e64269e63a7
|
||||
---
|
||||
tensorflow/core/kernels/maxpooling_op.cc | 4 +++-
|
||||
1 file changed, 3 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/tensorflow/core/kernels/maxpooling_op.cc b/tensorflow/core/kernels/maxpooling_op.cc
|
||||
index ceb6694ed665d..01f303eb26980 100644
|
||||
--- a/tensorflow/core/kernels/maxpooling_op.cc
|
||||
+++ b/tensorflow/core/kernels/maxpooling_op.cc
|
||||
@@ -199,7 +199,9 @@ static void SpatialMaxPoolWithArgMaxHelper(
|
||||
// CHECK(input_backprop_index >= in_start && input_backprop_index <
|
||||
// in_end)
|
||||
FastBoundsCheck(input_backprop_index - in_start, in_end - in_start);
|
||||
- input_backprop_flat(input_backprop_index) += out_backprop_flat(index);
|
||||
+ if (index < out_backprop.NumElements()) {
|
||||
+ input_backprop_flat(input_backprop_index) += out_backprop_flat(index);
|
||||
+ }
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -1,36 +0,0 @@
|
||||
From 32fdcbff9d06d010d908fcc4bd4b36eb3ce15925 Mon Sep 17 00:00:00 2001
|
||||
From: Mihai Maruseac <mihaimaruseac@google.com>
|
||||
Date: Wed, 5 May 2021 22:39:29 -0700
|
||||
Subject: [PATCH] Validate arguments of `FractionalMaxPoolGrad`
|
||||
|
||||
PiperOrigin-RevId: 372274982
|
||||
Change-Id: If46b0c442efa4eaef635ce6a476717060420122c
|
||||
---
|
||||
tensorflow/core/kernels/fractional_max_pool_op.cc | 14 ++++++++++++++
|
||||
1 file changed, 14 insertions(+)
|
||||
|
||||
diff --git a/tensorflow/core/kernels/fractional_max_pool_op.cc b/tensorflow/core/kernels/fractional_max_pool_op.cc
|
||||
index 619a3507ce415..1a2a783d135c5 100644
|
||||
--- a/tensorflow/core/kernels/fractional_max_pool_op.cc
|
||||
+++ b/tensorflow/core/kernels/fractional_max_pool_op.cc
|
||||
@@ -235,6 +235,20 @@ class FractionalMaxPoolGradOp : public OpKernel {
|
||||
|
||||
// Just to make it similar to FractionalMaxPoolOp.
|
||||
constexpr int tensor_in_and_out_dims = 4;
|
||||
+ OP_REQUIRES(
|
||||
+ context, tensor_in.dims() == tensor_in_and_out_dims,
|
||||
+ errors::InvalidArgument("orig_input should be a tensor of rank 4, got ",
|
||||
+ tensor_in.DebugString()));
|
||||
+ OP_REQUIRES(context, tensor_in.NumElements() > 0,
|
||||
+ errors::InvalidArgument("orig_input must not be empty, got ",
|
||||
+ tensor_in.DebugString()));
|
||||
+ OP_REQUIRES(context, tensor_out.dims() == tensor_in_and_out_dims,
|
||||
+ errors::InvalidArgument(
|
||||
+ "orig_output should be a tensor of rank 4, got ",
|
||||
+ tensor_out.DebugString()));
|
||||
+ OP_REQUIRES(context, tensor_out.NumElements() > 0,
|
||||
+ errors::InvalidArgument("orig_output must not be empty, got ",
|
||||
+ tensor_out.DebugString()));
|
||||
std::vector<int64> input_size(tensor_in_and_out_dims);
|
||||
std::vector<int64> output_size(tensor_in_and_out_dims);
|
||||
for (int i = 0; i < tensor_in_and_out_dims; ++i) {
|
||||
@ -1,25 +0,0 @@
|
||||
From b1b323042264740c398140da32e93fb9c2c9f33e Mon Sep 17 00:00:00 2001
|
||||
From: Mihai Maruseac <mihaimaruseac@google.com>
|
||||
Date: Thu, 6 May 2021 14:51:41 -0700
|
||||
Subject: [PATCH] Fix SEGV in CTC ops
|
||||
|
||||
PiperOrigin-RevId: 372430279
|
||||
Change-Id: I7ec2ad9d6f4d0980c33de45d27c6b17df5c6e26f
|
||||
---
|
||||
tensorflow/core/kernels/ctc_decoder_ops.cc | 3 +++
|
||||
1 file changed, 3 insertions(+)
|
||||
|
||||
diff --git a/tensorflow/core/kernels/ctc_decoder_ops.cc b/tensorflow/core/kernels/ctc_decoder_ops.cc
|
||||
index 22681f97437f0..9efdac60e369c 100644
|
||||
--- a/tensorflow/core/kernels/ctc_decoder_ops.cc
|
||||
+++ b/tensorflow/core/kernels/ctc_decoder_ops.cc
|
||||
@@ -70,6 +70,9 @@ class CTCDecodeHelper {
|
||||
if (inputs_shape.dims() != 3) {
|
||||
return errors::InvalidArgument("inputs is not a 3-Tensor");
|
||||
}
|
||||
+ if (inputs_shape.num_elements() == 0) {
|
||||
+ return errors::InvalidArgument("inputs must not be empty");
|
||||
+ }
|
||||
|
||||
const int64 max_time = inputs_shape.dim_size(0);
|
||||
const int64 batch_size = inputs_shape.dim_size(1);
|
||||
@ -1,36 +0,0 @@
|
||||
From 5899741d0421391ca878da47907b1452f06aaf1b Mon Sep 17 00:00:00 2001
|
||||
From: Mihai Maruseac <mihaimaruseac@google.com>
|
||||
Date: Thu, 6 May 2021 15:31:05 -0700
|
||||
Subject: [PATCH] Fix heap OOB read in dequantize op.
|
||||
|
||||
Also fixes SEGV in same op
|
||||
|
||||
PiperOrigin-RevId: 372437896
|
||||
Change-Id: I135e94d360c2a1ce374c10f7e0fed1af603dbc02
|
||||
---
|
||||
tensorflow/core/kernels/dequantize_op.cc | 12 ++++++++++++
|
||||
1 file changed, 12 insertions(+)
|
||||
|
||||
diff --git a/tensorflow/core/kernels/dequantize_op.cc b/tensorflow/core/kernels/dequantize_op.cc
|
||||
index 5393a677db242..7a90e0c340b09 100644
|
||||
--- a/tensorflow/core/kernels/dequantize_op.cc
|
||||
+++ b/tensorflow/core/kernels/dequantize_op.cc
|
||||
@@ -98,6 +98,18 @@ class DequantizeOp : public OpKernel {
|
||||
if (axis_ > -1) {
|
||||
num_slices = input.dim_size(axis_);
|
||||
}
|
||||
+ OP_REQUIRES(ctx, input_min_tensor.NumElements() == num_slices,
|
||||
+ errors::InvalidArgument(
|
||||
+ "input_min_tensor must have as many elements as input on "
|
||||
+ "the dequantization axis (",
|
||||
+ axis_, "), got ", input_min_tensor.NumElements(),
|
||||
+ ", expected ", num_slices));
|
||||
+ OP_REQUIRES(ctx, input_max_tensor.NumElements() == num_slices,
|
||||
+ errors::InvalidArgument(
|
||||
+ "input_max_tensor must have as many elements as input on "
|
||||
+ "the dequantization axis (",
|
||||
+ axis_, "), got ", input_max_tensor.NumElements(),
|
||||
+ ", expected ", num_slices));
|
||||
|
||||
Tensor* output = nullptr;
|
||||
OP_REQUIRES_OK(ctx, ctx->allocate_output(0, input.shape(), &output));
|
||||
@ -1,59 +0,0 @@
|
||||
From 6972f9dfe325636b3db4e0bc517ee22a159365c0 Mon Sep 17 00:00:00 2001
|
||||
From: Mihai Maruseac <mihaimaruseac@google.com>
|
||||
Date: Thu, 6 May 2021 17:45:51 -0700
|
||||
Subject: [PATCH] Add missing valuidation to FusedBatchNorm.
|
||||
|
||||
---
|
||||
.../core/kernels/fused_batch_norm_op.cc | 29 ++++++++++++++++++-
|
||||
1 file changed, 28 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/tensorflow/core/kernels/fused_batch_norm_op.cc b/tensorflow/core/kernels/fused_batch_norm_op.cc
|
||||
index 59470c8a..bd5dab36 100644
|
||||
--- a/tensorflow/core/kernels/fused_batch_norm_op.cc
|
||||
+++ b/tensorflow/core/kernels/fused_batch_norm_op.cc
|
||||
@@ -1267,6 +1267,33 @@ class FusedBatchNormOpBase : public OpKernel {
|
||||
context, estimated_variance.dims() == 1,
|
||||
errors::InvalidArgument("estimated_variance must be 1-dimensional",
|
||||
estimated_variance.shape().DebugString()));
|
||||
+
|
||||
+ const auto num_channels = GetTensorDim(x, tensor_format_, 'C');
|
||||
+ OP_REQUIRES(
|
||||
+ context, scale.NumElements() == num_channels,
|
||||
+ errors::InvalidArgument("scale must have the same number of elements "
|
||||
+ "as the channels of x, got ",
|
||||
+ scale.NumElements(), " and ", num_channels));
|
||||
+ OP_REQUIRES(
|
||||
+ context, offset.NumElements() == num_channels,
|
||||
+ errors::InvalidArgument("offset must have the same number of elements "
|
||||
+ "as the channels of x, got ",
|
||||
+ offset.NumElements(), " and ", num_channels));
|
||||
+ if (estimated_mean.NumElements() != 0) {
|
||||
+ OP_REQUIRES(context, estimated_mean.NumElements() == num_channels,
|
||||
+ errors::InvalidArgument(
|
||||
+ "mean must be empty or have the same number of "
|
||||
+ "elements as the channels of x, got ",
|
||||
+ estimated_mean.NumElements(), " and ",num_channels));
|
||||
+ }
|
||||
+ if (estimated_variance.NumElements() != 0) {
|
||||
+ OP_REQUIRES(context, estimated_variance.NumElements() == num_channels,
|
||||
+ errors::InvalidArgument(
|
||||
+ "variance must be empty or have the same number of "
|
||||
+ "elements as the channels of x, got ",
|
||||
+ estimated_variance.NumElements(), " and ", num_channels));
|
||||
+ }
|
||||
+
|
||||
if (has_side_input_) {
|
||||
OP_REQUIRES(context, side_input->shape() == x.shape(),
|
||||
errors::InvalidArgument(
|
||||
@@ -1279,7 +1306,7 @@ class FusedBatchNormOpBase : public OpKernel {
|
||||
// NOTE(ezhulenev): This requirement is coming from implementation
|
||||
// details of cudnnBatchNormalizationForwardTrainingEx.
|
||||
OP_REQUIRES(
|
||||
- context, !is_training_ || x.dim_size(3) % 4 == 0,
|
||||
+ context, !is_training_ || num_channels % 4 == 0,
|
||||
errors::InvalidArgument("FusedBatchNorm with activation requires "
|
||||
"channel dimension to be a multiple of 4."));
|
||||
}
|
||||
--
|
||||
2.23.0
|
||||
|
||||
@ -1,27 +0,0 @@
|
||||
From 49847ae69a4e1a97ae7f2db5e217c77721e37948 Mon Sep 17 00:00:00 2001
|
||||
From: Mihai Maruseac <mihaimaruseac@google.com>
|
||||
Date: Tue, 27 Apr 2021 15:37:08 -0700
|
||||
Subject: [PATCH] Fix division by zero in TFLite padding.
|
||||
|
||||
PiperOrigin-RevId: 370777494
|
||||
Change-Id: Ic1331e4a1603b9e4c8aa183012a6c8237410aa0f
|
||||
---
|
||||
tensorflow/lite/kernels/padding.h | 5 +++++
|
||||
1 file changed, 5 insertions(+)
|
||||
|
||||
diff --git a/tensorflow/lite/kernels/padding.h b/tensorflow/lite/kernels/padding.h
|
||||
index 85950eaf34bb9..d9cca3ea13515 100644
|
||||
--- a/tensorflow/lite/kernels/padding.h
|
||||
+++ b/tensorflow/lite/kernels/padding.h
|
||||
@@ -44,6 +44,11 @@ inline int ComputePaddingWithOffset(int stride, int dilation_rate, int in_size,
|
||||
inline int ComputeOutSize(TfLitePadding padding, int image_size,
|
||||
int filter_size, int stride, int dilation_rate = 1) {
|
||||
int effective_filter_size = (filter_size - 1) * dilation_rate + 1;
|
||||
+
|
||||
+ // TODO(b/186448822): This uses 0 since the function has no other way to
|
||||
+ // report error case
|
||||
+ if (stride == 0) return 0;
|
||||
+
|
||||
switch (padding) {
|
||||
case kTfLitePaddingSame:
|
||||
return (image_size + stride - 1) / stride;
|
||||
@ -1,51 +0,0 @@
|
||||
From 5f7975d09eac0f10ed8a17dbb6f5964977725adc Mon Sep 17 00:00:00 2001
|
||||
From: Mihai Maruseac <mihaimaruseac@google.com>
|
||||
Date: Tue, 27 Apr 2021 17:45:43 -0700
|
||||
Subject: [PATCH] Prevent another div by 0 in optimized pooling implementations
|
||||
TFLite
|
||||
|
||||
PiperOrigin-RevId: 370800091
|
||||
Change-Id: I2119352f57fb5ca4f2051e0e2d749403304a979b
|
||||
---
|
||||
tensorflow/lite/kernels/pooling.cc | 4 ++++
|
||||
tensorflow/lite/kernels/pooling_test.cc | 13 +++++++++++++
|
||||
2 files changed, 17 insertions(+)
|
||||
|
||||
diff --git a/tensorflow/lite/kernels/pooling.cc b/tensorflow/lite/kernels/pooling.cc
|
||||
index 1ae3d207b135e..474bd3825f4ff 100644
|
||||
--- a/tensorflow/lite/kernels/pooling.cc
|
||||
+++ b/tensorflow/lite/kernels/pooling.cc
|
||||
@@ -87,6 +87,10 @@ TfLiteStatus GenericPrepare(TfLiteContext* context, TfLiteNode* node) {
|
||||
auto padding = params->padding;
|
||||
int out_width, out_height;
|
||||
|
||||
+ // Prevent division by 0 in optimized pooling implementations
|
||||
+ TF_LITE_ENSURE(context, params->stride_height > 0);
|
||||
+ TF_LITE_ENSURE(context, params->stride_width > 0);
|
||||
+
|
||||
data->padding = ComputePaddingHeightWidth(
|
||||
params->stride_height, params->stride_width, 1, 1, height, width,
|
||||
params->filter_height, params->filter_width, padding, &out_height,
|
||||
diff --git a/tensorflow/lite/kernels/pooling_test.cc b/tensorflow/lite/kernels/pooling_test.cc
|
||||
index e614fedccfd50..108195388141d 100644
|
||||
--- a/tensorflow/lite/kernels/pooling_test.cc
|
||||
+++ b/tensorflow/lite/kernels/pooling_test.cc
|
||||
@@ -1151,5 +1151,18 @@ TEST(FloatPoolingOpTest, L2PoolPaddingValidSlide1) {
|
||||
EXPECT_THAT(m.GetOutput(), ElementsAreArray({3.5, 6.0, 6.5}));
|
||||
}
|
||||
|
||||
+#ifdef GTEST_HAS_DEATH_TEST
|
||||
+TEST(FloatPoolingOpTest, MaxPoolWithZeroStride) {
|
||||
+ EXPECT_DEATH(
|
||||
+ FloatPoolingOpModel m(BuiltinOperator_MAX_POOL_2D,
|
||||
+ /*input=*/{TensorType_FLOAT32, {1, 2, 4, 1}},
|
||||
+ /*filter_width=*/2, /*filter_height=*/2,
|
||||
+ /*output=*/{TensorType_FLOAT32, {}},
|
||||
+ /*padding=*/Padding_VALID,
|
||||
+ /*stride_w=*/0, /*stride_h=*/0),
|
||||
+ "Cannot allocate tensors");
|
||||
+}
|
||||
+#endif
|
||||
+
|
||||
} // namespace
|
||||
} // namespace tflite
|
||||
@ -1,23 +0,0 @@
|
||||
From 0d45ea1ca641b21b73bcf9c00e0179cda284e7e7 Mon Sep 17 00:00:00 2001
|
||||
From: Mihai Maruseac <mihaimaruseac@google.com>
|
||||
Date: Tue, 27 Apr 2021 17:45:57 -0700
|
||||
Subject: [PATCH] Prevent one more div by 0 in TFLite
|
||||
|
||||
PiperOrigin-RevId: 370800114
|
||||
Change-Id: I6b956aeb8c458cc6f514408d2e89ffacfe249e57
|
||||
---
|
||||
tensorflow/lite/kernels/space_to_depth.cc | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/tensorflow/lite/kernels/space_to_depth.cc b/tensorflow/lite/kernels/space_to_depth.cc
|
||||
index 4db7440b57e60..35a0fe1c26e20 100644
|
||||
--- a/tensorflow/lite/kernels/space_to_depth.cc
|
||||
+++ b/tensorflow/lite/kernels/space_to_depth.cc
|
||||
@@ -61,6 +61,7 @@ TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) {
|
||||
TF_LITE_ENSURE_TYPES_EQ(context, input->type, output->type);
|
||||
|
||||
const int block_size = params->block_size;
|
||||
+ TF_LITE_ENSURE(context, block_size > 0);
|
||||
const int input_height = input->dims->data[1];
|
||||
const int input_width = input->dims->data[2];
|
||||
int output_height = input_height / block_size;
|
||||
@ -1,26 +0,0 @@
|
||||
From 801c1c6be5324219689c98e1bd3e0ca365ee834d Mon Sep 17 00:00:00 2001
|
||||
From: Mihai Maruseac <mihaimaruseac@google.com>
|
||||
Date: Tue, 27 Apr 2021 17:46:25 -0700
|
||||
Subject: [PATCH] Fix another division by 0 in TFLite
|
||||
|
||||
PiperOrigin-RevId: 370800181
|
||||
Change-Id: I924809166a6131f5075e6d45c455106538d755f9
|
||||
---
|
||||
tensorflow/lite/kernels/transpose_conv.cc | 4 ++++
|
||||
1 file changed, 4 insertions(+)
|
||||
|
||||
diff --git a/tensorflow/lite/kernels/transpose_conv.cc b/tensorflow/lite/kernels/transpose_conv.cc
|
||||
index 497edac5762dc..cf9d53fb3b6ee 100644
|
||||
--- a/tensorflow/lite/kernels/transpose_conv.cc
|
||||
+++ b/tensorflow/lite/kernels/transpose_conv.cc
|
||||
@@ -591,6 +591,10 @@ TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) {
|
||||
const auto* params =
|
||||
reinterpret_cast<TfLiteTransposeConvParams*>(node->builtin_data);
|
||||
|
||||
+ // Prevent divisions by 0
|
||||
+ TF_LITE_ENSURE(context, params->stride_height > 0);
|
||||
+ TF_LITE_ENSURE(context, params->stride_width > 0);
|
||||
+
|
||||
// Resize any deferred dynamic tensors
|
||||
if (IsDynamicTensor(output)) {
|
||||
TF_LITE_ENSURE_OK(context, ResizeTensor(context, output_shape, output));
|
||||
@ -1,26 +0,0 @@
|
||||
From 8e45822aa0b9f5df4b4c64f221e64dc930a70a9d Mon Sep 17 00:00:00 2001
|
||||
From: Mihai Maruseac <mihaimaruseac@google.com>
|
||||
Date: Tue, 27 Apr 2021 17:46:10 -0700
|
||||
Subject: [PATCH] Handle one more division by 0 in TFLite.
|
||||
|
||||
---
|
||||
tensorflow/lite/kernels/gather_nd.cc | 3 +++
|
||||
1 file changed, 3 insertions(+)
|
||||
|
||||
diff --git a/tensorflow/lite/kernels/gather_nd.cc b/tensorflow/lite/kernels/gather_nd.cc
|
||||
index 288f7deb..5c9990a0 100644
|
||||
--- a/tensorflow/lite/kernels/gather_nd.cc
|
||||
+++ b/tensorflow/lite/kernels/gather_nd.cc
|
||||
@@ -155,6 +155,9 @@ TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) {
|
||||
const TfLiteTensor* indices = GetInput(context, node, kIndices);
|
||||
TfLiteTensor* output = GetOutput(context, node, kOutputTensor);
|
||||
|
||||
+ // Prevent division by 0 in the helper
|
||||
+ TF_LITE_ENSURE(context, NumElements(params) > 0);
|
||||
+
|
||||
switch (indices->type) {
|
||||
case kTfLiteInt32:
|
||||
return EvalGatherNd<int32_t>(context, params, indices, output);
|
||||
--
|
||||
2.23.0
|
||||
|
||||
@ -1,82 +0,0 @@
|
||||
From 953f28dca13c92839ba389c055587cfe6c723578 Mon Sep 17 00:00:00 2001
|
||||
From: Mihai Maruseac <mihaimaruseac@google.com>
|
||||
Date: Tue, 27 Apr 2021 17:46:38 -0700
|
||||
Subject: [PATCH] Prevent a null pointer exception in TFLite
|
||||
|
||||
PiperOrigin-RevId: 370800206
|
||||
Change-Id: Idd437ebce4ff224120d8eefc1c14c062173b71d6
|
||||
---
|
||||
tensorflow/lite/kernels/maximum_minimum.cc | 60 +++++++++++-----------
|
||||
1 file changed, 31 insertions(+), 29 deletions(-)
|
||||
|
||||
diff --git a/tensorflow/lite/kernels/maximum_minimum.cc b/tensorflow/lite/kernels/maximum_minimum.cc
|
||||
index 777e51442f120..176e020a5a8e5 100644
|
||||
--- a/tensorflow/lite/kernels/maximum_minimum.cc
|
||||
+++ b/tensorflow/lite/kernels/maximum_minimum.cc
|
||||
@@ -157,35 +157,37 @@ template <KernelType kernel_type, typename OpType>
|
||||
TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) {
|
||||
OpContext op_context(context, node);
|
||||
|
||||
- switch (op_context.output->type) {
|
||||
- case kTfLiteFloat32:
|
||||
- TFLiteOperation<kernel_type, float, OpType>(context, node, op_context);
|
||||
- break;
|
||||
- case kTfLiteUInt8:
|
||||
- TFLiteOperation<kernel_type, uint8_t, OpType>(context, node,
|
||||
- op_context);
|
||||
- break;
|
||||
- case kTfLiteInt8:
|
||||
- TFLiteOperation<kernel_type, int8_t, OpType>(context, node, op_context);
|
||||
- break;
|
||||
- case kTfLiteInt32:
|
||||
- TFLiteOperation<kernel_type, int32_t, OpType>(context, node,
|
||||
- op_context);
|
||||
- break;
|
||||
- case kTfLiteInt64:
|
||||
- TFLiteOperation<kernel_type, int64_t, OpType>(context, node,
|
||||
- op_context);
|
||||
- break;
|
||||
- case kTfLiteInt16:
|
||||
- TFLiteOperation<kernel_type, int16_t, OpType>(context, node,
|
||||
- op_context);
|
||||
- break;
|
||||
- default:
|
||||
- context->ReportError(context,
|
||||
- "Type %d is currently not supported by Maximum.",
|
||||
- op_context.output->type);
|
||||
- return kTfLiteError;
|
||||
- }
|
||||
+ // If inputs have no element, shortcircuit.
|
||||
+ if (NumElements(op_context.input1) == 0 ||
|
||||
+ NumElements(op_context.input2) == 0) {
|
||||
+ return kTfLiteOk;
|
||||
+ }
|
||||
+
|
||||
+ switch (op_context.output->type) {
|
||||
+ case kTfLiteFloat32:
|
||||
+ TFLiteOperation<kernel_type, float, OpType>(context, node, op_context);
|
||||
+ break;
|
||||
+ case kTfLiteUInt8:
|
||||
+ TFLiteOperation<kernel_type, uint8_t, OpType>(context, node, op_context);
|
||||
+ break;
|
||||
+ case kTfLiteInt8:
|
||||
+ TFLiteOperation<kernel_type, int8_t, OpType>(context, node, op_context);
|
||||
+ break;
|
||||
+ case kTfLiteInt32:
|
||||
+ TFLiteOperation<kernel_type, int32_t, OpType>(context, node, op_context);
|
||||
+ break;
|
||||
+ case kTfLiteInt64:
|
||||
+ TFLiteOperation<kernel_type, int64_t, OpType>(context, node, op_context);
|
||||
+ break;
|
||||
+ case kTfLiteInt16:
|
||||
+ TFLiteOperation<kernel_type, int16_t, OpType>(context, node, op_context);
|
||||
+ break;
|
||||
+ default:
|
||||
+ context->ReportError(context,
|
||||
+ "Type %d is currently not supported by Maximum.",
|
||||
+ op_context.output->type);
|
||||
+ return kTfLiteError;
|
||||
+ }
|
||||
return kTfLiteOk;
|
||||
}
|
||||
|
||||
@ -1,24 +0,0 @@
|
||||
From 9c1dc920d8ffb4893d6c9d27d1f039607b326743 Mon Sep 17 00:00:00 2001
|
||||
From: Mihai Maruseac <mihaimaruseac@google.com>
|
||||
Date: Tue, 27 Apr 2021 17:47:46 -0700
|
||||
Subject: [PATCH] Prevent infinite loop/stack overflow in TFLite `while` op.
|
||||
|
||||
PiperOrigin-RevId: 370800333
|
||||
Change-Id: I6a2e4ff849da339545c449db2af7e11ce6ff02c3
|
||||
---
|
||||
tensorflow/lite/kernels/while.cc | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
diff --git a/tensorflow/lite/kernels/while.cc b/tensorflow/lite/kernels/while.cc
|
||||
index e05959fe2a682..74ab81c2a9599 100644
|
||||
--- a/tensorflow/lite/kernels/while.cc
|
||||
+++ b/tensorflow/lite/kernels/while.cc
|
||||
@@ -138,6 +138,8 @@ TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) {
|
||||
auto* subgraphs = this_subgraph->GetSubgraphs();
|
||||
TF_LITE_ENSURE(context, op_data->cond_subgraph_index < subgraphs->size());
|
||||
TF_LITE_ENSURE(context, op_data->body_subgraph_index < subgraphs->size());
|
||||
+ TF_LITE_ENSURE(context,
|
||||
+ op_data->cond_subgraph_index != op_data->body_subgraph_index);
|
||||
|
||||
Subgraph* cond_subgraph = (*subgraphs)[op_data->cond_subgraph_index].get();
|
||||
Subgraph* body_subgraph = (*subgraphs)[op_data->body_subgraph_index].get();
|
||||
@ -1,36 +0,0 @@
|
||||
From f8378920345f4f4604202d4ab15ef64b2aceaa16 Mon Sep 17 00:00:00 2001
|
||||
From: Mihai Maruseac <mihaimaruseac@google.com>
|
||||
Date: Tue, 27 Apr 2021 17:47:59 -0700
|
||||
Subject: [PATCH] Prevent a null pointer dereference in TFLite.
|
||||
|
||||
PiperOrigin-RevId: 370800353
|
||||
Change-Id: Ic9c9712ce5c6e384c954dcd640a5bd9ff05c9a05
|
||||
---
|
||||
tensorflow/lite/core/subgraph.cc | 13 ++++++++++---
|
||||
1 file changed, 10 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/tensorflow/lite/core/subgraph.cc b/tensorflow/lite/core/subgraph.cc
|
||||
index 7f9dd2ce3363d..0273018b3bf03 100644
|
||||
--- a/tensorflow/lite/core/subgraph.cc
|
||||
+++ b/tensorflow/lite/core/subgraph.cc
|
||||
@@ -1060,10 +1060,17 @@ TfLiteStatus Subgraph::Invoke() {
|
||||
TF_LITE_ENSURE_STATUS(EnsureTensorDataIsReadable(tensor_index));
|
||||
}
|
||||
if (tensor->data.raw == nullptr && tensor->bytes > 0) {
|
||||
- if (registration.builtin_code == kTfLiteBuiltinReshape && i == 1) {
|
||||
+ if (registration.builtin_code == kTfLiteBuiltinReshape && i == 1 &&
|
||||
+ tensor->dims->size != 1) {
|
||||
// In general, having a tensor here with no buffer will be an error.
|
||||
- // However, for the reshape operator, the second input tensor is only
|
||||
- // used for the shape, not for the data. Thus, null buffer is ok.
|
||||
+ // However, for the reshape operator, the second input tensor is
|
||||
+ // sometimes only used for the shape, not for the data. Thus, null
|
||||
+ // buffer is ok in this situation.
|
||||
+ // The situation where null buffer is not ok for reshape operator is
|
||||
+ // only when there are 2 inputs given to the node and the one
|
||||
+ // corresponding to the shape (i == 1) is a vector that contains all
|
||||
+ // dimensions. See `GetOutputShape()` function in
|
||||
+ // `tensorflow/lite/kernels/reshape.cc`
|
||||
continue;
|
||||
} else {
|
||||
// In all other cases, we need to return an error as otherwise we will
|
||||
@ -1,23 +0,0 @@
|
||||
From 2c74674348a4708ced58ad6eb1b23354df8ee044 Mon Sep 17 00:00:00 2001
|
||||
From: Mihai Maruseac <mihaimaruseac@google.com>
|
||||
Date: Wed, 28 Apr 2021 13:57:37 -0700
|
||||
Subject: [PATCH] Prevent division by 0
|
||||
|
||||
PiperOrigin-RevId: 370979352
|
||||
Change-Id: Ic79191c316d986fc6072ecaebfec9d5f2b924d00
|
||||
---
|
||||
tensorflow/lite/kernels/batch_to_space_nd.cc | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/tensorflow/lite/kernels/batch_to_space_nd.cc b/tensorflow/lite/kernels/batch_to_space_nd.cc
|
||||
index 9d6492e0fcbf0..044ac1b3a5ee5 100644
|
||||
--- a/tensorflow/lite/kernels/batch_to_space_nd.cc
|
||||
+++ b/tensorflow/lite/kernels/batch_to_space_nd.cc
|
||||
@@ -78,6 +78,7 @@ TfLiteStatus ResizeOutputTensor(TfLiteContext* context,
|
||||
int output_batch_size = input_size->data[0];
|
||||
for (int dim = 0; dim < spatial_dims_num; ++dim) {
|
||||
// Number of batch must be multiple of (block_shape[dim]).
|
||||
+ TF_LITE_ENSURE(context, block_shape[dim] != 0);
|
||||
TF_LITE_ENSURE_EQ(context, output_batch_size % block_shape[dim], 0);
|
||||
output_batch_size = output_batch_size / block_shape[dim];
|
||||
output_size->data[dim + 1] = input_size->data[dim + 1] * block_shape[dim] -
|
||||
@ -1,41 +0,0 @@
|
||||
From 106d8f4fb89335a2c52d7c895b7a7485465ca8d9 Mon Sep 17 00:00:00 2001
|
||||
From: Mihai Maruseac <mihaimaruseac@google.com>
|
||||
Date: Tue, 27 Apr 2021 17:47:36 -0700
|
||||
Subject: [PATCH] Prevent division by 0 in TFLite
|
||||
|
||||
---
|
||||
tensorflow/lite/kernels/depth_to_space.cc | 1 +
|
||||
tensorflow/lite/kernels/depth_to_space_test.cc | 5 +++++
|
||||
2 files changed, 6 insertions(+)
|
||||
|
||||
diff --git a/tensorflow/lite/kernels/depth_to_space.cc b/tensorflow/lite/kernels/depth_to_space.cc
|
||||
index 1637ad43..c2047f10 100644
|
||||
--- a/tensorflow/lite/kernels/depth_to_space.cc
|
||||
+++ b/tensorflow/lite/kernels/depth_to_space.cc
|
||||
@@ -58,6 +58,7 @@ TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) {
|
||||
TF_LITE_ENSURE_TYPES_EQ(context, input->type, output->type);
|
||||
|
||||
const int block_size = params->block_size;
|
||||
+ TF_LITE_ENSURE(context, block_size > 0);
|
||||
const int input_height = input->dims->data[1];
|
||||
const int input_width = input->dims->data[2];
|
||||
const int input_channels = input->dims->data[3];
|
||||
diff --git a/tensorflow/lite/kernels/depth_to_space_test.cc b/tensorflow/lite/kernels/depth_to_space_test.cc
|
||||
index 4429faf9..e0de01a9 100644
|
||||
--- a/tensorflow/lite/kernels/depth_to_space_test.cc
|
||||
+++ b/tensorflow/lite/kernels/depth_to_space_test.cc
|
||||
@@ -60,6 +60,11 @@ TEST(DepthToSpaceOpModel, BadBlockSize) {
|
||||
EXPECT_DEATH(DepthToSpaceOpModel({TensorType_FLOAT32, {1, 1, 1, 4}}, 4),
|
||||
"Cannot allocate tensors");
|
||||
}
|
||||
+
|
||||
+TEST(DepthToSpaceOpModel, NoBlockSize) {
|
||||
+ EXPECT_DEATH(DepthToSpaceOpModel({TensorType_FLOAT32, {1, 1, 1, 4}}, 0),
|
||||
+ "Cannot allocate tensors");
|
||||
+}
|
||||
#endif
|
||||
|
||||
TEST(DepthToSpaceOpModel, Float32) {
|
||||
--
|
||||
2.23.0
|
||||
|
||||
@ -1,26 +0,0 @@
|
||||
From f61c57bd425878be108ec787f4d96390579fb83e Mon Sep 17 00:00:00 2001
|
||||
From: Mihai Maruseac <mihaimaruseac@google.com>
|
||||
Date: Wed, 28 Apr 2021 12:57:00 -0700
|
||||
Subject: [PATCH] Prevent division by 0
|
||||
|
||||
PiperOrigin-RevId: 370966645
|
||||
Change-Id: I831bfd96c7eb77b02d7ebb744335f59f6e5728cb
|
||||
---
|
||||
tensorflow/lite/kernels/embedding_lookup.cc | 4 ++++
|
||||
1 file changed, 4 insertions(+)
|
||||
|
||||
diff --git a/tensorflow/lite/kernels/embedding_lookup.cc b/tensorflow/lite/kernels/embedding_lookup.cc
|
||||
index d865f69eb9bd3..092868d5a6a74 100644
|
||||
--- a/tensorflow/lite/kernels/embedding_lookup.cc
|
||||
+++ b/tensorflow/lite/kernels/embedding_lookup.cc
|
||||
@@ -71,6 +71,10 @@ TfLiteStatus EvalSimple(TfLiteContext* context, TfLiteNode* node,
|
||||
const TfLiteTensor* lookup, const TfLiteTensor* value,
|
||||
TfLiteTensor* output) {
|
||||
const int row_size = SizeOfDimension(value, 0);
|
||||
+ if (row_size == 0) {
|
||||
+ // Propagate empty tensor if input is empty
|
||||
+ return kTfLiteOk;
|
||||
+ }
|
||||
const int row_bytes = value->bytes / row_size;
|
||||
|
||||
char* output_raw = GetTensorData<char>(output);
|
||||
@ -1,23 +0,0 @@
|
||||
From 6d36ba65577006affb272335b7c1abd829010708 Mon Sep 17 00:00:00 2001
|
||||
From: Mihai Maruseac <mihaimaruseac@google.com>
|
||||
Date: Wed, 28 Apr 2021 14:22:30 -0700
|
||||
Subject: [PATCH] Prevent division by 0
|
||||
|
||||
PiperOrigin-RevId: 370984990
|
||||
Change-Id: Ib324955bbeb1cbd97c82fd5d61a00a2697c9a2de
|
||||
---
|
||||
tensorflow/lite/kernels/space_to_batch_nd.cc | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/tensorflow/lite/kernels/space_to_batch_nd.cc b/tensorflow/lite/kernels/space_to_batch_nd.cc
|
||||
index 0d537e2d1892f..af7b9d9e914a1 100644
|
||||
--- a/tensorflow/lite/kernels/space_to_batch_nd.cc
|
||||
+++ b/tensorflow/lite/kernels/space_to_batch_nd.cc
|
||||
@@ -79,6 +79,7 @@ TfLiteStatus ResizeOutputTensor(TfLiteContext* context,
|
||||
for (int dim = 0; dim < spatial_dims_num; ++dim) {
|
||||
int final_dim_size = (input_size->data[dim + 1] + paddings_data[dim * 2] +
|
||||
paddings_data[dim * 2 + 1]);
|
||||
+ TF_LITE_ENSURE(context, block_shape[dim] != 0);
|
||||
TF_LITE_ENSURE_EQ(context, final_dim_size % block_shape[dim], 0);
|
||||
output_size->data[dim + 1] = final_dim_size / block_shape[dim];
|
||||
output_batch_size *= block_shape[dim];
|
||||
@ -1,23 +0,0 @@
|
||||
From 6841e522a3e7d48706a02e8819836e809f738682 Mon Sep 17 00:00:00 2001
|
||||
From: Mihai Maruseac <mihaimaruseac@google.com>
|
||||
Date: Wed, 28 Apr 2021 15:13:03 -0700
|
||||
Subject: [PATCH] Prevent division by 0
|
||||
|
||||
PiperOrigin-RevId: 370995582
|
||||
Change-Id: I670ffaf52d1ff8823ec31ea5f438f9125b402223
|
||||
---
|
||||
tensorflow/lite/kernels/svdf.cc | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/tensorflow/lite/kernels/svdf.cc b/tensorflow/lite/kernels/svdf.cc
|
||||
index 8f5c9a86bff5c..73024fd1e587a 100644
|
||||
--- a/tensorflow/lite/kernels/svdf.cc
|
||||
+++ b/tensorflow/lite/kernels/svdf.cc
|
||||
@@ -99,6 +99,7 @@ TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) {
|
||||
const int rank = params->rank;
|
||||
const int batch_size = input->dims->data[0];
|
||||
const int num_filters = weights_feature->dims->data[0];
|
||||
+ TF_LITE_ENSURE(context, rank != 0);
|
||||
TF_LITE_ENSURE_EQ(context, num_filters % rank, 0);
|
||||
const int num_units = num_filters / rank;
|
||||
const int memory_size = weights_time->dims->data[1];
|
||||
@ -1,23 +0,0 @@
|
||||
From b22786e7e9b7bdb6a56936ff29cc7e9968d7bc1d Mon Sep 17 00:00:00 2001
|
||||
From: Mihai Maruseac <mihaimaruseac@google.com>
|
||||
Date: Wed, 28 Apr 2021 15:31:26 -0700
|
||||
Subject: [PATCH] Prevent division by 0
|
||||
|
||||
PiperOrigin-RevId: 370998952
|
||||
Change-Id: I6b1d49079624ee1447d2d9b53a8976fb356cc8f5
|
||||
---
|
||||
tensorflow/lite/kernels/split.cc | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/tensorflow/lite/kernels/split.cc b/tensorflow/lite/kernels/split.cc
|
||||
index be7425cc0b5e2..cf778b0b95124 100644
|
||||
--- a/tensorflow/lite/kernels/split.cc
|
||||
+++ b/tensorflow/lite/kernels/split.cc
|
||||
@@ -60,6 +60,7 @@ TfLiteStatus ResizeOutputTensors(TfLiteContext* context, TfLiteNode* node,
|
||||
TF_LITE_ENSURE(context, axis_value < NumDimensions(input));
|
||||
|
||||
const int input_size = SizeOfDimension(input, axis_value);
|
||||
+ TF_LITE_ENSURE(context, num_splits != 0);
|
||||
TF_LITE_ENSURE_MSG(context, input_size % num_splits == 0,
|
||||
"Not an even split");
|
||||
const int slice_size = input_size / num_splits;
|
||||
@ -1,29 +0,0 @@
|
||||
From 3ebedd7e345453d68e279cfc3e4072648e5e12e5 Mon Sep 17 00:00:00 2001
|
||||
From: Mihai Maruseac <mihaimaruseac@google.com>
|
||||
Date: Wed, 28 Apr 2021 12:58:07 -0700
|
||||
Subject: [PATCH] Prevent division by 0 in OneHot implementation
|
||||
|
||||
If input indices is degenerate, the implementation would do a divide by zero. See https://github.com/tensorflow/tensorflow/blob/745d57df6d5e9bc568666a2a48ed8dd629c27241/tensorflow/lite/kernels/one_hot.cc#L68-L72
|
||||
|
||||
PiperOrigin-RevId: 370966870
|
||||
Change-Id: Ie018337811c8016b5a1d3a277d00d5f2e19a2058
|
||||
---
|
||||
tensorflow/lite/kernels/one_hot.cc | 5 +++++
|
||||
1 file changed, 5 insertions(+)
|
||||
|
||||
diff --git a/tensorflow/lite/kernels/one_hot.cc b/tensorflow/lite/kernels/one_hot.cc
|
||||
index f7b4e8e7e19d5..75bfb48d6b19c 100644
|
||||
--- a/tensorflow/lite/kernels/one_hot.cc
|
||||
+++ b/tensorflow/lite/kernels/one_hot.cc
|
||||
@@ -69,6 +69,11 @@ void OneHotComputeImpl(const OneHotContext& op_context) {
|
||||
for (int i = 0; i < op_context.axis; ++i) {
|
||||
prefix_dim_size *= op_context.indices->dims->data[i];
|
||||
}
|
||||
+ if (prefix_dim_size == 0) {
|
||||
+ // If indices tensor is degenerate, return a degenerate tensor, just like
|
||||
+ // TensorFlow does.
|
||||
+ return;
|
||||
+ }
|
||||
const int suffix_dim_size = NumElements(op_context.indices) / prefix_dim_size;
|
||||
const int depth = *op_context.depth->data.i32;
|
||||
|
||||
@ -1,35 +0,0 @@
|
||||
From 4253f96a58486ffe84b61c0415bb234a4632ee73 Mon Sep 17 00:00:00 2001
|
||||
From: Mihai Maruseac <mihaimaruseac@google.com>
|
||||
Date: Wed, 28 Apr 2021 16:50:55 -0700
|
||||
Subject: [PATCH] Fix integer overflow in TFLite concat
|
||||
|
||||
PiperOrigin-RevId: 371013841
|
||||
Change-Id: I6a4782ce7ca753e23ff31e7fb6aeb7f9d412cd29
|
||||
---
|
||||
tensorflow/lite/kernels/concatenation.cc | 6 ++++++
|
||||
1 file changed, 6 insertions(+)
|
||||
|
||||
diff --git a/tensorflow/lite/kernels/concatenation.cc b/tensorflow/lite/kernels/concatenation.cc
|
||||
index 61596a4ff0661..75bcd9403c0ae 100644
|
||||
--- a/tensorflow/lite/kernels/concatenation.cc
|
||||
+++ b/tensorflow/lite/kernels/concatenation.cc
|
||||
@@ -16,6 +16,8 @@ limitations under the License.
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
+#include <limits>
|
||||
+
|
||||
#include "tensorflow/lite/c/builtin_op_data.h"
|
||||
#include "tensorflow/lite/c/common.h"
|
||||
#include "tensorflow/lite/kernels/internal/compatibility.h"
|
||||
@@ -69,6 +71,10 @@ TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) {
|
||||
TF_LITE_ENSURE_EQ(context, t->type, input_type);
|
||||
for (int d = 0; d < t0->dims->size; ++d) {
|
||||
if (d == axis) {
|
||||
+ // Avoid integer overflow in sum_axis below
|
||||
+ TF_LITE_ENSURE(context, t->dims->data[axis] >= 0);
|
||||
+ TF_LITE_ENSURE(context, t->dims->data[axis] <=
|
||||
+ std::numeric_limits<int>::max() - sum_axis);
|
||||
sum_axis += t->dims->data[axis];
|
||||
} else {
|
||||
TF_LITE_ENSURE_EQ(context, t->dims->data[d], t0->dims->data[d]);
|
||||
@ -1,35 +0,0 @@
|
||||
From cbda3c6b2dbbd3fbdc482ff8c0170a78ec2e97d0 Mon Sep 17 00:00:00 2001
|
||||
From: Mihai Maruseac <mihaimaruseac@google.com>
|
||||
Date: Wed, 28 Apr 2021 15:53:48 -0700
|
||||
Subject: [PATCH] Prevent divisions by 0
|
||||
|
||||
---
|
||||
tensorflow/lite/kernels/depthwise_conv.cc | 4 +++-
|
||||
1 file changed, 3 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/tensorflow/lite/kernels/depthwise_conv.cc b/tensorflow/lite/kernels/depthwise_conv.cc
|
||||
index 3f75287e..fb031926 100644
|
||||
--- a/tensorflow/lite/kernels/depthwise_conv.cc
|
||||
+++ b/tensorflow/lite/kernels/depthwise_conv.cc
|
||||
@@ -276,6 +276,7 @@ TfLiteStatus ComputeDepthMultiplier(TfLiteContext* context,
|
||||
int16* depth_multiplier) {
|
||||
int num_filter_channels = SizeOfDimension(filter, 3);
|
||||
int num_input_channels = SizeOfDimension(input, 3);
|
||||
+ TF_LITE_ENSURE(context, num_input_channels != 0);
|
||||
TF_LITE_ENSURE_EQ(context, num_filter_channels % num_input_channels, 0);
|
||||
|
||||
*depth_multiplier = num_filter_channels / num_input_channels;
|
||||
@@ -446,8 +447,9 @@ TfLiteStatus EvalHybridPerChannel(TfLiteContext* context, TfLiteNode* node,
|
||||
float output_activation_min, output_activation_max;
|
||||
CalculateActivationRange(params->activation, &output_activation_min,
|
||||
&output_activation_max);
|
||||
- const int input_size = NumElements(input) / SizeOfDimension(input, 0);
|
||||
const int batch_size = SizeOfDimension(input, 0);
|
||||
+ TF_LITE_ENSURE(context, batch_size != 0);
|
||||
+ const int input_size = NumElements(input) / batch_size;
|
||||
const TfLiteTensor* input_quantized =
|
||||
GetTemporary(context, node, data->input_quantized_index);
|
||||
int8_t* quantized_input_ptr_batch = input_quantized->data.int8;
|
||||
--
|
||||
2.23.0
|
||||
|
||||
@ -1,27 +0,0 @@
|
||||
From c59c37e7b2d563967da813fa50fe20b21f4da683 Mon Sep 17 00:00:00 2001
|
||||
From: Mihai Maruseac <mihaimaruseac@google.com>
|
||||
Date: Wed, 28 Apr 2021 17:50:10 -0700
|
||||
Subject: [PATCH] Prevent array write out-of-bounds.
|
||||
|
||||
If user passes an invalid axis, then we copy one too many dimensions to the output in the loop below these checks. Even if we didn't do that, there will be further issues with an invalid axis, so we check for that right now.
|
||||
|
||||
PiperOrigin-RevId: 371023299
|
||||
Change-Id: I9eca37ffc2b29e8e48710f500701270ef0790224
|
||||
---
|
||||
tensorflow/lite/kernels/arg_min_max.cc | 3 +++
|
||||
1 file changed, 3 insertions(+)
|
||||
|
||||
diff --git a/tensorflow/lite/kernels/arg_min_max.cc b/tensorflow/lite/kernels/arg_min_max.cc
|
||||
index a0ba8cb9f8bbe..291fd61681f2a 100644
|
||||
--- a/tensorflow/lite/kernels/arg_min_max.cc
|
||||
+++ b/tensorflow/lite/kernels/arg_min_max.cc
|
||||
@@ -48,6 +48,9 @@ TfLiteStatus ResizeOutput(TfLiteContext* context, const TfLiteTensor* input,
|
||||
axis_value += NumDimensions(input);
|
||||
}
|
||||
|
||||
+ TF_LITE_ENSURE(context, axis_value >= 0);
|
||||
+ TF_LITE_ENSURE(context, axis_value < NumDimensions(input));
|
||||
+
|
||||
// Copy the input dimensions to output except the axis dimension.
|
||||
TfLiteIntArray* output_dims = TfLiteIntArrayCreate(NumDimensions(input) - 1);
|
||||
int j = 0;
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user