# Copyright (c) 2020 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 os import tempfile import unittest import numpy as np import paddle from paddle.static import InputSpec SEED = 2020 np.random.seed(SEED) @paddle.jit.to_static def test_slice_without_control_flow(x): # Python slice will not be transformed. x = paddle.to_tensor(x) a = [x] a[0] = paddle.full(shape=[2], fill_value=2, dtype="float32") return a[0] @paddle.jit.to_static def test_slice_in_if(x): x = paddle.to_tensor(x) a = [] if x.numpy()[0] > 0: a.append(x) else: a.append(paddle.full(shape=[1, 2], fill_value=9, dtype="int32")) if x.numpy()[0] > 0: a[0] = x a[0] = x + 1 out = a[0] return out @paddle.jit.to_static def test_slice_in_while_loop(x, iter_num=3): x = paddle.to_tensor(x) iter_num_var = paddle.full(shape=[1], fill_value=iter_num, dtype="int32") a = [] i = 0 while i < iter_num_var: a.append(x) i += 1 i = 0 while i < iter_num_var.numpy()[0]: a[i] = paddle.full(shape=[2], fill_value=2, dtype="float32") i += 1 out = a[0:iter_num] return out[0] @paddle.jit.to_static def test_slice_in_for_loop(x, iter_num=3): x = paddle.to_tensor(x) a = [] # Use `paddle.full` so that static analysis can analyze the type of iter_num is Tensor iter_num = paddle.full( shape=[1], fill_value=iter_num, dtype="int32" ) # TODO(liym27): Delete it if the type of parameter iter_num can be resolved for i in range(iter_num): a.append(x) for i in range(iter_num): a[i] = x out = a[2] return out @paddle.jit.to_static def test_set_value(x): x = paddle.to_tensor(x) x[0] = paddle.full(shape=[1], fill_value=2, dtype="float32") x[1:2, 0:1] = 10 return x class LayerWithSetValue(paddle.nn.Layer): def __init__(self, input_dim, hidden): super().__init__() self.linear = paddle.nn.Linear(input_dim, hidden) @paddle.jit.to_static def forward(self, x): x = self.linear(x) x[0] = 1 return x class TestSliceWithoutControlFlow(unittest.TestCase): def setUp(self): self.init_input() self.place = ( paddle.CUDAPlace(0) if paddle.is_compiled_with_cuda() else paddle.CPUPlace() ) self.init_dygraph_func() paddle.disable_static() def init_input(self): self.input = np.random.random(3).astype('int32') def init_dygraph_func(self): self.dygraph_func = test_slice_without_control_flow def run_dygraph_mode(self): return self._run(to_static=False) def _run(self, to_static): paddle.jit.enable_to_static(to_static) res = self.dygraph_func(self.input) return res.numpy() def run_static_mode(self): return self._run(to_static=True) def test_transformed_static_result(self): static_res = self.run_static_mode() dygraph_res = self.run_dygraph_mode() np.testing.assert_allclose(dygraph_res, static_res, rtol=1e-05) class TestSliceInIf(TestSliceWithoutControlFlow): def init_dygraph_func(self): self.dygraph_func = test_slice_in_if class TestSliceInWhileLoop(TestSliceWithoutControlFlow): def init_dygraph_func(self): self.dygraph_func = test_slice_in_while_loop class TestSliceInForLoop(TestSliceWithoutControlFlow): def init_dygraph_func(self): self.dygraph_func = test_slice_in_for_loop class TestSetValue(TestSliceWithoutControlFlow): def init_input(self): self.input = np.full([3, 4, 5], 5).astype('float32') def init_dygraph_func(self): self.dygraph_func = test_set_value class TestSetValueWithLayerAndSave(unittest.TestCase): def setUp(self): self.temp_dir = tempfile.TemporaryDirectory() self.model_path = os.path.join( self.temp_dir.name, "layer_use_set_value" ) def tearDown(self): self.temp_dir.cleanup() def test_set_value_with_save(self): paddle.jit.enable_to_static(True) model = LayerWithSetValue(input_dim=10, hidden=1) x = paddle.full(shape=[5, 10], fill_value=5.0, dtype="float32") paddle.jit.save( layer=model, path=self.model_path, input_spec=[x], output_spec=None ) class TestSliceSupplementSpecialCase(unittest.TestCase): # unittest for slice index which abs(step)>0. eg: x[::2] def test_static_slice_step(self): paddle.enable_static() array = np.arange(4**3).reshape((4, 4, 4)).astype('int64') x = paddle.static.data(name='x', shape=[4, 4, 4], dtype='int64') z1 = x[::2] z2 = x[::-2] place = paddle.CPUPlace() prog = paddle.static.default_main_program() exe = paddle.static.Executor(place) exe.run(paddle.static.default_startup_program()) out = exe.run(prog, feed={'x': array}, fetch_list=[z1, z2]) np.testing.assert_array_equal(out[0], array[::2]) np.testing.assert_array_equal(out[1], array[::-2]) def test_static_slice_step_dygraph2static(self): paddle.disable_static() array = np.arange(4**2 * 5).reshape((5, 4, 4)).astype('int64') inps = paddle.to_tensor(array) def func(inps): return inps[::2], inps[::-2] origin_result = func(inps) sfunc = paddle.jit.to_static( func, input_spec=[InputSpec(shape=[None, 4, 4])] ) static_result = sfunc(inps) np.testing.assert_array_equal( origin_result[0].numpy(), static_result[0].numpy() ) np.testing.assert_array_equal( origin_result[1].numpy(), static_result[1].numpy() ) class TestPaddleStridedSlice(unittest.TestCase): def test_compare_paddle_strided_slice_with_numpy(self): paddle.disable_static() array = np.arange(5) pt = paddle.to_tensor(array) s1 = 3 e1 = 1 stride1 = -2 sl = paddle.strided_slice( pt, axes=[ 0, ], starts=[ s1, ], ends=[ e1, ], strides=[ stride1, ], ) self.assertTrue(array[s1:e1:stride1], sl) array = np.arange(6 * 6).reshape((6, 6)) pt = paddle.to_tensor(array) s2 = [8, -1] e2 = [1, -5] stride2 = [-2, -3] sl = paddle.strided_slice( pt, axes=[0, 1], starts=s2, ends=e2, strides=stride2 ) np.testing.assert_array_equal( sl.numpy(), array[s2[0] : e2[0] : stride2[0], s2[1] : e2[1] : stride2[1]], ) array = np.arange(6 * 7 * 8).reshape((6, 7, 8)) pt = paddle.to_tensor(array) s2 = [7, -1] e2 = [2, -5] stride2 = [-2, -3] sl = paddle.strided_slice( pt, axes=[0, 2], starts=s2, ends=e2, strides=stride2 ) array_slice = array[ s2[0] : e2[0] : stride2[0], ::, s2[1] : e2[1] : stride2[1] ] np.testing.assert_array_equal(sl.numpy(), array_slice) def slice_zero_shape_tensor(x): y = x[1:2] return y class TestSliceZeroShapeTensor(unittest.TestCase): def test_slice(self): paddle.disable_static() x = paddle.ones([0, 0, 0, 0]) y = slice_zero_shape_tensor(x) np.testing.assert_equal(y.shape, [0, 0, 0, 0]) static_func = paddle.jit.to_static(slice_zero_shape_tensor) y = static_func(x) np.testing.assert_equal(y.shape, [0, 0, 0, 0]) if __name__ == '__main__': unittest.main()