Files
2026-07-13 12:40:42 +08:00

363 lines
10 KiB
Python

# 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 unittest
import numpy as np
from dygraph_to_static_utils import (
Dy2StTestBase,
enable_to_static_guard,
test_ast_only,
)
from ifelse_simple_func import (
dyfunc_with_if_else_early_return1,
dyfunc_with_if_else_early_return2,
)
import paddle
import paddle.jit.dy2static as _jst
from paddle.jit.dy2static.utils import func_to_source_code
np.random.seed(0)
# TODO(Aurelius): Currently, `to_static` don't support decorate the function
# that contains layers with initialized operation, like `fc = linear(10, 3)`.
# Because initialized ops will be added into program and be executed many times.
# The parameters are assumed to initialized outside of the function.
def simple_func(x, weight_numpy):
x = paddle.to_tensor(x)
w = paddle.to_tensor(weight_numpy)
y = paddle.matmul(x, w)
z = paddle.mean(y)
return z
def decorated_simple_func(x, weight_numpy):
x = paddle.to_tensor(x)
w = paddle.to_tensor(weight_numpy)
y = paddle.matmul(x, w)
z = paddle.mean(y)
return z
class StaticCode1:
def dyfunc_with_if_else(x_v, label=None):
loss = _jst.UndefinedVar('loss')
__return_1 = _jst.UndefinedVar('__return_1')
__return_0 = _jst.UndefinedVar('__return_0')
__return_value_0 = None
def get_args_0():
nonlocal x_v
return (x_v,)
def set_args_0(__args): # noqa: PYI063
nonlocal x_v
(x_v,) = __args
def true_fn_0():
nonlocal x_v
x_v = x_v - 1
return # noqa: PLR1711
def false_fn_0():
nonlocal x_v
x_v = x_v + 1
return # noqa: PLR1711
_jst.IfElse(
paddle.mean(x_v)[0] > 5,
true_fn_0,
false_fn_0,
get_args_0,
set_args_0,
('x_v',),
push_pop_names=None,
)
def get_args_1():
nonlocal __return_0, __return_1, __return_value_0, loss
return __return_0, __return_1, __return_value_0, loss
def set_args_1(__args): # noqa: PYI063
nonlocal __return_0, __return_1, __return_value_0, loss
__return_0, __return_1, __return_value_0, loss = __args
def true_fn_1():
nonlocal __return_0, __return_1, __return_value_0, loss
loss = paddle.nn.functional.cross_entropy(
x_v, label, reduction='none', use_softmax=False
)
__return_0 = _jst.create_bool_as_type(label is not None, True)
__return_value_0 = loss
return # noqa: PLR1711
def false_fn_1():
nonlocal __return_0, __return_1, __return_value_0, loss
__return_1 = _jst.create_bool_as_type(label is not None, True)
__return_value_0 = x_v
return # noqa: PLR1711
_jst.IfElse(
label is not None,
true_fn_1,
false_fn_1,
get_args_1,
set_args_1,
('__return_0', '__return_1', '__return_value_0', 'loss'),
push_pop_names=None,
)
return __return_value_0
class StaticCode2:
# TODO: Transform return statement
def dyfunc_with_if_else(x_v, label=None):
loss = _jst.UndefinedVar('loss')
__return_3 = _jst.UndefinedVar('__return_3')
__return_2 = _jst.UndefinedVar('__return_2')
__return_value_1 = None
def get_args_2():
nonlocal x_v
return (x_v,)
def set_args_2(__args): # noqa: PYI063
nonlocal x_v
(x_v,) = __args
def true_fn_2():
nonlocal x_v
x_v = x_v - 1
return # noqa: PLR1711
def false_fn_2():
nonlocal x_v
x_v = x_v + 1
return # noqa: PLR1711
_jst.IfElse(
paddle.mean(x_v)[0] > 5,
true_fn_2,
false_fn_2,
get_args_2,
set_args_2,
('x_v',),
push_pop_names=None,
)
def get_args_3():
nonlocal __return_2, __return_3, __return_value_1, loss
return __return_2, __return_3, __return_value_1, loss
def set_args_3(__args): # noqa: PYI063
nonlocal __return_2, __return_3, __return_value_1, loss
__return_2, __return_3, __return_value_1, loss = __args
def true_fn_3():
nonlocal __return_2, __return_3, __return_value_1, loss
loss = paddle.nn.functional.cross_entropy(
x_v, label, reduction='none', use_softmax=False
)
__return_2 = _jst.create_bool_as_type(label is not None, True)
__return_value_1 = loss
return # noqa: PLR1711
def false_fn_3():
nonlocal __return_2, __return_3, __return_value_1, loss
__return_3 = _jst.create_bool_as_type(label is not None, True)
__return_value_1 = x_v
return # noqa: PLR1711
_jst.IfElse(
label is not None,
true_fn_3,
false_fn_3,
get_args_3,
set_args_3,
('__return_2', '__return_3', '__return_value_1', 'loss'),
push_pop_names=None,
)
return __return_value_1
class NetWithError(paddle.nn.Layer):
__name__ = 'NetWithError'
def forward(self, x):
linear = paddle.nn.Linear(32, 64)
y = linear(x)
return y
class TestEnableDeclarative(Dy2StTestBase):
def setUp(self):
self.x = np.random.randn(30, 10, 32).astype('float32')
self.weight = np.random.randn(32, 64).astype('float32')
@test_ast_only
def test_raise_error(self):
net = paddle.jit.to_static(full_graph=True)(NetWithError())
with self.assertRaises(ValueError):
net(paddle.to_tensor(self.x))
def test_enable_disable_to_static(self):
static_output = paddle.jit.to_static(decorated_simple_func)(
self.x, self.weight
)
with enable_to_static_guard(False):
dygraph_output = paddle.jit.to_static(decorated_simple_func)(
self.x, self.weight
)
np.testing.assert_allclose(
static_output.numpy(),
dygraph_output.numpy(),
rtol=1e-05,
atol=1e-4,
)
class Net(paddle.nn.Layer):
def __init__(self):
super().__init__()
def forward(self, x):
return x + 1
class SwitchModeNet(paddle.nn.Layer):
def __init__(self):
super().__init__()
def forward(self, x):
return x + 1
def foo(self):
return True
def switch_mode_function():
return True
switch_mode_function = paddle.jit.to_static(full_graph=True)(
switch_mode_function
)
class TestFunctionTrainEvalMode(Dy2StTestBase):
@test_ast_only
def test_switch_mode(self):
switch_mode_function.eval()
switch_mode_function()
self.assertEqual(switch_mode_function._training, False)
_, partial_layer = switch_mode_function.program_cache.last()[-1]
self.assertEqual(partial_layer.training, False)
switch_mode_function.train()
switch_mode_function()
self.assertEqual(switch_mode_function._training, True)
_, partial_layer = switch_mode_function.program_cache.last()[-1]
self.assertEqual(partial_layer.training, True)
def test_raise_error(self):
net = paddle.jit.to_static(SwitchModeNet())
self.assertEqual(net.training, True)
with self.assertRaises(RuntimeError):
net.forward.eval()
net.eval()
self.assertEqual(net.training, False)
with self.assertRaises(RuntimeError):
paddle.jit.to_static(net.foo).train()
class TestIfElseEarlyReturn(Dy2StTestBase):
def test_ifelse_early_return1(self):
answer = np.zeros([2, 2]) + 1
static_func = paddle.jit.to_static(dyfunc_with_if_else_early_return1)
out = static_func()
if isinstance(out, paddle.Tensor):
np.testing.assert_allclose(
paddle.to_tensor(answer), out, rtol=1e-05
)
elif isinstance(out, tuple):
np.testing.assert_allclose(answer, out[0].numpy(), rtol=1e-05)
def test_ifelse_early_return2(self):
answer = np.zeros([2, 2]) + 3
static_func = paddle.jit.to_static(dyfunc_with_if_else_early_return2)
out = static_func()
if isinstance(out, paddle.Tensor):
np.testing.assert_allclose(
paddle.to_tensor(answer), out, rtol=1e-05
)
elif isinstance(out, tuple):
np.testing.assert_allclose(answer, out[0].numpy(), rtol=1e-05)
class TestRemoveCommentInDy2St(Dy2StTestBase):
def func_with_comment(self):
# Comment1
x = paddle.to_tensor([1, 2, 3])
# Comment2
# Comment3
y = paddle.to_tensor([4, 5, 6])
def test_remove_comment(self):
code_string = func_to_source_code(self.func_with_comment)
self.assertEqual('#' not in code_string, True)
class Obj:
def __init__(self):
pass
def func(self, x):
return x + 1
obj = Obj()
class Net2:
def __init__(self):
super().__init__()
self.layer1 = paddle.nn.Linear(10, 10)
def forward(self, data):
def func(ins, x, loss_fn):
x = ins.layer1(x)
return loss_fn(x)
def func1(x):
return paddle.jit.to_static(func)(self, x, obj.func)
return func1(data)
class TestParameterRecorder(Dy2StTestBase):
def test_recorder(self):
"""function calls nn.Layer case."""
net = Net()
x = paddle.randn([5, 10])
out = net.forward(x)
if __name__ == '__main__':
unittest.main()