2720 lines
92 KiB
Python
Executable File
2720 lines
92 KiB
Python
Executable File
# 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 functools
|
|
import unittest
|
|
|
|
import numpy as np
|
|
from op_test import get_device_place, get_places, is_custom_device
|
|
|
|
import paddle
|
|
|
|
|
|
class TestInplace(unittest.TestCase):
|
|
def test_forward_version(self):
|
|
with paddle.base.dygraph.guard():
|
|
var = paddle.to_tensor(np.ones((4, 2, 3)).astype(np.float32))
|
|
self.assertEqual(var.inplace_version, 0)
|
|
|
|
var[0] = 1.1
|
|
self.assertEqual(var.inplace_version, 1)
|
|
|
|
paddle.assign(paddle.ones(shape=[3]), var)
|
|
|
|
# NOTE(liym27): assign(input, output) is an inplace operation for output.
|
|
# There is inplace-related processing for api assign, var.inplace_version should be 2 not 1.
|
|
self.assertEqual(var.inplace_version, 2)
|
|
|
|
var[2] = 3
|
|
self.assertEqual(var.inplace_version, 3)
|
|
|
|
def test_backward_error(self):
|
|
# It raises an error because the inplace operator will result
|
|
# in incorrect gradient computation.
|
|
with paddle.base.dygraph.guard():
|
|
var_a = paddle.ones(shape=[4, 2, 3], dtype="float32")
|
|
var_a.stop_gradient = False
|
|
|
|
var_b = var_a**2
|
|
|
|
# Here, the gradient computation will use the value of var_b
|
|
var_c = var_b**2
|
|
var_b[1:2] = 3.3 # var_b is modified inplace after using it
|
|
|
|
var_d = var_b**2
|
|
|
|
loss = paddle.nn.functional.relu(var_c + var_d)
|
|
with self.assertRaisesRegex(
|
|
RuntimeError,
|
|
"received tensor_version:1 != wrapper_version_snapshot:0",
|
|
):
|
|
loss.backward()
|
|
|
|
def test_backward_success_1(self):
|
|
# var_b is modified inplace before using it, the inplace operator doesn't result
|
|
# in incorrect gradient computation.
|
|
with paddle.base.dygraph.guard():
|
|
var_a = paddle.ones(shape=[4, 2, 3], dtype="float32")
|
|
var_a.stop_gradient = False
|
|
|
|
var_b = var_a**2
|
|
var_b[1:2] = 3 # var_b is modified inplace before using it
|
|
|
|
# Here, the gradient computation will use the value of var_b
|
|
var_c = var_b**2
|
|
loss = var_c.sum()
|
|
loss.backward()
|
|
|
|
def test_backward_success_2(self):
|
|
# Although var_b is modified inplace after using it, it does not used in gradient computation.
|
|
# The inplace operator doesn't result in incorrect gradient computation.
|
|
with paddle.base.dygraph.guard():
|
|
var_a = paddle.ones(shape=[4, 2, 3], dtype="float32")
|
|
var_a.stop_gradient = False
|
|
|
|
var_b = var_a**2
|
|
|
|
var_b[1:2] = 3 # var_b is modified inplace before using it
|
|
|
|
var_c = (
|
|
var_b + var_b
|
|
) # Here, the grad op of sum doesn't use the value of var_b
|
|
loss = var_c.sum()
|
|
|
|
var_b[1:2] = 3 # var_b is modified inplace after using it
|
|
|
|
loss.backward()
|
|
|
|
|
|
class TestInplaceCompatibility(unittest.TestCase):
|
|
def setUp(self):
|
|
np.random.seed(2026)
|
|
self.shape = [10, 20, 1]
|
|
self.dtype = "float32"
|
|
self.x_np = np.random.uniform(-5, 5, self.shape).astype(self.dtype)
|
|
self.set_inplace_api()
|
|
|
|
def numpy_api_processing(self, var):
|
|
return np.abs(var)
|
|
|
|
def set_inplace_api(self):
|
|
self.inplace_api = paddle.abs_
|
|
|
|
def test_inplace_compatibility_dygraph(self):
|
|
paddle.disable_static()
|
|
ref_out = self.numpy_api_processing(self.x_np)
|
|
x = paddle.to_tensor(self.x_np)
|
|
# arg alias
|
|
out1 = self.inplace_api(x=x)
|
|
out2 = self.inplace_api(input=x)
|
|
np.testing.assert_allclose(out1.numpy(), ref_out, rtol=1e-05)
|
|
np.testing.assert_allclose(out2.numpy(), ref_out, rtol=1e-05)
|
|
# inplace behavior
|
|
np.testing.assert_allclose(x.numpy(), ref_out, rtol=1e-05)
|
|
self.assertTrue(id(x) == id(out1))
|
|
self.assertTrue(id(x) == id(out2))
|
|
# prohibited out arg
|
|
y = paddle.empty([])
|
|
with self.assertRaises(ValueError):
|
|
self.inplace_api(x, out=y)
|
|
|
|
def test_inplace_compatibility_static(self):
|
|
paddle.enable_static()
|
|
ref_out = self.numpy_api_processing(self.x_np)
|
|
main = paddle.static.Program()
|
|
startup = paddle.static.Program()
|
|
with paddle.base.program_guard(main, startup):
|
|
x = paddle.static.data(name="x", shape=self.shape, dtype=self.dtype)
|
|
out1 = self.inplace_api(x=x)
|
|
out2 = self.inplace_api(input=x)
|
|
fetch_list = [x, out1, out2]
|
|
exe = paddle.base.Executor()
|
|
fetches = exe.run(
|
|
main,
|
|
feed={"x": self.x_np},
|
|
fetch_list=fetch_list,
|
|
)
|
|
np.testing.assert_allclose(fetches[0], ref_out, rtol=1e-05)
|
|
np.testing.assert_allclose(fetches[1], ref_out, rtol=1e-05)
|
|
np.testing.assert_allclose(fetches[2], ref_out, rtol=1e-05)
|
|
|
|
|
|
class TestStaticInplace(unittest.TestCase):
|
|
def setUp(self):
|
|
np.random.seed(2026)
|
|
self.shape = [10, 20, 1]
|
|
self.dtype = "float32"
|
|
self.x_np = np.random.uniform(-5, 5, self.shape).astype(self.dtype)
|
|
|
|
def numpy_api_processing(self, var):
|
|
return np.abs(var)
|
|
|
|
def inplace_api_processing(self, var):
|
|
return paddle.abs_(var)
|
|
|
|
def test_inplace_static(self):
|
|
paddle.enable_static()
|
|
ref_out = self.numpy_api_processing(self.x_np)
|
|
main = paddle.static.Program()
|
|
startup = paddle.static.Program()
|
|
with paddle.base.program_guard(main, startup):
|
|
x = paddle.static.data(name="x", shape=self.shape, dtype=self.dtype)
|
|
out = self.inplace_api_processing(x)
|
|
fetch_list = [out, x]
|
|
exe = paddle.base.Executor()
|
|
fetches = exe.run(
|
|
main,
|
|
feed={"x": self.x_np},
|
|
fetch_list=fetch_list,
|
|
)
|
|
# test inplace output value
|
|
np.testing.assert_allclose(fetches[0], ref_out, rtol=1e-05)
|
|
# test inplace behavior
|
|
np.testing.assert_allclose(fetches[1], fetches[0], rtol=1e-05)
|
|
|
|
|
|
class TestDygraphInplace(unittest.TestCase):
|
|
def setUp(self):
|
|
self.init_data()
|
|
self.set_np_compare_func()
|
|
|
|
def init_data(self):
|
|
self.input_var_numpy = np.random.uniform(-5, 5, [10, 20, 1])
|
|
self.dtype = "float32"
|
|
|
|
def set_np_compare_func(self):
|
|
self.np_compare = np.array_equal
|
|
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.squeeze(var)
|
|
|
|
def inplace_api_processing(self, var):
|
|
return paddle.squeeze_(var)
|
|
|
|
def test_inplace_api(self):
|
|
var = paddle.to_tensor(self.input_var_numpy).astype(self.dtype)
|
|
inplace_var = self.inplace_api_processing(var)
|
|
self.assertTrue(id(var) == id(inplace_var))
|
|
|
|
inplace_var[0] = 2
|
|
np.testing.assert_array_equal(var.numpy(), inplace_var.numpy())
|
|
|
|
def test_forward_result(self):
|
|
var = paddle.to_tensor(self.input_var_numpy).astype(self.dtype)
|
|
no_inplace_var = self.non_inplace_api_processing(var)
|
|
inplace_var = self.inplace_api_processing(var)
|
|
np.testing.assert_array_equal(
|
|
no_inplace_var.numpy(), inplace_var.numpy()
|
|
)
|
|
|
|
def test_forward_version(self):
|
|
with paddle.base.dygraph.guard():
|
|
var = paddle.to_tensor(self.input_var_numpy).astype(self.dtype)
|
|
self.assertEqual(var.inplace_version, 0)
|
|
|
|
inplace_var = self.inplace_api_processing(var)
|
|
self.assertEqual(var.inplace_version, 1)
|
|
|
|
inplace_var[0] = 2
|
|
self.assertEqual(var.inplace_version, 2)
|
|
|
|
inplace_var = self.inplace_api_processing(inplace_var)
|
|
self.assertEqual(var.inplace_version, 3)
|
|
|
|
def test_leaf_inplace_var_error(self):
|
|
with paddle.base.dygraph.guard():
|
|
var = paddle.to_tensor(self.input_var_numpy).astype(self.dtype)
|
|
var.stop_gradient = False
|
|
|
|
def leaf_inplace_error():
|
|
self.inplace_api_processing(var)
|
|
|
|
self.assertRaises(ValueError, leaf_inplace_error)
|
|
|
|
def test_backward_error(self):
|
|
# It raises an error because the inplace operator will result
|
|
# in incorrect gradient computation.
|
|
with paddle.base.dygraph.guard():
|
|
var_a = paddle.to_tensor(self.input_var_numpy).astype(self.dtype)
|
|
var_a.stop_gradient = False
|
|
|
|
var_b = var_a**2
|
|
|
|
# Here, the gradient computation will use the value of var_b
|
|
var_c = var_b**2
|
|
self.inplace_api_processing(var_b)
|
|
var_c = paddle.cast(var_c, "float32")
|
|
|
|
loss = paddle.nn.functional.relu(var_c)
|
|
with self.assertRaisesRegex(
|
|
RuntimeError,
|
|
"received tensor_version:1 != wrapper_version_snapshot:0",
|
|
):
|
|
loss.backward()
|
|
|
|
def test_backward_success_1(self):
|
|
# var_b is modified inplace before using it, the inplace operator doesn't result
|
|
# in incorrect gradient computation.
|
|
grad_var_a, grad_var_a_inplace = 0, 1
|
|
with paddle.base.dygraph.guard():
|
|
var_a = paddle.to_tensor(self.input_var_numpy).astype(self.dtype)
|
|
var_a.stop_gradient = False
|
|
|
|
var_b = var_a**2
|
|
var_c = self.inplace_api_processing(
|
|
var_b
|
|
) # var_b is modified inplace before using it
|
|
|
|
# Here, the gradient computation will use the value of var_b
|
|
var_d = var_c**2
|
|
var_d = paddle.cast(var_d, "float32")
|
|
loss = var_d.sum()
|
|
loss.backward()
|
|
grad_var_a_inplace = var_a.grad.numpy()
|
|
|
|
with paddle.base.dygraph.guard():
|
|
var_a = paddle.to_tensor(self.input_var_numpy).astype(self.dtype)
|
|
var_a.stop_gradient = False
|
|
|
|
var_b = var_a**2
|
|
var_c = self.non_inplace_api_processing(var_b)
|
|
var_d = var_c**2
|
|
var_d = paddle.cast(var_d, "float32")
|
|
loss = var_d.sum()
|
|
loss.backward()
|
|
grad_var_a = var_a.grad.numpy()
|
|
self.assertTrue(self.np_compare(grad_var_a_inplace, grad_var_a))
|
|
|
|
def test_backward_success_2(self):
|
|
# Although var_b is modified inplace after using it, it does not used in gradient computation.
|
|
# The inplace operator doesn't result in incorrect gradient computation.
|
|
grad_var_a, grad_var_a_inplace = 0, 1
|
|
with paddle.base.dygraph.guard():
|
|
var_a = paddle.to_tensor(self.input_var_numpy).astype(self.dtype)
|
|
var_a.stop_gradient = False
|
|
|
|
var_b = var_a**2
|
|
|
|
var_c = self.inplace_api_processing(
|
|
var_b
|
|
) # var_b is modified inplace before using it
|
|
|
|
var_d = (
|
|
var_c + var_c
|
|
) # Here, the grad op of sum doesn't use the value of var_b
|
|
var_d = paddle.cast(var_d, "float32")
|
|
loss = var_d.sum()
|
|
|
|
loss.backward()
|
|
grad_var_a_inplace = var_a.grad.numpy()
|
|
|
|
with paddle.base.dygraph.guard():
|
|
var_a = paddle.to_tensor(self.input_var_numpy).astype(self.dtype)
|
|
var_a.stop_gradient = False
|
|
|
|
var_b = var_a**2
|
|
|
|
var_c = self.non_inplace_api_processing(var_b)
|
|
|
|
var_d = (
|
|
var_c + var_c
|
|
) # Here, the grad op of sum doesn't use the value of var_b
|
|
var_d = paddle.cast(var_d, "float32")
|
|
loss = var_d.sum()
|
|
|
|
loss.backward()
|
|
grad_var_a = var_a.grad.numpy()
|
|
np.testing.assert_array_equal(grad_var_a_inplace, grad_var_a)
|
|
|
|
|
|
class TestDygraphInplaceMaskedFill(TestDygraphInplace):
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.masked_fill(var, self.mask, self.value)
|
|
|
|
def inplace_api_processing(self, var):
|
|
return paddle.masked_fill_(var, self.mask, self.value)
|
|
|
|
def init_data(self):
|
|
self.dtype = "float32"
|
|
self.input_var_numpy = np.random.uniform(-5, 5, [30, 3])
|
|
self.value = np.random.uniform(-10, 10)
|
|
self.value = paddle.to_tensor(self.value, dtype=self.dtype)
|
|
self.mask = np.random.randint(0, 2, [30, 3]).astype('bool')
|
|
self.mask = paddle.to_tensor(self.mask, dtype='bool')
|
|
|
|
def test_forward_version(self):
|
|
with paddle.base.dygraph.guard():
|
|
var = paddle.to_tensor(self.input_var_numpy).astype(self.dtype)
|
|
self.assertEqual(var.inplace_version, 0)
|
|
|
|
inplace_var = self.inplace_api_processing(var)
|
|
self.assertEqual(var.inplace_version, 1)
|
|
|
|
inplace_var[0] = 2
|
|
self.assertEqual(var.inplace_version, 2)
|
|
|
|
inplace_var = self.inplace_api_processing(inplace_var)
|
|
self.assertEqual(var.inplace_version, 3)
|
|
|
|
def test_backward_error(self):
|
|
# It raises an error because the inplace operator will result
|
|
# in incorrect gradient computation.
|
|
with paddle.base.dygraph.guard():
|
|
var_a = paddle.to_tensor(self.input_var_numpy).astype(self.dtype)
|
|
var_a.stop_gradient = False
|
|
|
|
var_b = var_a**2
|
|
|
|
# Here, the gradient computation will use the value of var_b
|
|
var_c = var_b**2
|
|
self.inplace_api_processing(var_b)
|
|
|
|
loss = paddle.nn.functional.relu(var_c)
|
|
with self.assertRaisesRegex(
|
|
RuntimeError,
|
|
f"received tensor_version:{1} != wrapper_version_snapshot:{0}",
|
|
):
|
|
loss.backward()
|
|
|
|
|
|
class TestDygraphInplaceMaskedFill2(TestDygraphInplaceMaskedFill):
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.masked_fill(var, self.mask, self.value)
|
|
|
|
def inplace_api_processing(self, var):
|
|
return paddle.masked_fill_(var, self.mask, self.value)
|
|
|
|
def init_data(self):
|
|
self.dtype = "float32"
|
|
self.input_var_numpy = np.random.uniform(-5, 5, [30, 3])
|
|
self.value = np.random.uniform(-10, 10)
|
|
self.value = paddle.to_tensor(self.value, dtype=self.dtype)
|
|
self.mask = np.random.randint(0, 2, [30, 1]).astype('bool')
|
|
self.mask = paddle.to_tensor(self.mask, dtype='bool')
|
|
|
|
|
|
class TestDygraphInplaceMaskedScatter(TestDygraphInplace):
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.masked_scatter(var, self.mask, self.value)
|
|
|
|
def inplace_api_processing(self, var):
|
|
return paddle.masked_scatter_(var, self.mask, self.value)
|
|
|
|
def init_data(self):
|
|
self.dtype = "float32"
|
|
self.input_var_numpy = np.random.uniform(-5, 5, [30, 3])
|
|
self.value = np.random.uniform(size=(30, 30))
|
|
self.value = paddle.to_tensor(self.value, dtype=self.dtype)
|
|
self.mask = np.random.randint(0, 2, [30, 1]).astype('bool')
|
|
self.mask = paddle.to_tensor(self.mask, dtype='bool')
|
|
|
|
|
|
class TestDygraphInplaceWithContinuous(TestDygraphInplace):
|
|
def init_data(self):
|
|
self.input_var_numpy = np.random.uniform(-5, 5, [10, 20, 1])
|
|
self.dtype = "float32"
|
|
|
|
def set_np_compare_func(self):
|
|
np_array_equal_with_nan = functools.partial(
|
|
np.array_equal, equal_nan=True
|
|
)
|
|
self.np_compare = np_array_equal_with_nan
|
|
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.sin(var)
|
|
|
|
def inplace_api_processing(self, var):
|
|
return paddle.sin_(var)
|
|
|
|
def test_continuous_inplace_backward(self):
|
|
# The api that only relies on input to calculate the gradient will copy input before
|
|
# the inplace calculation, so here supports continuous inplace backward calculation.
|
|
grad_var_a, grad_var_a_inplace = 0, 1
|
|
with paddle.base.dygraph.guard():
|
|
var_a = paddle.to_tensor(self.input_var_numpy).astype(self.dtype)
|
|
var_a.stop_gradient = False
|
|
|
|
var_b = var_a**2
|
|
var_c = self.inplace_api_processing(var_b)
|
|
var_d = self.inplace_api_processing(var_c)
|
|
loss = var_d.sum()
|
|
var_d = paddle.cast(var_d, "float32")
|
|
loss.backward()
|
|
grad_var_a_inplace = var_a.grad.numpy()
|
|
|
|
with paddle.base.dygraph.guard():
|
|
var_a = paddle.to_tensor(self.input_var_numpy).astype(self.dtype)
|
|
var_a.stop_gradient = False
|
|
|
|
var_b = var_a**2
|
|
var_c = self.non_inplace_api_processing(var_b)
|
|
var_d = self.non_inplace_api_processing(var_c)
|
|
var_d = paddle.cast(var_d, "float32")
|
|
loss = var_d.sum()
|
|
loss.backward()
|
|
grad_var_a = var_a.grad.numpy()
|
|
|
|
self.assertTrue(self.np_compare(grad_var_a_inplace, grad_var_a))
|
|
|
|
|
|
class TestDygraphInplaceCopysign(TestDygraphInplace):
|
|
def init_data(self):
|
|
self.input_var_numpy = np.random.randn(10, 20)
|
|
self.dtype = "float32"
|
|
self.y = -3.0
|
|
|
|
def inplace_api_processing(self, var):
|
|
return paddle.copysign_(var, self.y)
|
|
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.copysign(var, self.y)
|
|
|
|
def test_leaf_inplace_var_error(self):
|
|
with paddle.base.dygraph.guard():
|
|
var = paddle.to_tensor(self.input_var_numpy).astype(self.dtype)
|
|
var.stop_gradient = False
|
|
self.y = paddle.rand([2, 10, 20])
|
|
|
|
def leaf_inplace_error():
|
|
self.inplace_api_processing(var)
|
|
|
|
self.assertRaises(ValueError, leaf_inplace_error)
|
|
|
|
|
|
class TestDygraphInplaceUnsqueeze(TestDygraphInplace):
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.unsqueeze(var, -1)
|
|
|
|
def inplace_api_processing(self, var):
|
|
return paddle.unsqueeze_(var, -1)
|
|
|
|
|
|
class TestDygraphInplaceReshape(TestDygraphInplace):
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.reshape(var, [-1])
|
|
|
|
def inplace_api_processing(self, var):
|
|
return paddle.reshape_(var, [-1])
|
|
|
|
|
|
class TestDygraphInplaceReshapeTensor(TestDygraphInplace):
|
|
def non_inplace_api_processing(self, var):
|
|
shape = paddle.to_tensor([-1])
|
|
return paddle.reshape(var, shape)
|
|
|
|
def inplace_api_processing(self, var):
|
|
shape = paddle.to_tensor([-1])
|
|
return paddle.reshape_(var, shape)
|
|
|
|
|
|
class TestDygraphInplaceFlatten(TestDygraphInplace):
|
|
def non_inplace_api_processing(self, var):
|
|
return var.flatten()
|
|
|
|
def inplace_api_processing(self, var):
|
|
return var.flatten_()
|
|
|
|
|
|
class TestDygraphInplaceFlattenStride(TestDygraphInplace):
|
|
def init_data(self):
|
|
self.input_var_numpy = np.random.randn(2, 3, 2)
|
|
self.dtype = "float32"
|
|
|
|
def non_inplace_api_processing(self, var):
|
|
return var.flatten(0, 1)
|
|
|
|
def inplace_api_processing(self, var):
|
|
return var.flatten_(0, 1)
|
|
|
|
|
|
class TestDygraphInplaceScatter(TestDygraphInplace):
|
|
def init_data(self):
|
|
self.input_var_numpy = np.array([[1, 1], [2, 2], [3, 3]])
|
|
self.dtype = "float32"
|
|
|
|
def non_inplace_api_processing(self, var):
|
|
index = paddle.to_tensor([2, 1, 0, 1], dtype='int64')
|
|
updates = paddle.to_tensor(
|
|
[[1, 1], [2, 2], [3, 3], [4, 4]], dtype='float32'
|
|
)
|
|
|
|
return paddle.scatter(var, index, updates, overwrite=False)
|
|
|
|
def inplace_api_processing(self, var):
|
|
index = paddle.to_tensor([2, 1, 0, 1], dtype='int64')
|
|
updates = paddle.to_tensor(
|
|
[[1, 1], [2, 2], [3, 3], [4, 4]], dtype='float32'
|
|
)
|
|
|
|
return paddle.scatter_(var, index, updates, overwrite=False)
|
|
|
|
|
|
class TestDygraphInplaceElu(TestDygraphInplace):
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.nn.functional.elu(var)
|
|
|
|
def inplace_api_processing(self, var):
|
|
return paddle.nn.functional.elu_(var)
|
|
|
|
|
|
class TestDygraphInplaceRelu(TestDygraphInplace):
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.nn.functional.relu(var)
|
|
|
|
def inplace_api_processing(self, var):
|
|
return paddle.nn.functional.relu_(var)
|
|
|
|
|
|
class TestDygraphInplaceSoftmax(TestDygraphInplace):
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.nn.functional.softmax(var)
|
|
|
|
def inplace_api_processing(self, var):
|
|
return paddle.nn.functional.softmax_(var)
|
|
|
|
|
|
class TestDygraphInplaceTanh(TestDygraphInplace):
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.tanh(var)
|
|
|
|
def inplace_api_processing(self, var):
|
|
return paddle.tanh_(var)
|
|
|
|
|
|
class TestDygraphInplaceCeil(TestDygraphInplace):
|
|
def non_inplace_api_processing(self, var):
|
|
return var.ceil()
|
|
|
|
def inplace_api_processing(self, var):
|
|
return var.ceil_()
|
|
|
|
|
|
class TestDygraphInplaceFloor(TestDygraphInplace):
|
|
def non_inplace_api_processing(self, var):
|
|
return var.floor()
|
|
|
|
def inplace_api_processing(self, var):
|
|
return var.floor_()
|
|
|
|
|
|
class TestDygraphInplaceExp(TestDygraphInplace):
|
|
def set_np_compare_func(self):
|
|
self.np_compare = np.allclose
|
|
|
|
def non_inplace_api_processing(self, var):
|
|
return var.exp()
|
|
|
|
def inplace_api_processing(self, var):
|
|
return var.exp_()
|
|
|
|
|
|
class TestDygraphInplaceReciprocal(TestDygraphInplace):
|
|
def non_inplace_api_processing(self, var):
|
|
return var.reciprocal()
|
|
|
|
def inplace_api_processing(self, var):
|
|
return var.reciprocal_()
|
|
|
|
|
|
class TestDygraphInplaceRound(TestDygraphInplace):
|
|
def non_inplace_api_processing(self, var):
|
|
return var.round()
|
|
|
|
def inplace_api_processing(self, var):
|
|
return var.round_()
|
|
|
|
|
|
class TestDygraphInplaceSqrt(TestDygraphInplace):
|
|
def init_data(self):
|
|
self.input_var_numpy = np.random.uniform(0, 5, [10, 20, 1])
|
|
self.dtype = "float32"
|
|
|
|
def non_inplace_api_processing(self, var):
|
|
return var.sqrt()
|
|
|
|
def inplace_api_processing(self, var):
|
|
return var.sqrt_()
|
|
|
|
|
|
class TestDygraphInplaceRsqrt(TestDygraphInplaceSqrt):
|
|
def non_inplace_api_processing(self, var):
|
|
return var.rsqrt()
|
|
|
|
def inplace_api_processing(self, var):
|
|
return var.rsqrt_()
|
|
|
|
|
|
class TestDygraphInplaceSquare(TestDygraphInplace):
|
|
def init_data(self):
|
|
self.input_var_numpy = np.random.uniform(0, 5, [10, 20, 1])
|
|
self.dtype = "float32"
|
|
|
|
def non_inplace_api_processing(self, var):
|
|
return var.square()
|
|
|
|
def inplace_api_processing(self, var):
|
|
return var.square_()
|
|
|
|
|
|
class TestDygraphInplaceClip(TestDygraphInplace):
|
|
def non_inplace_api_processing(self, var):
|
|
return var.clip(0.6, 1.5)
|
|
|
|
def inplace_api_processing(self, var):
|
|
return var.clip_(0.6, 1.5)
|
|
|
|
|
|
class TestDygraphInplaceScale(TestDygraphInplace):
|
|
def non_inplace_api_processing(self, var):
|
|
return var.scale(scale=2.0, bias=3.0)
|
|
|
|
def inplace_api_processing(self, var):
|
|
return var.scale_(scale=2.0, bias=3.0)
|
|
|
|
|
|
class TestDygraphInplaceAdd(TestDygraphInplace):
|
|
def init_data(self):
|
|
self.input_var_numpy = np.random.rand(2, 3, 4)
|
|
self.dtype = "float32"
|
|
self.input_var_numpy_2 = np.random.rand(2, 3, 4).astype(self.dtype)
|
|
|
|
def non_inplace_api_processing(self, var):
|
|
input_var_2 = paddle.to_tensor(self.input_var_numpy_2)
|
|
return var.add(input_var_2)
|
|
|
|
def inplace_api_processing(self, var):
|
|
input_var_2 = paddle.to_tensor(self.input_var_numpy_2)
|
|
return var.add_(input_var_2)
|
|
|
|
|
|
class TestDygraphInplaceSubtract(TestDygraphInplaceAdd):
|
|
def non_inplace_api_processing(self, var):
|
|
input_var_2 = paddle.to_tensor(self.input_var_numpy_2)
|
|
return var.subtract(input_var_2)
|
|
|
|
def inplace_api_processing(self, var):
|
|
input_var_2 = paddle.to_tensor(self.input_var_numpy_2)
|
|
return var.subtract_(input_var_2)
|
|
|
|
|
|
class TestDygraphInplaceRemainder(TestDygraphInplaceAdd):
|
|
def non_inplace_api_processing(self, var):
|
|
input_var_2 = paddle.to_tensor(self.input_var_numpy_2)
|
|
return var.remainder(input_var_2)
|
|
|
|
def inplace_api_processing(self, var):
|
|
input_var_2 = paddle.to_tensor(self.input_var_numpy_2)
|
|
return var.remainder_(input_var_2)
|
|
|
|
def test_leaf_inplace_var_error(self):
|
|
pass
|
|
|
|
def test_backward_error(self):
|
|
pass
|
|
|
|
def test_backward_success_1(self):
|
|
pass
|
|
|
|
def test_backward_success_2(self):
|
|
pass
|
|
|
|
|
|
class TestLossIsInplaceVar(unittest.TestCase):
|
|
def test_loss_is_inplace_var(self):
|
|
with paddle.base.dygraph.guard():
|
|
var_a = paddle.ones((2, 2))
|
|
var_a.stop_gradient = False
|
|
|
|
var_b = var_a * 2
|
|
loss = var_b.tanh_()
|
|
|
|
loss.backward()
|
|
inplace_grad_var_a = var_a.grad.numpy()
|
|
|
|
with paddle.base.dygraph.guard():
|
|
var_a = paddle.ones((2, 2))
|
|
var_a.stop_gradient = False
|
|
|
|
var_b = var_a * 2
|
|
loss = var_b.tanh()
|
|
|
|
loss.backward()
|
|
grad_var_a = var_a.grad.numpy()
|
|
|
|
np.testing.assert_array_equal(inplace_grad_var_a, grad_var_a)
|
|
|
|
|
|
class TestContinuouslyInplace(unittest.TestCase):
|
|
def test_continuously_inplace(self):
|
|
a = paddle.rand([2, 3])
|
|
a.stop_gradient = False
|
|
b = a * 2
|
|
|
|
b.reshape_([-1])
|
|
b.reshape_([2, 3])
|
|
b.reshape_([-1])
|
|
|
|
b.backward()
|
|
|
|
|
|
class TestGetitemBeforeInplace(unittest.TestCase):
|
|
def test_getitem_before_inplace(self):
|
|
a = paddle.ones(shape=[4, 2, 3], dtype="float32")
|
|
a.stop_gradient = False
|
|
b = a**2
|
|
b[0] = 3
|
|
# getitem has no_need_buffer input
|
|
c = b[0:2]
|
|
loss = c.sum()
|
|
b[1] = 2
|
|
loss.backward()
|
|
|
|
|
|
class TestDygraphInplaceAsin(TestDygraphInplaceWithContinuous):
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.asin(var)
|
|
|
|
def inplace_api_processing(self, var):
|
|
return paddle.asin_(var)
|
|
|
|
|
|
class TestDygraphInplaceSinh(TestDygraphInplaceWithContinuous):
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.sinh(var)
|
|
|
|
def inplace_api_processing(self, var):
|
|
return paddle.sinh_(var)
|
|
|
|
|
|
class TestDygraphInplaceAsinh(TestDygraphInplaceWithContinuous):
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.asinh(var)
|
|
|
|
def inplace_api_processing(self, var):
|
|
return paddle.asinh_(var)
|
|
|
|
|
|
class TestDygraphInplaceAbs(TestDygraphInplaceWithContinuous):
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.abs(var)
|
|
|
|
def inplace_api_processing(self, var):
|
|
return paddle.abs_(var)
|
|
|
|
|
|
class TestDygraphInplaceCos(TestDygraphInplaceWithContinuous):
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.cos(var)
|
|
|
|
def inplace_api_processing(self, var):
|
|
return paddle.cos_(var)
|
|
|
|
|
|
class TestDygraphInplaceCosh(TestDygraphInplaceWithContinuous):
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.cosh(var)
|
|
|
|
def inplace_api_processing(self, var):
|
|
return paddle.cosh_(var)
|
|
|
|
|
|
class TestDygraphInplaceAcos(TestDygraphInplaceWithContinuous):
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.acos(var)
|
|
|
|
def inplace_api_processing(self, var):
|
|
return paddle.acos_(var)
|
|
|
|
|
|
class TestDygraphInplaceAcosh(TestDygraphInplaceWithContinuous):
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.acosh(var)
|
|
|
|
def inplace_api_processing(self, var):
|
|
return paddle.acosh_(var)
|
|
|
|
|
|
class TestDygraphInplaceTan(TestDygraphInplaceWithContinuous):
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.tan(var)
|
|
|
|
def inplace_api_processing(self, var):
|
|
return paddle.tan_(var)
|
|
|
|
|
|
class TestDygraphInplaceATan(TestDygraphInplaceWithContinuous):
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.atan(var)
|
|
|
|
def inplace_api_processing(self, var):
|
|
return paddle.atan_(var)
|
|
|
|
|
|
class TestDygraphInplaceATanh(TestDygraphInplaceWithContinuous):
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.atanh(var)
|
|
|
|
def inplace_api_processing(self, var):
|
|
return paddle.atanh_(var)
|
|
|
|
|
|
class TestDygraphInplaceAddMM(TestDygraphInplaceWithContinuous):
|
|
def init_data(self):
|
|
self.input_var_numpy = np.random.uniform(-5, 5, [10, 10])
|
|
self.dtype = "float32"
|
|
self.x = paddle.randn([10, 10], dtype="float32")
|
|
self.y = paddle.randn([10, 10], dtype="float32")
|
|
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.addmm(var, x=self.x, y=self.y)
|
|
|
|
def inplace_api_processing(self, var):
|
|
return paddle.addmm_(var, x=self.x, y=self.y)
|
|
|
|
def test_errors(self):
|
|
var = paddle.to_tensor(self.input_var_numpy).astype(self.dtype)
|
|
x1 = paddle.randn([10])
|
|
self.assertRaises(ValueError, paddle.addmm_, var, x1, self.y)
|
|
|
|
y1 = paddle.randn([12, 10])
|
|
self.assertRaises(ValueError, paddle.addmm_, var, self.x, y1)
|
|
x2 = paddle.randn([12, 10])
|
|
self.assertRaises(ValueError, paddle.addmm_, var, x2, self.y)
|
|
var1 = paddle.randn([1, 5])
|
|
self.assertRaises(ValueError, paddle.addmm_, var1, x2, self.y)
|
|
y2 = paddle.randn([10, 12])
|
|
self.assertRaises(ValueError, paddle.addmm_, var, self.x, y2)
|
|
var2 = paddle.randn([6])
|
|
self.assertRaises(ValueError, paddle.addmm_, var2, self.x, self.y)
|
|
var3 = paddle.randn([2, 3, 4])
|
|
self.assertRaises(ValueError, paddle.addmm_, var3, self.x, self.y)
|
|
|
|
|
|
class TestDygraphInplacePowerScalar(TestDygraphInplaceWithContinuous):
|
|
def inplace_api_processing(self, var):
|
|
return paddle.pow_(var, 2)
|
|
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.pow(var, 2)
|
|
|
|
def test_type_error(self):
|
|
var = paddle.to_tensor(self.input_var_numpy, dtype=self.dtype)
|
|
with self.assertRaises(TypeError):
|
|
paddle.pow_(var, [2])
|
|
|
|
|
|
class TestDygraphInplaceTriu(TestDygraphInplaceWithContinuous):
|
|
def inplace_api_processing(self, var):
|
|
return paddle.triu_(var, 0)
|
|
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.triu(var, 0)
|
|
|
|
|
|
class TestDygraphInplaceTril(TestDygraphInplaceWithContinuous):
|
|
def inplace_api_processing(self, var):
|
|
return paddle.tril_(var, 0)
|
|
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.tril(var, 0)
|
|
|
|
|
|
class TestDygraphInplaceLogit(TestDygraphInplaceWithContinuous):
|
|
def inplace_api_processing(self, var):
|
|
return paddle.logit_(var, 1e-3)
|
|
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.logit(var, 1e-3)
|
|
|
|
|
|
class TestDygraphInplaceLog(TestDygraphInplaceWithContinuous):
|
|
def inplace_api_processing(self, var):
|
|
return paddle.log_(var)
|
|
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.log(var)
|
|
|
|
|
|
class TestDygraphInplaceLog2(TestDygraphInplaceWithContinuous):
|
|
def inplace_api_processing(self, var):
|
|
return paddle.log2_(var)
|
|
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.log2(var)
|
|
|
|
|
|
class TestDygraphInplaceLog10(TestDygraphInplaceWithContinuous):
|
|
def inplace_api_processing(self, var):
|
|
return paddle.log10_(var)
|
|
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.log10(var)
|
|
|
|
|
|
class TestDygraphInplaceLog1p(TestDygraphInplaceWithContinuous):
|
|
def inplace_api_processing(self, var):
|
|
return paddle.log1p_(var)
|
|
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.log1p(var)
|
|
|
|
|
|
class TestDygraphInplaceTrunc(TestDygraphInplaceWithContinuous):
|
|
def inplace_api_processing(self, var):
|
|
return paddle.trunc_(var)
|
|
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.trunc(var)
|
|
|
|
|
|
class TestDygraphInplaceDigamma(TestDygraphInplaceWithContinuous):
|
|
def inplace_api_processing(self, var):
|
|
return paddle.digamma_(var)
|
|
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.digamma(var)
|
|
|
|
|
|
class TestDygraphInplaceMutilgammaln(TestDygraphInplaceWithContinuous):
|
|
def init_data(self):
|
|
self.input_var_numpy = np.random.rand(10, 20).astype('float32') + 1.0
|
|
self.dtype = "float32"
|
|
self.p = 2
|
|
|
|
def inplace_api_processing(self, var):
|
|
return paddle.multigammaln_(var, self.p)
|
|
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.multigammaln(var, self.p)
|
|
|
|
def test_leaf_inplace_var_error(self):
|
|
pass
|
|
|
|
|
|
class TestDygraphInplaceGammaln(TestDygraphInplaceWithContinuous):
|
|
def inplace_api_processing(self, var):
|
|
return paddle.gammaln_(var)
|
|
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.gammaln(var)
|
|
|
|
|
|
class TestDygraphInplaceNeg(TestDygraphInplaceWithContinuous):
|
|
def inplace_api_processing(self, var):
|
|
return paddle.neg_(var)
|
|
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.neg(var)
|
|
|
|
|
|
class TestDygraphInplaceGammaincc(TestDygraphInplace):
|
|
def init_data(self):
|
|
self.shape = (3, 40)
|
|
self.dtype = "float32"
|
|
self.input_var_numpy = (
|
|
np.random.random(self.shape).astype(self.dtype) + 1
|
|
)
|
|
self.y = paddle.rand(shape=self.shape, dtype=self.dtype) + 1
|
|
|
|
def inplace_api_processing(self, var):
|
|
return paddle.gammaincc_(var, y=self.y)
|
|
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.gammaincc(var, y=self.y)
|
|
|
|
def test_backward_error(self):
|
|
pass
|
|
|
|
def test_backward_success_1(self):
|
|
pass
|
|
|
|
def test_backward_success_2(self):
|
|
pass
|
|
|
|
|
|
class TestDygraphInplaceGammainc(TestDygraphInplace):
|
|
def init_data(self):
|
|
self.shape = (3, 40)
|
|
self.dtype = "float32"
|
|
self.input_var_numpy = (
|
|
np.random.random(self.shape).astype(self.dtype) + 1
|
|
)
|
|
self.y = paddle.rand(shape=self.shape, dtype=self.dtype) + 1
|
|
|
|
def inplace_api_processing(self, var):
|
|
return paddle.gammainc_(var, y=self.y)
|
|
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.gammainc(var, y=self.y)
|
|
|
|
def test_forward_version(self):
|
|
with paddle.base.dygraph.guard():
|
|
var = paddle.to_tensor(self.input_var_numpy).astype(self.dtype)
|
|
self.assertEqual(var.inplace_version, 0)
|
|
|
|
inplace_var = self.inplace_api_processing(var)
|
|
self.assertEqual(var.inplace_version, 3)
|
|
|
|
inplace_var[0] = 2
|
|
self.assertEqual(var.inplace_version, 4)
|
|
|
|
inplace_var = self.inplace_api_processing(inplace_var)
|
|
self.assertEqual(var.inplace_version, 7)
|
|
|
|
def test_backward_error(self):
|
|
pass
|
|
|
|
def test_backward_success_1(self):
|
|
pass
|
|
|
|
def test_backward_success_2(self):
|
|
pass
|
|
|
|
|
|
class TestDygraphInplaceLgamma(TestDygraphInplaceWithContinuous):
|
|
def inplace_api_processing(self, var):
|
|
return paddle.lgamma_(var)
|
|
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.lgamma(var)
|
|
|
|
|
|
class TestDygraphInplaceFrac(TestDygraphInplaceWithContinuous):
|
|
def inplace_api_processing(self, var):
|
|
return paddle.frac_(var)
|
|
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.frac(var)
|
|
|
|
|
|
class TestDygraphInplaceI0(TestDygraphInplaceWithContinuous):
|
|
def inplace_api_processing(self, var):
|
|
return paddle.i0_(var)
|
|
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.i0(var)
|
|
|
|
|
|
class TestDygraphInplaceGcd(TestDygraphInplace):
|
|
def init_data(self):
|
|
self.input_var_numpy = np.random.randint(2, size=200)
|
|
self.input_var_numpy = self.input_var_numpy.reshape([10, 20])
|
|
self.dtype = "int32"
|
|
self.y = paddle.randint(low=-5, high=5, shape=[10, 20], dtype="int32")
|
|
|
|
def inplace_api_processing(self, var):
|
|
return paddle.gcd_(var, self.y)
|
|
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.gcd(var, self.y)
|
|
|
|
def test_forward_version(self):
|
|
pass
|
|
|
|
def test_backward_error(self):
|
|
pass
|
|
|
|
def test_backward_success_1(self):
|
|
pass
|
|
|
|
def test_backward_success_2(self):
|
|
pass
|
|
|
|
def test_error(self):
|
|
x = paddle.randn([1, 10])
|
|
y = paddle.randn([20, 1])
|
|
self.assertRaises(ValueError, paddle.gcd_, x, y)
|
|
|
|
|
|
class TestDygraphInplaceHypot(TestDygraphInplace):
|
|
def init_data(self):
|
|
self.input_var_numpy = np.random.randint(2, size=200)
|
|
self.input_var_numpy = self.input_var_numpy.reshape([10, 20])
|
|
self.dtype = "float32"
|
|
self.y = paddle.randn(shape=[10, 20], dtype="float32")
|
|
|
|
def inplace_api_processing(self, var):
|
|
return paddle.hypot_(var, self.y)
|
|
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.hypot(var, self.y)
|
|
|
|
def test_errors(self):
|
|
x = 3.0
|
|
self.assertRaises(TypeError, paddle.hypot_, x, self.y)
|
|
self.assertRaises(TypeError, paddle.hypot_, self.y, x)
|
|
|
|
def test_forward_version(self):
|
|
with paddle.base.dygraph.guard():
|
|
var = paddle.to_tensor(self.input_var_numpy).astype(self.dtype)
|
|
self.assertEqual(var.inplace_version, 0)
|
|
|
|
inplace_var = self.inplace_api_processing(var)
|
|
self.assertEqual(var.inplace_version, 3)
|
|
|
|
inplace_var[0] = 2.0
|
|
self.assertEqual(var.inplace_version, 4)
|
|
|
|
inplace_var = self.inplace_api_processing(inplace_var)
|
|
self.assertEqual(var.inplace_version, 7)
|
|
|
|
def test_backward_error(self):
|
|
# It raises an error because the inplace operator will result
|
|
# in incorrect gradient computation.
|
|
with paddle.base.dygraph.guard():
|
|
var_a = paddle.to_tensor(self.input_var_numpy).astype(self.dtype)
|
|
var_a.stop_gradient = False
|
|
|
|
var_b = var_a**2
|
|
# Here, the gradient computation will use the value of var_b
|
|
var_c = var_b**2
|
|
self.inplace_api_processing(var_b)
|
|
var_c = paddle.cast(var_c, "float32")
|
|
|
|
loss = paddle.nn.functional.relu(var_c)
|
|
with self.assertRaisesRegex(
|
|
RuntimeError,
|
|
f"received tensor_version:{3} != wrapper_version_snapshot:{0}",
|
|
):
|
|
loss.backward()
|
|
|
|
|
|
class TestDygraphInplaceNanToNum(TestDygraphInplace):
|
|
def init_data(self):
|
|
self.input_var_numpy = np.array(
|
|
["0.12334", "inf", "inf", "-inf", "nan", "-0.12342", "1.123", "nan"]
|
|
)
|
|
self.input_var_numpy = self.input_var_numpy.reshape([2, 4]).astype(
|
|
np.float32
|
|
)
|
|
self.dtype = "float32"
|
|
|
|
def inplace_api_processing(self, var):
|
|
return paddle.nan_to_num_(var)
|
|
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.nan_to_num(var)
|
|
|
|
def set_np_compare_func(self):
|
|
np_array_equal_with_nan = functools.partial(
|
|
np.array_equal, equal_nan=True
|
|
)
|
|
self.np_compare = np_array_equal_with_nan
|
|
|
|
def test_forward_version(self):
|
|
with paddle.base.dygraph.guard():
|
|
var = paddle.to_tensor(self.input_var_numpy).astype(self.dtype)
|
|
self.assertEqual(var.inplace_version, 0)
|
|
|
|
inplace_var = self.inplace_api_processing(var)
|
|
self.assertEqual(var.inplace_version, 3)
|
|
|
|
inplace_var[0] = 2
|
|
self.assertEqual(var.inplace_version, 4)
|
|
|
|
inplace_var = self.inplace_api_processing(inplace_var)
|
|
self.assertEqual(var.inplace_version, 7)
|
|
|
|
def test_backward_error(self):
|
|
# It raises an error because the inplace operator will result
|
|
# in incorrect gradient computation.
|
|
with paddle.base.dygraph.guard():
|
|
var_a = paddle.to_tensor(self.input_var_numpy).astype(self.dtype)
|
|
var_a.stop_gradient = False
|
|
|
|
var_b = var_a**2
|
|
|
|
# Here, the gradient computation will use the value of var_b
|
|
var_c = var_b**2
|
|
self.inplace_api_processing(var_b)
|
|
|
|
loss = paddle.nn.functional.relu(var_c)
|
|
with self.assertRaisesRegex(
|
|
RuntimeError,
|
|
"received tensor_version:3 != wrapper_version_snapshot:0",
|
|
):
|
|
loss.backward()
|
|
|
|
|
|
class TestDygraphInplaceLcm(TestDygraphInplace):
|
|
def init_data(self):
|
|
self.input_var_numpy = np.random.randint(2, size=200)
|
|
self.input_var_numpy = self.input_var_numpy.reshape([10, 20])
|
|
self.dtype = "int32"
|
|
self.y = paddle.randint(low=-5, high=5, shape=[10, 20], dtype="int32")
|
|
|
|
def inplace_api_processing(self, var):
|
|
return paddle.lcm_(var, self.y)
|
|
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.lcm(var, self.y)
|
|
|
|
def test_forward_version(self):
|
|
with paddle.base.dygraph.guard():
|
|
var = paddle.to_tensor(self.input_var_numpy).astype(self.dtype)
|
|
self.assertEqual(var.inplace_version, 0)
|
|
|
|
inplace_var = self.inplace_api_processing(var)
|
|
self.assertEqual(var.inplace_version, 4)
|
|
|
|
inplace_var[0] = 2
|
|
self.assertEqual(var.inplace_version, 5)
|
|
|
|
inplace_var = self.inplace_api_processing(inplace_var)
|
|
self.assertEqual(var.inplace_version, 9)
|
|
|
|
def test_backward_error(self):
|
|
pass
|
|
|
|
def test_backward_success_1(self):
|
|
pass
|
|
|
|
def test_backward_success_2(self):
|
|
pass
|
|
|
|
def test_leaf_inplace_var_error(self):
|
|
pass
|
|
|
|
|
|
class TestDygraphInplaceLdexp(TestDygraphInplaceWithContinuous):
|
|
def init_data(self):
|
|
super().init_data()
|
|
self.y = paddle.to_tensor([2], dtype="int32")
|
|
|
|
def inplace_api_processing(self, var):
|
|
return paddle.ldexp_(var, self.y)
|
|
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.ldexp(var, self.y)
|
|
|
|
def test_leaf_inplace_var_error(self):
|
|
pass
|
|
|
|
def test_forward_version(self):
|
|
with paddle.base.dygraph.guard():
|
|
var = paddle.to_tensor(self.input_var_numpy).astype(self.dtype)
|
|
self.assertEqual(var.inplace_version, 0)
|
|
|
|
inplace_var = self.inplace_api_processing(var)
|
|
self.assertEqual(var.inplace_version, 2)
|
|
|
|
inplace_var[0] = 2
|
|
self.assertEqual(var.inplace_version, 3)
|
|
|
|
inplace_var = self.inplace_api_processing(inplace_var)
|
|
self.assertEqual(var.inplace_version, 5)
|
|
|
|
def test_backward_error(self):
|
|
# It raises an error because the inplace operator will result
|
|
# in incorrect gradient computation.
|
|
with paddle.base.dygraph.guard():
|
|
var_a = paddle.to_tensor(self.input_var_numpy).astype("float64")
|
|
var_a.stop_gradient = False
|
|
|
|
var_b = var_a**2
|
|
|
|
# Here, the gradient computation will use the value of var_b
|
|
var_c = var_b**2
|
|
self.inplace_api_processing(var_b)
|
|
|
|
loss = paddle.nn.functional.relu(var_c)
|
|
with self.assertRaisesRegex(
|
|
RuntimeError,
|
|
"received tensor_version:2 != wrapper_version_snapshot:0",
|
|
):
|
|
loss.backward()
|
|
|
|
def test_error(self):
|
|
x = 1
|
|
x_normal = paddle.randn([3, 4])
|
|
y = 1
|
|
with self.assertRaisesRegex(
|
|
TypeError, f"x must be tensor type, but got {type(x)}"
|
|
):
|
|
paddle.ldexp_(x, y)
|
|
with self.assertRaisesRegex(
|
|
TypeError, f"y must be tensor type, but got {type(y)}"
|
|
):
|
|
paddle.ldexp_(x_normal, y)
|
|
|
|
|
|
class TestDygraphInplaceWhere(TestDygraphInplaceWithContinuous):
|
|
def init_data(self):
|
|
super().init_data()
|
|
self.y = paddle.randn([10, 20, 1])
|
|
|
|
def inplace_api_processing(self, var):
|
|
return paddle.where_(var > self.y, var, self.y)
|
|
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.where(var > self.y, var, self.y)
|
|
|
|
def test_error(self):
|
|
cond = paddle.to_tensor([[False, True, False], [False, True, False]])
|
|
self.assertRaises(ValueError, paddle.where_, cond, 1, 2)
|
|
self.assertRaises(ValueError, paddle.where_, cond, None, None)
|
|
|
|
|
|
class TestDygraphInplaceWhereBroadcast(TestDygraphInplaceWithContinuous):
|
|
def init_data(self):
|
|
super().init_data()
|
|
self.y = paddle.randn([10, 1, 1])
|
|
|
|
def inplace_api_processing(self, var):
|
|
return paddle.where_(var > self.y, var, self.y)
|
|
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.where(var > self.y, var, self.y)
|
|
|
|
def test_forward_version(self):
|
|
with paddle.base.dygraph.guard():
|
|
var = paddle.to_tensor(self.input_var_numpy).astype(self.dtype)
|
|
self.assertEqual(var.inplace_version, 0)
|
|
|
|
inplace_var = self.inplace_api_processing(var)
|
|
self.assertEqual(var.inplace_version, 1)
|
|
|
|
inplace_var[0] = 2
|
|
self.assertEqual(var.inplace_version, 2)
|
|
|
|
inplace_var = self.inplace_api_processing(inplace_var)
|
|
self.assertEqual(var.inplace_version, 3)
|
|
|
|
def test_backward_error(self):
|
|
# It raises an error because the inplace operator will result
|
|
# in incorrect gradient computation.
|
|
with paddle.base.dygraph.guard():
|
|
var_a = paddle.to_tensor(self.input_var_numpy).astype(self.dtype)
|
|
var_a.stop_gradient = False
|
|
|
|
var_b = var_a**2
|
|
|
|
# Here, the gradient computation will use the value of var_b
|
|
var_c = var_b**2
|
|
self.inplace_api_processing(var_b)
|
|
|
|
loss = paddle.nn.functional.relu(var_c)
|
|
with self.assertRaisesRegex(
|
|
RuntimeError,
|
|
"received tensor_version:1 != wrapper_version_snapshot:0",
|
|
):
|
|
loss.backward()
|
|
|
|
|
|
class TestDygraphInplacePolygamma(TestDygraphInplaceWithContinuous):
|
|
def inplace_api_processing(self, var):
|
|
return paddle.polygamma_(var, 1)
|
|
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.polygamma(var, 1)
|
|
|
|
|
|
class TestDygraphInplaceHardTanh(TestDygraphInplaceWithContinuous):
|
|
def inplace_api_processing(self, var):
|
|
return paddle.nn.functional.hardtanh_(var, -1.0, 1.0)
|
|
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.nn.functional.hardtanh(var, -1.0, 1.0)
|
|
|
|
|
|
class TestDygraphInplaceLeakyRelu(TestDygraphInplaceWithContinuous):
|
|
def inplace_api_processing(self, var):
|
|
return paddle.nn.functional.leaky_relu_(var, 0.01)
|
|
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.nn.functional.leaky_relu(var, 0.01)
|
|
|
|
|
|
class TestDygraphInplaceThresholdedRelu(TestDygraphInplaceWithContinuous):
|
|
def inplace_api_processing(self, var):
|
|
return paddle.nn.functional.thresholded_relu_(var, 1.0)
|
|
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.nn.functional.thresholded_relu(var, 1.0)
|
|
|
|
|
|
class TestDygraphInplaceLogicAnd(TestDygraphInplace):
|
|
def init_data(self):
|
|
self.input_var_numpy = np.random.uniform(-5, 5, [10, 20, 1])
|
|
self.dtype = "float32"
|
|
self.y = paddle.randn([10, 20, 1])
|
|
|
|
def test_forward_result(self):
|
|
var = paddle.to_tensor(self.input_var_numpy).astype(self.dtype)
|
|
no_inplace_var = self.non_inplace_api_processing(var)
|
|
inplace_var = self.inplace_api_processing(var)
|
|
np.testing.assert_array_equal(
|
|
no_inplace_var.numpy(), inplace_var.numpy()
|
|
)
|
|
|
|
def test_forward_version(self):
|
|
with paddle.base.dygraph.guard():
|
|
var = paddle.to_tensor(self.input_var_numpy).astype(self.dtype)
|
|
self.assertEqual(var.inplace_version, 0)
|
|
|
|
inplace_var = self.inplace_api_processing(var)
|
|
self.assertEqual(var.inplace_version, 1)
|
|
inplace_var[0] = True
|
|
self.assertEqual(var.inplace_version, 2)
|
|
|
|
def inplace_api_processing(self, var):
|
|
return paddle.logical_and_(var, self.y)
|
|
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.logical_and(var, self.y)
|
|
|
|
def test_broadcast_error(self):
|
|
broadcast_input = paddle.randn([10, 1, 20])
|
|
with self.assertRaises(ValueError):
|
|
self.inplace_api_processing(broadcast_input)
|
|
|
|
def test_backward_error(self):
|
|
pass
|
|
|
|
def test_backward_success_1(self):
|
|
pass
|
|
|
|
def test_backward_success_2(self):
|
|
pass
|
|
|
|
def test_leaf_inplace_var_error(self):
|
|
pass
|
|
|
|
|
|
class TestDygraphInplaceLogicOr(TestDygraphInplaceLogicAnd):
|
|
def inplace_api_processing(self, var):
|
|
return paddle.logical_or_(var, self.y)
|
|
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.logical_or(var, self.y)
|
|
|
|
|
|
class TestDygraphInplaceLogicXor(TestDygraphInplaceLogicAnd):
|
|
def inplace_api_processing(self, var):
|
|
return paddle.logical_xor_(var, self.y)
|
|
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.logical_xor(var, self.y)
|
|
|
|
|
|
class TestDygraphInplaceLogicNot(TestDygraphInplaceLogicAnd):
|
|
def inplace_api_processing(self, var):
|
|
return paddle.logical_not_(var)
|
|
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.logical_not(var)
|
|
|
|
def test_broadcast_error(self):
|
|
pass
|
|
|
|
|
|
class TestDygraphInplaceLessThan(TestDygraphInplaceLogicAnd):
|
|
def inplace_api_processing(self, var):
|
|
return paddle.less_than_(var, self.y)
|
|
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.less_than(var, self.y)
|
|
|
|
|
|
class TestDygraphInplaceLess(TestDygraphInplaceLogicAnd):
|
|
def inplace_api_processing(self, var):
|
|
return paddle.less_(var, self.y)
|
|
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.less(var, self.y)
|
|
|
|
|
|
class TestDygraphInplaceLessEqual(TestDygraphInplaceLogicAnd):
|
|
def inplace_api_processing(self, var):
|
|
return paddle.less_equal_(var, self.y)
|
|
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.less_equal(var, self.y)
|
|
|
|
|
|
class TestDygraphInplaceGreaterEqual(TestDygraphInplaceLogicAnd):
|
|
def inplace_api_processing(self, var):
|
|
return paddle.greater_equal_(var, self.y)
|
|
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.greater_equal(var, self.y)
|
|
|
|
|
|
class TestDygraphInplaceGreaterThan(TestDygraphInplaceLogicAnd):
|
|
def inplace_api_processing(self, var):
|
|
return paddle.greater_than_(var, self.y)
|
|
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.greater_than(var, self.y)
|
|
|
|
|
|
class TestDygraphInplaceEqual(TestDygraphInplaceLogicAnd):
|
|
def inplace_api_processing(self, var):
|
|
return paddle.equal_(var, self.y)
|
|
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.equal(var, self.y)
|
|
|
|
|
|
class TestDygraphInplaceNotEqual(TestDygraphInplaceLogicAnd):
|
|
def inplace_api_processing(self, var):
|
|
return paddle.not_equal_(var, self.y)
|
|
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.not_equal(var, self.y)
|
|
|
|
|
|
class TestDygraphInplacBitwiseAnd(TestDygraphInplaceLogicAnd):
|
|
def init_data(self):
|
|
self.input_var_numpy = paddle.randint(
|
|
low=0, high=10, shape=[3, 4, 1], dtype="int32"
|
|
)
|
|
self.dtype = "int32"
|
|
self.y = paddle.randint(low=0, high=10, shape=[3, 4, 1], dtype="int32")
|
|
|
|
def inplace_api_processing(self, var):
|
|
return paddle.bitwise_and_(var, self.y)
|
|
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.bitwise_and(var, self.y)
|
|
|
|
def test_forward_result(self):
|
|
var = paddle.to_tensor(self.input_var_numpy).astype(self.dtype)
|
|
no_inplace_var = self.non_inplace_api_processing(var)
|
|
inplace_var = self.inplace_api_processing(var)
|
|
np.testing.assert_array_equal(
|
|
no_inplace_var.numpy(), inplace_var.numpy()
|
|
)
|
|
|
|
def test_broadcast_error(self):
|
|
broadcast_input = paddle.randint(
|
|
low=0, high=10, shape=[3, 1, 4], dtype="int32"
|
|
)
|
|
with self.assertRaises(ValueError):
|
|
self.inplace_api_processing(broadcast_input)
|
|
|
|
|
|
class TestDygraphInplacBitwiseOr(TestDygraphInplacBitwiseAnd):
|
|
def inplace_api_processing(self, var):
|
|
return paddle.bitwise_or_(var, self.y)
|
|
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.bitwise_or(var, self.y)
|
|
|
|
|
|
class TestDygraphInplacBitwiseOrAlias1(TestDygraphInplacBitwiseAnd):
|
|
def inplace_api_processing(self, var):
|
|
return paddle.bitwise_or_(var, other=self.y)
|
|
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.bitwise_or(var, other=self.y)
|
|
|
|
|
|
class TestDygraphInplacBitwiseOrAlias2(TestDygraphInplacBitwiseAnd):
|
|
def inplace_api_processing(self, var):
|
|
return paddle.bitwise_or_(input=var, other=self.y)
|
|
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.bitwise_or(input=var, other=self.y)
|
|
|
|
|
|
class TestDygraphInplacBitwiseXor(TestDygraphInplacBitwiseAnd):
|
|
def inplace_api_processing(self, var):
|
|
return paddle.bitwise_xor_(var, self.y)
|
|
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.bitwise_xor(var, self.y)
|
|
|
|
|
|
class TestDygraphInplacBitwiseNot(TestDygraphInplacBitwiseAnd):
|
|
def inplace_api_processing(self, var):
|
|
return paddle.bitwise_not_(var)
|
|
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.bitwise_not(var)
|
|
|
|
def test_broadcast_error(self):
|
|
pass
|
|
|
|
|
|
class TestDygraphInplacBitwiseInvert(TestDygraphInplacBitwiseAnd):
|
|
def inplace_api_processing(self, var):
|
|
return paddle.bitwise_invert_(var)
|
|
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.bitwise_invert(var)
|
|
|
|
def test_broadcast_error(self):
|
|
pass
|
|
|
|
|
|
class TestDygraphInplaceDivide(TestDygraphInplace):
|
|
def init_data(self):
|
|
self.input_var_numpy = np.random.uniform(-5, 5, [10, 20, 1])
|
|
self.dtype = "float32"
|
|
self.y = paddle.randn([10, 20, 1])
|
|
|
|
def inplace_api_processing(self, var):
|
|
return paddle.divide_(var, self.y)
|
|
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.divide(var, self.y)
|
|
|
|
def test_broadcast_error(self):
|
|
broadcast_input = paddle.randn([10, 1, 20])
|
|
with self.assertRaises(ValueError):
|
|
self.inplace_api_processing(broadcast_input)
|
|
|
|
|
|
class TestDygraphInplaceCast(TestDygraphInplaceWithContinuous):
|
|
def inplace_api_processing(self, var):
|
|
return paddle.cast_(var, "float64")
|
|
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.cast(var, "float64")
|
|
|
|
|
|
class TestDygraphInplaceFloorDivide(TestDygraphInplace):
|
|
def init_data(self):
|
|
self.input_var_numpy = np.random.uniform(-5, 5, [10, 20, 1])
|
|
self.dtype = "float32"
|
|
self.y = paddle.randn([10, 20, 1])
|
|
|
|
def inplace_api_processing(self, var):
|
|
return paddle.floor_divide_(var, self.y)
|
|
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.floor_divide(var, self.y)
|
|
|
|
def test_backward_error(self):
|
|
pass
|
|
|
|
def test_backward_success_1(self):
|
|
pass
|
|
|
|
def test_backward_success_2(self):
|
|
pass
|
|
|
|
def test_leaf_inplace_var_error(self):
|
|
pass
|
|
|
|
def test_error(self):
|
|
x = paddle.randn([1, 10])
|
|
y = paddle.randn([20, 1])
|
|
self.assertRaises(ValueError, paddle.floor_divide_, x, y)
|
|
|
|
|
|
class TestDygraphInplaceCumsum(TestDygraphInplaceWithContinuous):
|
|
def inplace_api_processing(self, var):
|
|
return paddle.cumsum_(var, dtype="float32")
|
|
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.cumsum(var, dtype="float32")
|
|
|
|
def test_backward_error(self):
|
|
# It raises an error because the inplace operator will result
|
|
# in incorrect gradient computation.
|
|
with paddle.base.dygraph.guard():
|
|
var_a = paddle.to_tensor(self.input_var_numpy).astype("float64")
|
|
var_a.stop_gradient = False
|
|
|
|
var_b = var_a**2
|
|
|
|
# Here, the gradient computation will use the value of var_b
|
|
var_c = var_b**2
|
|
paddle.cumsum_(var_b, -1, dtype="float32")
|
|
|
|
loss = paddle.nn.functional.relu(var_c)
|
|
with self.assertRaisesRegex(
|
|
RuntimeError,
|
|
"received tensor_version:2 != wrapper_version_snapshot:0",
|
|
):
|
|
loss.backward()
|
|
|
|
def test_forward_version(self):
|
|
with paddle.base.dygraph.guard():
|
|
var = paddle.to_tensor(self.input_var_numpy).astype(self.dtype)
|
|
self.assertEqual(var.inplace_version, 0)
|
|
|
|
inplace_var = self.inplace_api_processing(var)
|
|
self.assertEqual(var.inplace_version, 1)
|
|
|
|
inplace_var[0] = 2
|
|
self.assertEqual(var.inplace_version, 2)
|
|
|
|
inplace_var = self.inplace_api_processing(inplace_var)
|
|
self.assertEqual(var.inplace_version, 3)
|
|
|
|
|
|
class TestDygraphInplaceCumprod(TestDygraphInplace):
|
|
def inplace_api_processing(self, var):
|
|
return paddle.cumprod_(var, -1, dtype="float32")
|
|
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.cumprod(var, -1, dtype="float32")
|
|
|
|
def test_backward_error(self):
|
|
# It raises an error because the inplace operator will result
|
|
# in incorrect gradient computation.
|
|
with paddle.base.dygraph.guard():
|
|
var_a = paddle.to_tensor(self.input_var_numpy).astype(self.dtype)
|
|
var_a.stop_gradient = False
|
|
|
|
var_b = var_a**2
|
|
|
|
# Here, the gradient computation will use the value of var_b
|
|
var_c = var_b**2
|
|
paddle.cumprod_(var_b, -1, dtype="float64")
|
|
|
|
loss = paddle.nn.functional.relu(var_c)
|
|
with self.assertRaisesRegex(
|
|
RuntimeError,
|
|
"received tensor_version:2 != wrapper_version_snapshot:0",
|
|
):
|
|
loss.backward()
|
|
|
|
def test_forward_version(self):
|
|
with paddle.base.dygraph.guard():
|
|
var = paddle.to_tensor(self.input_var_numpy).astype(self.dtype)
|
|
self.assertEqual(var.inplace_version, 0)
|
|
|
|
inplace_var = self.inplace_api_processing(var)
|
|
self.assertEqual(var.inplace_version, 1)
|
|
|
|
inplace_var[0] = 2
|
|
self.assertEqual(var.inplace_version, 2)
|
|
|
|
inplace_var = self.inplace_api_processing(inplace_var)
|
|
self.assertEqual(var.inplace_version, 3)
|
|
|
|
|
|
class TestDygraphInplaceCumprodWithFlatten(TestDygraphInplace):
|
|
def inplace_api_processing(self, var):
|
|
return paddle.cumprod_(var, None, dtype="float32")
|
|
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.cumprod(var, None, dtype="float32")
|
|
|
|
def test_backward_error(self):
|
|
# It raises an error because the inplace operator will result
|
|
# in incorrect gradient computation.
|
|
with paddle.base.dygraph.guard():
|
|
var_a = paddle.to_tensor(self.input_var_numpy).astype(self.dtype)
|
|
var_a.stop_gradient = False
|
|
|
|
var_b = var_a**2
|
|
|
|
# Here, the gradient computation will use the value of var_b
|
|
var_c = var_b**2
|
|
paddle.cumprod_(var_b, None, dtype="float64")
|
|
|
|
loss = paddle.nn.functional.relu(var_c)
|
|
with self.assertRaisesRegex(
|
|
RuntimeError,
|
|
"received tensor_version:3 != wrapper_version_snapshot:0",
|
|
):
|
|
loss.backward()
|
|
|
|
def test_forward_version(self):
|
|
with paddle.base.dygraph.guard():
|
|
var = paddle.to_tensor(self.input_var_numpy).astype(self.dtype)
|
|
self.assertEqual(var.inplace_version, 0)
|
|
|
|
inplace_var = self.inplace_api_processing(var)
|
|
self.assertEqual(var.inplace_version, 2)
|
|
|
|
inplace_var[0] = 2
|
|
self.assertEqual(var.inplace_version, 3)
|
|
|
|
inplace_var = self.inplace_api_processing(inplace_var)
|
|
self.assertEqual(var.inplace_version, 5)
|
|
|
|
|
|
class TestDygrapInplaceRenorm(TestDygraphInplaceWithContinuous):
|
|
def inplace_api_processing(self, var):
|
|
return paddle.renorm_(var, 1.0, -1, 2.05)
|
|
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.renorm(var, 1.0, -1, 2.05)
|
|
|
|
def test_error(self):
|
|
var = paddle.randn([3, 4, 1])
|
|
self.assertRaises(ValueError, paddle.renorm_, var, 1.0, 5, 2.05)
|
|
self.assertRaises(ValueError, paddle.renorm_, var, 1.0, -5, 2.05)
|
|
|
|
|
|
class TestDygrapInplaceMultiply(TestDygraphInplaceWithContinuous):
|
|
def init_data(self):
|
|
self.input_var_numpy = np.random.uniform(-5, 5, [10, 20, 1])
|
|
self.dtype = "float32"
|
|
self.y = paddle.randn([10, 20, 1])
|
|
|
|
def inplace_api_processing(self, var):
|
|
return paddle.multiply_(var, self.y)
|
|
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.multiply(var, self.y)
|
|
|
|
|
|
class TestDygrapInplaceT(TestDygraphInplaceWithContinuous):
|
|
def init_data(self):
|
|
self.input_var_numpy = np.random.uniform(-5, 5, [10, 20])
|
|
self.dtype = "float32"
|
|
|
|
def inplace_api_processing(self, var):
|
|
return paddle.t_(var)
|
|
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.t(var)
|
|
|
|
def test_forward_version(self):
|
|
with paddle.base.dygraph.guard():
|
|
var = paddle.to_tensor(self.input_var_numpy).astype(self.dtype)
|
|
self.assertEqual(var.inplace_version, 0)
|
|
|
|
inplace_var = self.inplace_api_processing(var)
|
|
self.assertEqual(var.inplace_version, 1)
|
|
|
|
inplace_var[0] = 2
|
|
self.assertEqual(var.inplace_version, 2)
|
|
|
|
inplace_var = self.inplace_api_processing(inplace_var)
|
|
self.assertEqual(var.inplace_version, 3)
|
|
|
|
|
|
class TestDygrapInplaceTranspose(TestDygraphInplaceWithContinuous):
|
|
def inplace_api_processing(self, var):
|
|
return paddle.transpose_(var, [1, 0, 2])
|
|
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.transpose(var, [1, 0, 2])
|
|
|
|
def test_forward_version(self):
|
|
with paddle.base.dygraph.guard():
|
|
var = paddle.to_tensor(self.input_var_numpy).astype(self.dtype)
|
|
self.assertEqual(var.inplace_version, 0)
|
|
|
|
inplace_var = self.inplace_api_processing(var)
|
|
self.assertEqual(var.inplace_version, 1)
|
|
|
|
inplace_var[0] = 2
|
|
self.assertEqual(var.inplace_version, 2)
|
|
|
|
inplace_var = self.inplace_api_processing(inplace_var)
|
|
self.assertEqual(var.inplace_version, 3)
|
|
|
|
|
|
class TestDygraphInplaceBitwiseLeftShift_arithmetic(TestDygraphInplaceLogicAnd):
|
|
def init_data(self):
|
|
self.input_var_numpy = np.random.randint(
|
|
low=-(2**31), high=2**31, size=[3, 4, 5], dtype="int32"
|
|
)
|
|
self.input_var_numpy = paddle.to_tensor(self.input_var_numpy)
|
|
self.dtype = "int32"
|
|
self.y = np.random.randint(
|
|
low=-(2**31), high=2**31, size=[3, 4, 5], dtype="int32"
|
|
)
|
|
self.y = paddle.to_tensor(self.y)
|
|
self.is_arithmetic = True
|
|
|
|
def inplace_api_processing(self, var):
|
|
return paddle.bitwise_left_shift_(var, self.y, self.is_arithmetic)
|
|
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.bitwise_left_shift(var, self.y, self.is_arithmetic)
|
|
|
|
def test_broadcast_error(self):
|
|
broadcast_input = paddle.randn([4, 5])
|
|
with self.assertRaises(ValueError):
|
|
self.inplace_api_processing(broadcast_input)
|
|
|
|
|
|
class TestDygraphInplaceBitwiseRightShift_arithmetic(
|
|
TestDygraphInplaceLogicAnd
|
|
):
|
|
def init_data(self):
|
|
self.input_var_numpy = np.random.randint(
|
|
low=-(2**31), high=2**31, size=[3, 4, 5], dtype="int32"
|
|
)
|
|
self.input_var_numpy = paddle.to_tensor(self.input_var_numpy)
|
|
self.dtype = "int32"
|
|
self.y = np.random.randint(
|
|
low=-(2**31), high=2**31, size=[3, 4, 5], dtype="int32"
|
|
)
|
|
self.y = paddle.to_tensor(self.y)
|
|
self.is_arithmetic = True
|
|
|
|
def inplace_api_processing(self, var):
|
|
return paddle.bitwise_right_shift_(var, self.y, self.is_arithmetic)
|
|
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.bitwise_right_shift_(var, self.y, self.is_arithmetic)
|
|
|
|
def test_broadcast_error(self):
|
|
broadcast_input = paddle.randn([4, 5])
|
|
with self.assertRaises(ValueError):
|
|
self.inplace_api_processing(broadcast_input)
|
|
|
|
|
|
class TestDygraphInplaceBitwiseLeftShift_logic(TestDygraphInplaceLogicAnd):
|
|
def init_data(self):
|
|
self.input_var_numpy = np.random.randint(
|
|
low=-(2**31), high=2**31, size=[3, 4, 5], dtype="int32"
|
|
)
|
|
self.input_var_numpy = paddle.to_tensor(self.input_var_numpy)
|
|
self.dtype = "int32"
|
|
self.y = np.random.randint(
|
|
low=-(2**31), high=2**31, size=[3, 4, 5], dtype="int32"
|
|
)
|
|
self.y = paddle.to_tensor(self.y)
|
|
self.is_arithmetic = False
|
|
|
|
def inplace_api_processing(self, var):
|
|
return paddle.bitwise_left_shift_(var, self.y, self.is_arithmetic)
|
|
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.bitwise_left_shift(var, self.y, self.is_arithmetic)
|
|
|
|
def test_broadcast_error(self):
|
|
broadcast_input = paddle.randn([4, 5])
|
|
with self.assertRaises(ValueError):
|
|
self.inplace_api_processing(broadcast_input)
|
|
|
|
|
|
class TestDygraphInplaceBitwiseRightShift_logic(TestDygraphInplaceLogicAnd):
|
|
def init_data(self):
|
|
self.input_var_numpy = np.random.randint(
|
|
low=-(2**31), high=2**31, size=[3, 4, 5], dtype="int32"
|
|
)
|
|
self.input_var_numpy = paddle.to_tensor(self.input_var_numpy)
|
|
self.dtype = "int32"
|
|
self.y = np.random.randint(
|
|
low=-(2**31), high=2**31, size=[3, 4, 5], dtype="int32"
|
|
)
|
|
self.y = paddle.to_tensor(self.y)
|
|
self.is_arithmetic = False
|
|
|
|
def inplace_api_processing(self, var):
|
|
return paddle.bitwise_right_shift_(var, self.y, self.is_arithmetic)
|
|
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.bitwise_right_shift_(var, self.y, self.is_arithmetic)
|
|
|
|
def test_broadcast_error(self):
|
|
broadcast_input = paddle.randn([4, 5])
|
|
with self.assertRaises(ValueError):
|
|
self.inplace_api_processing(broadcast_input)
|
|
|
|
|
|
class TestDygraphInplaceIndexFill(TestDygraphInplace):
|
|
def init_data(self):
|
|
self.input_var_numpy = np.random.random((20, 40))
|
|
self.dtype = "float32"
|
|
self.axis = 1
|
|
self.index = paddle.to_tensor([0, 2])
|
|
self.value = -1
|
|
|
|
def _use_kernel_path(self):
|
|
"""Check if using C++ kernel path (version +1) or fallback path (version +3)"""
|
|
return (
|
|
paddle.is_compiled_with_cuda()
|
|
or paddle.device.get_device().startswith('cpu')
|
|
)
|
|
|
|
def inplace_api_processing(self, var):
|
|
return paddle.index_fill_(var, self.index, self.axis, self.value)
|
|
|
|
def non_inplace_api_processing(self, var):
|
|
return paddle.index_fill(var, self.index, self.axis, self.value)
|
|
|
|
def test_forward_version(self):
|
|
with paddle.base.dygraph.guard():
|
|
var = paddle.to_tensor(self.input_var_numpy).astype(self.dtype)
|
|
self.assertEqual(var.inplace_version, 0)
|
|
|
|
version_delta = 1 if self._use_kernel_path() else 3
|
|
|
|
inplace_var = self.inplace_api_processing(var)
|
|
self.assertEqual(var.inplace_version, version_delta)
|
|
|
|
inplace_var[0] = 2
|
|
self.assertEqual(var.inplace_version, version_delta + 1)
|
|
|
|
inplace_var = self.inplace_api_processing(inplace_var)
|
|
self.assertEqual(var.inplace_version, 2 * version_delta + 1)
|
|
|
|
def test_backward_error(self):
|
|
with paddle.base.dygraph.guard():
|
|
var_a = paddle.to_tensor(self.input_var_numpy).astype(self.dtype)
|
|
var_a.stop_gradient = False
|
|
|
|
var_b = var_a**2
|
|
|
|
version_delta = 1 if self._use_kernel_path() else 3
|
|
|
|
var_c = var_b**2
|
|
self.inplace_api_processing(var_b)
|
|
var_c = paddle.cast(var_c, "float32")
|
|
|
|
loss = paddle.nn.functional.relu(var_c)
|
|
with self.assertRaisesRegex(
|
|
RuntimeError,
|
|
f"received tensor_version:{version_delta} != wrapper_version_snapshot:{0}",
|
|
):
|
|
loss.backward()
|
|
|
|
|
|
class TestDygraphTensorApplyInplace(unittest.TestCase):
|
|
def setUp(self):
|
|
self.init_data()
|
|
self.set_np_compare_func()
|
|
|
|
def init_data(self):
|
|
self.input_var_numpy = np.random.uniform(-5, 5, [10, 20, 1])
|
|
self.dtype = "float32"
|
|
|
|
def set_np_compare_func(self):
|
|
self.np_compare = np.array_equal
|
|
|
|
def non_inplace_api_processing(self, var, f):
|
|
return var.apply(f)
|
|
|
|
def inplace_api_processing(self, var, f):
|
|
return var.apply_(f)
|
|
|
|
def test_inplace_api(self):
|
|
var = paddle.to_tensor(self.input_var_numpy, stop_gradient=True).astype(
|
|
self.dtype
|
|
)
|
|
f = lambda x: 3 * x + 2
|
|
non_inplace_var = self.non_inplace_api_processing(var, f)
|
|
inplace_var = self.inplace_api_processing(var, f)
|
|
self.assertTrue(id(var) == id(inplace_var))
|
|
np.testing.assert_array_equal(
|
|
non_inplace_var.numpy(), inplace_var.numpy()
|
|
)
|
|
|
|
|
|
class TestDygraphInplaceBernoulli(unittest.TestCase):
|
|
def setUp(self):
|
|
self.init_data()
|
|
self.set_np_compare_func()
|
|
|
|
def init_data(self):
|
|
self.shape = (100, 1000)
|
|
self.input_var_numpy = np.random.random(self.shape)
|
|
self.dtype = "float32"
|
|
self.p = 0.5
|
|
|
|
def set_np_compare_func(self):
|
|
self.np_compare = np.array_equal
|
|
|
|
def inplace_api_processing(self, var):
|
|
return paddle.bernoulli_(var, p=self.p)
|
|
|
|
def inplace_class_method_processing(self, var):
|
|
return var.bernoulli_(self.p)
|
|
|
|
def non_inplace_api_processing(self):
|
|
return paddle.bernoulli(paddle.full(self.shape, self.p))
|
|
|
|
def test_inplace_api(self):
|
|
var = paddle.to_tensor(self.input_var_numpy).astype(self.dtype)
|
|
non_inplace_var = self.non_inplace_api_processing()
|
|
inplace_var = self.inplace_api_processing(var)
|
|
self.assertTrue(id(var) == id(inplace_var))
|
|
np.testing.assert_allclose(
|
|
non_inplace_var.numpy().mean(),
|
|
inplace_var.numpy().mean(),
|
|
atol=0.01,
|
|
)
|
|
np.testing.assert_allclose(
|
|
non_inplace_var.numpy().var(), inplace_var.numpy().var(), atol=0.01
|
|
)
|
|
|
|
def test_inplace_api_backward(self):
|
|
var_a = paddle.to_tensor(self.input_var_numpy).astype(self.dtype)
|
|
var_a.stop_gradient = False
|
|
var_b = var_a.clone()
|
|
expected_gradient = np.zeros(self.shape)
|
|
inplace_var = self.inplace_api_processing(var_b)
|
|
inplace_var.backward()
|
|
np.testing.assert_equal(
|
|
var_a.grad.numpy(),
|
|
expected_gradient,
|
|
)
|
|
|
|
def test_inplace_class_method(self):
|
|
var = paddle.to_tensor(self.input_var_numpy).astype(self.dtype)
|
|
non_inplace_var = self.non_inplace_api_processing()
|
|
inplace_var = self.inplace_class_method_processing(var)
|
|
self.assertTrue(id(var) == id(inplace_var))
|
|
np.testing.assert_allclose(
|
|
non_inplace_var.numpy().mean(),
|
|
inplace_var.numpy().mean(),
|
|
atol=0.01,
|
|
)
|
|
np.testing.assert_allclose(
|
|
non_inplace_var.numpy().var(), inplace_var.numpy().var(), atol=0.01
|
|
)
|
|
|
|
def test_inplace_class_method_backward(self):
|
|
var_a = paddle.to_tensor(self.input_var_numpy).astype(self.dtype)
|
|
var_a.stop_gradient = False
|
|
var_b = var_a.clone()
|
|
expected_gradient = np.zeros(self.shape)
|
|
inplace_var = self.inplace_class_method_processing(var_b)
|
|
inplace_var.backward()
|
|
np.testing.assert_equal(
|
|
var_a.grad.numpy(),
|
|
expected_gradient,
|
|
)
|
|
|
|
|
|
class TestDygraphInplaceBernoulli2(TestDygraphInplaceBernoulli):
|
|
def init_data(self):
|
|
self.shape = (100, 1000)
|
|
self.input_var_numpy = np.random.random(self.shape)
|
|
self.dtype = "float64"
|
|
self.p = 0.5
|
|
|
|
|
|
class TestDygraphInplaceBernoulliError(unittest.TestCase):
|
|
def test_broadcast_error(self):
|
|
var = paddle.randn([3, 4])
|
|
p = paddle.randn([5])
|
|
with self.assertRaises(ValueError):
|
|
var.bernoulli_(p)
|
|
|
|
|
|
class TestDygraphInplaceSet(unittest.TestCase):
|
|
def setUp(self):
|
|
self.init_data()
|
|
self.places = get_places()
|
|
self.support_dtypes = [
|
|
'float32',
|
|
'float64',
|
|
'bool',
|
|
'int8',
|
|
'int16',
|
|
'int32',
|
|
'int64',
|
|
'uint8',
|
|
'complex64',
|
|
'complex128',
|
|
]
|
|
|
|
def init_data(self):
|
|
self.x_np = np.random.uniform(-5, 5, [7, 20, 2])
|
|
self.new_x_np = np.random.uniform(-5, 5, [15, 3])
|
|
self.dtype = "float32"
|
|
self.new_shape = [20]
|
|
self.new_stride = [2]
|
|
self.new_offset = 0
|
|
|
|
def non_inplace_api_processing(
|
|
self, x, new_x=None, shape=None, stride=None, offset=0
|
|
):
|
|
if new_x is None:
|
|
return paddle.empty([0], dtype=x.dtype)
|
|
if stride is None:
|
|
if shape is None:
|
|
stride = new_x.strides
|
|
else:
|
|
stride = paddle.empty(shape).strides
|
|
if shape is None:
|
|
shape = new_x.shape
|
|
return paddle.as_strided(new_x, shape, stride, offset)
|
|
|
|
def inplace_api_processing(
|
|
self, x, new_x=None, shape=None, stride=None, offset=0
|
|
):
|
|
return paddle.Tensor.set_(x, new_x, shape, stride, offset)
|
|
|
|
def test_inplace_api(self):
|
|
for dtype in self.support_dtypes:
|
|
for place in self.places:
|
|
with paddle.base.dygraph.guard(place):
|
|
x = paddle.to_tensor(self.x_np).astype(dtype)
|
|
new_x = paddle.to_tensor(self.new_x_np).astype(dtype)
|
|
inplace_x = self.inplace_api_processing(
|
|
x,
|
|
new_x,
|
|
self.new_shape,
|
|
self.new_stride,
|
|
self.new_offset,
|
|
)
|
|
self.assertTrue(id(x) == id(inplace_x))
|
|
self.assertTrue(x._is_shared_buffer_with(new_x))
|
|
|
|
def test_forward_result(self):
|
|
x = paddle.to_tensor(self.x_np).astype(self.dtype)
|
|
new_x = paddle.to_tensor(self.new_x_np).astype(self.dtype)
|
|
no_inplace_x1 = self.non_inplace_api_processing(x)
|
|
inplace_x1 = self.inplace_api_processing(x)
|
|
np.testing.assert_array_equal(no_inplace_x1.numpy(), inplace_x1.numpy())
|
|
|
|
x = paddle.to_tensor(self.x_np).astype(self.dtype)
|
|
new_x = paddle.to_tensor(self.new_x_np).astype(self.dtype)
|
|
no_inplace_x2 = self.non_inplace_api_processing(x, new_x=new_x)
|
|
inplace_x2 = self.inplace_api_processing(x, new_x=new_x)
|
|
np.testing.assert_array_equal(no_inplace_x2.numpy(), inplace_x2.numpy())
|
|
|
|
x = paddle.to_tensor(self.x_np).astype(self.dtype)
|
|
new_x = paddle.to_tensor(self.new_x_np).astype(self.dtype)
|
|
no_inplace_x3 = self.non_inplace_api_processing(
|
|
x, new_x=new_x, shape=self.new_shape
|
|
)
|
|
inplace_x3 = self.inplace_api_processing(
|
|
x, new_x=new_x, shape=self.new_shape
|
|
)
|
|
np.testing.assert_array_equal(no_inplace_x3.numpy(), inplace_x3.numpy())
|
|
|
|
x = paddle.to_tensor(self.x_np).astype(self.dtype)
|
|
new_x = paddle.to_tensor(self.new_x_np).astype(self.dtype)
|
|
no_inplace_x4 = self.non_inplace_api_processing(
|
|
x, new_x=new_x, stride=self.new_stride
|
|
)
|
|
inplace_x4 = self.inplace_api_processing(
|
|
x, new_x=new_x, stride=self.new_stride
|
|
)
|
|
np.testing.assert_array_equal(no_inplace_x4.numpy(), inplace_x4.numpy())
|
|
|
|
x = paddle.to_tensor(self.x_np).astype(self.dtype)
|
|
new_x = paddle.to_tensor(self.new_x_np).astype(self.dtype)
|
|
no_inplace_x5 = self.non_inplace_api_processing(
|
|
x, new_x=new_x, offset=self.new_offset
|
|
)
|
|
inplace_x5 = self.inplace_api_processing(
|
|
x, new_x=new_x, offset=self.new_offset
|
|
)
|
|
np.testing.assert_array_equal(no_inplace_x5.numpy(), inplace_x5.numpy())
|
|
|
|
x = paddle.to_tensor(self.x_np).astype(self.dtype)
|
|
new_x = paddle.to_tensor(self.new_x_np).astype(self.dtype)
|
|
no_inplace_x6 = self.non_inplace_api_processing(
|
|
x, new_x=new_x, shape=self.new_shape, stride=self.new_stride
|
|
)
|
|
inplace_x6 = self.inplace_api_processing(
|
|
x, new_x=new_x, shape=self.new_shape, stride=self.new_stride
|
|
)
|
|
np.testing.assert_array_equal(no_inplace_x6.numpy(), inplace_x6.numpy())
|
|
|
|
x = paddle.to_tensor(self.x_np).astype(self.dtype)
|
|
new_x = paddle.to_tensor(self.new_x_np).astype(self.dtype)
|
|
no_inplace_x7 = self.non_inplace_api_processing(
|
|
x, new_x=new_x, shape=self.new_shape, offset=self.new_offset
|
|
)
|
|
inplace_x7 = self.inplace_api_processing(
|
|
x, new_x=new_x, shape=self.new_shape, offset=self.new_offset
|
|
)
|
|
np.testing.assert_array_equal(no_inplace_x7.numpy(), inplace_x7.numpy())
|
|
|
|
x = paddle.to_tensor(self.x_np).astype(self.dtype)
|
|
new_x = paddle.to_tensor(self.new_x_np).astype(self.dtype)
|
|
no_inplace_x8 = self.non_inplace_api_processing(
|
|
x, new_x=new_x, stride=self.new_stride, offset=self.new_offset
|
|
)
|
|
inplace_x8 = self.inplace_api_processing(
|
|
x, new_x=new_x, stride=self.new_stride, offset=self.new_offset
|
|
)
|
|
np.testing.assert_array_equal(no_inplace_x8.numpy(), inplace_x8.numpy())
|
|
|
|
x = paddle.to_tensor(self.x_np).astype(self.dtype)
|
|
new_x = paddle.to_tensor(self.new_x_np).astype(self.dtype)
|
|
no_inplace_x9 = self.non_inplace_api_processing(
|
|
x,
|
|
new_x=new_x,
|
|
shape=self.new_shape,
|
|
stride=self.new_stride,
|
|
offset=self.new_offset,
|
|
)
|
|
inplace_x9 = self.inplace_api_processing(
|
|
x,
|
|
new_x=new_x,
|
|
shape=self.new_shape,
|
|
stride=self.new_stride,
|
|
offset=self.new_offset,
|
|
)
|
|
np.testing.assert_array_equal(no_inplace_x9.numpy(), inplace_x9.numpy())
|
|
|
|
def test_forward_version(self):
|
|
with paddle.base.dygraph.guard():
|
|
x = paddle.to_tensor(self.x_np).astype(self.dtype)
|
|
new_x = paddle.to_tensor(self.new_x_np).astype(self.dtype)
|
|
self.assertEqual(x.inplace_version, 0)
|
|
|
|
x = self.inplace_api_processing(x, new_x=new_x)
|
|
self.assertEqual(x.inplace_version, 1)
|
|
|
|
x = self.inplace_api_processing(x)
|
|
self.assertEqual(x.inplace_version, 2)
|
|
self.assertEqual(x.get_strides(), [1])
|
|
|
|
x = self.inplace_api_processing(x, new_x=new_x)
|
|
self.assertEqual(x.inplace_version, 3)
|
|
|
|
def test_leaf_inplace_var_error(self):
|
|
with paddle.base.dygraph.guard():
|
|
x = paddle.to_tensor(self.x_np).astype(self.dtype)
|
|
x.stop_gradient = False
|
|
|
|
def leaf_inplace_error():
|
|
self.inplace_api_processing(x)
|
|
|
|
self.assertRaises(ValueError, leaf_inplace_error)
|
|
|
|
|
|
@unittest.skipIf(
|
|
not (paddle.base.core.is_compiled_with_cuda() or is_custom_device())
|
|
or not paddle.base.core.is_float16_supported(get_device_place()),
|
|
"core is not compiled with CUDA and not support the float16",
|
|
)
|
|
class TestDygraphInplaceSetFP16(TestDygraphInplaceSet):
|
|
def setUp(self):
|
|
self.init_data()
|
|
self.places = get_places()
|
|
|
|
def init_data(self):
|
|
self.x_np = np.random.uniform(-5, 5, [7, 20, 2])
|
|
self.new_x_np = np.random.uniform(-5, 5, [6, 3])
|
|
self.dtype = "float16"
|
|
self.new_shape = [3, 8]
|
|
self.new_stride = [2, 2]
|
|
self.new_offset = 0
|
|
|
|
def test_inplace_api(self):
|
|
for place in self.places:
|
|
with paddle.base.dygraph.guard(place):
|
|
x = paddle.to_tensor(self.x_np).astype(self.dtype)
|
|
new_x = paddle.to_tensor(self.new_x_np).astype(self.dtype)
|
|
inplace_x = self.inplace_api_processing(
|
|
x, new_x, self.new_shape, self.new_stride, self.new_offset
|
|
)
|
|
self.assertTrue(id(x) == id(inplace_x))
|
|
self.assertTrue(x._is_shared_buffer_with(new_x))
|
|
|
|
|
|
@unittest.skipIf(
|
|
not (paddle.base.core.is_compiled_with_cuda() or is_custom_device())
|
|
or not paddle.base.core.is_bfloat16_supported(get_device_place()),
|
|
"core is not compiled with CUDA and not support the bfloat16",
|
|
)
|
|
class TestDygraphInplaceSetBF16(TestDygraphInplaceSet):
|
|
def setUp(self):
|
|
self.init_data()
|
|
self.places = get_places()
|
|
|
|
def init_data(self):
|
|
self.x_np = np.random.uniform(-5, 5, [7, 20, 2])
|
|
self.new_x_np = np.random.uniform(-5, 5, [6, 3])
|
|
self.dtype = "uint16"
|
|
self.new_shape = [3, 8]
|
|
self.new_stride = [2, 2]
|
|
self.new_offset = 0
|
|
|
|
def test_inplace_api(self):
|
|
for place in self.places:
|
|
with paddle.base.dygraph.guard(place):
|
|
x = paddle.to_tensor(self.x_np).astype(self.dtype)
|
|
new_x = paddle.to_tensor(self.new_x_np).astype(self.dtype)
|
|
inplace_x = self.inplace_api_processing(
|
|
x, new_x, self.new_shape, self.new_stride, self.new_offset
|
|
)
|
|
self.assertTrue(id(x) == id(inplace_x))
|
|
self.assertTrue(x._is_shared_buffer_with(new_x))
|
|
|
|
|
|
class TestDygraphInplaceResize(unittest.TestCase):
|
|
def setUp(self):
|
|
self.init_data()
|
|
self.places = get_places()
|
|
self.support_dtypes = [
|
|
'float32',
|
|
'float64',
|
|
'bool',
|
|
'int8',
|
|
'int16',
|
|
'int32',
|
|
'int64',
|
|
'uint8',
|
|
'complex64',
|
|
'complex128',
|
|
]
|
|
|
|
def init_data(self):
|
|
self.x_np = np.random.uniform(-5, 5, [3, 10, 2])
|
|
self.dtype = "float32"
|
|
self.new_shape1 = [20]
|
|
self.new_shape2 = [9, 11]
|
|
|
|
def non_inplace_api_processing(self, x, shape, fill_zero=False):
|
|
x = x.numpy().copy()
|
|
x.resize(shape, refcheck=False)
|
|
return paddle.to_tensor(x)
|
|
|
|
def inplace_api_processing(self, x, shape, fill_zero=False):
|
|
return paddle.Tensor.resize_(x, shape, fill_zero)
|
|
|
|
def test_inplace_api(self):
|
|
for dtype in self.support_dtypes:
|
|
for place in self.places:
|
|
with paddle.base.dygraph.guard(place):
|
|
x = paddle.to_tensor(self.x_np).astype(dtype)
|
|
inplace_x1 = self.inplace_api_processing(x, self.new_shape1)
|
|
self.assertTrue(id(x) == id(inplace_x1))
|
|
|
|
x = paddle.to_tensor(self.x_np).astype(dtype)
|
|
inplace_x2 = self.inplace_api_processing(x, self.new_shape2)
|
|
self.assertTrue(id(x) == id(inplace_x2))
|
|
|
|
def test_forward_result(self):
|
|
old_numel = np.prod(self.x_np.shape)
|
|
|
|
x = paddle.to_tensor(self.x_np).astype(self.dtype)
|
|
no_inplace_x1 = self.non_inplace_api_processing(x, self.new_shape1)
|
|
inplace_x1 = self.inplace_api_processing(x, self.new_shape1)
|
|
np.testing.assert_array_equal(no_inplace_x1.numpy(), inplace_x1.numpy())
|
|
|
|
x = paddle.to_tensor(self.x_np).astype(self.dtype)
|
|
no_inplace_x2 = self.non_inplace_api_processing(x, self.new_shape2)
|
|
inplace_x2 = self.inplace_api_processing(x, self.new_shape2)
|
|
np.testing.assert_array_equal(
|
|
no_inplace_x2.numpy().flatten()[:old_numel],
|
|
inplace_x2.numpy().flatten()[:old_numel],
|
|
)
|
|
|
|
x = paddle.to_tensor(self.x_np).astype(self.dtype)
|
|
no_inplace_x3 = self.non_inplace_api_processing(
|
|
x, self.new_shape1, fill_zero=True
|
|
)
|
|
inplace_x3 = self.inplace_api_processing(
|
|
x, self.new_shape1, fill_zero=True
|
|
)
|
|
np.testing.assert_array_equal(no_inplace_x3.numpy(), inplace_x3.numpy())
|
|
|
|
x = paddle.to_tensor(self.x_np).astype(self.dtype)
|
|
no_inplace_x2 = self.non_inplace_api_processing(
|
|
x, self.new_shape2, fill_zero=True
|
|
)
|
|
inplace_x2 = self.inplace_api_processing(
|
|
x, self.new_shape2, fill_zero=True
|
|
)
|
|
np.testing.assert_array_equal(no_inplace_x2.numpy(), inplace_x2.numpy())
|
|
|
|
def test_forward_version(self):
|
|
with paddle.base.dygraph.guard():
|
|
x = paddle.to_tensor(self.x_np).astype(self.dtype)
|
|
self.assertEqual(x.inplace_version, 0)
|
|
|
|
x = self.inplace_api_processing(x, self.new_shape1)
|
|
self.assertEqual(x.inplace_version, 1)
|
|
|
|
x = self.inplace_api_processing(x, self.new_shape2)
|
|
self.assertEqual(x.inplace_version, 2)
|
|
|
|
def test_leaf_inplace_var_error(self):
|
|
with paddle.base.dygraph.guard():
|
|
x = paddle.to_tensor(self.x_np).astype(self.dtype)
|
|
x.stop_gradient = False
|
|
|
|
def leaf_inplace_error():
|
|
self.inplace_api_processing(x, self.new_shape1)
|
|
|
|
self.assertRaises(ValueError, leaf_inplace_error)
|
|
|
|
def test_argument_error(self):
|
|
with paddle.base.dygraph.guard():
|
|
x = paddle.to_tensor(self.x_np).astype(self.dtype)
|
|
|
|
def argument_error():
|
|
self.inplace_api_processing(x, 2.0)
|
|
|
|
self.assertRaises(ValueError, argument_error)
|
|
|
|
|
|
@unittest.skipIf(
|
|
not (paddle.base.core.is_compiled_with_cuda() or is_custom_device())
|
|
or not paddle.base.core.is_float16_supported(get_device_place()),
|
|
"core is not compiled with CUDA and not support the float16",
|
|
)
|
|
class TestDygraphInplaceResizeFP16(TestDygraphInplaceResize):
|
|
def setUp(self):
|
|
self.init_data()
|
|
self.places = get_places()
|
|
|
|
def init_data(self):
|
|
self.x_np = np.random.uniform(-5, 5, [3, 10, 2])
|
|
self.dtype = "float16"
|
|
self.new_shape1 = [20]
|
|
self.new_shape2 = [8, 12]
|
|
|
|
def test_inplace_api(self):
|
|
for place in self.places:
|
|
with paddle.base.dygraph.guard(place):
|
|
x = paddle.to_tensor(self.x_np).astype(self.dtype)
|
|
inplace_x1 = self.inplace_api_processing(x, self.new_shape1)
|
|
self.assertTrue(id(x) == id(inplace_x1))
|
|
|
|
x = paddle.to_tensor(self.x_np).astype(self.dtype)
|
|
inplace_x2 = self.inplace_api_processing(x, self.new_shape2)
|
|
self.assertTrue(id(x) == id(inplace_x2))
|
|
|
|
|
|
@unittest.skipIf(
|
|
not (paddle.base.core.is_compiled_with_cuda() or is_custom_device())
|
|
or not paddle.base.core.is_bfloat16_supported(get_device_place()),
|
|
"core is not compiled with CUDA and not support the bfloat16",
|
|
)
|
|
class TestDygraphInplaceResizeBF16(TestDygraphInplaceResize):
|
|
def setUp(self):
|
|
self.init_data()
|
|
self.places = get_places()
|
|
|
|
def init_data(self):
|
|
self.x_np = np.random.uniform(-5, 5, [3, 10, 2])
|
|
self.dtype = "bfloat16"
|
|
self.new_shape1 = [15]
|
|
self.new_shape2 = [9, 11]
|
|
|
|
def test_inplace_api(self):
|
|
for place in self.places:
|
|
with paddle.base.dygraph.guard(place):
|
|
x = paddle.to_tensor(self.x_np).astype(self.dtype)
|
|
inplace_x1 = self.inplace_api_processing(x, self.new_shape1)
|
|
self.assertTrue(id(x) == id(inplace_x1))
|
|
|
|
x = paddle.to_tensor(self.x_np).astype(self.dtype)
|
|
inplace_x2 = self.inplace_api_processing(x, self.new_shape2)
|
|
self.assertTrue(id(x) == id(inplace_x2))
|
|
|
|
|
|
class TestSet_API_ZeroSize(unittest.TestCase):
|
|
def setUp(self):
|
|
self.places = get_places()
|
|
|
|
def test_zero_size_source_with_nonzero_shape(self):
|
|
"""When source is 0-size but user specifies non-zero dims/stride,
|
|
output should respect user-specified shape (matching PyTorch behavior).
|
|
Storage is expanded if needed to avoid out-of-bounds access."""
|
|
for place in self.places:
|
|
with paddle.base.dygraph.guard(place):
|
|
source = paddle.randn([0, 3])
|
|
x = paddle.randn([20])
|
|
out = x.set_(source, [20], [2])
|
|
self.assertEqual(list(out.shape), [20])
|
|
# contiguous should work without OOB
|
|
c = out.contiguous()
|
|
self.assertEqual(list(c.shape), [20])
|
|
|
|
def test_zero_size_source_default_args(self):
|
|
"""set_ with 0-size source and no explicit shape/stride."""
|
|
for place in self.places:
|
|
with paddle.base.dygraph.guard(place):
|
|
source = paddle.randn([0, 5])
|
|
x = paddle.randn([10])
|
|
out = x.set_(source)
|
|
self.assertEqual(out.numel().item(), 0)
|
|
self.assertEqual(list(out.shape), [0, 5])
|
|
self.assertTrue(id(x) == id(out))
|
|
|
|
def test_zero_size_x_nonzero_source(self):
|
|
"""set_ with 0-size x but non-zero source should work normally."""
|
|
for place in self.places:
|
|
with paddle.base.dygraph.guard(place):
|
|
source = paddle.to_tensor([1.0, 2.0, 3.0])
|
|
x = paddle.randn([0])
|
|
out = x.set_(source)
|
|
self.assertEqual(list(out.shape), [3])
|
|
self.assertTrue(x._is_shared_buffer_with(source))
|
|
|
|
def test_both_zero_size(self):
|
|
"""set_ with both x and source being 0-size."""
|
|
for place in self.places:
|
|
with paddle.base.dygraph.guard(place):
|
|
source = paddle.randn([0])
|
|
x = paddle.randn([0])
|
|
out = x.set_(source)
|
|
self.assertEqual(out.numel().item(), 0)
|
|
self.assertTrue(id(x) == id(out))
|
|
|
|
def test_both_zero_size_with_nonzero_shape(self):
|
|
"""Both x and source are 0-size but user specifies non-zero dims/stride.
|
|
This covers the branch that allocates zero-filled storage when both
|
|
tensors are empty but a non-zero output shape is requested."""
|
|
for place in self.places:
|
|
with paddle.base.dygraph.guard(place):
|
|
source = paddle.randn([0])
|
|
x = paddle.randn([0])
|
|
out = x.set_(source, [4], [1])
|
|
self.assertEqual(list(out.shape), [4])
|
|
self.assertTrue(id(x) == id(out))
|
|
# The allocated storage should be zero-filled and accessible
|
|
c = out.contiguous()
|
|
self.assertEqual(list(c.shape), [4])
|
|
np.testing.assert_array_equal(
|
|
c.numpy(), np.zeros([4], dtype='float32')
|
|
)
|
|
|
|
def test_both_zero_size_with_nonzero_shape_and_offset(self):
|
|
"""Both x and source are 0-size, user specifies non-zero shape with
|
|
a non-zero offset. Verifies storage is large enough to accommodate
|
|
the offset without out-of-bounds access."""
|
|
for place in self.places:
|
|
with paddle.base.dygraph.guard(place):
|
|
source = paddle.randn([0])
|
|
x = paddle.randn([0])
|
|
# offset must be a multiple of element size (4 bytes for
|
|
# float32) to avoid misaligned GPU memory access.
|
|
out = x.set_(source, [3], [2], 4)
|
|
self.assertEqual(list(out.shape), [3])
|
|
self.assertTrue(id(x) == id(out))
|
|
c = out.contiguous()
|
|
self.assertEqual(list(c.shape), [3])
|
|
np.testing.assert_array_equal(
|
|
c.numpy(), np.zeros([3], dtype='float32')
|
|
)
|
|
|
|
def test_both_zero_size_with_nonzero_2d_shape(self):
|
|
"""Both x and source are 0-size, user specifies a 2D non-zero shape.
|
|
Verifies multi-dimensional strided view is allocated correctly."""
|
|
for place in self.places:
|
|
with paddle.base.dygraph.guard(place):
|
|
source = paddle.randn([0, 0])
|
|
x = paddle.randn([0])
|
|
out = x.set_(source, [2, 3], [3, 1])
|
|
self.assertEqual(list(out.shape), [2, 3])
|
|
self.assertTrue(id(x) == id(out))
|
|
c = out.contiguous()
|
|
self.assertEqual(list(c.shape), [2, 3])
|
|
np.testing.assert_array_equal(
|
|
c.numpy(), np.zeros([2, 3], dtype='float32')
|
|
)
|
|
|
|
def test_zero_size_source_no_crash_on_contiguous(self):
|
|
"""Ensure contiguous() works correctly on a tensor
|
|
that was set_ with a 0-size source but user-specified shape."""
|
|
for place in self.places:
|
|
with paddle.base.dygraph.guard(place):
|
|
source = paddle.randn([0, 3])
|
|
x = paddle.randn([20])
|
|
out = x.set_(source, [20], [2])
|
|
# contiguous should produce a valid tensor with correct shape
|
|
c = out.contiguous()
|
|
self.assertEqual(list(c.shape), [20])
|
|
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|