diff --git a/paddle/fluid/operators/nearest_neighbor_interp_op.cc b/paddle/fluid/operators/nearest_neighbor_interp_op.cc index 4e29fe5ac37e18b2a7e76fa5e3bcd93021721427..b50648d61771b4a4dfee83b094f47cd25cdddcb2 100644 --- a/paddle/fluid/operators/nearest_neighbor_interp_op.cc +++ b/paddle/fluid/operators/nearest_neighbor_interp_op.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserve. +/* Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserve. 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 diff --git a/paddle/fluid/operators/nearest_neighbor_interp_op.cu b/paddle/fluid/operators/nearest_neighbor_interp_op.cu index 11002d2e1efd48b44f9e4e8a8276db3917400a00..16acc694ab1eee60d7c7f062b634d43bda21fe90 100644 --- a/paddle/fluid/operators/nearest_neighbor_interp_op.cu +++ b/paddle/fluid/operators/nearest_neighbor_interp_op.cu @@ -1,4 +1,4 @@ -/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserve. +/* Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserve. 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 diff --git a/paddle/fluid/operators/nearest_neighbor_interp_op.h b/paddle/fluid/operators/nearest_neighbor_interp_op.h index 5ba12eaa7ce20cb461a38d594b1025c88d223214..a37cc703b1afa00db2695408fdd3b79c45f032c3 100644 --- a/paddle/fluid/operators/nearest_neighbor_interp_op.h +++ b/paddle/fluid/operators/nearest_neighbor_interp_op.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserve. +/* Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserve. 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 @@ -37,12 +37,12 @@ class NearestNeighborInterpKernel : public framework::OpKernel { out_w = out_size_data[1]; } - const int in_n = input->dims()[0]; - const int in_c = input->dims()[1]; + const int n = input->dims()[0]; + const int c = input->dims()[1]; const int in_h = input->dims()[2]; const int in_w = input->dims()[3]; - output->mutable_data({in_n, in_c, out_h, out_w}, ctx.GetPlace()); + output->mutable_data({n, c, out_h, out_w}, ctx.GetPlace()); auto& device_ctx = ctx.template device_context(); math::SetConstant zero; @@ -61,11 +61,11 @@ class NearestNeighborInterpKernel : public framework::OpKernel { auto input_t = EigenTensor::From(*input); auto output_t = EigenTensor::From(*output); for (int k = 0; k < out_h; k++) { // loop for images + int in_k = static_cast(round(ratio_h * k)); for (int l = 0; l < out_w; l++) { - int in_k = static_cast(round(ratio_h * k)); int in_l = static_cast(round(ratio_w * l)); - for (int i = 0; i < in_n; i++) { // loop for batches - for (int j = 0; j < in_c; j++) { // loop for channels + for (int i = 0; i < n; i++) { // loop for batches + for (int j = 0; j < c; j++) { // loop for channels output_t(i, j, k, l) = input_t(i, j, in_k, in_l); } } @@ -78,6 +78,7 @@ template class NearestNeighborInterpGradKernel : public framework::OpKernel { public: void Compute(const framework::ExecutionContext& ctx) const override { + auto* input = ctx.Input("X"); auto* input_grad = ctx.Output(framework::GradVarName("X")); auto* output_grad = ctx.Input(framework::GradVarName("Out")); @@ -90,11 +91,12 @@ class NearestNeighborInterpGradKernel : public framework::OpKernel { out_w = out_size_data[1]; } - const int in_n = input_grad->dims()[0]; - const int in_c = input_grad->dims()[1]; - const int in_h = input_grad->dims()[2]; - const int in_w = input_grad->dims()[3]; + const int n = input->dims()[0]; + const int c = input->dims()[1]; + const int in_h = input->dims()[2]; + const int in_w = input->dims()[3]; + input_grad->mutable_data({n, c, in_h, in_w}, ctx.GetPlace()); auto& device_ctx = ctx.template device_context(); math::SetConstant zero; @@ -113,11 +115,11 @@ class NearestNeighborInterpGradKernel : public framework::OpKernel { auto input_grad_t = EigenTensor::From(*input_grad); auto output_grad_t = EigenTensor::From(*output_grad); for (int k = 0; k < out_h; k++) { // loop for images + int in_k = static_cast(round(ratio_h * k)); for (int l = 0; l < out_w; l++) { - int in_k = static_cast(round(ratio_h * k)); int in_l = static_cast(round(ratio_w * l)); - for (int i = 0; i < in_n; i++) { // loop for batches - for (int j = 0; j < in_c; j++) { // loop for channels + for (int i = 0; i < n; i++) { // loop for batches + for (int j = 0; j < c; j++) { // loop for channels input_grad_t(i, j, in_k, in_l) += output_grad_t(i, j, k, l); } } diff --git a/python/paddle/fluid/tests/unittests/test_nearest_neighbor_interp_op.py b/python/paddle/fluid/tests/unittests/test_nearest_neighbor_interp_op.py new file mode 100644 index 0000000000000000000000000000000000000000..78ad3b98f5385059de615f21d3d39d37e6f70a2e --- /dev/null +++ b/python/paddle/fluid/tests/unittests/test_nearest_neighbor_interp_op.py @@ -0,0 +1,158 @@ +# Copyright (c) 2018 PaddlePaddle 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. + +from __future__ import print_function + +import unittest +import numpy as np +from op_test import OpTest +import paddle.fluid.core as core + + +def nearest_neighbor_interp_np(X, out_h, out_w, out_size=None): + """nearest neighbor interpolation implement in shape [N, C, H, W]""" + if out_size is not None: + out_h = out_size[0] + out_w = out_size[1] + n, c, in_h, in_w = X.shape + + ratio_h = ratio_w = 0.0 + if out_h > 1: + ratio_h = (in_h - 1.0) / (out_h - 1.0) + if out_w > 1: + ratio_w = (in_w - 1.0) / (out_w - 1.0) + + out = np.zeros((n, c, out_h, out_w)) + for i in range(out_h): + in_i = int(round(ratio_h * i)) + for j in range(out_w): + in_j = int(round(ratio_w * j)) + out[:, :, i, j] = X[:, :, in_i, in_j] + + return out.astype(X.dtype) + + +class TestBilinearInterpOp(OpTest): + def setUp(self): + self.out_size = None + self.init_test_case() + self.op_type = "nearest_neighbor_interp" + input_np = np.random.random(self.input_shape).astype("float32") + output_np = nearest_neighbor_interp_np(input_np, self.out_h, self.out_w, + self.out_size) + self.inputs = {'X': input_np} + if self.out_size is not None: + self.inputs['OutSize'] = self.out_size + self.attrs = {'out_h': self.out_h, 'out_w': self.out_w} + self.outputs = {'Out': output_np} + + def test_check_output(self): + self.check_output() + + def test_check_grad(self): + self.check_grad(['X'], 'Out', in_place=True) + + def init_test_case(self): + self.input_shape = [2, 3, 4, 4] + self.out_h = 2 + self.out_w = 2 + self.out_size = np.array([3, 3]).astype("int32") + + +class TestCase1(TestBilinearInterpOp): + def init_test_case(self): + self.input_shape = [4, 1, 7, 8] + self.out_h = 1 + self.out_w = 1 + + +class TestCase2(TestBilinearInterpOp): + def init_test_case(self): + self.input_shape = [3, 3, 9, 6] + self.out_h = 12 + self.out_w = 12 + + +class TestCase3(TestBilinearInterpOp): + def init_test_case(self): + self.input_shape = [1, 1, 128, 64] + self.out_h = 64 + self.out_w = 128 + + +class TestCase4(TestBilinearInterpOp): + def init_test_case(self): + self.input_shape = [4, 1, 7, 8] + self.out_h = 1 + self.out_w = 1 + self.out_size = np.array([2, 2]).astype("int32") + + +class TestCase5(TestBilinearInterpOp): + def init_test_case(self): + self.input_shape = [3, 3, 9, 6] + self.out_h = 12 + self.out_w = 12 + self.out_size = np.array([11, 11]).astype("int32") + + +class TestCase6(TestBilinearInterpOp): + def init_test_case(self): + self.input_shape = [1, 1, 128, 64] + self.out_h = 64 + self.out_w = 128 + self.out_size = np.array([65, 129]).astype("int32") + + +class TestBilinearInterpOpUint8(OpTest): + def setUp(self): + self.out_size = None + self.init_test_case() + self.op_type = "nearest_neighbor_interp" + input_np = np.random.randint( + low=0, high=256, size=self.input_shape).astype("uint8") + output_np = nearest_neighbor_interp_np(input_np, self.out_h, self.out_w, + self.out_size) + self.inputs = {'X': input_np} + if self.out_size is not None: + self.inputs['OutSize'] = self.out_size + self.attrs = {'out_h': self.out_h, 'out_w': self.out_w} + self.outputs = {'Out': output_np} + + def test_check_output(self): + self.check_output_with_place(place=core.CPUPlace(), atol=1) + + def init_test_case(self): + self.input_shape = [1, 3, 9, 6] + self.out_h = 10 + self.out_w = 9 + + +class TestCase1Uint8(TestBilinearInterpOpUint8): + def init_test_case(self): + self.input_shape = [2, 3, 128, 64] + self.out_h = 120 + self.out_w = 50 + + +class TestCase2Uint8(TestBilinearInterpOpUint8): + def init_test_case(self): + self.input_shape = [4, 1, 7, 8] + self.out_h = 5 + self.out_w = 13 + self.out_size = np.array([6, 15]).astype("int32") + + +if __name__ == "__main__": + unittest.main()