diff --git a/tensorflow/compiler/xla/reference_util.cc b/tensorflow/compiler/xla/reference_util.cc index 86c9c3b1ac3..5630033ac89 100644 --- a/tensorflow/compiler/xla/reference_util.cc +++ b/tensorflow/compiler/xla/reference_util.cc @@ -649,4 +649,39 @@ ReferenceUtil::ReduceToRowArray2D( return result; } +/* static */ Array4D ReferenceUtil::PadArray4D( + const Array4D& operand, const PaddingConfig& padding, + const float pad) { + CHECK_EQ(padding.dimensions_size(), 4); + + const std::vector input_bounds = {operand.n1(), operand.n2(), + operand.n3(), operand.n4()}; + std::vector pad_low(4); + std::vector pad_high(4); + std::vector output_bounds(4); + for (int64 i = 0; i < 4; ++i) { + pad_low[i] = padding.dimensions(i).edge_padding_low(); + pad_high[i] = padding.dimensions(i).edge_padding_high(); + CHECK_EQ(padding.dimensions(i).interior_padding(), 0) << "not implemented"; + + output_bounds[i] = pad_low[i] + input_bounds[i] + pad_high[i]; + } + + Array4D result(output_bounds[0], output_bounds[1], output_bounds[2], + output_bounds[3]); + result.Each([&](tensorflow::gtl::ArraySlice indices, float* value) { + for (int i = 0; i < 4; ++i) { + bool in_low_padding = indices[i] < pad_low[i]; + bool in_high_padding = indices[i] >= output_bounds[i] - pad_high[i]; + if (in_low_padding || in_high_padding) { + *value = pad; + return; + } + } + *value = operand(indices[0] - pad_low[0], indices[1] - pad_low[1], + indices[2] - pad_low[2], indices[3] - pad_low[3]); + }); + return result; +} + } // namespace xla diff --git a/tensorflow/compiler/xla/reference_util.h b/tensorflow/compiler/xla/reference_util.h index 9e0f2472038..eb1eea7fc4c 100644 --- a/tensorflow/compiler/xla/reference_util.h +++ b/tensorflow/compiler/xla/reference_util.h @@ -395,6 +395,11 @@ class ReferenceUtil { const Array2D& operand, const PaddingConfig& padding, const float pad); + // Returns the result of a 4D pad on an input array. + static Array4D PadArray4D(const Array4D& operand, + const PaddingConfig& padding, + const float pad); + private: TF_DISALLOW_COPY_AND_ASSIGN(ReferenceUtil); }; diff --git a/tensorflow/compiler/xla/service/shape_inference.cc b/tensorflow/compiler/xla/service/shape_inference.cc index 9472086e2b4..338d63f1a00 100644 --- a/tensorflow/compiler/xla/service/shape_inference.cc +++ b/tensorflow/compiler/xla/service/shape_inference.cc @@ -309,6 +309,10 @@ StatusOr InferWindowOutputShape(const Shape& base_shape, return InvalidArgument( "the rank of the operand and the padding configuration do not match."); } + if (operand_shape.element_type() != padding_value_shape.element_type()) { + return InvalidArgument( + "the element types of the operands to pad do not match"); + } std::vector dimensions(ShapeUtil::Rank(operand_shape)); for (int64 i = 0; i < operand_shape.dimensions_size(); ++i) { dimensions[i] = operand_shape.dimensions(i) + @@ -338,7 +342,7 @@ StatusOr InferWindowOutputShape(const Shape& base_shape, // Check if both element types are the same. if (lhs.element_type() != rhs.element_type()) { - return fail("element types mismatch"); + return fail("element types do not match"); } if (ShapeUtil::Rank(lhs) < 1 || ShapeUtil::Rank(lhs) > 2 || diff --git a/tensorflow/compiler/xla/util.h b/tensorflow/compiler/xla/util.h index 8ec4f1b528d..32b5fbba003 100644 --- a/tensorflow/compiler/xla/util.h +++ b/tensorflow/compiler/xla/util.h @@ -31,6 +31,7 @@ limitations under the License. #include "tensorflow/core/lib/gtl/array_slice.h" #include "tensorflow/core/lib/math/math_util.h" #include "tensorflow/core/lib/strings/numbers.h" +#include "tensorflow/core/lib/strings/strcat.h" #include "tensorflow/core/platform/logging.h" #include "tensorflow/core/platform/macros.h" #include "tensorflow/core/platform/protobuf.h" @@ -200,6 +201,46 @@ int64 PositionInContainer(const Container& container, int64 value) { std::find(container.begin(), container.end(), value)); } +// Formats the container as a comma-separated string. StrAppend must support +// appending the elements of the container. Prefix is prepended and suffix is +// appended to the returned string. +template +string CommaSeparatedString(const Container& c, const char* prefix = "", + const char* suffix = "") { + // Not using Join() since the implementation here is simple anyway and this + // avoids copying the string to append prefix. + string comma_separated = prefix; + const char* separator = ""; + for (const auto& entry : c) { + tensorflow::strings::StrAppend(&comma_separated, separator, entry); + separator = ", "; + } + comma_separated += suffix; + return comma_separated; +} + +// Overload needed to allow the container to be an initializer list. The default +// type for T makes an empty initializer list work as well. +template +string CommaSeparatedString(const std::initializer_list& c, + const char* prefix = "", const char* suffix = "") { + return CommaSeparatedString>(c, prefix, suffix); +} + +// Formats the container in the mathematical notation for a vector, e.g. (1, 3, +// 7). StrAppend must support appending the elements of c. +template +string VectorString(const Container& c) { + return CommaSeparatedString(c, "(", ")"); +} + +// Overload needed to allow the container to be an initializer list. The default +// type for T makes an empty initializer list work as well. +template +string VectorString(const std::initializer_list& c) { + return VectorString>(c); +} + // Returns a PaddingConfig object that represents no padding for the given rank. PaddingConfig MakeNoPaddingConfig(int64 rank); diff --git a/tensorflow/compiler/xla/util_test.cc b/tensorflow/compiler/xla/util_test.cc index a81014f3b7a..547b924180b 100644 --- a/tensorflow/compiler/xla/util_test.cc +++ b/tensorflow/compiler/xla/util_test.cc @@ -80,6 +80,26 @@ TEST(UtilTest, HumanReadableNumFlopsExample) { ASSERT_EQ("1.00GFLOP/s", HumanReadableNumFlops(1e9, 1e9)); } +TEST(UtilTest, CommaSeparatedString) { + EXPECT_EQ(CommaSeparatedString({}), ""); + EXPECT_EQ(CommaSeparatedString({"hello world"}), "hello world"); + EXPECT_EQ(CommaSeparatedString({1, 57, 2}, "foo", "bar"), "foo1, 57, 2bar"); +} + +TEST(UtilTest, VectorString) { + std::list empty_list; + EXPECT_EQ(VectorString(empty_list), "()"); + + std::vector float_vector = {5.5}; + EXPECT_EQ(VectorString(float_vector), "(5.5)"); + + std::set string_set = {"a", "b"}; + EXPECT_EQ(VectorString(string_set), "(a, b)"); + + EXPECT_EQ(VectorString({}), "()"); + EXPECT_EQ(VectorString({1, 57, 2}), "(1, 57, 2)"); +} + TEST(UtilTest, LogLines) { // Just make sure this code runs (not verifying the output). LogLines(tensorflow::INFO, "hello\n\nworld", __FILE__, __LINE__);