# Copyright (c) 2023 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. import unittest import numpy as np import paddle def numpy_unflatten(x, axis, shape): if isinstance(shape, (list, tuple)): if len(shape) == 0: raise ValueError("The input for shape cannot be empty.") if isinstance(shape, list) or isinstance(shape, tuple): if np.min(shape) < -1: raise ValueError(f"invalid shape dimension {np.min(shape)}.") if shape.count(-1) > 1: raise ValueError("The shape can contain only one -1.") elif shape.count(-1) == 1: list(shape)[shape.index(-1)] = x.shape[axis] / abs( np.prod(shape) ) else: sizes = np.prod(shape) if sizes != x.shape[axis]: raise ValueError( "The product of the elements in shape{} is not equal to {}.".format( shape, x.shape[axis] ) ) else: raise TypeError( "The data type of x should be one of ['List', 'Tuple', 'Tensor'], but got {}".format( type(shape) ) ) length = len(x.shape) if axis < 0: axis = axis + length new_shape = x.shape[:axis] + tuple(shape) + x.shape[axis + 1 :] x = x.reshape(new_shape) return x class TestUnflattenAPI(unittest.TestCase): def set_args(self): self.x = np.random.rand(4, 6, 16) self.axis = 0 self.shape = (2, 2) self.shape_is_tensor = False def get_output(self): self.output = self.ref_api(self.x, self.axis, self.shape) def set_api(self): self.ref_api = numpy_unflatten self.paddle_api = paddle.unflatten def setUp(self): self.set_api() self.set_args() self.get_output() self.places = [paddle.CPUPlace()] if paddle.device.is_compiled_with_cuda(): self.places.append(paddle.CUDAPlace(0)) def func_dygraph(self): for place in self.places: paddle.disable_static() x = paddle.to_tensor(self.x, place=place) if self.shape_is_tensor: shape = paddle.to_tensor(self.shape) else: shape = self.shape out = self.paddle_api(x=x, axis=self.axis, shape=shape) np.testing.assert_allclose(out, self.output, rtol=1e-05) def test_dygraph(self): self.setUp() self.func_dygraph() def test_static(self): paddle.enable_static() places = [paddle.CPUPlace()] if paddle.device.is_compiled_with_cuda(): places.append(paddle.CUDAPlace(0)) for place in places: with paddle.static.program_guard( paddle.static.Program(), paddle.static.Program() ): x = paddle.static.data( name="x", shape=self.x.shape, dtype=self.x.dtype ) if self.shape_is_tensor: shape = np.array(self.shape) shape = paddle.static.data( name='shape', shape=shape.shape, dtype=shape.dtype ) else: shape = self.shape exe = paddle.static.Executor(place) out = self.paddle_api(x=x, axis=self.axis, shape=shape) fetches = exe.run( paddle.static.default_main_program(), feed={ "x": self.x, "axis": self.axis, "shape": self.shape, }, fetch_list=[out], ) np.testing.assert_allclose(fetches[0], self.output, rtol=1e-05) # check the data type of the input x class TestUnflattenInputInt16(TestUnflattenAPI): def set_args(self): self.x = np.random.rand(4, 6, 16).astype('int16') self.axis = 0 self.shape = (2, 2) self.shape_is_tensor = False class TestUnflattenInputInt32(TestUnflattenAPI): def set_args(self): self.x = np.random.rand(4, 6, 16).astype('int32') self.axis = 0 self.shape = (2, 2) self.shape_is_tensor = False class TestUnflattenInputInt64(TestUnflattenAPI): def set_args(self): self.x = np.random.rand(4, 6, 16).astype('int64') self.axis = 0 self.shape = (2, 2) self.shape_is_tensor = False class TestUnflattenInputFloat16(TestUnflattenAPI): def set_args(self): self.x = np.random.rand(4, 6, 16).astype('float16') self.axis = 0 self.shape = (2, 2) self.shape_is_tensor = False class TestUnflattenInputFloat32(TestUnflattenAPI): def set_args(self): self.x = np.random.rand(4, 6, 16).astype('float32') self.axis = 0 self.shape = (2, 2) self.shape_is_tensor = False class TestUnflattenInputFloat64(TestUnflattenAPI): def set_args(self): self.x = np.random.rand(4, 6, 16).astype('float64') self.axis = 0 self.shape = (2, 2) self.shape_is_tensor = False class TestUnflattenInputbool(TestUnflattenAPI): def set_args(self): self.x = np.random.rand(4, 6, 16).astype('bool') self.axis = 0 self.shape = (2, 2) self.shape_is_tensor = False # check the data type and edge cases of shape class TestUnflattenShapeList1(TestUnflattenAPI): def set_args(self): self.x = np.random.rand(4, 6, 16).astype('float32') self.axis = 0 self.shape = [2, 2] self.shape_is_tensor = False class TestUnflattenShapeList2(TestUnflattenAPI): def set_args(self): self.x = np.random.rand(4, 6, 16).astype('float32') self.axis = -1 self.shape = [-1, 2] self.shape_is_tensor = False class TestUnflattenShapeList3(TestUnflattenAPI): def set_args(self): self.x = np.random.rand(4, 6, 16).astype('float32') self.axis = 0 self.shape = [-1] self.shape_is_tensor = False class TestUnflattenTupleShape1(TestUnflattenAPI): def set_args(self): self.x = np.random.rand(4, 6, 16).astype('float32') self.axis = 0 self.shape = (2, 2) self.shape_is_tensor = False class TestUnflattenTupleShape2(TestUnflattenAPI): def set_args(self): self.x = np.random.rand(4, 6, 16).astype('float32') self.axis = 0 self.shape = (-1, 2) self.shape_is_tensor = False class TestUnflattenTupleShape3(TestUnflattenAPI): def set_args(self): self.x = np.random.rand(4, 6, 16).astype('float32') self.axis = 0 self.shape = (-1,) self.shape_is_tensor = False class TestUnflattenShapeTensorInt32(TestUnflattenAPI): def set_args(self): self.x = np.random.rand(4, 6, 16).astype('float32') self.axis = 0 self.shape = tuple(np.array((-1, 4)).astype('int32')) self.shape_is_tensor = True # check the value of axis class TestUnflattenAxis1(TestUnflattenAPI): def set_args(self): self.x = np.random.rand(4, 6, 16).astype('float32') self.axis = 1 self.shape = (2, 3) self.shape_is_tensor = False class TestUnflattenAxis2(TestUnflattenAPI): def set_args(self): self.x = np.random.rand(4, 6, 16).astype('float32') self.axis = -1 self.shape = (2, 8) self.shape_is_tensor = False class TestLayer(unittest.TestCase): def set_args(self): self.x = np.random.randn(3, 4, 4, 5).astype('float32') self.axis = 1 self.shape = [2, 2] def setUp(self): self.set_args() self.places = [paddle.CPUPlace()] if paddle.device.is_compiled_with_cuda(): self.places.append(paddle.CUDAPlace(0)) def test_layer(self): paddle.enable_static() places = [paddle.CPUPlace()] if paddle.device.is_compiled_with_cuda(): places.append(paddle.CUDAPlace(0)) for place in places: with paddle.static.program_guard( paddle.static.Program(), paddle.static.Program() ): x = paddle.static.data( name="x", dtype=self.x.dtype, shape=self.x.shape ) exe = paddle.static.Executor(place) unflatten = paddle.nn.Unflatten(self.axis, self.shape) out = unflatten(x) static_ret = exe.run( paddle.static.default_main_program(), feed={"x": self.x, "axis": self.axis, "shape": self.shape}, fetch_list=[out], )[0] for place in self.places: paddle.disable_static() x = paddle.to_tensor(self.x, dtype='float32', place=place) unflatten = paddle.nn.Unflatten(self.axis, self.shape) dy_ret_value = unflatten(self.x) np.testing.assert_array_equal(static_ret, dy_ret_value) class TestLayerName(unittest.TestCase): def test_name(self): self.x = np.random.randn(3, 4, 4, 5).astype('float32') self.axis = 1 self.shape = [2, 2] self.name = 'unflatten' unflatten = paddle.nn.Unflatten(self.axis, self.shape, self.name) _name = unflatten.extra_repr() if __name__ == '__main__': paddle.enable_static() unittest.main()