test_bilinear_interp_op.py 17.0 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
#   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
21
import paddle.fluid as fluid
22 23


24 25 26 27 28 29
def bilinear_interp_np(input,
                       out_h,
                       out_w,
                       out_size=None,
                       actual_shape=None,
                       align_corners=True,
30 31
                       align_mode=0,
                       data_layout='NCHW'):
32
    """bilinear interpolation implement in shape [N, C, H, W]"""
33 34
    if data_layout == "NHWC":
        input = np.transpose(input, (0, 3, 1, 2))  # NHWC => NCHW
35 36 37
    if out_size is not None:
        out_h = out_size[0]
        out_w = out_size[1]
38 39 40
    if actual_shape is not None:
        out_h = actual_shape[0]
        out_w = actual_shape[1]
41
    batch_size, channel, in_h, in_w = input.shape
42 43

    ratio_h = ratio_w = 0.0
T
tink2123 已提交
44 45 46 47 48 49 50 51 52 53
    if out_h > 1:
        if (align_corners):
            ratio_h = (in_h - 1.0) / (out_h - 1.0)
        else:
            ratio_h = 1.0 * in_h / out_h
    if out_w > 1:
        if (align_corners):
            ratio_w = (in_w - 1.0) / (out_w - 1.0)
        else:
            ratio_w = 1.0 * in_w / out_w
54 55

    out = np.zeros((batch_size, channel, out_h, out_w))
56

57
    for i in range(out_h):
58 59 60 61 62
        if (align_mode == 0 and not align_corners):
            h = int(ratio_h * (i + 0.5) - 0.5)
        else:
            h = int(ratio_h * i)

T
tink2123 已提交
63
        h = max(0, h)
64
        hid = 1 if h < in_h - 1 else 0
65
        if (align_mode == 0 and not align_corners):
66 67
            idx_src_h = max(ratio_h * (i + 0.5) - 0.5, 0)
            h1lambda = idx_src_h - h
68 69
        else:
            h1lambda = ratio_h * i - h
70 71
        h2lambda = 1.0 - h1lambda
        for j in range(out_w):
72 73 74 75
            if (align_mode == 0 and not align_corners):
                w = int(ratio_w * (j + 0.5) - 0.5)
            else:
                w = int(ratio_w * j)
T
tink2123 已提交
76
            w = max(0, w)
77
            wid = 1 if w < in_w - 1 else 0
78
            if (align_mode == 0 and not align_corners):
79 80
                idx_src_w = max(ratio_w * (j + 0.5) - 0.5, 0)
                w1lambda = idx_src_w - w
81 82
            else:
                w1lambda = ratio_w * j - w
83 84 85 86 87 88
            w2lambda = 1.0 - w1lambda

            out[:, :, i, j] = h2lambda*(w2lambda*input[:, :, h, w] +
                                        w1lambda*input[:, :, h, w+wid]) + \
                h1lambda*(w2lambda*input[:, :, h+hid, w] +
                          w1lambda*input[:, :, h+hid, w+wid])
89 90 91 92

    if data_layout == "NHWC":
        out = np.transpose(out, (0, 2, 3, 1))  # NCHW => NHWC

93 94 95
    return out.astype(input.dtype)


96
class TestBilinearInterpOp(OpTest):
97 98
    def setUp(self):
        self.out_size = None
99
        self.actual_shape = None
100
        self.data_layout = 'NCHW'
101
        self.init_test_case()
102
        self.op_type = "bilinear_interp"
103 104
        input_np = np.random.random(self.input_shape).astype("float32")

105 106 107 108 109 110 111
        if self.data_layout == "NCHW":
            in_h = self.input_shape[2]
            in_w = self.input_shape[3]
        else:
            in_h = self.input_shape[1]
            in_w = self.input_shape[2]

D
dengkaipeng 已提交
112
        if self.scale > 0:
113 114
            out_h = int(in_h * self.scale)
            out_w = int(in_w * self.scale)
D
dengkaipeng 已提交
115 116 117 118
        else:
            out_h = self.out_h
            out_w = self.out_w

D
dengkaipeng 已提交
119 120
        output_np = bilinear_interp_np(input_np, out_h, out_w, self.out_size,
                                       self.actual_shape, self.align_corners,
121
                                       self.align_mode, self.data_layout)
122 123 124
        self.inputs = {'X': input_np}
        if self.out_size is not None:
            self.inputs['OutSize'] = self.out_size
125 126
        if self.actual_shape is not None:
            self.inputs['OutSize'] = self.actual_shape
D
dengkaipeng 已提交
127

128 129 130
        self.attrs = {
            'out_h': self.out_h,
            'out_w': self.out_w,
D
dengkaipeng 已提交
131
            'scale': self.scale,
132 133
            'interp_method': self.interp_method,
            'align_corners': self.align_corners,
134 135
            'align_mode': self.align_mode,
            'data_layout': self.data_layout
136 137 138 139 140 141 142 143 144 145 146 147 148 149
        }
        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.interp_method = 'bilinear'
        self.input_shape = [2, 3, 4, 4]
        self.out_h = 2
        self.out_w = 2
D
dengkaipeng 已提交
150
        self.scale = 0.
151
        self.out_size = np.array([3, 3]).astype("int32")
T
tink2123 已提交
152 153
        self.align_corners = True
        self.align_mode = 1
154 155


156
class TestBilinearInterpCase1(TestBilinearInterpOp):
157 158 159 160 161
    def init_test_case(self):
        self.interp_method = 'bilinear'
        self.input_shape = [4, 1, 7, 8]
        self.out_h = 1
        self.out_w = 1
D
dengkaipeng 已提交
162
        self.scale = 0.
T
tink2123 已提交
163 164
        self.align_corners = True
        self.align_mode = 1
165 166


167
class TestBilinearInterpCase2(TestBilinearInterpOp):
168 169 170 171 172
    def init_test_case(self):
        self.interp_method = 'bilinear'
        self.input_shape = [3, 3, 9, 6]
        self.out_h = 12
        self.out_w = 12
D
dengkaipeng 已提交
173
        self.scale = 0.
T
tink2123 已提交
174 175
        self.align_corners = True
        self.align_mode = 1
176 177


178
class TestBilinearInterpCase3(TestBilinearInterpOp):
179 180 181 182 183
    def init_test_case(self):
        self.interp_method = 'bilinear'
        self.input_shape = [1, 1, 128, 64]
        self.out_h = 64
        self.out_w = 128
D
dengkaipeng 已提交
184
        self.scale = 0.
T
tink2123 已提交
185 186
        self.align_corners = True
        self.align_mode = 1
187 188


189
class TestBilinearInterpCase4(TestBilinearInterpOp):
190 191 192 193 194
    def init_test_case(self):
        self.interp_method = 'bilinear'
        self.input_shape = [4, 1, 7, 8]
        self.out_h = 1
        self.out_w = 1
D
dengkaipeng 已提交
195
        self.scale = 0.
196
        self.out_size = np.array([2, 2]).astype("int32")
T
tink2123 已提交
197 198
        self.align_corners = True
        self.align_mode = 1
199 200


201
class TestBilinearInterpCase5(TestBilinearInterpOp):
202 203 204 205 206
    def init_test_case(self):
        self.interp_method = 'bilinear'
        self.input_shape = [3, 3, 9, 6]
        self.out_h = 12
        self.out_w = 12
D
dengkaipeng 已提交
207
        self.scale = 0.
208
        self.out_size = np.array([11, 11]).astype("int32")
T
tink2123 已提交
209 210
        self.align_corners = True
        self.align_mode = 1
211 212


213
class TestBilinearInterpCase6(TestBilinearInterpOp):
214 215 216 217 218
    def init_test_case(self):
        self.interp_method = 'bilinear'
        self.input_shape = [1, 1, 128, 64]
        self.out_h = 64
        self.out_w = 128
D
dengkaipeng 已提交
219
        self.scale = 0.
220
        self.out_size = np.array([65, 129]).astype("int32")
T
tink2123 已提交
221 222
        self.align_corners = True
        self.align_mode = 1
223 224


K
Kaipeng Deng 已提交
225 226 227 228 229 230 231 232 233 234 235
class TestBilinearInterpSame(TestBilinearInterpOp):
    def init_test_case(self):
        self.interp_method = 'bilinear'
        self.input_shape = [2, 3, 128, 64]
        self.out_h = 128
        self.out_w = 64
        self.scale = 0.
        self.align_corners = True
        self.align_mode = 1


236
class TestBilinearInterpActualShape(TestBilinearInterpOp):
237 238 239 240 241
    def init_test_case(self):
        self.interp_method = 'bilinear'
        self.input_shape = [3, 2, 32, 16]
        self.out_h = 64
        self.out_w = 32
D
dengkaipeng 已提交
242
        self.scale = 0.
243
        self.out_size = np.array([66, 40]).astype("int32")
T
tink2123 已提交
244 245
        self.align_corners = True
        self.align_mode = 1
246 247


248 249 250 251 252 253 254 255 256 257 258 259 260
class TestBilinearInterpDataLayout(TestBilinearInterpOp):
    def init_test_case(self):
        self.interp_method = 'bilinear'
        self.input_shape = [2, 4, 4, 3]
        self.out_h = 2
        self.out_w = 2
        self.scale = 0.
        self.out_size = np.array([3, 3]).astype("int32")
        self.align_corners = True
        self.align_mode = 1
        self.data_layout = "NHWC"


261
class TestBilinearInterpOpUint8(OpTest):
262 263
    def setUp(self):
        self.out_size = None
264
        self.actual_shape = None
265
        self.init_test_case()
266
        self.op_type = "bilinear_interp"
267 268
        input_np = np.random.randint(
            low=0, high=256, size=self.input_shape).astype("uint8")
D
dengkaipeng 已提交
269 270 271 272 273 274 275 276

        if self.scale > 0:
            out_h = int(self.input_shape[2] * self.scale)
            out_w = int(self.input_shape[3] * self.scale)
        else:
            out_h = self.out_h
            out_w = self.out_w

D
dengkaipeng 已提交
277 278 279
        output_np = bilinear_interp_np(input_np, out_h, out_w, self.out_size,
                                       self.actual_shape, self.align_corners,
                                       self.align_mode)
280 281 282
        self.inputs = {'X': input_np}
        if self.out_size is not None:
            self.inputs['OutSize'] = self.out_size
D
dengkaipeng 已提交
283

284 285 286
        self.attrs = {
            'out_h': self.out_h,
            'out_w': self.out_w,
D
dengkaipeng 已提交
287
            'scale': self.scale,
288 289 290
            'interp_method': self.interp_method,
            'align_corners': self.align_corners,
            'align_mode': self.align_mode
291 292 293 294 295 296 297 298 299 300 301
        }
        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.interp_method = 'bilinear'
        self.input_shape = [1, 3, 9, 6]
        self.out_h = 10
        self.out_w = 9
D
dengkaipeng 已提交
302
        self.scale = 0.
T
tink2123 已提交
303 304
        self.align_corners = True
        self.align_mode = 1
305 306


307
class TestBilinearInterpCase1Uint8(TestBilinearInterpOpUint8):
308 309 310 311 312
    def init_test_case(self):
        self.interp_method = 'bilinear'
        self.input_shape = [2, 3, 128, 64]
        self.out_h = 120
        self.out_w = 50
D
dengkaipeng 已提交
313
        self.scale = 0.
T
tink2123 已提交
314 315
        self.align_corners = True
        self.align_mode = 1
316 317


318
class TestBilinearInterpCase2Uint8(TestBilinearInterpOpUint8):
319 320 321 322 323
    def init_test_case(self):
        self.interp_method = 'bilinear'
        self.input_shape = [4, 1, 7, 8]
        self.out_h = 5
        self.out_w = 13
D
dengkaipeng 已提交
324
        self.scale = 0.
325
        self.out_size = np.array([6, 15]).astype("int32")
T
tink2123 已提交
326 327
        self.align_corners = True
        self.align_mode = 1
328 329 330 331 332


class TestBilinearInterpOtherMethod1(TestBilinearInterpOp):
    def set_align_mode(self):
        self.align_corners = False
T
tink2123 已提交
333
        self.align_mode = 1
334 335 336 337


class TestBilinearInterpWithMethod2(TestBilinearInterpOp):
    def set_align_mode(self):
T
tink2123 已提交
338 339
        self.align_corners = False
        self.align_mode = 0
340 341 342 343 344 345


class TestBilinearInterpWithMethod3(TestBilinearInterpOp):
    def set_align_mode(self):
        self.align_corners = True
        self.align_mode = 0
346 347


D
dengkaipeng 已提交
348 349 350
class TestBilinearInterpScale1(TestBilinearInterpOp):
    def init_test_case(self):
        self.interp_method = 'bilinear'
351
        self.input_shape = [2, 3, 5, 7]
D
dengkaipeng 已提交
352 353 354 355 356 357 358 359 360 361
        self.out_h = 60
        self.out_w = 25
        self.scale = 2.
        self.align_corners = True
        self.align_mode = 1


class TestBilinearInterpScale2(TestBilinearInterpOp):
    def init_test_case(self):
        self.interp_method = 'bilinear'
362
        self.input_shape = [2, 3, 5, 7]
D
dengkaipeng 已提交
363 364 365 366 367 368 369 370 371 372
        self.out_h = 60
        self.out_w = 25
        self.scale = 1.
        self.align_corners = True
        self.align_mode = 1


class TestBilinearInterpScale3(TestBilinearInterpOp):
    def init_test_case(self):
        self.interp_method = 'bilinear'
373
        self.input_shape = [2, 3, 5, 7]
D
dengkaipeng 已提交
374 375 376 377 378 379 380
        self.out_h = 60
        self.out_w = 25
        self.scale = 1.5
        self.align_corners = True
        self.align_mode = 1


381 382 383 384 385 386 387 388 389 390 391
class TestBilinearInterpZero(TestBilinearInterpOp):
    def init_test_case(self):
        self.interp_method = 'bilinear'
        self.input_shape = [2, 3, 5, 7]
        self.out_h = 60
        self.out_w = 25
        self.scale = 0.2
        self.align_corners = False
        self.align_mode = 0


392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540
class TestBilinearInterpOp_attr_tensor(OpTest):
    def setUp(self):
        self.out_size = None
        self.actual_shape = None
        self.init_test_case()
        self.op_type = "bilinear_interp"
        self.shape_by_1Dtensor = False
        self.scale_by_1Dtensor = False
        self.attrs = {
            'interp_method': self.interp_method,
            'align_corners': self.align_corners,
        }

        input_np = np.random.random(self.input_shape).astype("float32")
        self.inputs = {'X': input_np}

        if self.scale_by_1Dtensor:
            self.inputs['Scale'] = np.array([self.scale]).astype("float32")
        elif self.scale > 0:
            out_h = int(self.input_shape[2] * self.scale)
            out_w = int(self.input_shape[3] * self.scale)
            self.attrs['scale'] = self.scale
        else:
            out_h = self.out_h
            out_w = self.out_w

        if self.shape_by_1Dtensor:
            self.inputs['OutSize'] = self.out_size
        elif self.out_size is not None:
            size_tensor = []
            for index, ele in enumerate(self.out_size):
                size_tensor.append(("x" + str(index), np.ones(
                    (1)).astype('int32') * ele))
            self.inputs['SizeTensor'] = size_tensor

        self.attrs['out_h'] = self.out_h
        self.attrs['out_w'] = self.out_w
        output_np = bilinear_interp_np(input_np, out_h, out_w, self.out_size,
                                       self.actual_shape, self.align_corners)
        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.interp_method = 'bilinear'
        self.input_shape = [2, 3, 4, 4]
        self.out_h = 3
        self.out_w = 3
        self.scale = 0.
        self.out_size = [3, 3]
        self.align_corners = True


# out_size is a 1-D tensor
class TestBilinearInterp_attr_tensor_Case1(TestBilinearInterpOp_attr_tensor):
    def init_test_case(self):
        self.interp_method = 'bilinear'
        self.input_shape = [3, 3, 9, 6]
        self.out_h = 12
        self.out_w = 12
        self.scale = 0.
        self.out_size = [8, 12]
        self.align_corners = True


# scale is a 1-D tensor
class TestBilinearInterp_attr_tensor_Case2(TestBilinearInterpOp_attr_tensor):
    def init_test_case(self):
        self.interp_method = 'bilinear'
        self.input_shape = [3, 2, 32, 16]
        self.out_h = 64
        self.out_w = 32
        self.scale = 0.
        self.out_size = np.array([66, 40]).astype("int32")
        self.align_corners = True
        self.shape_by_1Dtensor = True


# scale is a 1-D tensor
class TestBilinearInterp_attr_tensor_Case3(TestBilinearInterpOp_attr_tensor):
    def init_test_case(self):
        self.interp_method = 'bilinear'
        self.input_shape = [3, 2, 32, 16]
        self.out_h = 64
        self.out_w = 32
        self.scale = 2.0
        self.out_size = None
        self.align_corners = True
        self.scale_by_1Dtensor = True


class TestBilinearInterpOpAPI(OpTest):
    def test_case(self):
        x = fluid.layers.data(name="x", shape=[3, 6, 6], dtype="float32")

        dim = fluid.layers.data(
            name="dim", shape=[1], dtype="int32", append_batch_size=False)
        shape_tensor = fluid.layers.data(
            name="shape_tensor",
            shape=[2],
            dtype="int32",
            append_batch_size=False)
        actual_size = fluid.layers.data(
            name="actual_size",
            shape=[2],
            dtype="int32",
            append_batch_size=False)
        scale_tensor = fluid.layers.data(
            name="scale_tensor",
            shape=[1],
            dtype="float32",
            append_batch_size=False)

        out1 = fluid.layers.resize_bilinear(x, out_shape=[12, 12])
        out2 = fluid.layers.resize_bilinear(x, out_shape=[12, dim])
        out3 = fluid.layers.resize_bilinear(x, out_shape=shape_tensor)
        out4 = fluid.layers.resize_bilinear(
            x, out_shape=[4, 4], actual_shape=actual_size)
        out5 = fluid.layers.resize_bilinear(x, scale=scale_tensor)

        x_data = np.random.random((1, 3, 6, 6)).astype("float32")
        dim_data = np.array([12]).astype("int32")
        shape_data = np.array([12, 12]).astype("int32")
        actual_size_data = np.array([12, 12]).astype("int32")
        scale_data = np.array([2.0]).astype("float32")

        place = core.CPUPlace()
        exe = fluid.Executor(place)
        results = exe.run(fluid.default_main_program(),
                          feed={
                              "x": x_data,
                              "dim": dim_data,
                              "shape_tensor": shape_data,
                              "actual_size": actual_size_data,
                              "scale_tensor": scale_data
                          },
                          fetch_list=[out1, out2, out3, out4, out5],
                          return_numpy=True)

        expect_res = bilinear_interp_np(
            x_data, out_h=12, out_w=12, align_corners=True)
        for res in results:
            self.assertTrue(np.allclose(res, expect_res))


541 542
if __name__ == "__main__":
    unittest.main()