Skip to content

Commit

Permalink
Merge commit for internal changes
Browse files Browse the repository at this point in the history
  • Loading branch information
keveman committed Jan 7, 2016
2 parents 63bddb3 + 4be49cc commit 5d824f1
Show file tree
Hide file tree
Showing 16 changed files with 1,405 additions and 456 deletions.
33 changes: 26 additions & 7 deletions tensorflow/core/kernels/resize_bilinear_op.cc
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,9 @@ typedef Eigen::ThreadPoolDevice CPUDevice;
template <typename Device, typename T>
class ResizeBilinearOp : public OpKernel {
public:
explicit ResizeBilinearOp(OpKernelConstruction* context)
: OpKernel(context) {}
explicit ResizeBilinearOp(OpKernelConstruction* context) : OpKernel(context) {
OP_REQUIRES_OK(context, context->GetAttr("align_corners", &align_corners_));
}

void Compute(OpKernelContext* context) override {
const Tensor& input = context->input(0);
Expand Down Expand Up @@ -73,8 +74,14 @@ class ResizeBilinearOp : public OpKernel {
typename TTypes<T, 4>::ConstTensor input_data = input.tensor<T, 4>();
typename TTypes<float, 4>::Tensor output_data = output->tensor<float, 4>();

const float height_scale = in_height / static_cast<float>(out_height);
const float width_scale = in_width / static_cast<float>(out_width);
const float height_scale =
(align_corners_ && out_height > 1)
? (in_height - 1) / static_cast<float>(out_height - 1)
: in_height / static_cast<float>(out_height);
const float width_scale =
(align_corners_ && out_width > 1)
? (in_width - 1) / static_cast<float>(out_width - 1)
: in_width / static_cast<float>(out_width);

for (int b = 0; b < batch_size; ++b) {
for (int y = 0; y < out_height; ++y) {
Expand Down Expand Up @@ -110,13 +117,18 @@ class ResizeBilinearOp : public OpKernel {
}
}
}

private:
bool align_corners_;
};

template <typename Device, typename T>
class ResizeBilinearOpGrad : public OpKernel {
public:
explicit ResizeBilinearOpGrad(OpKernelConstruction* context)
: OpKernel(context) {}
: OpKernel(context) {
OP_REQUIRES_OK(context, context->GetAttr("align_corners", &align_corners_));
}

void Compute(OpKernelContext* context) override {
// Validate input.
Expand Down Expand Up @@ -166,9 +178,13 @@ class ResizeBilinearOpGrad : public OpKernel {
}

const float height_scale =
original_height / static_cast<float>(resized_height);
(align_corners_ && resized_height > 1)
? (original_height - 1) / static_cast<float>(resized_height - 1)
: original_height / static_cast<float>(resized_height);
const float width_scale =
original_width / static_cast<float>(resized_width);
(align_corners_ && resized_width > 1)
? (original_width - 1) / static_cast<float>(resized_width - 1)
: original_width / static_cast<float>(resized_width);

// Each resized pixel was computed as a weighted average of four input
// pixels. Here we find the pixels that contributed to each output pixel
Expand Down Expand Up @@ -206,6 +222,9 @@ class ResizeBilinearOpGrad : public OpKernel {
}
}
}

private:
bool align_corners_;
};

#define REGISTER_KERNEL(T) \
Expand Down
149 changes: 143 additions & 6 deletions tensorflow/core/kernels/resize_bilinear_op_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,20 @@ class ResizeBilinearOpTest : public OpsTestBase {
EXPECT_OK(NodeDefBuilder("resize_bilinear_op", "ResizeBilinear")
.Input(FakeInput(DT_FLOAT))
.Input(FakeInput(DT_INT32))
.Attr("align_corners", false)
.Finalize(node_def()));
EXPECT_OK(InitOp());
}
};

class ResizeBilinearOpAlignCornersTest : public OpsTestBase {
protected:
ResizeBilinearOpAlignCornersTest() {
RequireDefaultOps();
EXPECT_OK(NodeDefBuilder("resize_bilinear_op", "ResizeBilinear")
.Input(FakeInput(DT_FLOAT))
.Input(FakeInput(DT_INT32))
.Attr("align_corners", true)
.Finalize(node_def()));
EXPECT_OK(InitOp());
}
Expand All @@ -50,7 +64,22 @@ TEST_F(ResizeBilinearOpTest, TestBilinear2x2To1x1) {
ASSERT_OK(RunOpKernel());

// When scaling down, we have to arbitrarily pick a pixel from the
// original input. In this case, we choose the top/left most pixel.
// original input. In this case, we choose the top/left most pixel.
Tensor expected(allocator(), DT_FLOAT, TensorShape({1, 1, 1, 1}));
test::FillValues<float>(&expected, {1.0});
test::ExpectTensorEqual<float>(expected, *GetOutput(0));
}

TEST_F(ResizeBilinearOpAlignCornersTest, TestBilinearAlignCorners2x2To1x1) {
// Input:
// 1, 2
// 3, 4
AddInputFromArray<float>(TensorShape({1, 2, 2, 1}), {1, 2, 3, 4});
AddInputFromArray<int32>(TensorShape({2}), {1, 1});
ASSERT_OK(RunOpKernel());

// When scaling down, we have to arbitrarily pick a pixel from the
// original input. In this case, we choose the top/left most pixel.
Tensor expected(allocator(), DT_FLOAT, TensorShape({1, 1, 1, 1}));
test::FillValues<float>(&expected, {1.0});
test::ExpectTensorEqual<float>(expected, *GetOutput(0));
Expand All @@ -66,9 +95,6 @@ TEST_F(ResizeBilinearOpTest, TestBilinear2x2To3x3) {

Tensor expected(allocator(), DT_FLOAT, TensorShape({1, 3, 3, 1}));

// The corners should match the original corners, and we bilinear
// interpolate the values in between.

// clang-format off
test::FillValues<float>(&expected,
{1, 5.0/3, 2,
Expand All @@ -79,6 +105,71 @@ TEST_F(ResizeBilinearOpTest, TestBilinear2x2To3x3) {
test::ExpectTensorEqual<float>(expected, *GetOutput(0));
}

TEST_F(ResizeBilinearOpAlignCornersTest, TestBilinearAlignCorners2x2To3x3) {
// Input:
// 1, 2
// 3, 4
AddInputFromArray<float>(TensorShape({1, 2, 2, 1}), {1, 2, 3, 4});
AddInputFromArray<int32>(TensorShape({2}), {3, 3});
ASSERT_OK(RunOpKernel());

Tensor expected(allocator(), DT_FLOAT, TensorShape({1, 3, 3, 1}));

// The corners exactly align with the original corners, and we bilinear
// interpolate the values in between.

// clang-format off
test::FillValues<float>(&expected,
{1, 1.5, 2,
2, 2.5, 3,
3, 3.5, 4});

// clang-format on
test::ExpectTensorEqual<float>(expected, *GetOutput(0));
}

TEST_F(ResizeBilinearOpTest, TestBilinear3x3To2x2) {
// Input:
// 1, 2, 3
// 4, 5, 6
// 7, 8, 9
AddInputFromArray<float>(TensorShape({1, 3, 3, 1}),
{1, 2, 3, 4, 5, 6, 7, 8, 9});
AddInputFromArray<int32>(TensorShape({2}), {2, 2});
ASSERT_OK(RunOpKernel());

Tensor expected(allocator(), DT_FLOAT, TensorShape({1, 2, 2, 1}));

// clang-format off
test::FillValues<float>(&expected,
{1, 2.5,
5.5, 7});

// clang-format on
test::ExpectTensorEqual<float>(expected, *GetOutput(0));
}

TEST_F(ResizeBilinearOpAlignCornersTest, TestBilinearAlignCorners3x3To2x2) {
// Input:
// 1, 2, 3
// 4, 5, 6
// 7, 8, 9
AddInputFromArray<float>(TensorShape({1, 3, 3, 1}),
{1, 2, 3, 4, 5, 6, 7, 8, 9});
AddInputFromArray<int32>(TensorShape({2}), {2, 2});
ASSERT_OK(RunOpKernel());

Tensor expected(allocator(), DT_FLOAT, TensorShape({1, 2, 2, 1}));

// clang-format off
test::FillValues<float>(&expected,
{1, 3,
7, 9});

// clang-format on
test::ExpectTensorEqual<float>(expected, *GetOutput(0));
}

TEST_F(ResizeBilinearOpTest, TestBilinear3x3To4x4) {
// Input:
// 1, 2, 3,
Expand All @@ -89,8 +180,6 @@ TEST_F(ResizeBilinearOpTest, TestBilinear3x3To4x4) {
AddInputFromArray<int32>(TensorShape({2}), {4, 4});
ASSERT_OK(RunOpKernel());

// The corners should match the original corners, and we bilinear
// interpolate the values in between.
Tensor expected(allocator(), DT_FLOAT, TensorShape({1, 4, 4, 1}));
// clang-format off
test::FillValues<float>(&expected,
Expand All @@ -103,6 +192,54 @@ TEST_F(ResizeBilinearOpTest, TestBilinear3x3To4x4) {
test::ExpectTensorEqual<float>(expected, *GetOutput(0));
}

TEST_F(ResizeBilinearOpTest, TestBilinear4x4To3x3) {
// Input:
// 1, 2, 3, 4
// 5, 6, 7, 8
// 9, 10, 11, 12
// 13, 14, 15, 16
AddInputFromArray<float>(
TensorShape({1, 4, 4, 1}),
{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16});
AddInputFromArray<int32>(TensorShape({2}), {3, 3});
ASSERT_OK(RunOpKernel());

Tensor expected(allocator(), DT_FLOAT, TensorShape({1, 3, 3, 1}));

// clang-format off
test::FillValues<float>(&expected,
{1, 7.0/3, 11.0/3,
19.0/3, 23.0/3, 27.0/3,
35.0/3, 39.0/3, 43.0/3});

// clang-format on
test::ExpectTensorEqual<float>(expected, *GetOutput(0));
}

TEST_F(ResizeBilinearOpAlignCornersTest, TestBilinearAlignCorners4x4To3x3) {
// Input:
// 1, 2, 3, 4
// 5, 6, 7, 8
// 9, 10, 11, 12
// 13, 14, 15, 16
AddInputFromArray<float>(
TensorShape({1, 4, 4, 1}),
{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16});
AddInputFromArray<int32>(TensorShape({2}), {3, 3});
ASSERT_OK(RunOpKernel());

Tensor expected(allocator(), DT_FLOAT, TensorShape({1, 3, 3, 1}));

// clang-format off
test::FillValues<float>(&expected,
{ 1, 2.5, 4,
7, 8.5, 10,
13, 14.5, 16});

// clang-format on
test::ExpectTensorEqual<float>(expected, *GetOutput(0));
}

TEST_F(ResizeBilinearOpTest, TestBilinear2x2To3x3Batch2) {
// Input:
// 1, 2
Expand Down
8 changes: 8 additions & 0 deletions tensorflow/core/ops/image_ops.cc
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ REGISTER_OP("ResizeBilinear")
.Input("size: int32")
.Output("resized_images: float")
.Attr("T: {uint8, int8, int16, int32, int64, float, double}")
.Attr("align_corners: bool = false")
.Doc(R"doc(
Resize `images` to `size` using bilinear interpolation.
Expand All @@ -67,6 +68,9 @@ Input images can be of different types but output images are always float.
images: 4-D with shape `[batch, height, width, channels]`.
size:= A 1-D int32 Tensor of 2 elements: `new_height, new_width`. The
new size for the images.
align_corners: If true, rescale input by (new_height - 1) / (height - 1), which
exactly aligns the 4 corners of images and resized images. If false, rescale
by new_height / height. Treat similarly the width dimension.
resized_images: 4-D with shape
`[batch, new_height, new_width, channels]`.
)doc");
Expand All @@ -77,12 +81,16 @@ REGISTER_OP("ResizeBilinearGrad")
.Input("original_image: T")
.Output("output: T")
.Attr("T: {float, double}")
.Attr("align_corners: bool = false")
.Doc(R"doc(
Computes the gradient of bilinear interpolation.
grads: 4-D with shape `[batch, height, width, channels]`.
original_image: 4-D with shape `[batch, orig_height, orig_width, channels]`,
The image tensor that was resized.
align_corners: If true, rescale grads by (orig_height - 1) / (height - 1), which
exactly aligns the 4 corners of grads and original_image. If false, rescale by
orig_height / height. Treat similarly the width dimension.
output: 4-D with shape `[batch, orig_height, orig_width, channels]`.
Gradients with respect to the input image. Input image must have been
float or double.
Expand Down
16 changes: 16 additions & 0 deletions tensorflow/core/ops/ops.pbtxt
Original file line number Diff line number Diff line change
Expand Up @@ -6210,6 +6210,14 @@ op {
}
}
}
attr {
name: "align_corners"
type: "bool"
default_value {
b: false
}
description: "If true, rescale input by (new_height - 1) / (height - 1), which\nexactly aligns the 4 corners of images and resized images. If false, rescale\nby new_height / height. Treat similarly the width dimension."
}
summary: "Resize `images` to `size` using bilinear interpolation."
description: "Input images can be of different types but output images are always float."
}
Expand Down Expand Up @@ -6240,6 +6248,14 @@ op {
}
}
}
attr {
name: "align_corners"
type: "bool"
default_value {
b: false
}
description: "If true, rescale grads by (orig_height - 1) / (height - 1), which\nexactly aligns the 4 corners of grads and original_image. If false, rescale by\norig_height / height. Treat similarly the width dimension."
}
summary: "Computes the gradient of bilinear interpolation."
}
op {
Expand Down
4 changes: 3 additions & 1 deletion tensorflow/core/util/tensor_slice_writer.h
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,9 @@ Status TensorSliceWriter::Add(const string& name, const TensorShape& shape,
// list the tensor slices we want to save and then another pass to actually
// set the data. Need to figure out if the interface works well.
std::pair<string, string> key_value(key, "");
sts.AppendToString(&key_value.second);
if (!sts.AppendToString(&key_value.second)) {
return errors::Internal("Error writing Tensor. Possible size overflow.");
}
data_.insert(key_value);
}
++slices_;
Expand Down

0 comments on commit 5d824f1

Please sign in to comment.