test_reshape_op.py 18.8 KB
Newer Older
1
#   Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved.
D
dzhwinter 已提交
2
#
D
dzhwinter 已提交
3 4 5
# 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
D
dzhwinter 已提交
6
#
D
dzhwinter 已提交
7
#     http://www.apache.org/licenses/LICENSE-2.0
D
dzhwinter 已提交
8
#
D
dzhwinter 已提交
9 10 11 12 13 14
# 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.

Y
Yibing Liu 已提交
15 16 17
import unittest
import numpy as np

18
from op_test import OpTest, convert_float_to_uint16
19
import paddle
20
import paddle.fluid as fluid
J
joejiong 已提交
21
from paddle.static import Program, program_guard
Y
Yibing Liu 已提交
22

C
caoying03 已提交
23

24
# situation 1: have shape( list, no tensor), no actual shape(Tensor)
C
caoying03 已提交
25
class TestReshapeOp(OpTest):
26

C
caoying03 已提交
27
    def setUp(self):
28 29 30 31 32 33 34 35
        self.init_data()
        self.op_type = "reshape2"
        self.inputs = {"X": np.random.random(self.ori_shape).astype("float32")}
        self.attrs = {"shape": self.new_shape}
        self.outputs = {
            "Out": self.inputs["X"].reshape(self.infered_shape),
            'XShape': np.random.random(self.ori_shape).astype("float32")
        }
Y
ying 已提交
36

37
    def init_data(self):
Z
zhupengyang 已提交
38 39 40
        self.ori_shape = (2, 60)
        self.new_shape = (12, 10)
        self.infered_shape = (12, 10)
41 42

    def test_check_output(self):
43
        self.check_output(no_check_set=['XShape'])
44 45 46

    def test_check_grad(self):
        self.check_grad(["X"], "Out")
47 48


49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
class TestReshapeOp_ZeroDim1(OpTest):

    def init_data(self):
        self.ori_shape = ()
        self.new_shape = (1)
        self.infered_shape = (1)


class TestReshapeOp_ZeroDim2(OpTest):

    def init_data(self):
        self.ori_shape = (1)
        self.new_shape = ()
        self.infered_shape = ()


class TestReshapeOp_ZeroDim3(OpTest):

    def init_data(self):
        self.ori_shape = ()
        self.new_shape = (-1)
        self.infered_shape = (1)


73
class TestReshapeBF16Op(OpTest):
74

75 76 77 78 79 80 81 82 83
    def setUp(self):
        self.init_data()
        self.op_type = "reshape2"
        self.dtype = np.uint16
        x = np.random.random(self.ori_shape).astype("float32")
        out = x.reshape(self.infered_shape)
        self.inputs = {"X": convert_float_to_uint16(x)}
        self.attrs = {"shape": self.new_shape}
        self.outputs = {
84 85 86 87
            "Out":
            convert_float_to_uint16(out),
            'XShape':
            convert_float_to_uint16(
88 89 90 91 92 93 94 95 96 97 98 99 100
                np.random.random(self.ori_shape).astype("float32"))
        }

    def init_data(self):
        self.ori_shape = (2, 60)
        self.new_shape = (12, 10)
        self.infered_shape = (12, 10)

    def test_check_output(self):
        self.check_output(no_check_set=['XShape'])

    def test_check_grad(self):
        self.check_grad(["X"], "Out")
101 102


103
class TestReshapeOpDimInfer1(TestReshapeOp):
104

105
    def init_data(self):
Z
zhupengyang 已提交
106
        self.ori_shape = (5, 25)
107 108
        self.new_shape = (5, -1, 5)
        self.infered_shape = (5, -1, 5)
C
caoying03 已提交
109 110


111
class TestReshapeOpDimInfer2(TestReshapeOp):
112

113
    def init_data(self):
Z
zhupengyang 已提交
114 115 116
        self.ori_shape = (10, 2, 6)
        self.new_shape = (10, 0, 3, -1)
        self.infered_shape = (10, 2, 3, -1)
C
caoying03 已提交
117

C
caoying03 已提交
118

119
# situation 2: have shape(list, no tensor), have actual shape(Tensor)
120
class TestReshapeOpWithInputShape(OpTest):
121

122
    def setUp(self):
123
        self.init_data()
124
        self.op_type = "reshape2"
125

126
        self.inputs = {
127
            "X": np.random.random(self.ori_shape).astype("float32"),
128
            "Shape": np.array(self.actual_shape, dtype="int32")
129
        }
130
        self.attrs = {"shape": self.new_shape}
131
        self.outputs = {
132 133
            "Out": self.inputs["X"].reshape(self.actual_shape),
            'XShape': np.random.random(self.ori_shape).astype("float32")
134
        }
135

136
    def init_data(self):
Z
zhupengyang 已提交
137 138 139
        self.ori_shape = (6, 20)
        self.new_shape = (0, -1, 20)
        self.actual_shape = (2, 3, 20)
140

141
    def test_check_output(self):
142
        self.check_output(no_check_set=['XShape'])
143

G
guosheng 已提交
144
    def test_check_grad(self):
C
chengduo 已提交
145
        self.check_grad(["X"], "Out")
146 147


148 149
# Situation 3: have shape(list, have tensor), no actual shape(Tensor)
class TestReshapeOp_attr_ShapeTensor(OpTest):
150

151 152 153 154 155 156 157 158 159 160 161 162 163
    def setUp(self):
        self.init_data()
        self.op_type = "reshape2"

        shape_tensor = []
        for index, ele in enumerate(self.new_shape):
            shape_tensor.append(("x" + str(index), np.ones(
                (1)).astype('int32') * ele))

        self.inputs = {
            "X": np.random.random(self.ori_shape).astype("float32"),
            'ShapeTensor': shape_tensor
        }
164 165 166 167 168 169 170
        self.attrs = {'shape': self.shape}
        self.outputs = {
            "Out": self.inputs["X"].reshape(self.infered_shape),
            'XShape': np.random.random(self.ori_shape).astype("float32")
        }

    def init_data(self):
Z
zhupengyang 已提交
171 172 173
        self.ori_shape = (4, 25)
        self.new_shape = (10, 10)
        self.infered_shape = (10, 10)
174 175 176 177 178 179 180 181 182 183
        self.shape = (-1, -1)

    def test_check_output(self):
        self.check_output(no_check_set=['XShape'])

    def test_check_grad(self):
        self.check_grad(["X"], "Out")


class TestReshapeOpDimInfer1_attr_ShapeTensor(TestReshapeOp_attr_ShapeTensor):
184

185
    def init_data(self):
Z
zhupengyang 已提交
186 187 188
        self.ori_shape = (5, 20)
        self.new_shape = (5, -1, 20)
        self.infered_shape = (5, -1, 20)
189 190 191 192
        self.shape = (5, -1, -1)


class TestReshapeOpDimInfer2_attr_ShapeTensor(TestReshapeOp_attr_ShapeTensor):
193

194
    def init_data(self):
Z
zhupengyang 已提交
195 196 197 198
        self.ori_shape = (10, 2, 6)
        self.new_shape = (10, 0, 3, -1)
        self.infered_shape = (10, 2, 3, -1)
        self.shape = (10, 0, 3, -1)
199 200 201 202


# Situation 4: have shape(Tensor), no actual shape(Tensor)
class TestReshapeOp_attr_OnlyShape(OpTest):
203

204 205 206 207 208 209
    def setUp(self):
        self.init_data()
        self.op_type = "reshape2"

        self.inputs = {
            "X": np.random.random(self.ori_shape).astype("float32"),
210
            "Shape": np.array(self.new_shape, dtype="int32")
211
        }
212 213 214 215 216 217 218
        self.attrs = {}
        self.outputs = {
            "Out": self.inputs["X"].reshape(self.infered_shape),
            'XShape': np.random.random(self.ori_shape).astype("float32")
        }

    def init_data(self):
Z
zhupengyang 已提交
219 220 221
        self.ori_shape = (4, 25)
        self.new_shape = (10, 10)
        self.infered_shape = (10, 10)
222 223 224 225 226 227 228 229

    def test_check_output(self):
        self.check_output(no_check_set=['XShape'])

    def test_check_grad(self):
        self.check_grad(["X"], "Out")


230
class TestReshapeOpDimInfer1_attr_OnlyShape(TestReshapeOp_attr_OnlyShape):
231

232
    def init_data(self):
Z
zhupengyang 已提交
233 234 235
        self.ori_shape = (5, 20)
        self.new_shape = (5, -1, 10)
        self.infered_shape = (5, -1, 10)
236
        self.shape = (5, -1, -1)
237 238


239
class TestReshapeOpDimInfer2_attr_OnlyShape(TestReshapeOp_attr_OnlyShape):
240

241
    def init_data(self):
Z
zhupengyang 已提交
242 243 244 245
        self.ori_shape = (10, 2, 6)
        self.new_shape = (10, 0, 3, -1)
        self.infered_shape = (10, 2, 3, -1)
        self.shape = (10, 0, 3, -1)
246 247


248 249
# test int8 data type on CPU
class TestReshapeInt8Op(OpTest):
250

251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271
    def setUp(self):
        self.init_dtype()
        self.init_data()
        self.use_mkldnn = True
        self._cpu_only = True
        self.op_type = "reshape2"
        input = np.random.randint(0, 127, self.ori_shape).astype(self.dtype)
        self.inputs = {'X': OpTest.np_dtype_to_fluid_dtype(input)}
        self.attrs = {
            'shape': self.new_shape,
            'use_mkldnn': self.use_mkldnn,
        }
        self.outputs = {
            "Out": self.inputs["X"].reshape(self.infered_shape),
            'XShape': np.random.random(self.ori_shape).astype(np.float32)
        }

    def init_dtype(self):
        self.dtype = np.int8

    def init_data(self):
Z
zhupengyang 已提交
272 273 274
        self.ori_shape = (10, 2, 6)
        self.new_shape = (10, 0, 3, -1)
        self.infered_shape = (10, 2, 3, -1)
275 276

    def test_check_output(self):
277 278 279
        self.check_output_with_place(fluid.core.CPUPlace(),
                                     atol=1e-5,
                                     no_check_set=['XShape'])
280 281 282 283 284 285 286

    def test_check_grad(self):
        pass


# test unt8 data type on CPU
class TestReshapeUint8Op(TestReshapeInt8Op):
287

288 289 290 291
    def init_dtype(self):
        self.dtype = np.uint8


292
class TestReshapeOpBool(TestReshapeOp):
293

294 295 296 297
    def setUp(self):
        self.init_data()
        self.op_type = "reshape2"
        self.inputs = {
298
            "X": np.random.choice([True, False], size=self.ori_shape)
299 300 301 302 303 304 305 306 307 308 309
        }
        self.attrs = {"shape": self.new_shape}
        self.outputs = {
            "Out": self.inputs["X"].reshape(self.infered_shape),
            'XShape': np.random.random(self.ori_shape).astype("float32")
        }

    def test_check_grad(self):
        pass


310
# Test python API
311
class TestReshapeAPI(unittest.TestCase):
312

313
    def _set_paddle_api(self):
314
        self.fill_constant = paddle.fluid.layers.fill_constant
J
joejiong 已提交
315
        self.data = paddle.static.data
316
        self.to_tensor = paddle.to_tensor
317 318 319 320
        self._executed_api()

    def _executed_api(self):
        self.reshape = paddle.reshape
321 322 323

    def _set_fluid_api(self):
        self.fill_constant = fluid.layers.fill_constant
J
joejiong 已提交
324
        self.data = paddle.static.data
325 326 327
        self.reshape = fluid.layers.reshape

    def _test_api(self):
J
joejiong 已提交
328
        paddle.enable_static()
329 330
        input = np.random.random([2, 25]).astype("float32")
        shape = [2, 5, 5]
331 332 333 334
        main_prog = Program()
        with program_guard(main_prog, Program()):
            positive_five = self.fill_constant([1], "int32", 5)
            x = self.data(name="x", shape=[2, 25], dtype="float32")
335

336
            actual_shape = self.data(name="shape", shape=[3], dtype="int32")
337

338 339
            # situation 1: have shape( list, no tensor), no actual shape(Tensor)
            out_1 = self.reshape(x, shape)
340

341
            # situation 2: have shape(list, no tensor), have actual shape(Tensor)
342 343 344
            out_2 = fluid.layers.reshape(x,
                                         shape=shape,
                                         actual_shape=actual_shape)
345

346 347
            # Situation 3: have shape(list, have tensor), no actual shape(Tensor)
            out_3 = self.reshape(x, shape=[positive_five, 10])
348

349 350
            # Situation 4: have shape(Tensor), no actual shape(Tensor)
            out_4 = self.reshape(x, shape=actual_shape)
351

J
joejiong 已提交
352
        exe = paddle.static.Executor(place=paddle.CPUPlace())
353
        res_1, res_2, res_3, res_4 = exe.run(
354
            main_prog,
355 356 357 358
            feed={
                "x": input,
                "shape": np.array([2, 5, 5]).astype("int32")
            },
359 360 361 362 363 364
            fetch_list=[out_1, out_2, out_3, out_4])

        assert np.array_equal(res_1, input.reshape(shape))
        assert np.array_equal(res_2, input.reshape(shape))
        assert np.array_equal(res_3, input.reshape([5, 10]))
        assert np.array_equal(res_4, input.reshape(shape))
365

366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392
    def test_paddle_api(self):
        self._set_paddle_api()
        self._test_api()

    def test_fluid_api(self):
        self._set_fluid_api()
        self._test_api()

    def test_imperative(self):
        self._set_paddle_api()
        input = np.random.random([2, 25]).astype("float32")
        shape = [2, 5, 5]
        with fluid.dygraph.guard():
            x = self.to_tensor(input)
            positive_five = self.fill_constant([1], "int32", 5)

            out_1 = self.reshape(x, shape)

            out_2 = self.reshape(x, shape=[positive_five, 10])

            shape_tensor = self.to_tensor(np.array([2, 5, 5]).astype("int32"))
            out_3 = self.reshape(x, shape=shape_tensor)

        assert np.array_equal(out_1.numpy(), input.reshape(shape))
        assert np.array_equal(out_2.numpy(), input.reshape([5, 10]))
        assert np.array_equal(out_3.numpy(), input.reshape(shape))

393

394
class TestStaticReshape_(TestReshapeAPI):
395

396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418
    def _executed_api(self):
        self.reshape = paddle.reshape_

    def test_imperative(self):
        self._set_paddle_api()
        input = np.random.random([2, 25]).astype("float32")
        shape = [2, 5, 5]
        with fluid.dygraph.guard():
            x = self.to_tensor(input)
            positive_five = self.fill_constant([1], "int32", 5)

            out_1 = self.reshape(x, shape)

            out_2 = self.reshape(x, shape=[positive_five, 10])

            shape_tensor = self.to_tensor(np.array([2, 5, 5]).astype("int32"))
            out_3 = self.reshape(x, shape=shape_tensor)

        assert np.array_equal(out_1.numpy(), input.reshape(shape))
        assert np.array_equal(out_2.numpy(), input.reshape(shape))
        assert np.array_equal(out_3.numpy(), input.reshape(shape))


419
# Test Input Error
420
class TestReshapeOpError(unittest.TestCase):
421

422
    def _set_paddle_api(self):
J
joejiong 已提交
423
        self.data = paddle.static.data
424 425 426 427 428 429 430
        self.reshape = paddle.reshape

    def _set_fluid_api(self):
        self.data = fluid.data
        self.reshape = fluid.layers.reshape

    def _test_errors(self):
431 432 433
        with program_guard(Program(), Program()):
            # The x type of reshape_op must be Variable.
            def test_x_type():
434 435
                x1 = fluid.create_lod_tensor(np.array([[-1]]), [[1]],
                                             paddle.CPUPlace())
436
                self.reshape(x1, shape=[1])
437 438 439

            self.assertRaises(TypeError, test_x_type)

440
            # The x dtype of reshape_op must be float16, float32, float64, int32 or int64.
441
            def test_x_dtype():
442
                x2 = self.data(name="x2", shape=[2, 25], dtype="int8")
443
                self.reshape(x2, shape=[2, 5, 5])
444 445 446

            self.assertRaises(TypeError, test_x_dtype)

447
            def test_x_dtype_float16():
448 449 450
                x_float16 = self.data(name="x_float16",
                                      shape=[2, 25],
                                      dtype="float16")
451
                self.reshape(x_float16, shape=[2, 5, 5])
452 453 454

            test_x_dtype_float16()

455
            x3 = self.data(name="x3", shape=[2, 25], dtype="float32")
456 457 458

            # The argument shape's type of reshape_op must be list, tuple or Variable.
            def test_shape_type():
459
                self.reshape(x3, shape=1)
460 461 462 463 464

            self.assertRaises(TypeError, test_shape_type)

            # The argument actual_shape's type of reshape_op must be Variable or None.
            def test_actual_shape_type():
465
                self.reshape(x3, shape=[25, 2], actual_shape=1)
466 467 468 469 470

            self.assertRaises(TypeError, test_actual_shape_type)

            # The argument shape have more than one -1.
            def test_shape_1():
471
                self.reshape(x3, shape=[-1, -1, 5])
472 473 474 475 476

            self.assertRaises(AssertionError, test_shape_1)

            # The argument shape have element 0 whose index exceed the input dimension.
            def test_shape_2():
477
                self.reshape(x3, [2, 5, 5, 0])
478 479 480

            self.assertRaises(AssertionError, test_shape_2)

T
tianshuo78520a 已提交
481
            # The argument shape have more than one negative value.
482
            def test_shape_3():
483
                self.reshape(x3, [-1, -2, 5])
484 485 486

            self.assertRaises(AssertionError, test_shape_3)

487 488 489 490 491 492 493 494
    def test_paddle_api_error(self):
        self._set_paddle_api()
        self._test_errors()

    def test_fluid_api_error(self):
        self._set_fluid_api()
        self._test_errors()

495

496
class TestDygraphReshapeAPI(unittest.TestCase):
497

498 499 500 501 502 503
    def setUp(self):
        self.executed_api()

    def executed_api(self):
        self.reshape = paddle.reshape

J
joejiong 已提交
504 505 506 507
    def test_out(self):
        paddle.disable_static()
        input_1 = np.random.random([5, 1, 10]).astype("int32")
        input = paddle.to_tensor(input_1)
508
        output = self.reshape(x=input, shape=[5, 10])
J
joejiong 已提交
509 510
        out_np = output.numpy()
        expected_out = np.reshape(input_1, newshape=[5, 10])
511
        np.testing.assert_allclose(expected_out, out_np, rtol=1e-05)
J
joejiong 已提交
512 513 514 515 516

    def test_out_uint8(self):
        paddle.disable_static()
        input_1 = np.random.random([5, 1, 10]).astype("uint8")
        input = paddle.to_tensor(input_1)
517
        output = self.reshape(x=input, shape=[5, 10])
J
joejiong 已提交
518 519
        out_np = output.numpy()
        expected_out = np.reshape(input_1, newshape=[5, 10])
520
        np.testing.assert_allclose(expected_out, out_np, rtol=1e-05)
J
joejiong 已提交
521 522 523 524 525

    def test_out_float32(self):
        paddle.disable_static()
        input_1 = np.random.random([5, 1, 10]).astype("float32")
        input = paddle.to_tensor(input_1)
526
        output = self.reshape(x=input, shape=[5, 10])
J
joejiong 已提交
527 528
        out_np = output.numpy()
        expected_out = np.reshape(input_1, newshape=[5, 10])
529
        np.testing.assert_allclose(expected_out, out_np, rtol=1e-05)
J
joejiong 已提交
530 531


532
class TestDygraphReshapeInplaceAPI(TestDygraphReshapeAPI):
533

534 535 536 537
    def executed_api(self):
        self.reshape = paddle.reshape_


538
class TestReshapeZeroTensor(unittest.TestCase):
539

540 541
    def test_reshape_zero_tensor_success(self):
        zero_tensor = paddle.zeros([0, 2, 3])
542
        # since we use "0" as the dimension copy semantically in reshape,
543 544 545 546 547 548 549 550 551 552
        # we need to copy the 0 dim in the src tensor in order to make a successful zero tensor reshape
        zero_tensor = zero_tensor.reshape([0, 6])
        self.assertTrue(list(zero_tensor.shape) == [0, 6])

    def test_reshape_zero_tensor_error(self):
        zero_tensor = paddle.zeros([0, 2, 3])
        with self.assertRaises(ValueError):
            zero_tensor.reshape([2, 3])


553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604
class TestReshapeAPI_ZeroDim(unittest.TestCase):

    def test_dygraph(self):
        paddle.disable_static()
        fluid.set_flags({"FLAGS_retain_grad_for_all_tensor": True})
        x = paddle.rand([])
        x.stop_gradient = False

        out = paddle.reshape(x, [1])
        out.backward()
        self.assertEqual(out.shape, [1])
        self.assertEqual(x.grad.shape, [])
        self.assertEqual(out.grad.shape, [1])

        out = paddle.reshape(x, [-1, 1])
        out.backward()
        self.assertEqual(out.shape, [1, 1])
        self.assertEqual(x.grad.shape, [])
        self.assertEqual(out.grad.shape, [1, 1])

        paddle.enable_static()

    def test_static(self):
        main_prog = fluid.Program()
        with fluid.program_guard(main_prog, fluid.Program()):
            x = paddle.rand([])
            x.stop_gradient = False
            out = paddle.reshape(x, [-1])
            fluid.backward.append_backward(out)

            prog = paddle.static.default_main_program()
            block = prog.global_block()

            x_grad = block.var(fluid.framework.grad_var_name(x.name))
            out_grad = block.var(fluid.framework.grad_var_name(out.name))

            # Test compile shape
            self.assertEqual(x.shape, ())
            self.assertEqual(out.shape, (1, ))
            self.assertEqual(x_grad.shape, ())
            self.assertEqual(out_grad.shape, (1, ))

            exe = fluid.Executor()
            result = exe.run(main_prog, fetch_list=[x, out, x_grad, out_grad])

            # Test runtime shape
            self.assertEqual(result[0].shape, ())
            self.assertEqual(result[1].shape, (1, ))
            self.assertEqual(result[2].shape, ())
            self.assertEqual(result[3].shape, (1, ))


Y
ying 已提交
605
if __name__ == "__main__":
H
hong 已提交
606
    paddle.enable_static()
Y
Yibing Liu 已提交
607
    unittest.main()